From: stv Date: Mon, 9 Jul 2007 12:22:44 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: For_HDF~6 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=71963ac42b16eaeaa9f5bc14989a8efff77b5de9;p=modules%2Fgui.git *** empty log message *** --- diff --git a/src/Qtx/Qtx.cxx b/src/Qtx/Qtx.cxx index fd10d1724..db5c4d0b7 100755 --- a/src/Qtx/Qtx.cxx +++ b/src/Qtx/Qtx.cxx @@ -21,37 +21,72 @@ #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 +/*! + \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; - int l = len; const unsigned char* s = str; while ( len < 0 || res.length() < len ) { @@ -64,10 +99,15 @@ QString Qtx::toQString( const unsigned char* str, const int len ) 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; - int l = len; const unsigned short* s = str; while ( len < 0 || res.length() < len ) { @@ -81,32 +121,34 @@ QString Qtx::toQString( const unsigned short* str, const int len ) } /*! - Name: setTabOrder [static public] - Desc: Set tab order for specified list of widgets. Last parameter should be null pointer. -*/ + \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 ) @@ -123,132 +165,81 @@ 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; - - 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(); - - if ( srcWidth <= 0 ) - srcWidth = src->sizeHint().width(); + 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 ); + + 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 ( 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(); - - QObjectList delList; - - bool isPrevSep = true; - QObject* lastVis = 0; // last visible - for ( QObjectList::const_iterator it = objList.begin(); it != objList.end(); ++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() ) { - QObject* obj = *it; - if ( !obj || !obj->isWidgetType() ) - continue; - bool isSep = obj->inherits( "QToolBarSeparator" ); - if ( !isSep && !((QWidget*)obj)->isVisibleTo( toolbar ) ) - continue; - if ( isPrevSep && isSep ) - delList.append( obj ); - else - { - isPrevSep = isSep; - lastVis = obj; - } + QPoint pos = src->parentWidget()->mapFromGlobal( QPoint( x, y ) ); + x = pos.x(); + y = pos.y(); } - // remove last visible separator - if ( lastVis && lastVis->inherits( "QToolBarSeparator" ) ) - delList.append( lastVis ); - for ( QObjectList::iterator itr = delList.begin(); itr != delList.end(); ++itr ) - delete *itr; + 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 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( QWidget* wid, const bool recursive ) { @@ -260,7 +251,7 @@ void Qtx::simplifySeparators( QWidget* wid, const bool recursive ) return; QList toRemove; - for ( uint i = 1; i < items.count(); i++ ) + for ( int i = 1; i < items.count(); i++ ) { if ( items[i]->isSeparator() && items[i - 1]->isSeparator() ) toRemove.append( items[i] ); @@ -282,8 +273,17 @@ void Qtx::simplifySeparators( QWidget* wid, const bool recursive ) } /*! - 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 ) { @@ -301,21 +301,32 @@ bool Qtx::isParent( QObject* child, QObject* parent ) } /*! - Name: dir [static public] - Desc: Returns dir name or null string. + \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 ) { 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 ) { @@ -330,8 +341,12 @@ QString Qtx::file( const QString& path, bool withExt ) } /*! - 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, const bool full ) { @@ -339,9 +354,15 @@ QString Qtx::extension( const QString& path, const bool full ) } /*! - 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 ) { @@ -375,94 +396,99 @@ 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 ) - { + 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 ) { - return QDir().mkpath( dirPath ); + 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 ); - QFileInfoList anEntries = aDir.entryInfoList(); + 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; + continue; stat = stat && rmDir( inf.absoluteFilePath() ); - } - stat = stat && aDir.rmdir( thePath ); - } - return stat; + } + 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. + \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.toLatin1(), "rb" ); if ( !src ) - return false; + return false; /* we'll use temporary file */ char temp[512] = { '\0' }; QString dir = Qtx::dir( absName ); FILE* tgt = ::fopen( strcpy( temp, ::tempnam( dir.toLatin1(), "__x" ) ), "wb" ); if ( !tgt ) - return false; + return false; /* temp -> result of conversion */ const char CR = 0x0d; @@ -508,7 +534,7 @@ bool Qtx::dos2unix( const QString& absName ) break; /* converted ok */ } ::fclose( src ); - ::fclose( tgt ); + ::fclose( tgt ); /* rename temp -> src */ if ( !QFile::remove( absName ) ) @@ -518,8 +544,60 @@ 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 Pack the specified color into integer RGB set. + \param c unpacked color + \return packed color */ int Qtx::rgbSet( const QColor& c ) { @@ -527,8 +605,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 ) { @@ -536,8 +617,9 @@ 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) */ QColor Qtx::rgbSet( const int rgb ) { @@ -547,8 +629,11 @@ QColor Qtx::rgbSet( const int rgb ) } /*! - 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 ) { @@ -558,8 +643,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 ) { @@ -567,7 +655,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 ) @@ -586,10 +674,11 @@ QColor Qtx::scaleColor( const int index, const int min, const int max ) } /*! - 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, QList& lst ) +void Qtx::scaleColors( const int num, QColorList& lst ) { lst.clear(); for ( int i = 0; i < num; i++ ) @@ -597,8 +686,9 @@ void Qtx::scaleColors( const int num, QList& lst ) } /*! - Name: grayscale [static public] - Desc: Convert color image to grayscale image. + \brief Convert given image to the grayscale format. + \param img initial image + \return converted to the grayscale image */ QImage Qtx::grayscale( const QImage& img ) { @@ -626,8 +716,9 @@ QImage Qtx::grayscale( const QImage& img ) } /*! - Name: grayscale [static public] - Desc: Convert color pixmap to grayscale pixmap. + \brief Convert given pixmap to the grayscale format. + \param pix initial pixmap + \return converted to the grayscale pixmap */ QPixmap Qtx::grayscale( const QPixmap& pix ) { @@ -637,8 +728,11 @@ QPixmap Qtx::grayscale( const QPixmap& pix ) } /*! - Name: transparentImage [static public] - Desc: Create transparent image with specified width \aw, height \ah and color depth \ad. + \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 ) { @@ -671,8 +765,11 @@ QImage Qtx::transparentImage( const int w, const int h, const int d ) } /*! - Name: transparentPixmap [static public] - Desc: Create transparent pixmap with specified width \aw, height \ah and color depth \ad. + \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 ) { @@ -684,10 +781,17 @@ QPixmap Qtx::transparentPixmap( const int w, const int h, const int d ) } /*! - Name: composite [static public] - Desc: Create composite pixmap. Pixmap 'pix' draws over pixmap 'dest' with coordinates - specified relative upper left corner of 'dest'. If 'dest' not given then new empty - pixmap with appropriate size created. + \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 ) { diff --git a/src/Qtx/Qtx.h b/src/Qtx/Qtx.h index 066847e9a..845e28c13 100755 --- a/src/Qtx/Qtx.h +++ b/src/Qtx/Qtx.h @@ -22,18 +22,14 @@ #ifndef QTX_H #define QTX_H -#if defined QTX_EXPORTS #if defined WIN32 -#define QTX_EXPORT _declspec( dllexport ) +# if defined QTX_EXPORTS +# define QTX_EXPORT _declspec( dllexport ) +# else +# define QTX_EXPORT _declspec( dllimport ) +# endif #else -#define QTX_EXPORT -#endif -#else -#if defined WIN32 -#define QTX_EXPORT _declspec( dllimport ) -#else -#define QTX_EXPORT -#endif +# define QTX_EXPORT #endif #if defined SOLARIS @@ -42,102 +38,97 @@ #define true 1 #endif -#define QT_VER 4 - -#include +#include +#include +#include +#include +#include -#include -#include -#include - -class QMenu; class QObject; -class QString; class QWidget; -class QToolBar; - -template class QList; - -typedef QList QIntList; -typedef QList QShortList; -typedef QList QDoubleList; +class QCompleter; -/*! - \class Qtx - \brief Set of auxiliary static methods -*/ +typedef QList QIntList; //!< list of int values +typedef QList QShortList; //!< list of short int values +typedef QList QDoubleList; //!< list of double values +typedef QList QColorList; //!< list of colors -#ifndef QT_MOC_RUN class QTX_EXPORT Qtx -#else -class QTX_EXPORT Qtx : public Qt -#endif { public: - enum AlignmentFlags + //! Widget alignment flags + typedef enum { - AlignLeft = Qt::AlignLeft, - AlignLeading = Qt::AlignLeading, - AlignRight = Qt::AlignRight, - AlignTrailing = Qt::AlignTrailing, - AlignHCenter = Qt::AlignHCenter, - AlignJustify = Qt::AlignJustify, - AlignAbsolute = Qt::AlignAbsolute, - AlignHorizontal_Mask = Qt::AlignHorizontal_Mask, - - AlignTop = Qt::AlignTop, - AlignBottom = Qt::AlignBottom, - AlignVCenter = Qt::AlignVCenter, - AlignVertical_Mask = Qt::AlignVertical_Mask, - - AlignCenter = Qt::AlignCenter, - - AlignOutLeft = Qt::AlignVCenter << 2, - AlignOutRight = AlignOutLeft << 2, - AlignOutTop = AlignOutRight << 2, - AlignOutBottom = AlignOutTop << 2 - }; - - static QString toQString( const char*, const int = -1 ); - static QString toQString( const short*, const int = -1 ); - static QString toQString( const unsigned char*, const int = -1 ); - static QString toQString( const unsigned short*, const int = -1 ); - - static void setTabOrder( QWidget*, ... ); - static void setTabOrder( const QWidgetList& ); - static void alignWidget( QWidget*, const QWidget*, const int ); - -// static void simplifySeparators( QToolBar* ); - static void simplifySeparators( QWidget*, const bool = true ); - - static bool isParent( QObject*, QObject* ); - - static QString dir( const QString&, const bool = true ); - static QString file( const QString&, const bool = true ); - static QString extension( const QString&, const bool = false ); - - static QString library( const QString& ); - - static QString tmpDir(); - static bool mkDir( const QString& ); - static bool rmDir( const QString& ); - static bool dos2unix( const QString& ); - static QString addSlash( const QString& ); - - static int rgbSet( const QColor& ); - static int rgbSet( const int, const int, const int ); - - static QColor rgbSet( const int ); - static void rgbSet( const int, int&, int&, int& ); - - static QColor scaleColor( const int, const int, const int ); - static void scaleColors( const int, QList& ); - - static QImage grayscale( const QImage& ); - static QPixmap grayscale( const QPixmap& ); - static QImage transparentImage( const int, const int, const int = -1 ); - static QPixmap transparentPixmap( const int, const int, const int = -1 ); - static QPixmap composite( const QPixmap&, const int, const int, const QPixmap& = QPixmap() ); + AlignLeft = Qt::AlignLeft, //!< align left side of one widget to the left side of another widget + AlignLeading = Qt::AlignLeading, //!< synonim for AlignLeft + AlignRight = Qt::AlignRight, //!< align right side of one widget to the right side of another widget + AlignTrailing = Qt::AlignTrailing, //!< synonim for AlignRight + AlignHCenter = Qt::AlignHCenter, //!< align one widget to the center of another widget in horizontal dimension + AlignJustify = Qt::AlignJustify, //!< synonym of Qt::AlignJustify + AlignAbsolute = Qt::AlignAbsolute, //!< synonym of Qt::AlignAbsolute + AlignHorizontal_Mask = Qt::AlignHorizontal_Mask, //!< synonym of Qt::AlignHorizontal_Mask + + AlignTop = Qt::AlignTop, //!< align top side of one widget to the top side of another widget + AlignBottom = Qt::AlignBottom, //!< align bottom side of one widget to the bottom side of another widget + AlignVCenter = Qt::AlignVCenter, //!< align one widget to the center of another widget in vertical dimension + AlignVertical_Mask = Qt::AlignVertical_Mask, //!< synonym of Qt::AlignVertical_Mask + + AlignCenter = Qt::AlignCenter, //!< align one widget to the center of another widget in both dimensions + + AlignOutLeft = Qt::AlignVCenter << 2, //!< align right side of one widget to the left side of another widget + AlignOutRight = AlignOutLeft << 2, //!< align left side of one widget to the right side of another widget + AlignOutTop = AlignOutRight << 2, //!< align bottom side of one widget to the top side of another widget + AlignOutBottom = AlignOutTop << 2 //!< align top side of one widget to the bottom side of another widget + } AlignmentFlags; + + //! Path type, indicates required directory/file operation + typedef enum { + PT_OpenFile, //!< the file is opened + PT_SaveFile, //!< the file is saved + PT_Directory //!< the directory path is required + } PathType; + + static QString toQString( const char*, const int = -1 ); + static QString toQString( const short*, const int = -1 ); + static QString toQString( const unsigned char*, const int = -1 ); + static QString toQString( const unsigned short*, const int = -1 ); + + static void setTabOrder( QWidget*, ... ); + static void setTabOrder( const QWidgetList& ); + static void alignWidget( QWidget*, const QWidget*, const int ); + + static void simplifySeparators( QWidget*, const bool = true ); + + static bool isParent( QObject*, QObject* ); + + static QString dir( const QString&, const bool = true ); + static QString file( const QString&, const bool = true ); + static QString extension( const QString&, const bool = false ); + + static QString library( const QString& ); + + static QString tmpDir(); + static bool mkDir( const QString& ); + static bool rmDir( const QString& ); + static bool dos2unix( const QString& ); + static QString addSlash( const QString& ); + + static QCompleter* pathCompleter( const PathType, const QString& = QString() ); + + static int rgbSet( const QColor& ); + static int rgbSet( const int, const int, const int ); + + static QColor rgbSet( const int ); + static void rgbSet( const int, int&, int&, int& ); + + static QColor scaleColor( const int, const int, const int ); + static void scaleColors( const int, QColorList& ); + + static QImage grayscale( const QImage& ); + static QPixmap grayscale( const QPixmap& ); + static QImage transparentImage( const int, const int, const int = -1 ); + static QPixmap transparentPixmap( const int, const int, const int = -1 ); + static QPixmap composite( const QPixmap&, const int, const int, const QPixmap& = QPixmap() ); }; #endif diff --git a/src/Qtx/QtxAction.cxx b/src/Qtx/QtxAction.cxx index 9da4b3417..1e46ce16d 100755 --- a/src/Qtx/QtxAction.cxx +++ b/src/Qtx/QtxAction.cxx @@ -21,144 +21,182 @@ #include "QtxAction.h" -#include -#include -#include -#include +#include +#include +#include /*! - Name: QtxAction [public] - Desc: Constructs an action with given parent and name. If toggle is true the - action will be a toggle action, otherwise it will be a command action. + \class QtxAction::ActionNotify + \brief Notify event used to signalize about event adding/removing. + \internal */ -QtxAction::QtxAction( QObject* parent, const char* name, bool toggle ) -: QAction( parent ) +class QtxAction::ActionNotify : public QEvent +{ +public: + ActionNotify( bool add, QWidget* wid ) : QEvent( QEvent::User ), myAdd( add ), myWidget( wid ) {}; + ~ActionNotify() {}; + + bool isAdded() const { return myAdd; } + QWidget* widget() const { return myWidget; } + +private: + bool myAdd; + QWidget* myWidget; +}; + +/*! + \class QtxAction + \brief Generic action class. + + The class QtxAction inherits QWidgetAction class and can be used + as base class when implementing any custom menu/toolbar actions. + It is necessary to subclass from QtxAction and redefine virtual + callback methods addedTo(), removedFrom() (which are called automatically + when the action is added to the widget and removed from it) to customize + the action behavior. +*/ + +/*! + \brief Constructor. + + Creates an action owned by \a parent. + Parameter \a toggle can be used to make the action checkable. + + \param parent parent object + \param toggle if \c true the action will be a toggle action +*/ +QtxAction::QtxAction( QObject* parent, bool toggle ) +: QWidgetAction( parent ) { - setObjectName( name ); setCheckable( toggle ); QApplication::instance()->installEventFilter( this ); } /*! - Name: QtxAction [public] - Desc: This constructor creates an action with the following properties: the - description text, the icon or iconset icon, the menu text and keyboard - accelerator. It is a child of given parent and named specified name. - If toggle is true the action will be a toggle action, otherwise it will - be a command action. + \brief Constructor. + + Creates an action owned by \a parent. Parameters \a text, + \a icon, \a menuText and \a accel specify the action's attributes. + Parameter \a toggle can be used to make the action checkable. + + \param text tooltip text + \param icon iconset + \param menuText menu text + \param accel shortcut key sequence + \param parent parent object + \param toggle if \c true the action will be a toggle action */ - QtxAction::QtxAction( const QString& text, const QIcon& icon, - const QString& menuText, int accel, - QObject* parent, const char* name, bool toggle ) -: QAction( icon, menuText, parent ) + const QString& menuText, int accel, QObject* parent, bool toggle ) +: QWidgetAction( parent ) { + setIcon( icon ); + setText( menuText ); setToolTip( text ); setShortcut( accel ); - setObjectName( name ); setCheckable( toggle ); QApplication::instance()->installEventFilter( this ); } /*! - Name: QtxAction [public] - Desc: This constructor creates an action with the following properties: the - description text, the menu text and keyboard accelerator. It is a child - of given parent and named specified name. If toggle is true the action - will be a toggle action, otherwise it will be a command action. -*/ + \brief Constructor. -QtxAction::QtxAction( const QString& text, const QString& menuText, int accel, - QObject* parent, const char* name, bool toggle ) -: QAction( menuText, parent ) + Creates an action owned by \a parent. Parameters \a text, + \a menuText and \a accel specify the action's attributes. + Parameter \a toggle can be used to make the action checkable. + + \param text tooltip text + \param menuText menu text + \param accel shortcut key sequence + \param parent parent object + \param toggle if \c true the action is a toggle action +*/ +QtxAction::QtxAction( const QString& text, const QString& menuText, + int accel, QObject* parent, bool toggle ) +: QWidgetAction( parent ) { + setText( menuText ); setToolTip( text ); setShortcut( accel ); - setObjectName( name ); setCheckable( toggle ); QApplication::instance()->installEventFilter( this ); } /*! - Name: ~QtxAction [virtual public] - Desc: Destructor. + \brief Destructor. */ - QtxAction::~QtxAction() { } +/*! + \brief Customize action events. + + Sends a notification event to the action when it is added to + the widget or removed from it in order to perform custom processing. + + \param o object + \param e event + \return \c true if further event processing should be stopped + \sa customEvent(), addedTo(), removedFrom() +*/ bool QtxAction::eventFilter( QObject* o, QEvent* e ) { if ( o && o->isWidgetType() ) { if ( e->type() == QEvent::ActionAdded && ((QActionEvent*)e)->action() == this ) - addedTo( (QWidget*)o ); + QApplication::postEvent( this, new ActionNotify( true, (QWidget*)o ) ); if ( e->type() == QEvent::ActionRemoved && ((QActionEvent*)e)->action() == this ) - removedFrom( (QWidget*)o ); + QApplication::postEvent( this, new ActionNotify( false, (QWidget*)o ) ); } - return QAction::eventFilter( o, e ); + return QWidgetAction::eventFilter( o, e ); } /*! - Name: addTo [virtual public] - Desc: Adds this action to widget. Returns true if the action was added - successfully and false otherwise. -*/ + \brief Called when the action is added to the widget. -bool QtxAction::addTo( QWidget* w ) -{ - if ( !w ) - return false; - - w->addAction( this ); - return true; -} + This method can be redefined in the subclasses to customize + the action behavior. Base implementation does nothing. -/*! - Name: addTo [virtual public] - Desc: Adds this action to widget. If widget is QPopupMenu given index will - be used for menu item inserting. Returns true if the action was added - successfully and false otherwise. + \param w widget (should be menu or toolbar) + \sa removedFrom() */ - -bool QtxAction::addTo( QWidget* w, const int index ) +void QtxAction::addedTo( QWidget* /*w*/ ) { - if ( !w ) - return false; - - QAction* b = 0; - if ( 0 <= index && index < w->actions().count() ) - b = w->actions().at( index ); - - w->insertAction( b, this ); - - return true; } /*! - Name: removeFrom [virtual public] - Desc: Removes this action from widget. Returns true if the action was removed - successfully and false otherwise. -*/ - -bool QtxAction::removeFrom( QWidget* w ) -{ - if ( !w ) - return false; + \brief Called when the action is removed from the widget. - w->removeAction( this ); - return true; -} + This method can be redefined in the subclasses to customize + the action behavior. Base implementation does nothing. -void QtxAction::addedTo( QWidget* ) + \param w widget (should be menu or toolbar) + \sa addedTo() +*/ +void QtxAction::removedFrom( QWidget* /*w*/ ) { } -void QtxAction::removedFrom( QWidget* ) +/*! + \brief Process notification events. + + Calls addedTo() method when the action is added to the widget + and removedFrom() when it is removed from the widget + in order to perform custom processing. + + \param e noification event + \sa eventFilter(), addedTo(), removedFrom() +*/ +void QtxAction::customEvent( QEvent* e ) { + ActionNotify* ae = (ActionNotify*)e; + if ( ae->isAdded() ) + addedTo( ae->widget() ); + else + removedFrom( ae->widget() ); } diff --git a/src/Qtx/QtxAction.h b/src/Qtx/QtxAction.h index fa184e2c3..c1a206110 100755 --- a/src/Qtx/QtxAction.h +++ b/src/Qtx/QtxAction.h @@ -16,7 +16,7 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File: QtxAction.hxx +// File: QtxAction.h // Author: Sergey TELKOV #ifndef QTXACTION_H @@ -24,35 +24,33 @@ #include "Qtx.h" -#include -#include -#include +#include + +class QIcon; #ifdef WIN32 #pragma warning ( disable:4251 ) #endif -class QMenu; - -class QTX_EXPORT QtxAction : public QAction +class QTX_EXPORT QtxAction : public QWidgetAction { Q_OBJECT + class ActionNotify; + public: - QtxAction( QObject* = 0, const char* = 0, bool = false ); - QtxAction( const QString&, const QString&, int, QObject*, const char* = 0, bool = false ); - QtxAction( const QString&, const QIcon&, const QString&, int, QObject*, const char* = 0, bool = false ); + QtxAction( QObject* = 0, bool = false ); + QtxAction( const QString&, const QString&, int, QObject*, bool = false ); + QtxAction( const QString&, const QIcon&, const QString&, int, QObject*, bool = false ); virtual ~QtxAction(); virtual bool eventFilter( QObject*, QEvent* ); - virtual bool addTo( QWidget* ); - virtual bool addTo( QWidget*, const int ); - virtual bool removeFrom( QWidget* ); - protected: virtual void addedTo( QWidget* ); virtual void removedFrom( QWidget* ); + + virtual void customEvent( QEvent* ); }; #ifdef WIN32 diff --git a/src/Qtx/QtxActionMenuMgr.cxx b/src/Qtx/QtxActionMenuMgr.cxx index 78a3f5826..f3b42a46d 100644 --- a/src/Qtx/QtxActionMenuMgr.cxx +++ b/src/Qtx/QtxActionMenuMgr.cxx @@ -17,298 +17,142 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File: QtxActionMenuMgr.cxx -// Author: Alexander SOLOVYEV, Sergey TELKOV +// Author: Alexander SOLOVYOV, Sergey TELKOV #include "QtxActionMenuMgr.h" #include "QtxAction.h" -#include -#include - -#include -#include -#include -#include - -#include - -// VSR: Uncomment this #define in order to allow dynamic menus support -// (emit signals when popup menu is pre-activated) -// Currently this support is disabled. -//#define ENABLE_DYNAMIC_MENU +#include +#include +#include +#include /*! - Service functions - Level: Internal -*/ -namespace { -/* - QList prepareIds( const QWidget* w ) - { - QList l; - const QMenuData* md = 0; - if ( w->inherits( "QMenuBar" ) ) - md = ::qt_cast( w ); - else if ( w->inherits( "QPopupMenu" ) ) - md = ::qt_cast( w ); - if ( md ) - { - for ( uint i = 0; i < md->count(); i++ ) - l.append( md->idAt( i ) ); - } - return l; - } - - int getNewId( const QWidget* w, const QValueList& l, bool retId = true ) - { - const QMenuData* md = 0; - if ( w->inherits( "QMenuBar" ) ) - md = ::qt_cast( w ); - else if ( w->inherits( "QPopupMenu" ) ) - md = ::qt_cast( w ); - if ( md ) - { - for ( uint i = 0, j = 0; i < md->count() && j < l.count(); i++, j++ ) - if ( md->idAt( i ) != l[ j ] ) - return retId ? md->idAt( i ) : i; - if ( md->count() > l.count() ) - return retId ? md->idAt( md->count()-1 ) : md->count() - 1; - } - return -1; - } - - void dumpMenu( QWidget* w, bool before ) - { - if ( !w ) - return; - - QMenuData* md = 0; - if ( w->inherits( "QMenuBar" ) ) - md = ::qt_cast( w ); - else if ( w->inherits( "QPopupMenu" ) ) - md = ::qt_cast( w ); - - if ( !md ) - return; - - printf( ">>> start dump menu (%s) >>>\n", before ? "before" : "after" ); - for ( uint i = 0; i < md->count(); i++ ) - printf( "%d: %d: %s\n", i, md->idAt( i ), md->text( md->idAt( i ) ).latin1() ); - printf( "<<< end dump menu (%s) <<<\n", before ? "before" : "after" ); - } + \class QtxActionMenuMgr::MenuNode + \brief Represents a menu item inside main menu structure. + \internal */ -}; -/*! - Class: QtxActionMenuMgr::MenuAction - Level: Internal -*/ - -class QtxActionMenuMgr::MenuAction : public QtxAction +class QtxActionMenuMgr::MenuNode { public: - MenuAction( const QString&, const QString&, QObject*, const int = -1, const bool = false ); - virtual ~MenuAction(); - -private: - int myId; - bool myEmptyEnabled; + MenuNode(); + MenuNode( MenuNode*, const int, const int, const int ); + ~MenuNode(); + + MenuNode* parent; //!< parent menu node + int id; //!< menu nodeID + int idx; //!< menu node index + int group; //!< menu group ID + bool visible; //!< visibility status + NodeList children; //!< children menu nodes list }; /*! - Constructor for menu action - \param text - description text - \param menutext - menu text - \param parent - parent object - \param id - integer identificator of action - \param allowEmpty - if it is true, it makes possible to add this action with empty popup to menu -*/ -/* -QtxActionMenuMgr::MenuAction::MenuAction( const QString& text, const QString& menuText, - QObject* parent, const int id, const bool allowEmpty ) -: QtxAction( text, menuText, 0, parent ), -myId( id ), -myPopup( 0 ), -myEmptyEnabled( allowEmpty ) + \brief Default constructor. + \internal +*/ +QtxActionMenuMgr::MenuNode::MenuNode() +: parent( 0 ), id( -1 ), idx( -1 ), group( -1 ), visible( true ) { - myPopup = new QMenu(); } -*/ + /*! - Destructor: deletes internal popup -*/ -/* -QtxActionMenuMgr::MenuAction::~MenuAction() + \brief Constructor. + \internal + \param p parent menu node + \param _id menu node ID + \param _idx menu node index + \param _group menu node group ID +*/ +QtxActionMenuMgr::MenuNode::MenuNode( MenuNode* p, + const int _id, + const int _idx, + const int _group ) +: parent( p ), id( _id ), idx( _idx ), group( _group ), visible( true ) { - delete myPopup; + if ( p ) + p->children.append( this ); } -*/ + /*! - Adds action to widget, for example, to popup menu or menu bar + \brief Destructor. + \internal */ -/* -bool QtxActionMenuMgr::MenuAction::addTo( QWidget* w ) +QtxActionMenuMgr::MenuNode::~MenuNode() { - if ( !w ) - return false; // bad widget - - if ( !w->inherits( "QPopupMenu" ) && !w->inherits( "QMenuBar" ) ) - return false; // not allowed widget type - - if ( myIds.find( w ) != myIds.end() ) - return false; // already added - - if ( !myPopup ) - return false; // bad own popup menu - - if ( !myEmptyEnabled && !myPopup->actions().count() ) - return false; // not allowed empty menu - - if ( w->inherits( "QPopupMenu" ) ) - { - QValueList l = prepareIds( w ); - int idx; - if ( QtxAction::addTo( w ) && ( idx = getNewId( w, l, false ) ) != -1 ) - { - QPopupMenu* pm = (QPopupMenu*)w; - myIds[ w ] = pm->idAt( idx ); - if ( myId != -1 ) - pm->setId( idx, myId ); - setPopup( pm, myId != -1 ? myId : myIds[ w ], myPopup ); - } - } - else if ( w->inherits( "QMenuBar" ) ) - { - QValueList l = prepareIds( w ); - int idx; - if ( QtxAction::addTo( w ) && ( idx = getNewId( w, l, false ) ) != -1 ) - { - QMenuBar* mb = (QMenuBar*)w; - myIds[ w ] = mb->idAt( idx ); - if ( myId != -1 ) - mb->setId( idx, myId ); - setPopup( mb, myId != -1 ? myId : myIds[ w ], myPopup ); - } - - } - else - return false; - - return true; + for ( NodeList::iterator it = children.begin(); it != children.end(); ++it ) + delete *it; } -*/ /*! - Removes action from widget, for example, from popup menu or menu bar -*/ -/* -bool QtxActionMenuMgr::MenuAction::removeFrom( QWidget* w ) -{ - if ( !w ) - return false; // bad widget + \class QtxActionMenuMgr + \brief Main menu actions manager. - if ( !w->inherits( "QPopupMenu" ) && !w->inherits( "QMenuBar" ) ) - return false; // not allowed widget type + Menu manager allows using of set of action for automatic generating of + application main menu and dynamic update of its contents. - if ( myIds.find( w ) == myIds.end() ) - return false; // not yet added + Use insert(), append() and remove() methods to create main menu. + Methods show(), hide() allow displaying/erasing of specified menu items. - if ( w->inherits( "QPopupMenu" ) ) - { - if ( myId != -1 ) - { - QPopupMenu* pm = (QPopupMenu*)w; - int idx = pm->indexOf( myId ); - if ( idx != -1 ) - pm->setId( idx, myIds[ w ] ); - } - myIds.remove( w ); - return QtxAction::removeFrom( w );; - } - else if ( w->inherits( "QMenuBar" ) ) - { - if ( myId != -1 ) - { - QMenuBar* mb = (QMenuBar*)w; - int idx = mb->indexOf( myId ); - if ( idx != -1 ) - mb->setId( idx, myIds[ w ] ); - } - myIds.remove( w ); - return QtxAction::removeFrom( w ); - } - return false; -} -*/ + Actions can be grouped with help of group identificator. Inside the popup + or main menu bar menu items are ordered by the group identifier (ascending). -/*! - \return internal popup of action -*/ -/* -QMenu* QtxActionMenuMgr::MenuAction::popup() const -{ - return myPopup; -} + Menu manager automatically optimizes the menu by removing extra separators, + hiding empty popup menus etc. */ /*! - Class: QtxActionMenuMgr - Level: Public + \brief Constructor. + \param p parent main window */ QtxActionMenuMgr::QtxActionMenuMgr( QMainWindow* p ) -: QtxActionMgr( p ), -myMenu( p ? p->menuBar() : 0 ) +: QtxActionMgr( p ), + myRoot( new MenuNode() ), + myMenu( p ? p->menuBar() : 0 ) { - myRoot.id = -1; - myRoot.group = -1; - if ( myMenu ) { connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); -#ifdef ENABLE_DYNAMIC_MENU - if ( myMenu->inherits( "QMenuBar" ) ) - connect( myMenu, SIGNAL( highlighted( int ) ), this, SLOT( onHighlighted( int ) ) ); -#endif } } /*! - Constructor + \brief Constructor. + \param mw menu widget + \param p parent object */ QtxActionMenuMgr::QtxActionMenuMgr( QWidget* mw, QObject* p ) -: QtxActionMgr( p ), -myMenu( mw ) +: QtxActionMgr( p ), + myRoot( new MenuNode() ), + myMenu( mw ) { - myRoot.id = -1; - myRoot.group = -1; - - if ( myMenu ) + if ( myMenu ) { connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); + } } /*! - Destructor + \brief Destructor. */ QtxActionMenuMgr::~QtxActionMenuMgr() { - for ( NodeList::iterator it = myRoot.children.begin(); it != myRoot.children.end() && myMenu; ++it ) + for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr ) { - QAction* a = itemAction( (*it)->id ); - if ( !a ) - a = menuAction( (*it)->id ); - -// if ( a ) -// a->removeFrom( myMenu ); + delete itr.value()->menu(); + delete itr.value(); } - for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr ) - delete itr.value(); + delete myRoot; } /*! - \return whether menu item corresponding to action is visible - \param actId - identificator of action - \param place - identificator of some parent action + \brief Check if an action with \a actId identifier is visible to + the parent action with \a place identifier. + \param actId action ID + \param place some parent action ID + \return \c true if an action is visible to the parent + \sa setVisible() */ bool QtxActionMenuMgr::isVisible( const int actId, const int place ) const { @@ -317,10 +161,11 @@ bool QtxActionMenuMgr::isVisible( const int actId, const int place ) const } /*! - Sets visible state of action - \param actId - identificator of action - \param place - identificator of some parent action - \param v - visibility state + \brief Set action's visibility flag. + \param actId action ID + \param place some parent action ID + \param v new visibility state + \sa isVisible() */ void QtxActionMenuMgr::setVisible( const int actId, const int place, const bool v ) { @@ -330,12 +175,18 @@ void QtxActionMenuMgr::setVisible( const int actId, const int place, const bool } /*! - Insert action as children menu item - \param id - identificator of action - \param menus - few names of parent menu items, separated by '|'. It means sequence of menu items, - for example "File|Edit" means File->Edit submenu. If submenu doesn't exist, it will be created. - \param group - group identificator - \param idx - index inside Qt menu + \brief Insert action to the menu. + + Insert an action to the named menu. The \a menus parameter represents + the menu name: it can be a sequence of strings, separated by '|' symbol. + For example, "File|Edit" means \c File->Edit submenu. + If submenu doesn't exist, it will be created. + + \param id action ID + \param menus menu name + \param group group ID + \param idx menu index inside the menu group + \return action ID */ int QtxActionMenuMgr::insert( const int id, const QString& menus, const int group, const int idx ) { @@ -343,12 +194,18 @@ int QtxActionMenuMgr::insert( const int id, const QString& menus, const int grou } /*! - Insert action as children menu item - \param a - action - \param menus - few names of parent menu items, separated by '|'. It means sequence of menu items, - for example "File|Edit" means File->Edit submenu. If submenu doesn't exist, it will be created. - \param group - group identificator - \param idx - index inside Qt menu + \brief Insert action to the menu. + + Insert an action to the named menu. The \a menus parameter represents + the menu name: it can be a sequence of strings, separated by '|' symbol. + For example, "File|Edit" means \c File->Edit submenu. + If submenu doesn't exist, it will be created. + + \param a action + \param menus menu name + \param group group ID + \param idx menu index inside the menu group + \return action ID */ int QtxActionMenuMgr::insert( QAction* a, const QString& menus, const int group, const int idx ) { @@ -356,12 +213,19 @@ int QtxActionMenuMgr::insert( QAction* a, const QString& menus, const int group, } /*! - Insert action as children menu item - \param id - identificator of action - \param menus - list of names of parent menu items, separated by |. It means sequence of menu items, - for example "File|Edit" means File->Edit submenu. If submenu doesn't exist, it will be created. - \param group - group identificator - \param idx - index inside Qt menu + \brief Insert action to the menu. + + Insert an action to the named menu. The \a menus parameter represents + the menu names list. + For example, string list consisting from two items "File" and "Edit" + means \c File->Edit submenu. + If submenu doesn't exist, it will be created. + + \param id action ID + \param menus menu names list + \param group group ID + \param idx menu index inside the menu group + \return action ID */ int QtxActionMenuMgr::insert( const int id, const QStringList& menus, const int group, const int idx ) { @@ -373,12 +237,19 @@ int QtxActionMenuMgr::insert( const int id, const QStringList& menus, const int } /*! - Insert action as children menu item - \param a - action - \param menus - list of names of parent menu items. It means sequence of menu items, - for example "File|Edit" means File->Edit submenu. If submenu doesn't exist, it will be created. - \param group - group identificator - \param idx - index inside Qt menu + \brief Insert action to the menu. + + Insert an action to the named menu. The \a menus parameter represents + the menu names list. + For example, string list consisting from two items "File" and "Edit" + means \c File->Edit submenu. + If submenu doesn't exist, it will be created. + + \param a action + \param menus menu names list + \param group group ID + \param idx menu index inside the menu group + \return action ID */ int QtxActionMenuMgr::insert( QAction* a, const QStringList& menus, const int group, const int idx ) { @@ -390,40 +261,36 @@ int QtxActionMenuMgr::insert( QAction* a, const QStringList& menus, const int gr } /*! - Insert action as children menu item - \param id - identificator of action - \param pId - identificator of action corresponding to parent menu item - \param group - group identificator - \param idx - index inside Qt menu + \brief Insert action to the menu. + \param id action ID + \param pId parent menu action ID + \param group group ID + \param idx menu index inside the menu group + \return action ID */ int QtxActionMenuMgr::insert( const int id, const int pId, const int group, const int idx ) { if ( id == -1 ) return -1; - MenuNode* pNode = pId == -1 ? &myRoot : find( pId ); + MenuNode* pNode = pId == -1 ? myRoot : find( pId ); if ( !pNode ) return -1; - MenuNode* node = new MenuNode( pNode ); - node->id = id; - node->idx = idx; - node->group = group; - - pNode->children.append( node ); + MenuNode* node = new MenuNode( pNode, id, idx, group ); triggerUpdate( pNode->id, false ); - return node->id; } /*! - Insert action as children menu item - \param a - action - \param pId - identificator of action corresponding to parent menu item - \param group - group identificator - \param idx - index inside Qt menu + \brief Insert action to the menu. + \param a action + \param pId parent menu action ID + \param group group ID + \param idx menu index inside the menu group + \return action ID */ int QtxActionMenuMgr::insert( QAction* a, const int pId, const int group, const int idx ) { @@ -431,18 +298,17 @@ int QtxActionMenuMgr::insert( QAction* a, const int pId, const int group, const } /*! - Create and insert action as children menu item - \return identificator of inserted action - \param title - menu text of action - \param pId - identificator of action corresponding to parent menu item - \param group - group identificator - \param id - identificator of new action - \param idx - index inside Qt menu - \param allowEmpty - indicates, that it is possible to add this action with empty popup menu to other menu -*/ -int QtxActionMenuMgr::insert( const QString& title, const int pId, const int group, const int id, const int idx, const bool allowEmpty ) + \brief Create and insert menu item action to the menu. + \param title menu text + \param pId parent menu action ID + \param group group ID + \param id action ID + \param idx menu index inside the menu group + \return action ID +*/ +int QtxActionMenuMgr::insert( const QString& title, const int pId, const int group, const int id, const int idx ) { - MenuNode* pNode = pId == -1 ? &myRoot : find( pId ); + MenuNode* pNode = pId == -1 ? myRoot : find( pId ); if ( !pNode ) return -1; @@ -462,20 +328,12 @@ int QtxActionMenuMgr::insert( const QString& title, const int pId, const int gro int gid = (id == -1 || eNode ) ? generateId() : id; QAction* ma = new QAction( title, this ); - ma->setMenu( new QMenu( myMenu ) ); + ma->setMenu( new QMenu( 0 ) ); connect( ma->menu(), SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) ); connect( ma->menu(), SIGNAL( aboutToHide() ), this, SLOT( onAboutToHide() ) ); -#ifdef ENABLE_DYNAMIC_MENU - connect( ma->menu(), SIGNAL( highlighted( int ) ), this, SLOT( onHighlighted( int ) ) ); -#endif - - MenuNode* node = new MenuNode( pNode ); - node->group = group; - node->idx = idx; - node->id = myMenus.insert( gid, ma ).key(); - pNode->children.append( node ); + MenuNode* node = new MenuNode( pNode, myMenus.insert( gid, ma ).key(), idx, group ); triggerUpdate( pNode->id, false ); @@ -483,56 +341,66 @@ int QtxActionMenuMgr::insert( const QString& title, const int pId, const int gro } /*! - Create and insert action as children menu item - \return identificator of inserted action - \param title - menu text of action - \param menus - string list of parents' menu texts, separated by | - \param group - group identificator - \param id - identificator of new action - \param idx - index inside Qt menu - \param allowEmpty - indicates, that it is possible to add this action with empty popup menu to other menu + \brief Create and insert menu item action to the menu. + + Insert an action to the named menu. The \a menus parameter represents + the menu name: it can be a sequence of strings, separated by '|' symbol. + For example, "File|Edit" means \c File->Edit submenu. + If submenu doesn't exist, it will be created. + + \param title menu text + \param menus menu name + \param group group ID + \param id action ID + \param idx menu index inside the menu group + \return action ID */ -int QtxActionMenuMgr::insert( const QString& title, const QString& menus, const int group, const int id, const int idx, const bool allowEmpty ) +int QtxActionMenuMgr::insert( const QString& title, const QString& menus, const int group, const int id, const int idx ) { - return insert( title, menus.split( "|", QString::SkipEmptyParts ), group, id, idx, allowEmpty ); + return insert( title, menus.split( "|", QString::SkipEmptyParts ), group, id, idx ); } /*! - Create and insert action as children menu item - \return identificator of inserted action - \param title - menu text of action - \param menus - list of parents menu items - \param group - group identificator - \param id - identificator of new action - \param idx - index inside Qt menu - \param allowEmpty - indicates, that it is possible to add this action with empty popup menu to other menu -*/ -int QtxActionMenuMgr::insert( const QString& title, const QStringList& menus, const int group, const int id, const int idx, const bool allowEmpty ) + \brief Create and insert menu item action to the menu. + + Insert an action to the named menu. The \a menus parameter represents + the menu names list. + For example, string list consisting from two items "File" and "Edit" + means \c File->Edit submenu. + If submenu doesn't exist, it will be created. + + \param title menu text + \param menus menu names list + \param group group ID + \param id action ID + \param idx menu index inside the menu group + \return action ID +*/ +int QtxActionMenuMgr::insert( const QString& title, const QStringList& menus, const int group, const int id, const int idx ) { int pId = createMenu( menus, -1 ); - return insert( title, pId, group, id, idx, allowEmpty ); + return insert( title, pId, group, id, idx ); } /*! - Create and append action as last children - \return identificator of inserted action - \param title - menu text of action - \param pId - id of action corresponding to parent menu item - \param group - group identificator - \param id - identificator of new action - \param allowEmpty - indicates, that it is possible to add this action with empty popup menu to other menu -*/ -int QtxActionMenuMgr::append( const QString& title, const int pId, const int group, const int id, const bool allowEmpty ) + \brief Create and add menu item action to the end of menu. + \param title menu text + \param pId parent menu action ID + \param group group ID + \param id action ID + \return action ID +*/ +int QtxActionMenuMgr::append( const QString& title, const int pId, const int group, const int id ) { - return insert( title, pId, group, id, allowEmpty ); + return insert( title, pId, group, id ); } /*! - Create and append action as last children - \return identificator of inserted action - \param id - identificator of existing action - \param pId - id of action corresponding to parent menu item - \param group - group identificator + \brief Create and add menu item action to the end of menu. + \param id action ID + \param pId parent menu action ID + \param group group ID + \return action ID */ int QtxActionMenuMgr::append( const int id, const int pId, const int group ) { @@ -540,11 +408,11 @@ int QtxActionMenuMgr::append( const int id, const int pId, const int group ) } /*! - Create and append action as last children - \return identificator of inserted action - \param a - action - \param pId - id of action corresponding to parent menu item - \param group - group identificator + \brief Create and add menu item action to the end of menu. + \param a action + \param pId parent menu action ID + \param group group ID + \return action ID */ int QtxActionMenuMgr::append( QAction* a, const int pId, const int group ) { @@ -552,25 +420,24 @@ int QtxActionMenuMgr::append( QAction* a, const int pId, const int group ) } /*! - Create and insert action as first children - \return identificator of inserted action - \param title - menu text of action - \param pId - id of action corresponding to parent menu item - \param group - group identificator - \param id - identificator of new action - \param allowEmpty - indicates, that it is possible to add this action with empty popup menu to other menu -*/ -int QtxActionMenuMgr::prepend( const QString& title, const int pId, const int group, const int id, const bool allowEmpty ) + \brief Create and add menu item action to the beginning of menu. + \param title menu text + \param pId parent menu action ID + \param group group ID + \param id action ID + \return action ID +*/ +int QtxActionMenuMgr::prepend( const QString& title, const int pId, const int group, const int id ) { - return insert( title, pId, group, id, 0, allowEmpty ); + return insert( title, pId, group, id, 0 ); } /*! - Create and insert action as last children - \return identificator of inserted action - \param id - identificator of existing action - \param pId - id of action corresponding to parent menu item - \param group - group identificator + \brief Create and add menu item action to the beginning of menu. + \param id action ID + \param pId parent menu action ID + \param group group ID + \return action ID */ int QtxActionMenuMgr::prepend( const int id, const int pId, const int group ) { @@ -578,11 +445,11 @@ int QtxActionMenuMgr::prepend( const int id, const int pId, const int group ) } /*! - Create and insert action as last children - \return identificator of inserted action - \param a - action - \param pId - id of action corresponding to parent menu item - \param group - group identificator + \brief Create and add menu item action to the beginning of menu. + \param a action + \param pId parent menu action ID + \param group group ID + \return action ID */ int QtxActionMenuMgr::prepend( QAction* a, const int pId, const int group ) { @@ -590,8 +457,8 @@ int QtxActionMenuMgr::prepend( QAction* a, const int pId, const int group ) } /*! - Removes menu item corresponding to action - \param id - identificator of action + \brief Remove menu item with given \a id. + \param id menu action ID */ void QtxActionMenuMgr::remove( const int id ) { @@ -600,14 +467,14 @@ void QtxActionMenuMgr::remove( const int id ) } /*! - Removes menu item - \param id - identificator of action - \param pId - identificator of action corresponding to parent menu item - \param group - group identificator + \brief Remove menu item with given \a id. + \param id menu action ID + \param pId parent menu action ID + \param group group ID */ void QtxActionMenuMgr::remove( const int id, const int pId, const int group ) { - MenuNode* pNode = pId == -1 ? &myRoot : find( pId ); + MenuNode* pNode = pId == -1 ? myRoot : find( pId ); if ( !pNode ) return; @@ -625,8 +492,9 @@ void QtxActionMenuMgr::remove( const int id, const int pId, const int group ) } /*! - Shows menu item corresponding to action - \param id - identificator of action + \brief Show menu item with given \a id. + \param id menu action ID + \sa hide() */ void QtxActionMenuMgr::show( const int id ) { @@ -634,8 +502,9 @@ void QtxActionMenuMgr::show( const int id ) } /*! - Hides menu item corresponding to action - \param id - identificator of action + \brief Hide menu item with given \a id. + \param id menu action ID + \sa show() */ void QtxActionMenuMgr::hide( const int id ) { @@ -643,8 +512,10 @@ void QtxActionMenuMgr::hide( const int id ) } /*! - \return shown status of menu item corresponding to action - \param id - identificator of action + \brief Get visibility status for menu item with given \a id. + \param id menu action ID + \return \c true if an item is shown + \sa setShown() */ bool QtxActionMenuMgr::isShown( const int id ) const { @@ -656,9 +527,10 @@ bool QtxActionMenuMgr::isShown( const int id ) const } /*! - Sets shown status of menu item corresponding to action - \param id - identificator of action - \param on - new shown status + \brief Set visibility status for menu item with given \a id. + \param id menu action ID + \param on new visibility status + \sa isShown() */ void QtxActionMenuMgr::setShown( const int id, const bool on ) { @@ -670,13 +542,15 @@ void QtxActionMenuMgr::setShown( const int id, const bool on ) if ( (*it)->visible != on ) { (*it)->visible = on; - triggerUpdate( (*it)->parent ? (*it)->parent->id : myRoot.id, false ); + triggerUpdate( (*it)->parent ? (*it)->parent->id : myRoot->id, false ); } } } /*! - Changes the specified menu title + \brief Change menu title for the action with given \a id. + \param id menu action ID + \param title new menu title */ void QtxActionMenuMgr::change( const int id, const QString& title ) { @@ -685,6 +559,11 @@ void QtxActionMenuMgr::change( const int id, const QString& title ) a->setText( title ); } +/*! + \brief Called when the submenu is about to show. + + Emits the signal menuAboutToShow(QMenu*). +*/ void QtxActionMenuMgr::onAboutToShow() { QMenu* m = ::qobject_cast( sender() ); @@ -692,6 +571,11 @@ void QtxActionMenuMgr::onAboutToShow() emit menuAboutToShow( m ); } +/*! + \brief Called when the submenu is about to hide. + + Emits the signal menuAboutToHide(QMenu*). +*/ void QtxActionMenuMgr::onAboutToHide() { QMenu* m = ::qobject_cast( sender() ); @@ -700,7 +584,11 @@ void QtxActionMenuMgr::onAboutToHide() } /*! - SLOT: called when corresponding menu is destroyed, clears internal pointer to menu + \brief Called when the corresponding menu object is destroyed. + + Clears internal pointer to menu to disable crashes. + + \param obj (menu) object being destroyed */ void QtxActionMenuMgr::onDestroyed( QObject* obj ) { @@ -708,39 +596,33 @@ void QtxActionMenuMgr::onDestroyed( QObject* obj ) myMenu = 0; } + +/*! + \fn void QtxActionMenuMgr::menuAboutToShow( QMenu* m ) + \brief Emitted when the menu is about to be shown. + \param m menu being shown +*/ + +/*! + \fn void QtxActionMenuMgr::menuAboutToHide( QMenu* m ) + \brief Emitted when the menu is about to be hidden. + \param m menu being hidden +*/ + /*! - SLOT: called when menu item is highlighted + \brief Get the menu widget. + \return menu widget (QMenuBar) */ -void QtxActionMenuMgr::onHighlighted( int id ) +QWidget* QtxActionMenuMgr::menuWidget() const { - const QObject* snd = sender(); - int pid = 0, realId; - if ( myMenu && snd == myMenu ) - pid = -1; - else - { - for ( MenuMap::Iterator itr = myMenus.begin(); itr != myMenus.end(); ++itr ) - { - if ( itr.value()->menu() && itr.value()->menu() == snd ) - pid = itr.key(); - } - } - if ( pid ) - { - realId = findId( id, pid ); - if ( realId != -1 ) - { - emit menuHighlighted( pid, realId ); - triggerUpdate( realId ); - } - } + return myMenu; } /*! - Assignes new menu with manager - \param mw - new menu + \brief Assign new menu widget to the menu manager. + \param mw new menu widget */ -void QtxActionMenuMgr::setWidget( QWidget* mw ) +void QtxActionMenuMgr::setMenuWidget( QWidget* mw ) { if ( myMenu == mw ) return; @@ -752,29 +634,33 @@ void QtxActionMenuMgr::setWidget( QWidget* mw ) if ( myMenu ) connect( myMenu, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); + + triggerUpdate( -1, true ); } /*! - \return menu node by it's place description - \param actId - identificator of action - \param pId - identificator of action corresponding to start menu item - \param rec - recursive search + \brief Search menu node. + \param id menu action ID + \param pId parent menu item ID + \param rec if \c true perform recursive search + \return menu node or 0 if it is not found */ -QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int actId, const int pId, const bool rec ) const +QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, const int pId, const bool rec ) const { - return find( actId, find( pId ), rec ); + return find( id, find( pId ), rec ); } /*! - \return menu node by it's place description - \param actId - identificator of action - \param startNode - start menu item - \param rec - recursive search + \brief Search menu node. + \param id menu action ID + \param startNode start menu node (if 0, search from root node) + \param rec if \c true perform recursive search + \return menu node or 0 if it is not found */ QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, MenuNode* startNode, const bool rec ) const { MenuNode* node = 0; - MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot; + MenuNode* start = startNode ? startNode : myRoot; for ( NodeList::iterator it = start->children.begin(); it != start->children.end() && !node; ++it ) { if ( (*it)->id == id ) @@ -786,15 +672,15 @@ QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const int id, MenuNode* star } /*! - Finds menu node - \return true if at least one node is found - \param id - identificator of action - \param lst - list to be filled with found nodes - \param startNode - start menu item + \brief Search recursively all menu nodes with given \a id. + \param id menu action ID + \param NodeList resulting list of menu nodes + \param startNode start menu node (if 0, search from root node) + \return \c true if at least one node is found */ bool QtxActionMenuMgr::find( const int id, NodeList& lst, MenuNode* startNode ) const { - MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot; + MenuNode* start = startNode ? startNode : myRoot; for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it ) { MenuNode* node = *it; @@ -807,11 +693,11 @@ bool QtxActionMenuMgr::find( const int id, NodeList& lst, MenuNode* startNode ) } /*! - Finds menu node - \return menu node - \param title - menu text of searched node - \param pId - id of action corresponding to start menu item - \param rec - recursive searching + \brief Search menu node. + \param title menu item title + \param pId parent menu item ID + \param rec if \c true perform recursive search + \return menu node or 0 if it is not found */ QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, const int pId, const bool rec ) const { @@ -819,15 +705,15 @@ QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, const } /*! - Finds menu node - \return true if at least one node is found - \param title - menu text of node - \param lst - list to be filled with found nodes - \param startNode - start menu item + \brief Search recursively all menu nodes with given \a title. + \param title menu item title + \param NodeList resulting list of menu nodes + \param startNode start menu node (if 0, search from root node) + \return \c true if at least one node is found */ bool QtxActionMenuMgr::find( const QString& title, NodeList& lst, MenuNode* startNode ) const { - MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot; + MenuNode* start = startNode ? startNode : myRoot; for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it ) { QAction* a = itemAction( (*it)->id ); @@ -842,16 +728,16 @@ bool QtxActionMenuMgr::find( const QString& title, NodeList& lst, MenuNode* star } /*! - Finds menu node - \return menu node - \param title - menu text of searched node - \param startNode - start menu item - \param rec - recursive searching + \brief Search menu node. + \param title menu item title + \param startNode start menu node (if 0, search from root node) + \param rec if \c true perform recursive search + \return menu node or 0 if it is not found */ QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, MenuNode* startNode, const bool rec ) const { MenuNode* node = 0; - MenuNode* start = startNode ? startNode : (MenuNode*)&myRoot; + MenuNode* start = startNode ? startNode : myRoot; for ( NodeList::iterator it = start->children.begin(); it != start->children.end() && !node; ++it ) { QAction* a = itemAction( (*it)->id ); @@ -866,14 +752,14 @@ QtxActionMenuMgr::MenuNode* QtxActionMenuMgr::find( const QString& title, MenuNo } /*! - Find id among children - \return id (>0) if on success or -1 on fail - \param id - id to be searched - \param pid - id of parent, among children of that 'id' must be searched + \brief Find menu item by given ID (one-level only). + \param id menu action ID + \param pid parent meun item ID + \return id (>0) on success or -1 if menu item is not found */ int QtxActionMenuMgr::findId( const int id, const int pid ) const { - MenuNode* start = pid != -1 ? find( pid ) : (MenuNode*)&myRoot; + MenuNode* start = pid != -1 ? find( pid ) : myRoot; if ( start ) { for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it ) @@ -886,13 +772,13 @@ int QtxActionMenuMgr::findId( const int id, const int pid ) const } /*! - Removes child - \param id - id of child to be removed - \param startNode - parent menu item + \brief Removes menu node (with all its children). + \param id menu action ID + \param startNode parent menu node which search starts from (if 0, search starts from root) */ void QtxActionMenuMgr::removeMenu( const int id, MenuNode* startNode ) { - MenuNode* start = startNode ? startNode : &myRoot; + MenuNode* start = startNode ? startNode : myRoot; for ( NodeList::iterator it = start->children.begin(); it != start->children.end(); ++it ) { if ( (*it)->id == id ) @@ -903,8 +789,9 @@ void QtxActionMenuMgr::removeMenu( const int id, MenuNode* startNode ) } /*! - \return menu item action by id - \param id - id of action + \brief Get action by \a id. + \param id action ID + \return action or 0 if \a id is invalid */ QAction* QtxActionMenuMgr::itemAction( const int id ) const { @@ -912,8 +799,9 @@ QAction* QtxActionMenuMgr::itemAction( const int id ) const } /*! - \return menu action by id - \param id - id of action + \brief Get submenu action by \a id. + \param id submenu ID + \return submenu action or 0 if action is not found */ QAction* QtxActionMenuMgr::menuAction( const int id ) const { @@ -926,18 +814,38 @@ QAction* QtxActionMenuMgr::menuAction( const int id ) const } /*! - Updates menu ( isUpdatesEnabled() must return true ) - \param startNode - first menu item to be updated - \param rec - recursive update - \param updParent - update also parent item (without recursion) - \sa isUpdatesEnabled() + \brief Get submenu action by \a id. + \param id submenu ID + \return submenu action or 0 if it is not found +*/ +int QtxActionMenuMgr::menuActionId( QAction* a ) const +{ + int id = -1; + for ( MenuMap::ConstIterator itr = myMenus.begin(); itr != myMenus.end() && id == -1; ++itr ) + { + if ( itr.value() == a ) + id = itr.key(); + } + return id; +} + +/*! + \brief Update menu. + + Does nothing if update is disabled. + + \param startNode start menu item to be updated + \param rec if \c true, perform recursive update + \param updParent if \c true update also parent item (without recursion) + + \sa isUpdatesEnabled() and setUpdatesEnabled() */ void QtxActionMenuMgr::updateMenu( MenuNode* startNode, const bool rec, const bool updParent ) { if ( !isUpdatesEnabled() ) return; - MenuNode* node = startNode ? startNode : &myRoot; + MenuNode* node = startNode ? startNode : myRoot; QWidget* mw = menuWidget( node ); if ( !mw ) @@ -1010,7 +918,9 @@ void QtxActionMenuMgr::updateMenu( MenuNode* startNode, const bool rec, const bo } /*! - Updates menu (virtual variant). To be redefined for custom activity on menu updating + \brief Internal update. + + Customizes the menu update processing. */ void QtxActionMenuMgr::internalUpdate() { @@ -1022,8 +932,9 @@ void QtxActionMenuMgr::internalUpdate() } /*! - \return true if widget is non-empty menu - \param wid - widget to be checked + \brief Check if menu widget has any actions. + \param wid widget to be checked + \return \c true if widget contains action(s) */ bool QtxActionMenuMgr::checkWidget( QWidget* wid ) const { @@ -1034,12 +945,14 @@ bool QtxActionMenuMgr::checkWidget( QWidget* wid ) const } /*! - \return popup of menu item - \param node - menu item + \brief Get menu widget for the given \a node. + \param node menu node + \return popup menu or main menu corresponding to the menu node + (or 0 if it is not found) */ -QWidget* QtxActionMenuMgr::menuWidget( MenuNode* node) const +QWidget* QtxActionMenuMgr::menuWidget( MenuNode* node ) const { - if ( !node || node == &myRoot ) + if ( !node || node == myRoot ) return myMenu; if ( !myMenus.contains( node->id ) || !myMenus[node->id] ) @@ -1049,8 +962,8 @@ QWidget* QtxActionMenuMgr::menuWidget( MenuNode* node) const } /*! - Removes excess separators of menu - \param wid - menu to be processed + \brief Remove extra separators from menu widget. + \param wid menu widget to be processed */ void QtxActionMenuMgr::simplifySeparators( QWidget* wid ) { @@ -1058,9 +971,9 @@ void QtxActionMenuMgr::simplifySeparators( QWidget* wid ) } /*! - Removes special symbols (&) from string - \param txt - string to be processed - \return clear variant of string + \brief Remove special symbols (&) from string to get clear menu title. + \param txt string to be processed + \return clear title */ QString QtxActionMenuMgr::clearTitle( const QString& txt ) const { @@ -1076,9 +989,10 @@ QString QtxActionMenuMgr::clearTitle( const QString& txt ) const } /*! - Creates and inserts many menu items - \param lst - list of menu texts - \param pId - id of action corresponding to parent menu item + \brief Create and inserts menu item recursively. + \param lst list of menu names + \param pId parent menu item ID + \return created menu item ID (last in the chain) */ int QtxActionMenuMgr::createMenu( const QStringList& lst, const int pId ) { @@ -1096,10 +1010,10 @@ int QtxActionMenuMgr::createMenu( const QStringList& lst, const int pId ) } /*! - Loads actions description from file - \param fname - name of file - \param r - reader of file - \return true on success + \brief Load actions description from the file. + \param fname file name + \param r action reader + \return \c true on success and \c false on error */ bool QtxActionMenuMgr::load( const QString& fname, QtxActionMgr::Reader& r ) { @@ -1108,9 +1022,10 @@ bool QtxActionMenuMgr::load( const QString& fname, QtxActionMgr::Reader& r ) } /*! - \return true if item has such child - \param title - menu text of child - \param pid - id of action corresponding to item + \brief Check if the parent menu contains menu item with given \a title. + \param title menu title + \param pid parent menu item ID + \return \c true if parent menu item contains such child item */ bool QtxActionMenuMgr::containsMenu( const QString& title, const int pid ) const { @@ -1118,9 +1033,10 @@ bool QtxActionMenuMgr::containsMenu( const QString& title, const int pid ) const } /*! - \return true if item has such child - \param id - id of action corresponding to child - \param pid - id of action corresponding to item + \brief Check if the parent menu contains menu item with given \a id. + \param id menu item ID + \param pid parent menu item ID + \return \c true if parent menu item contains such child item */ bool QtxActionMenuMgr::containsMenu( const int id, const int pid ) const { @@ -1128,7 +1044,23 @@ bool QtxActionMenuMgr::containsMenu( const int id, const int pid ) const } /*! - \Sets trigger for delayed update + \brief Get menu by the specified identifier. + \param id menu item ID + \return menu pointer or 0 if menu is not found +*/ +QMenu* QtxActionMenuMgr::findMenu( const int id ) const +{ + QMenu* m = 0; + QAction* a = menuAction( id ); + if ( a ) + m = a->menu(); + return m; +} + +/*! + \brief Perform delayed menu update. + \param id menu item ID + \param rec if \c true, perform recursive update */ void QtxActionMenuMgr::triggerUpdate( const int id, const bool rec ) { @@ -1141,20 +1073,23 @@ void QtxActionMenuMgr::triggerUpdate( const int id, const bool rec ) } /*! - \Sets trigger for delayed update + \brief Called when delayed content update is performed. + + Customizes the content update operation. */ void QtxActionMenuMgr::updateContent() { - // Warning: For correct updating it is necessary to update the most enclosed submenu firstly - // because not updated empty submenu will be skipped. Now the submenu are iterated in - // ascending order their identifiers. For a submenu with automatically generated identifiers - // will work correctly as the uppermost submenu have the biggest number (identifiers generated - // reduction from -1). Generally when any submenu will have positive identifiers are obviously - // appropriated can to work not truly. In this case it is required to improve the given method - // and to add preliminary sorting a submenu on depth of an enclosure. + // Warning: For correct updating it is necessary to update the most enclosed submenu in first turn + // because not updated empty submenu will be skipped. Now the submenus are iterated in + // ascending order according to their identifiers. For a submenus with automatically generated + // identifiers this will work correctly since the uppermost submenus have the biggest number + // (identifiers are generated by decrementing 1 starting from -1). In general, if any submenu + // have positive identifiers this method might not work correctly. In this case it would be + // necessary to improve this method and to add preliminary sorting a submenus by depth of an + // enclosure. for ( QMap::const_iterator it = myUpdateIds.constBegin(); it != myUpdateIds.constEnd(); ++it ) { - MenuNode* node = it.key() == -1 ? &myRoot : find( it.key() ); + MenuNode* node = it.key() == -1 ? myRoot : find( it.key() ); if ( node ) updateMenu( node, it.value() ); } @@ -1162,29 +1097,38 @@ void QtxActionMenuMgr::updateContent() } /*! - Constructor - \param r - menu reader - \param mgr - menu manager + \class QtxActionMenuMgr::MenuCreator + \brief Menu actions creator. + + Used by Reader to create actions by reading descriptions from the file + and fill in the action manager with the actions. +*/ + +/*! + \brief Constructor. + \param r menu actions reader + \param mgr menu manager */ QtxActionMenuMgr::MenuCreator::MenuCreator( QtxActionMgr::Reader* r, QtxActionMenuMgr* mgr ) : QtxActionMgr::Creator( r ), -myMgr( mgr ) + myMgr( mgr ) { } /*! - Destructor + \brief Destructor. */ QtxActionMenuMgr::MenuCreator::~MenuCreator() { } /*! - Appends new menu items - \param tag - tag of item - \param subMenu - it has submenu - \param attr - list of attributes - \param pId - id of action corresponding to parent item + \brief Create and append to the action manager a new action. + \param tag item tag name + \param subMenu \c true if this item is submenu + \param attr attributes map + \param pId parent action ID + \return menu action ID */ int QtxActionMenuMgr::MenuCreator::append( const QString& tag, const bool subMenu, const ItemAttributes& attr, const int pId ) diff --git a/src/Qtx/QtxActionMenuMgr.h b/src/Qtx/QtxActionMenuMgr.h index e1cf03493..96d15b51b 100644 --- a/src/Qtx/QtxActionMenuMgr.h +++ b/src/Qtx/QtxActionMenuMgr.h @@ -17,7 +17,7 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File: QtxActionMenuMgr.h -// Author: Alexander SOLOVYEV, Sergey TELKOV +// Author: Alexander SOLOVYOV, Sergey TELKOV #ifndef QTXACTIONMENUMGR_H #define QTXACTIONMENUMGR_H @@ -25,61 +25,23 @@ #include "Qtx.h" #include "QtxActionMgr.h" -#include -#include +#include -class QPopupMenu; +class QMenu; class QMainWindow; +class QStringList; #ifdef WIN32 #pragma warning( disable:4251 ) #endif -/*! - \class QtxActionMenuMgr - Allows to use set of action to automatically build main menu. - With help of methods insert/append/remove it is possible to - describe whole structure of menu. Method hide allows - to temporary remove some items from menu, method show allows to - recreate them. - Actions can be grouped with help of group identifictor. - Inside popup or menu bar items have order by increasing group id. - This manager is able to attune menu: to remove excess separators, - to remove empty popup menu etc. -*/ class QTX_EXPORT QtxActionMenuMgr : public QtxActionMgr { Q_OBJECT class MenuNode; - typedef QList NodeList; - - /*! - \class MenuNode - Represents a menu item inside main menu structure. - For internal purposes only - */ - class MenuNode - { - public: - MenuNode() : parent( 0 ), visible( true ) {}; - MenuNode( MenuNode* p ) : parent( p ), visible( true ) {}; - ~MenuNode() - { - for ( NodeList::iterator it = children.begin(); it != children.end(); ++it ) - delete *it; - } - - int id; - int idx; - int group; - MenuNode* parent; - bool visible; - NodeList children; - }; - - class MenuAction; + typedef QList NodeList; //!< menu nodes list protected: class MenuCreator; @@ -89,6 +51,8 @@ public: QtxActionMenuMgr( QWidget*, QObject* ); virtual ~QtxActionMenuMgr(); + QWidget* menuWidget() const; + virtual bool isVisible( const int, const int ) const; virtual void setVisible( const int, const int, const bool ); @@ -101,17 +65,17 @@ public: virtual int insert( const int, const int, const int, const int = -1 ); int insert( QAction*, const int, const int, const int = -1 ); - int insert( const QString&, const QString&, const int, const int = -1, const int = -1, const bool = false ); - int insert( const QString&, const QStringList&, const int, const int = -1, const int = -1, const bool = false ); - virtual int insert( const QString&, const int, const int, const int = -1, const int = -1, const bool = false ); + int insert( const QString&, const QString&, const int, const int = -1, const int = -1 ); + int insert( const QString&, const QStringList&, const int, const int = -1, const int = -1 ); + virtual int insert( const QString&, const int, const int, const int = -1, const int = -1 ); int append( const int, const int, const int ); int append( QAction*, const int, const int ); - int append( const QString&, const int, const int, const int = -1, const bool = false ); + int append( const QString&, const int, const int, const int = -1 ); int prepend( const int, const int, const int ); int prepend( QAction*, const int, const int ); - int prepend( const QString&, const int, const int, const int = -1, const bool = false ); + int prepend( const QString&, const int, const int, const int = -1 ); void remove( const int ); void remove( const int, const int, const int = -1 ); @@ -129,20 +93,20 @@ public: bool containsMenu( const QString&, const int ) const; bool containsMenu( const int, const int ) const; -private Q_SLOTS: + QMenu* findMenu( const int ) const; + +private slots: void onAboutToShow(); void onAboutToHide(); - void onHighlighted( int ); void onDestroyed( QObject* ); -Q_SIGNALS: +signals: void menuAboutToShow( QMenu* ); void menuAboutToHide( QMenu* ); - void menuHighlighted( int, int ); - protected: - void setWidget( QWidget* ); + void setMenuWidget( QWidget* ); + MenuNode* find( const int, const int, const bool = true ) const; MenuNode* find( const int, MenuNode* = 0, const bool = true ) const; bool find( const int, NodeList&, MenuNode* = 0 ) const; @@ -155,9 +119,10 @@ protected: QAction* itemAction( const int ) const; QAction* menuAction( const int ) const; + int menuActionId( QAction* ) const; void updateMenu( MenuNode* = 0, const bool = true, const bool = true ); - virtual void internalUpdate(); + virtual void internalUpdate(); virtual void updateContent(); private: @@ -170,19 +135,15 @@ private: void triggerUpdate( const int, const bool rec = true ); private: - typedef QMap MenuMap; - + typedef QMap MenuMap; //!< actions map + private: - MenuNode myRoot; - QWidget* myMenu; - MenuMap myMenus; - QMap myUpdateIds; + MenuNode* myRoot; //!< root menu node + QWidget* myMenu; //!< menu widget + MenuMap myMenus; //!< actions map + QMap myUpdateIds; //!< list of actions ID being updated }; -/*! - \class QtxActionMenuMgr::MenuCreator - Allows to create automatically main menu by data read from file -*/ class QtxActionMenuMgr::MenuCreator : public QtxActionMgr::Creator { public: @@ -193,7 +154,7 @@ public: const ItemAttributes&, const int ); private: - QtxActionMenuMgr* myMgr; + QtxActionMenuMgr* myMgr; //!< menu manager }; diff --git a/src/Qtx/QtxActionMgr.cxx b/src/Qtx/QtxActionMgr.cxx index bd6a6bd5e..366dd24e8 100644 --- a/src/Qtx/QtxActionMgr.cxx +++ b/src/Qtx/QtxActionMgr.cxx @@ -1,41 +1,42 @@ // Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D -// +// // 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 +// License as published by the Free Software Foundation; either // version 2.1 of the License. -// -// 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 +// +// 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 +// 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: QtxActionMgr.cxx -// Author: Alexander SOLOVYEV, Sergey TELKOV +// Author: Alexander SOLOVYOV, Sergey TELKOV #include "Qtx.h" #include "QtxActionMgr.h" #include "QtxAction.h" - -#include -#include - -#include -#include -#include -#include - -#include +#include +#include +#ifndef QT_NO_DOM +#include +#include +#include +#endif typedef QList< QPointer > qtx_actionlist; static qtx_actionlist qtx_separator_actions; +/*! + \brief Clean all cashed separator actions. + \internal +*/ void qtxSeparatorActionCleanup() { for ( qtx_actionlist::iterator it = qtx_separator_actions.begin(); it != qtx_separator_actions.end(); ++it ) @@ -43,8 +44,9 @@ void qtxSeparatorActionCleanup() } /*! - Class: QtxActionMenuMgr::SeparatorAction - Level: Internal + \class QtxActionMgr::SeparatorAction + \brief Separator action class. + \internal */ class QtxActionMgr::SeparatorAction : public QtxAction @@ -55,7 +57,9 @@ public: }; /*! - Constructor + \brief Constructor. + \internal + \param parent parent object */ QtxActionMgr::SeparatorAction::SeparatorAction( QObject* parent ) : QtxAction( parent ) @@ -64,39 +68,65 @@ QtxActionMgr::SeparatorAction::SeparatorAction( QObject* parent ) } /*! - Destructor + \brief Destructor. */ QtxActionMgr::SeparatorAction::~SeparatorAction() { } /*! - Class: QtxActionMgr - Level: Public + \class QtxActionMgr + \brief Manages a set of actions accessible by unique identifier. + + Base class for menu, toolbar actions containers and popup menu creators. + + Actions are registered in the manager with the registerAction() method + and unregistered from it with the unRegisterAction() method. + + Functions action() and actionId() allow getting action by its identifier + and vice versa. Method contains() returns \c true if the action with + the specified identifier is already registered. + + To get total number of the registered actions can be retrieved by + the method count(). Function isEmpty() returns \c true if manager does not + contains any actions. The list of all actions identifiers can be retrieved + with the idList() function. + + The method separator() allows creating a separator action which can be + used in the menus or toolbars to separate logical groups of actions. + + To enable/disable any action by its identifier, use setEnabled() method. */ /*! - Constructor + \brief Constructor. + \param parent parent object */ QtxActionMgr::QtxActionMgr( QObject* parent ) : QObject( parent ), -myUpdate( true ), -myUpdTimer( 0 ) + myUpdate( true ), + myUpdTimer( 0 ) { } /*! - Destructor + \brief Destructor. */ QtxActionMgr::~QtxActionMgr() { } /*! - Stores action in internal map - If action with such id is registered already, then it will be unregistered - \param a - action to be registered - \param userId - proposed id (if it is less than 0, then id will be generated automatically) + \brief Register an action in the internal map. + + If \a userId is less than 0, the identifier for the action + is generated automatically. If action with given \a userId + is already registered, it will be re-registered. + + \param a action to be registered + \param userId action ID + \return action ID (the same as userId or generated one) + \sa unRegisterAction() */ int QtxActionMgr::registerAction( QAction* a, const int userId ) { @@ -123,8 +153,9 @@ int QtxActionMgr::registerAction( QAction* a, const int userId ) } /*! - Removes action from internal map - \param id - action id + \brief Unregister action from internal map. + \param id action ID + \sa registerAction() */ void QtxActionMgr::unRegisterAction( const int id ) { @@ -133,8 +164,10 @@ void QtxActionMgr::unRegisterAction( const int id ) } /*! - \return action by id - \param id - action id + \brief Get action by specified identifier. + \param id action ID + \return action (or 0 if \a id is invalid) + \sa actionId() */ QAction* QtxActionMgr::action( const int id ) const { @@ -145,8 +178,10 @@ QAction* QtxActionMgr::action( const int id ) const } /*! - \return id by action - \param a - action + \brief Get action identifier. + \param a action + \return action ID (or -1 if action is not found) + \sa action() */ int QtxActionMgr::actionId( const QAction* a ) const { @@ -164,8 +199,9 @@ int QtxActionMgr::actionId( const QAction* a ) const } /*! - \return true if internal map contains such id - \param id - action id + \brief Check if an action with given \a id is registered in the action manager. + \param id action ID + \return \c true if internal map contains action with such identifier */ bool QtxActionMgr::contains( const int id ) const { @@ -173,7 +209,9 @@ bool QtxActionMgr::contains( const int id ) const } /*! - \return count of actions in internal map + \brief Get total number of registered actions. + \return number of actions in the internal map + \sa isEmpty() */ int QtxActionMgr::count() const { @@ -181,7 +219,9 @@ int QtxActionMgr::count() const } /*! - \return true if internal map is empty + \brief Check if there are no actions registered in the action manager. + \return \c true if internal map is empty + \sa count() */ bool QtxActionMgr::isEmpty() const { @@ -189,15 +229,18 @@ bool QtxActionMgr::isEmpty() const } /*! - Fills list with ids of registered actions + \brief Get all registered actions identifiers. + \return list of actions identifiers */ -void QtxActionMgr::idList( QIntList& lst ) const +QIntList QtxActionMgr::idList() const { - lst = myActions.keys(); + return myActions.keys(); } /*! - \return true if updates are enabled + \brief Check if update is enabled. + \return \c true if update is enabled + \sa setUpdatesEnabled(), update() */ bool QtxActionMgr::isUpdatesEnabled() const { @@ -205,8 +248,9 @@ bool QtxActionMgr::isUpdatesEnabled() const } /*! - Enables/disables updates - \param upd - new state + \brief Enable/disable update operation. + \param upd new state + \sa isUpdatesEnabled(), update() */ void QtxActionMgr::setUpdatesEnabled( const bool upd ) { @@ -214,23 +258,44 @@ void QtxActionMgr::setUpdatesEnabled( const bool upd ) } /*! - \return true if action is visible (by default \return always true) + \brief Check if an action with \a actId identifier is visible to + the parent action with \a place identifier. + + This method can be redefined in subclasses. + Base implementatin always returns \c true. + + \param actId action ID + \param place some parent action ID + \return \c true if an action is visible to the parent + \sa setVisible() */ -bool QtxActionMgr::isVisible( const int, const int ) const +bool QtxActionMgr::isVisible( const int /*actId*/, const int /*place*/ ) const { return true; } /*! - Sets visibility of action (by default, empty implementation) + \brief Set action's visibility flag. + + This method can be redefined in subclasses. + Base implementatin does nothing. + + \param actId action ID + \param place some parent action ID + \param v new visibility state + \sa isVisible() */ -void QtxActionMgr::setVisible( const int, const int, const bool ) +void QtxActionMgr::setVisible( const int /*actId*/, const int /*place*/, const bool /*v*/ ) { } /*! - Updates actions, check isUpdatesEnabled() and call internalUpdate() - \sa isUpdatesEnabled(), internalUpdate() + \brief Update actions. + + Calls virtual function internalUpdate to update the contents. + Does nothing if update is disabled. + + \sa setUpdatesEnabled(), isUpdatesEnabled(), internalUpdate() */ void QtxActionMgr::update() { @@ -243,14 +308,19 @@ void QtxActionMgr::update() } /*! - Real update (to be redefined in successors) + \brief Internal update. + + This method is called by update() function and can be redefined + in subclasses to customize update operation. Base implementation + does nothing. */ void QtxActionMgr::internalUpdate() { } /*! - \return global free id + \brief Generate unique action identifier. + \return new ID */ int QtxActionMgr::generateId() const { @@ -259,8 +329,9 @@ int QtxActionMgr::generateId() const } /*! - \return true if action is enabled - \param id - action id + \brief Check is action with given \a id is enabled. + \param id action ID + \return \c true if action is enabled */ bool QtxActionMgr::isEnabled( const int id ) const { @@ -272,25 +343,30 @@ bool QtxActionMgr::isEnabled( const int id ) const } /*! - Enables/disables action - \param id - action id - \param en - new state + Enable/disable action with given \a id. + \param id action ID + \param enable new state */ -void QtxActionMgr::setEnabled( const int id, const bool en ) +void QtxActionMgr::setEnabled( const int id, const bool enable ) { QAction* a = action( id ); if ( a ) - a->setEnabled( en ); + a->setEnabled( enable ); } /*! - \return action for separator - If this action doesn't exist, then it will be created - \param individual - if it is false, then action will be shared, otherwise it will be created on every call + \brief Create new separator action. + + If \a own is \c true, then the caller is responsible for the action + destroying. If \a own is \c false, new separator action will be owned by the + action manager which will destroy it on application exit. + + \param own ownership flag + \return new separator action */ -QAction* QtxActionMgr::separator( const bool individual ) +QAction* QtxActionMgr::separator( const bool own ) { - if ( individual ) + if ( own ) return new SeparatorAction(); if ( qtx_separator_actions.isEmpty() ) @@ -303,7 +379,10 @@ QAction* QtxActionMgr::separator( const bool individual ) } /*! - \initialise timer for delayed update + \brief Perform delayed update. + + Does nothing if update is disabled. + \sa isUpdatesEnabled(), setUpdatesEnabled(), update() */ void QtxActionMgr::triggerUpdate() { @@ -322,15 +401,22 @@ void QtxActionMgr::triggerUpdate() } /*! - \perform delayed update - \default implementation is empty + \brief Internal content update operation. + + Called automatically by onUpdateContent() when the delayed update + is triggered. Base implementation does nothing. + + \sa triggerUpdate(), onUpdateContent() */ void QtxActionMgr::updateContent() -{} +{ +} /*! - \perform delayed update - \default implementation is empty + \brief Called when delayed update is performed (via timer event). + + Calls virtual method updateContent() which can be redefined in the + subclasses to customize the content update operation. */ void QtxActionMgr::onUpdateContent() { @@ -338,26 +424,30 @@ void QtxActionMgr::onUpdateContent() } /*! - Class: QtxActionMgr::Reader - Level: Public + \class QtxActionMgr::Reader + \brief Generic actions description files reader class. + + This class is used to read files of some format to create actions + and fill an action manager with the actions automatically. */ /*! - Constructor + \brief Constructor. */ QtxActionMgr::Reader::Reader() { } /*! - Destructor + \brief Destructor */ QtxActionMgr::Reader::~Reader() { } /*! - \return list of options + \brief Get the list of options. + \return options list */ QStringList QtxActionMgr::Reader::options() const { @@ -365,9 +455,13 @@ QStringList QtxActionMgr::Reader::options() const } /*! - \return value of option - \param name - option name - \param def - default option value (is returned, if there is no such option) + \brief Get option value. + + If there is no such option the default value (\a def) is returned. + + \param name option name + \param def default option value + \return option value */ QString QtxActionMgr::Reader::option( const QString& name, const QString& def ) const { @@ -378,19 +472,40 @@ QString QtxActionMgr::Reader::option( const QString& name, const QString& def ) } /*! - Sets value of option - \param name - option name - \param value - option value + \brief Set option value. + \param name option name + \param value new option value */ void QtxActionMgr::Reader::setOption( const QString& name, const QString& value ) { myOptions[ name ] = value; } +/*! + \fn bool QtxActionMgr::Reader::read( const QString& fname, Creator& cr ) const + \brief Read the file and fill and action manager with actions + by using help actions creator. + + This method should be redefined in the subclasses. + + \param fname XML file name + \param cr actions creator + \return \c true on success and \c false in case of error +*/ /*! - Class: QtxActionMgr::XMLReader - Level: Public + \class QtxActionMgr::XMLReader + \brief XML file reader. + + This class is used to read files of XML format to create + actions and fill an action manager with actions automatically. +*/ + +/*! + \brief Constructor. + \param root root XML tag name + \param item menu item XML tag name + \param dir resources directory (containing icons, etc) */ QtxActionMgr::XMLReader::XMLReader( const QString& root, const QString& item, @@ -412,20 +527,22 @@ QtxActionMgr::XMLReader::XMLReader( const QString& root, } /*! - Destructor + \brief Destructor. */ QtxActionMgr::XMLReader::~XMLReader() { } /*! - Reads file and fills action manager with help of creator - \param fname - file name - \param cr - creator + \brief Read the file and fill and action manager with actions + by using actions creator. + \param fname XML file name + \param cr actions creator + \return \c true on success and \c false in case of error */ bool QtxActionMgr::XMLReader::read( const QString& fname, Creator& cr ) const { - bool res = false; + bool res = false; #ifndef QT_NO_DOM @@ -464,10 +581,10 @@ bool QtxActionMgr::XMLReader::read( const QString& fname, Creator& cr ) const } /*! - Create item by xml node - \param parent_node - parent node - \param parent_id - parent id - \param cr - creator + \brief Read XML mode and create an item if requied. + \param parent_node parent XML file node + \param parent_id parent action ID + \param cr actions creator */ void QtxActionMgr::XMLReader::read( const QDomNode& parent_node, const int parent_id, @@ -504,14 +621,17 @@ void QtxActionMgr::XMLReader::read( const QDomNode& parent_node, } /*! - \return true if node satisfies pattern + \brief Check node name correspondance to some pattern. + \param node XML file node + \param pattern node name pattern + \return \c true if node satisfies pattern */ bool QtxActionMgr::XMLReader::isNodeSimilar( const QDomNode& node, const QString& pattern ) const { if( node.nodeName()==pattern ) return true; - + QDomDocument temp; QString mes; temp.setContent( pattern, true, &mes ); @@ -529,24 +649,30 @@ bool QtxActionMgr::XMLReader::isNodeSimilar( const QDomNode& node, return ok; } - /*! - Class: QtxActionMgr::Creator - Level: Public + \class QtxActionMgr::Creator + \brief Generic actions creator class. + + Used by Reader to create actions and fill in the action + manager with the actions. */ /*! - \return integer value by attributes - \param attrs - attributes - \param name - name of attribute - \param def - default value (is returned on fail) + \brief Get integer attribute value from the attribute map. + + Returns default value (\a def) if the attribute is not found. + + \param attrs attributes map + \param name attribute name + \param def default attribute value + \return attribute value */ int QtxActionMgr::Creator::intValue( const ItemAttributes& attrs, const QString& name, int def ) { if( attrs.contains( name ) ) { - bool ok; + bool ok; int res = attrs[ name ].toInt( &ok ); if( ok ) return res; @@ -555,10 +681,14 @@ int QtxActionMgr::Creator::intValue( const ItemAttributes& attrs, } /*! - \return string value by attributes - \param attrs - attributes - \param name - name of attribute - \param def - default value (is returned on fail) + \brief Get string attribute value from the attribute map. + + Returns default value (\a def) if the attribute is not found. + + \param attrs attributes map + \param name attribute name + \param def default attribute value + \return attribute value */ QString QtxActionMgr::Creator::strValue( const ItemAttributes& attrs, const QString& name, @@ -571,7 +701,8 @@ QString QtxActionMgr::Creator::strValue( const ItemAttributes& attrs, } /*! - Constructor + \brief Constructor. + \param r action reader */ QtxActionMgr::Creator::Creator( QtxActionMgr::Reader* r ) : myReader( r ) @@ -579,14 +710,15 @@ QtxActionMgr::Creator::Creator( QtxActionMgr::Reader* r ) } /*! - Destructor + \brief Destructor. */ QtxActionMgr::Creator::~Creator() { } /*! - \return corresponding reader + \brief Get actions reader. + \return actions reader */ QtxActionMgr::Reader* QtxActionMgr::Creator::reader() const { @@ -594,16 +726,22 @@ QtxActionMgr::Reader* QtxActionMgr::Creator::reader() const } /*! - Connects action to some slots (default implementation is empty) + \brief Connect action to some specific slot(s). + + This method can be redefined in subclasses. + Base implementation does nothing. + + \param a action */ -void QtxActionMgr::Creator::connect( QAction* ) const +void QtxActionMgr::Creator::connect( QAction* /*a*/ ) const { } /*! - Loads pixmap - \param fname - file name - \param pix - to return loaded pixmap + \brief Load pixmap from the file. + \param fname file name + \param pix used to return pixmap + \return \c true if pixmap is loaded successfully and \c false in case of error */ bool QtxActionMgr::Creator::loadPixmap( const QString& fname, QPixmap& pix ) const { @@ -619,3 +757,19 @@ bool QtxActionMgr::Creator::loadPixmap( const QString& fname, QPixmap& pix ) con return res; } + +/*! + \fn int QtxActionMgr::Creator::append( const QString& tag, + const bool subMenu, + const ItemAttributes& attr, + const int pId ) + \brief Create (and probably append to the action manager) new action. + + This method should be redefined in the subclasses. + + \param tag item tag name + \param subMenu \c true if this item is submenu + \param attr attributes map + \param pId parent action ID + \return item (for example action) ID +*/ diff --git a/src/Qtx/QtxActionMgr.h b/src/Qtx/QtxActionMgr.h index a2fee6b7f..98d99e3c6 100644 --- a/src/Qtx/QtxActionMgr.h +++ b/src/Qtx/QtxActionMgr.h @@ -17,16 +17,16 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File: QtxActionMgr.h -// Author: Alexander SOLOVYEV, Sergey TELKOV +// Author: Alexander SOLOVYOV, Sergey TELKOV #ifndef QTXACTIONMGR_H #define QTXACTIONMGR_H #include "Qtx.h" -#include -#include -#include +#include +#include +#include class QTimer; class QAction; @@ -37,11 +37,6 @@ class QDomNode; #endif -/*! - \class QtxActionMgr - Contains set of actions accessible by id. - Base class for menu, popup creators and other action containers. -*/ class QTX_EXPORT QtxActionMgr : public QObject { Q_OBJECT @@ -68,7 +63,7 @@ public: int count() const; bool isEmpty() const; - void idList( QIntList& ) const; + QIntList idList() const; bool isUpdatesEnabled() const; virtual void setUpdatesEnabled( const bool ); @@ -87,7 +82,6 @@ protected: virtual void internalUpdate(); int generateId() const; - //! initialise timer for delayed update void triggerUpdate(); virtual void updateContent(); @@ -95,23 +89,19 @@ private slots: void onUpdateContent(); private: - typedef QPointer ActionPtr; - typedef QMap ActionMap; + typedef QPointer ActionPtr; //!< Action guarded pointer + typedef QMap ActionMap; //!< Actions map private: - bool myUpdate; - ActionMap myActions; - QTimer* myUpdTimer; + bool myUpdate; //!< update flag + ActionMap myActions; //!< actions map + QTimer* myUpdTimer; //!< update timer }; -QTX_EXPORT typedef QMap ItemAttributes; +QTX_EXPORT typedef QMap ItemAttributes; //!< attributes map -/*! - \class QtxActionMgr::Creator - Allows to fill automatically action manager with actions created by data from file -*/ -class QtxActionMgr::Creator +class QTX_EXPORT QtxActionMgr::Creator { public: Creator( QtxActionMgr::Reader* ); @@ -119,57 +109,47 @@ public: Reader* reader() const; - virtual int append( const QString&, const bool, - const ItemAttributes&, const int ) = 0; - virtual void connect( QAction* ) const; + virtual int append( const QString&, const bool, + const ItemAttributes&, const int ) = 0; + virtual void connect( QAction* ) const; - virtual bool loadPixmap( const QString&, QPixmap& ) const; + virtual bool loadPixmap( const QString&, QPixmap& ) const; protected: static int intValue( const ItemAttributes&, const QString&, const int ); static QString strValue( const ItemAttributes&, const QString&, - const QString& = QString::null ); + const QString& = QString::null ); private: - QtxActionMgr::Reader* myReader; + QtxActionMgr::Reader* myReader; //!< actions reader }; -/*! - \class QtxActionMgr::Reader - This class is used to read files of some format - to create actions and to fill action manager automatically -*/ -class QtxActionMgr::Reader +class QTX_EXPORT QtxActionMgr::Reader { public: - QTX_EXPORT Reader(); - QTX_EXPORT virtual ~Reader(); + Reader(); + virtual ~Reader(); - QTX_EXPORT QStringList options() const; - QTX_EXPORT QString option( const QString&, const QString& = QString::null ) const; - QTX_EXPORT void setOption( const QString&, const QString& ); + QStringList options() const; + QString option( const QString&, const QString& = QString::null ) const; + void setOption( const QString&, const QString& ); - QTX_EXPORT virtual bool read( const QString&, Creator& ) const = 0; + virtual bool read( const QString&, Creator& ) const = 0; private: - QMap< QString, QString > myOptions; + QMap< QString, QString > myOptions; //!< options map }; -/*! - \class QtxActionMgr::Reader - This class is used to read files of XML format - to create actions and to fill action manager automatically -*/ -class QtxActionMgr::XMLReader : public Reader +class QTX_EXPORT QtxActionMgr::XMLReader : public Reader { public: - QTX_EXPORT XMLReader( const QString&, const QString&, const QString& ); - QTX_EXPORT virtual ~XMLReader(); + XMLReader( const QString&, const QString&, const QString& ); + virtual ~XMLReader(); - QTX_EXPORT virtual bool read( const QString&, Creator& ) const; + virtual bool read( const QString&, Creator& ) const; protected: - QTX_EXPORT virtual void read( const QDomNode&, const int, Creator& ) const; - QTX_EXPORT virtual bool isNodeSimilar( const QDomNode&, const QString& ) const; + virtual void read( const QDomNode&, const int, Creator& ) const; + virtual bool isNodeSimilar( const QDomNode&, const QString& ) const; }; diff --git a/src/Qtx/QtxActionSet.cxx b/src/Qtx/QtxActionSet.cxx new file mode 100644 index 000000000..b25caad93 --- /dev/null +++ b/src/Qtx/QtxActionSet.cxx @@ -0,0 +1,370 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxActionSet.cxx +// Author: Sergey TELKOV + +#include "QtxActionSet.h" + +/*! + \class QtxActionSet + \brief An action class which is represented in the menu bar (or toolbar) as + a group of items (which can be customized). + + Example: Window menu in the MDI application with menu items: + - Cascade + - Tile vertically + - Tile horizontally + - + - Window1 + - Window2 +*/ + +/*! + \brief Constructor. + \param parent parent object +*/ +QtxActionSet::QtxActionSet( QObject* parent ) +: QtxAction( parent ) +{ + connect( this, SIGNAL( changed() ), this, SLOT( onChanged() ) ); + + setVisible( false ); + + update(); +} + +/*! + \brief Destructor. +*/ +QtxActionSet::~QtxActionSet() +{ +} + +/*! + \brief Get list of child actions. + \return list of assigned actions +*/ +QList QtxActionSet::actions() const +{ + return mySet; +} + +/*! + \brief Assign child actions. + \param lst list of actions +*/ +void QtxActionSet::setActions( const QList& lst ) +{ + for ( ActionList::iterator it = mySet.begin(); it != mySet.end(); ++it ) + { + if ( !lst.contains( *it ) ) + delete *it; + } + + mySet.clear(); + + insertActions( lst ); +} + +/*! + \brief Insert actions at the specified position. + \param lst list of actions + \param index position in the action list (if < 0, items are appended to the end of list) +*/ +void QtxActionSet::insertActions( const QList& lst, const int index ) +{ + int idx = qMin( index < 0 ? mySet.count() : index, mySet.count() ); + + for ( QList::const_iterator it = lst.begin(); it != lst.end(); ++it ) + { + QAction* a = *it; + int ident = generateId(); + + a->setParent( this ); + mySet.insert( idx++, a ); + a->setData( ident ); + + connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onActionTriggered( bool ) ) ); + } + + update(); +} + +/*! + \brief Insert action at the specified position. + + If \a id < 0, it is generated automatically. + + \param a action being inserted + \param id action ID + \param index position in the action list (if < 0, item is appended to the end of list) + \return action identifier +*/ +int QtxActionSet::insertAction( QAction* a, const int id, const int index ) +{ + if ( !a ) + return -1; + + int ident = id < 0 ? generateId() : id; + int idx = qMin( index < 0 ? mySet.count() : index, mySet.count() ); + + a->setParent( this ); + mySet.insert( idx, a ); + a->setData( ident ); + + connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onActionTriggered( bool ) ) ); + + update(); + + return ident; +} + +/*! + \brief Insert action at the specified position. + + If \a id < 0, it is generated automatically. + + \param txt action text + \param id action ID + \param index position in the action list (if < 0, item is appended to the end of list) + \return action identifier +*/ +int QtxActionSet::insertAction( const QString& txt, const int id, const int index ) +{ + return insertAction( new QtxAction( txt, txt, 0, this ), id, index ); +} + +/*! + \brief Insert action at the specified position. + + If \a id < 0, it is generated automatically. + + \param txt action text + \param icon action icon + \param id action ID + \param index position in the action list (if < 0, item is appended to the end of list) + \return action identifier +*/ +int QtxActionSet::insertAction( const QString& txt, const QIcon& icon, const int id, const int index ) +{ + return insertAction( new QtxAction( txt, icon, txt, 0, this ), id, index ); +} + +/*! + \brief Remove specified action. + + An action is removed from the action list and destroyed. + + \param a action to be removed. +*/ +void QtxActionSet::removeAction( QAction* a ) +{ + if ( !mySet.contains( a ) ) + return; + + mySet.removeAll( a ); + delete a; +} + +/*! + \brief Remove specified action. + + An action is removed from the action list and destroyed. + + \param id action identifier +*/ +void QtxActionSet::removeAction( const int id ) +{ + removeAction( action( id ) ); +} + +/*! + \brief Remove all actions. + + An actions list is cleared and all actions are destroyed. +*/ +void QtxActionSet::clear() +{ + qDeleteAll( mySet ); + mySet.clear(); + + update(); +} + +/*! + \brief Called when action is changed. + + Update action state. +*/ +void QtxActionSet::onChanged() +{ + if ( !isVisible() || !isEmptyAction() ) + return; + + bool block = signalsBlocked(); + blockSignals( true ); + setVisible( false ); + blockSignals( block ); +} + +/*! + \brief Called when some action is activated by the user. + \param on toggled state (not used) +*/ +void QtxActionSet::onActionTriggered( bool /*on*/ ) +{ + QAction* a = ::qobject_cast( sender() ); + if ( !a ) + return; + + int id = actionId( a ); + if ( id != -1 ) + emit triggered( id ); + emit triggered( a ); +} + +/*! + \brief Called when this action set is added to the menu bar (or toolbar). + \param w widget this action set is added to +*/ +void QtxActionSet::addedTo( QWidget* w ) +{ + QtxAction::addedTo( w ); + + update( w ); +} + +/*! + \brief Called when this action set is removed from the menu bar (or toolbar). + \param w widget this action set is removed from +*/ +void QtxActionSet::removedFrom( QWidget* w ) +{ + QtxAction::removedFrom( w ); + + update( w ); +} + +/*! + \brief Get action by specified identifier. + \param id action ID + \return action or 0 if it is not found +*/ +QAction* QtxActionSet::action( int id ) const +{ + QAction* a = 0; + for ( ActionList::const_iterator it = mySet.begin(); it != mySet.end() && !a; ++it ) + { + if ( actionId( *it ) == id ) + a = *it; + } + return a; +} + +/*! + \brief Get action identifier for the action. + \param a action + \return action ID or -1 if it is not found +*/ +int QtxActionSet::actionId( QAction* a ) const +{ + int id = -1; + if ( a && a->data().canConvert( QVariant::Int ) ) + id = a->data().toInt(); + return id; +} + +/*! + \brief Set action identifier for the action. + \param a action + \param id new action ID +*/ +void QtxActionSet::setActionId( QAction* a, const int id ) +{ + if ( !a || id == -1 ) + return; + + a->setData( id ); +} + +/*! + \brief Getneration unique action identifier + \return generation action ID +*/ +int QtxActionSet::generateId() const +{ + QMap map; + for ( ActionList::const_iterator it = mySet.begin(); it != mySet.end(); ++it ) + map.insert( (*it)->data().toInt(), 0 ); + + int id = -2; + while ( map.contains( id ) ) + id--; + + return id; +} + +/*! + \brief Update action set. +*/ +void QtxActionSet::update() +{ + QList lst = associatedWidgets(); + for ( QList::iterator it = lst.begin(); it != lst.end(); ++it ) + update( *it ); +} + +/*! + \brief Update action set for the specified widget. + \param w a widget this action is added to +*/ +void QtxActionSet::update( QWidget* w ) +{ + if ( !w ) + return; + + for ( ActionList::iterator it = mySet.begin(); it != mySet.end(); ++it ) + w->removeAction( *it ); + + if ( !associatedWidgets().contains( w ) ) + return; + + for ( int i = 0; i < mySet.count(); i++ ) + { + QAction* a = mySet.at( i ); + w->insertAction( this, a ); + } +} + +bool QtxActionSet::isEmptyAction() const +{ + return true; +} + +/*! + \fn void QtxActionSet::triggered( int id ); + \brief Emitted when some child action is activated by the user. + \param action ID +*/ + +/*! + \fn void QtxActionSet::triggered( QAction* a ); + \brief Emitted when some child action is activated by the user. + \param a action being activated +*/ diff --git a/src/Qtx/QtxActionSet.h b/src/Qtx/QtxActionSet.h new file mode 100644 index 000000000..4de899787 --- /dev/null +++ b/src/Qtx/QtxActionSet.h @@ -0,0 +1,89 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxActionSet.h +// Author: Sergey TELKOV + +#ifndef QTXACTIONSET_H +#define QTXACTIONSET_H + +#include "QtxAction.h" + +#include + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +class QTX_EXPORT QtxActionSet : public QtxAction +{ + Q_OBJECT + +public: + QtxActionSet( QObject* = 0 ); + virtual ~QtxActionSet(); + + QList actions() const; + void setActions( const QList& ); + + void insertActions( const QList&, const int = -1 ); + + int insertAction( QAction*, const int id = -1, const int = -1 ); + int insertAction( const QString&, const int id = -1, const int = -1 ); + int insertAction( const QString&, const QIcon&, const int id = -1, const int = -1 ); + + void removeAction( QAction* ); + void removeAction( const int ); + + void clear(); + +signals: + void triggered( int ); + void triggered( QAction* ); + +private slots: + void onChanged(); + void onActionTriggered( bool = false ); + +protected: + virtual void addedTo( QWidget* ); + virtual void removedFrom( QWidget* ); + + QAction* action( int ) const; + int actionId( QAction* ) const; + void setActionId( QAction*, const int ); + + virtual bool isEmptyAction() const; + +private: + void update(); + void update( QWidget* ); + int generateId() const; + +private: + typedef QList ActionList; + +private: + ActionList mySet; //!< actions list +}; + +#ifdef WIN32 +#pragma warning( default:4251 ) +#endif + +#endif diff --git a/src/Qtx/QtxActionToolMgr.cxx b/src/Qtx/QtxActionToolMgr.cxx index ed0455cc3..a13c60e3c 100644 --- a/src/Qtx/QtxActionToolMgr.cxx +++ b/src/Qtx/QtxActionToolMgr.cxx @@ -17,33 +17,67 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File: QtxActionToolMgr.cxx -// Author: Alexander SOLOVYEV, Sergey TELKOV +// Author: Alexander SOLOVYOV, Sergey TELKOV #include "QtxActionToolMgr.h" #include "QtxAction.h" #include "QtxToolBar.h" -#include +#include /*! - Constructor + \class QtxActionToolMgr::ToolNode + \brief Represents a toolbutton inside toolbar structure. + \internal +*/ + +/*! + \fn QtxActionToolMgr::ToolNode::ToolNode() + \internal + \brief Default constructor. +*/ + +/*! + \fn QtxActionToolMgr::ToolNode::ToolNode( const int _id ) + \brief Constructor. + \internal + \param _id toolbar node ID +*/ + +/*! + \class QtxActionToolMgr + \brief Toolbar actions manager. + + Toolbar manager allows using of set of action for automatic generating of + application toolbars and dynamic update of toolbars contents. + + Use insert(), append() and remove() methods to create toolbar and add actions to it. + Methods show(), hide() allow displaying/erasing of specified toolbar items. + + Toolbar manager automatically optimizes toolbars by removing extra separators, etc. +*/ + +/*! + \brief Constructor. + \param p parent main window */ QtxActionToolMgr::QtxActionToolMgr( QMainWindow* p ) : QtxActionMgr( p ), -myMainWindow( p ) + myMainWindow( p ) { } /*! - Destructor + \brief Destructor. */ QtxActionToolMgr::~QtxActionToolMgr() { } /*! - \return desktop + \brief Get parent main window. + \return main window pointer */ QMainWindow* QtxActionToolMgr::mainWindow() const { @@ -51,26 +85,30 @@ QMainWindow* QtxActionToolMgr::mainWindow() const } /*! - Creates toolbar - \return id of just created toolbar - \param name - name of toolbar - \param tid - proposed id (if such id is used already, then it will be returned without creation) + \brief Create toolbar and assign \a id to it. + + If \a tid is less than 0, the identifier is generated automatically. + If toolbar with given \a tid is already registered, the toolbar will not be created. + + \param title toolbar title + \param tid requested toolbar ID + \return id of created/found toolbar */ -int QtxActionToolMgr::createToolBar( const QString& name, const int tid ) +int QtxActionToolMgr::createToolBar( const QString& title, const int tid ) { static int _toolBarId = -1; int tbId = -1; for ( ToolBarMap::ConstIterator it = myToolBars.begin(); it != myToolBars.end() && tbId == -1; ++it ) { - if ( it.value().toolBar->windowTitle().toLower() == name.toLower() ) + if ( it.value().toolBar->windowTitle().toLower() == title.toLower() ) tbId = it.key(); } if ( tbId != -1 ) return tbId; - QToolBar* tb = find( name, mainWindow() ); + QToolBar* tb = find( title, mainWindow() ); tbId = tid < 0 ? --_toolBarId : tid; @@ -81,7 +119,8 @@ int QtxActionToolMgr::createToolBar( const QString& name, const int tid ) { tb = new QtxToolBar( true, mainWindow() ); mainWindow()->addToolBar( tb ); - tb->setWindowTitle( name ); + tb->setWindowTitle( title ); + tb->setObjectName( title ); } tInfo.toolBar = tb; @@ -91,16 +130,17 @@ int QtxActionToolMgr::createToolBar( const QString& name, const int tid ) } /*! - \return toolbar by title - \param label - toolbar title - \param mw - desktop + \brief Search toolbar with given \a title owned by main window \mw. + \param title toolbar title + \param mw main window + \return toolbar or 0 if it is not found */ -QToolBar* QtxActionToolMgr::find( const QString& label, QMainWindow* mw ) const +QToolBar* QtxActionToolMgr::find( const QString& title, QMainWindow* mw ) const { if ( !mw ) return 0; - QString pattern = label.toLower(); + QString pattern = title.toLower(); QToolBar* res = 0; QList toolbars = qFindChildren( mw ); @@ -113,8 +153,8 @@ QToolBar* QtxActionToolMgr::find( const QString& label, QMainWindow* mw ) const } /*! - Removes toolbar - \param tid - toolbar id + \brief Remove toolbar. + \param tid toolbar ID */ void QtxActionToolMgr::removeToolBar( const int tid ) { @@ -126,19 +166,20 @@ void QtxActionToolMgr::removeToolBar( const int tid ) } /*! - Removes toolbar - \param tname - toolbar name + \brief Remove toolbar. + \param title toolbar title */ -void QtxActionToolMgr::removeToolBar( const QString& tname ) +void QtxActionToolMgr::removeToolBar( const QString& title ) { - removeToolBar( find( tname ) ); + removeToolBar( find( title ) ); } /*! - Insert action into toolbar - \param id - identificator of action - \param tId - identificator of toolbar - \param idx - position inside toolbar + \brief Insert action into toolbar. + \param id action ID + \param tid toolbar ID + \param idx action index in the toolbar (if < 0, action is appended to the end) + \return action ID */ int QtxActionToolMgr::insert( const int id, const int tid, const int idx ) { @@ -148,8 +189,7 @@ int QtxActionToolMgr::insert( const int id, const int tid, const int idx ) if ( containsAction( id, tid ) ) remove( id, tid ); */ - ToolNode node; - node.id = id; + ToolNode node( id ); NodeList& list = myToolBars[tid].nodes; int index = idx < 0 ? list.count() : qMin( idx, (int)list.count() ); @@ -160,42 +200,46 @@ int QtxActionToolMgr::insert( const int id, const int tid, const int idx ) } /*! - Insert action into toolbar - \param act - action - \param tId - identificator of toolbar - \param pos - position inside toolbar + \brief Insert action into toolbar. + \param a action + \param tid toolbar ID + \param idx action index in the toolbar (if < 0, action is appended to the end) + \return action ID */ -int QtxActionToolMgr::insert( QAction* act, const int tid, const int pos ) +int QtxActionToolMgr::insert( QAction* a, const int tid, const int idx ) { - return insert( registerAction( act ), tid, pos ); + return insert( registerAction( a ), tid, idx ); } /*! - Insert action into toolbar - \param id - identificator of action - \param tname - name of toolbar - \param pos - position inside toolbar + \brief Insert action into toolbar. + \param id action ID + \param title toolbar title + \param idx action index in the toolbar (if < 0, action is appended to the end) + \return action ID */ -int QtxActionToolMgr::insert( const int id, const QString& tname, const int pos ) +int QtxActionToolMgr::insert( const int id, const QString& title, const int idx ) { - return insert( id, createToolBar( tname ), pos ); + return insert( id, createToolBar( title ), idx ); } /*! - Insert action into toolbar - \param act - action - \param tname - name of toolbar - \param pos - position inside toolbar + \brief Insert action into toolbar. + \param a action + \param title toolbar title + \param idx action index in the toolbar (if < 0, action is appended to the end) + \return action ID */ -int QtxActionToolMgr::insert( QAction* act, const QString& tname, const int pos ) +int QtxActionToolMgr::insert( QAction* a, const QString& title, const int idx ) { - return insert( registerAction( act ), createToolBar( tname ), pos ); + return insert( registerAction( a ), createToolBar( title ), idx ); } /*! - Append action into toolbar as last toolbutton - \param id - identificator of action - \param tId - identificator of toolbar + \brief Append action to the end of toolbar. + \param id action ID + \param tid toolbar ID + \return action ID */ int QtxActionToolMgr::append( const int id, const int tid ) { @@ -203,39 +247,43 @@ int QtxActionToolMgr::append( const int id, const int tid ) } /*! - Append action into toolbar as last toolbutton - \param act - action - \param tId - identificator of toolbar + \brief Append action to the end of toolbar. + \param a action + \param tid toolbar ID + \return action ID */ -int QtxActionToolMgr::append( QAction* act, const int tid ) +int QtxActionToolMgr::append( QAction* a, const int tid ) { - return insert( act, tid ); + return insert( a, tid ); } /*! - Append action into toolbar as last toolbutton - \param id - identificator of action - \param tname - toolbar name + \brief Append action to the end of toolbar. + \param id action ID + \param title toolbar title + \return action ID */ -int QtxActionToolMgr::append( const int id, const QString& tname ) +int QtxActionToolMgr::append( const int id, const QString& title ) { - return insert( id, tname ); + return insert( id, title ); } /*! - Append action into toolbar as last toolbutton - \param act - action - \param tname - toolbar name + \brief Append action to the end of toolbar. + \param a action + \param title toolbar title + \return action ID */ -int QtxActionToolMgr::append( QAction* act, const QString& tname ) +int QtxActionToolMgr::append( QAction* a, const QString& title ) { - return insert( act, tname ); + return insert( a, title ); } /*! - Append action into toolbar as first toolbutton - \param id - identificator of action - \param tId - identificator of toolbar + \brief Insert action to the beginning of toolbar. + \param id action ID + \param tid toolbar ID + \return action ID */ int QtxActionToolMgr::prepend( const int id, const int tid ) { @@ -243,39 +291,42 @@ int QtxActionToolMgr::prepend( const int id, const int tid ) } /*! - Append action into toolbar as first toolbutton - \param act - action - \param tId - identificator of toolbar + \brief Insert action to the beginning of toolbar. + \param a action + \param tid toolbar ID + \return action ID */ -int QtxActionToolMgr::prepend( QAction* act, const int tid ) +int QtxActionToolMgr::prepend( QAction* a, const int tid ) { - return insert( act, tid, 0 ); + return insert( a, tid, 0 ); } /*! - Append action into toolbar as first toolbutton - \param id - identificator of action - \param tname - toolbar name + \brief Insert action to the beginning of toolbar. + \param id action ID + \param title toolbar title + \return action ID */ -int QtxActionToolMgr::prepend( const int id, const QString& tname ) +int QtxActionToolMgr::prepend( const int id, const QString& title ) { - return insert( id, tname, 0 ); + return insert( id, title, 0 ); } /*! - Append action into toolbar as first toolbutton - \param act - action - \param tname - toolbar name + \brief Insert action to the beginning of toolbar. + \param a action ID + \param title toolbar title + \return action ID */ -int QtxActionToolMgr::prepend( QAction* act, const QString& tname ) +int QtxActionToolMgr::prepend( QAction* a, const QString& title ) { - return insert( act, tname, 0 ); + return insert( a, title, 0 ); } /*! - Remove action from toolbar - \param id - identificator of action - \param tId - identificator of toolbar + \brief Remove action from toolbar. + \param id action ID + \param tid toolbar ID */ void QtxActionToolMgr::remove( const int id, const int tid ) { @@ -296,18 +347,19 @@ void QtxActionToolMgr::remove( const int id, const int tid ) } /*! - Remove action from toolbar - \param id - identificator of action - \param tname - name of toolbar + \brief Remove action from toolbar. + \param id action ID + \param title toolbar title */ -void QtxActionToolMgr::remove( const int id, const QString& tname ) +void QtxActionToolMgr::remove( const int id, const QString& title ) { - remove( id, find( tname ) ); + remove( id, find( title ) ); } /*! - \return toolbar by it's id - \param tId - identificator of toolbar + \brief Get toolbar by given \a tid. + \param tid toolbar ID + \return toolbar or 0 if it is not found */ QToolBar* QtxActionToolMgr::toolBar( const int tid ) const { @@ -318,17 +370,19 @@ QToolBar* QtxActionToolMgr::toolBar( const int tid ) const } /*! - \return toolbar by it's name - \param tname - name of toolbar + \brief Get toolbar by given \a title. + \param title toolbar title + \return toolbar or 0 if it is not found */ -QToolBar* QtxActionToolMgr::toolBar( const QString& tname ) const +QToolBar* QtxActionToolMgr::toolBar( const QString& title ) const { - return toolBar( find( tname ) ); + return toolBar( find( title ) ); } /*! - \return true if manager contains toolbar with such id - \param tId - identificator of toolbar + \brief Check if toolbar with given \a id already registered. + \param tid toolbar ID + \return \c true if toolbar is registered in the toolbar manager */ bool QtxActionToolMgr::hasToolBar( const int tid ) const { @@ -336,18 +390,20 @@ bool QtxActionToolMgr::hasToolBar( const int tid ) const } /*! - \return true if manager contains toolbar with such name - \param tname - name of toolbar + \brief Check if toolbar with given \a id already registered. + \param title toolbar title + \return \c true if toolbar is registered in the toolbar manager */ -bool QtxActionToolMgr::hasToolBar( const QString& tname ) const +bool QtxActionToolMgr::hasToolBar( const QString& title ) const { - return find( tname ) != -1; + return find( title ) != -1; } /*! - \return true if toolbar contains action - \param id - identificator of action - \param tId - identificator of toolbar + \brief Check if toolbar contains given action. + \param id action ID + \param tid toolbar ID + \return \c true if toolbar contains action */ bool QtxActionToolMgr::containsAction( const int id, const int tid ) const { @@ -365,7 +421,9 @@ bool QtxActionToolMgr::containsAction( const int id, const int tid ) const } /*! - SLOT: called when toolbar is destroyed, removes just destroyed toolbar from map + \brief Called when toolbar is destroyed. + + Clears internal pointer to the toolbar to disable crashes. */ void QtxActionToolMgr::onToolBarDestroyed() { @@ -373,49 +431,51 @@ void QtxActionToolMgr::onToolBarDestroyed() } /*! - \return id of toolbar by it's name - \param tname - name of toolbar + \brief Search toolbar by given \a name. + \param title toolbar title + \return toolbar ID or -1 if it is not found */ -int QtxActionToolMgr::find( const QString& tname ) const +int QtxActionToolMgr::find( const QString& title ) const { int id = -1; for ( ToolBarMap::ConstIterator it = myToolBars.begin(); it != myToolBars.end() && id == -1; ++it ) { - if ( it.value().toolBar->windowTitle() == tname ) + if ( it.value().toolBar->windowTitle() == title ) id = it.key(); } return id; } /*! - \return id of toolbar - \param t - toolbar + \brief Get toolbar identifier. + \param tb toolbar + \return toolbar ID or -1 if toolbar is not registered */ -int QtxActionToolMgr::find( QToolBar* t ) const +int QtxActionToolMgr::find( QToolBar* tb ) const { int id = -1; for ( ToolBarMap::ConstIterator it = myToolBars.begin(); it != myToolBars.end() && id == -1; ++it ) { - if ( it.value().toolBar == t ) + if ( it.value().toolBar == tb ) id = it.key(); } return id; } /*! - Updates toolbar - \param tId - toolbar id + \brief Update toolbar. + \param tid toolbar ID */ -void QtxActionToolMgr::updateToolBar( const int tId ) +void QtxActionToolMgr::updateToolBar( const int tid ) { if ( !isUpdatesEnabled() ) return; - if ( !myToolBars.contains( tId ) ) + if ( !myToolBars.contains( tid ) ) return; - QToolBar* tb = myToolBars[tId].toolBar; - const NodeList& list = myToolBars[tId].nodes; + QToolBar* tb = myToolBars[tid].toolBar; + const NodeList& list = myToolBars[tid].nodes; for ( NodeList::const_iterator it = list.begin(); it != list.end(); ++it ) { @@ -429,7 +489,7 @@ void QtxActionToolMgr::updateToolBar( const int tId ) for ( NodeList::const_iterator itr = list.begin(); itr != list.end(); ++itr ) { - if ( !isVisible( (*itr).id, tId ) ) + if ( !isVisible( (*itr).id, tid ) ) continue; QAction* a = action( (*itr).id ); @@ -442,7 +502,7 @@ void QtxActionToolMgr::updateToolBar( const int tId ) } /*! - Updates all toolbars + \brief Update all registered toolbars. */ void QtxActionToolMgr::internalUpdate() { @@ -456,35 +516,36 @@ void QtxActionToolMgr::internalUpdate() } /*! - Removes excess separators from toolbar + \brief Remove extra separators from the toolbar. + \param tb toolbar */ -void QtxActionToolMgr::simplifySeparators( QToolBar* t ) +void QtxActionToolMgr::simplifySeparators( QToolBar* tb ) { - Qtx::simplifySeparators( t ); + Qtx::simplifySeparators( tb ); } /*! - Shows action in all toolbars - \param actId - action id + \brief Show action (in all toolbars). + \param id action ID */ -void QtxActionToolMgr::show( const int actId ) +void QtxActionToolMgr::show( const int id ) { - setShown( actId, true ); + setShown( id, true ); } /*! - Hides action in all toolbars - \param actId - action id + \brief Hide action (in all toolbars). + \param id action ID */ -void QtxActionToolMgr::hide( const int actId ) +void QtxActionToolMgr::hide( const int id ) { - setShown( actId, false ); + setShown( id, false ); } /*! - Changes shown status of action in all toolbars - \param id - action id - \param on - new shown status + \brief Set visibility status for toolbar action with given \a id. + \param id action ID + \param on new visibility status */ void QtxActionToolMgr::setShown( const int id, const bool on ) { @@ -493,8 +554,9 @@ void QtxActionToolMgr::setShown( const int id, const bool on ) } /*! - \return true if action is shown in all toolbars - \param id - action id + \brief Get visibility status for toolbar action with given \a id. + \param id action ID + \return \c true if action is shown in all toolbars */ bool QtxActionToolMgr::isShown( const int id ) const { @@ -521,39 +583,41 @@ bool QtxActionToolMgr::isShown( const int id ) const } /*! - \return shown status of action in toolbar - \param id - action id - \param tId - toolbar id + \brief Check if an action with given \a id is visible in the toolbar \a tid. + \param id action ID + \param tid toolbar ID + \return \c true if action is shown in the toolbar */ -bool QtxActionToolMgr::isVisible( const int id, const int tId ) const +bool QtxActionToolMgr::isVisible( const int id, const int tid ) const { - if ( !myToolBars.contains( tId ) ) + if ( !myToolBars.contains( tid ) ) return false; bool vis = false; - const NodeList& lst = myToolBars[tId].nodes; + const NodeList& lst = myToolBars[tid].nodes; for ( NodeList::const_iterator it = lst.begin(); it != lst.end() && !vis; ++it ) { const ToolNode& node = *it; if ( node.id == id ) + vis = node.visible; } return vis; } /*! - Changes action shown status in certain toolbar - \param id - action id - \param tId - toolbar id - \param on - new shown status + \brief Show/hide action with given \a id in the toolbar \a tid. + \param id action ID + \param tid toolbar ID + \param on new visibility status */ -void QtxActionToolMgr::setVisible( const int id, const int tId, const bool on ) +void QtxActionToolMgr::setVisible( const int id, const int tid, const bool on ) { - if ( !myToolBars.contains( tId ) ) + if ( !myToolBars.contains( tid ) ) return; bool changed = false; - NodeList& lst = myToolBars[tId].nodes; + NodeList& lst = myToolBars[tid].nodes; for ( NodeList::iterator it = lst.begin(); it != lst.end(); ++it ) { ToolNode& node = *it; @@ -565,13 +629,14 @@ void QtxActionToolMgr::setVisible( const int id, const int tId, const bool on ) } if ( changed ) - triggerUpdate( tId ); + triggerUpdate( tid ); } /*! - Loads toolbar content from file - \param fname - file name - \param r - reader + \brief Load toolbar contents from the file. + \param fname file name + \param r actions reader + \return \c true on success and \c false on error */ bool QtxActionToolMgr::load( const QString& fname, QtxActionMgr::Reader& r ) { @@ -580,7 +645,9 @@ bool QtxActionToolMgr::load( const QString& fname, QtxActionMgr::Reader& r ) } /*! - \Perform delayed update + \brief Called when delayed content update is performed. + + Customizes the content update operation. */ void QtxActionToolMgr::updateContent() { @@ -593,17 +660,28 @@ void QtxActionToolMgr::updateContent() } /*! - \ Sets trigger to update + \brief Perform delayed toolbar update. + \param tid toolbar ID */ -void QtxActionToolMgr::triggerUpdate( const int id ) +void QtxActionToolMgr::triggerUpdate( const int tid ) { - myUpdateIds.insert( id, 0 ); + myUpdateIds.insert( tid, 0 ); QtxActionMgr::triggerUpdate(); } + +/*! + \class QtxActionToolMgr::ToolCreator + \brief Toolbars creator. + + Used by Reader to create actions by reading descriptions from the file, + create toolbars and fill in the toolbara with the actions. +*/ + /*! - Class: QtxActionToolMgr::ToolCreator - Level: Public + \brief Constructor. + \param r actions reader + \param mgr toolbar manager */ QtxActionToolMgr::ToolCreator::ToolCreator( QtxActionMgr::Reader* r, QtxActionToolMgr* mgr ) @@ -613,21 +691,22 @@ QtxActionToolMgr::ToolCreator::ToolCreator( QtxActionMgr::Reader* r, } /*! - Destructor + \brief Destructor. */ QtxActionToolMgr::ToolCreator::~ToolCreator() { } /*! - Appends new tool buttons - \param tag - tag of toolmenu - \param subMenu - it has submenu (not used here) - \param attr - list of attributes - \param pId - id of action corresponding to parent item + \brief Create and append to the action manager a new toolbar or toolbar action. + \param tag item tag name + \param subMenu \c true if this item is submenu (not used) + \param attr attributes map + \param tid toolbar ID + \return toolbar or toolbar action ID */ -int QtxActionToolMgr::ToolCreator::append( const QString& tag, const bool subMenu, - const ItemAttributes& attr, const int tId ) +int QtxActionToolMgr::ToolCreator::append( const QString& tag, const bool /*subMenu*/, + const ItemAttributes& attr, const int tid ) { if( !myMgr || !reader() ) return -1; @@ -643,10 +722,10 @@ int QtxActionToolMgr::ToolCreator::append( const QString& tag, const bool subMen toggle = reader()->option( "toggle", "toggle" ); int res = -1, actId = intValue( attr, id, -1 ); - if( tId==-1 ) + if( tid==-1 ) res = myMgr->createToolBar( strValue( attr, label ), intValue( attr, id, -1 ) ); else if( tag==sep ) - res = myMgr->insert( separator(), tId, intValue( attr, pos, -1 ) ); + res = myMgr->insert( separator(), tid, intValue( attr, pos, -1 ) ); else { QIcon set; @@ -663,7 +742,7 @@ int QtxActionToolMgr::ToolCreator::append( const QString& tag, const bool subMen connect( newAct ); int aid = myMgr->registerAction( newAct, actId ); - res = myMgr->insert( aid, tId, intValue( attr, pos, -1 ) ); + res = myMgr->insert( aid, tid, intValue( attr, pos, -1 ) ); } return res; diff --git a/src/Qtx/QtxActionToolMgr.h b/src/Qtx/QtxActionToolMgr.h index b8b39227d..be8bda268 100644 --- a/src/Qtx/QtxActionToolMgr.h +++ b/src/Qtx/QtxActionToolMgr.h @@ -17,53 +17,40 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File: QtxActionToolMgr.h -// Author: Alexander SOLOVYEV, Sergey TELKOV +// Author: Alexander SOLOVYOV, Sergey TELKOV #ifndef QTXACTIONTOOLMGR_H #define QTXACTIONTOOLMGR_H #include "Qtx.h" - -#include -#include - -#include - #include "QtxActionMgr.h" +#include +#include + class QToolBar; class QMainWindow; +class QAction; #ifdef WIN32 #pragma warning( disable:4251 ) #endif -/*! - \class QtxActionToolMgr - Allows to use set of action to automatically build set of toolbars. - With help of methods insert/append/remove it is possible to - describe toolbars and its internal structure. - This manager is able to attune toolbar by removing excess separators -*/ class QTX_EXPORT QtxActionToolMgr : public QtxActionMgr { Q_OBJECT - /*! - \class ToolNode - Represents a toolbutton inside toolbar - For internal purposes only - */ class ToolNode { public: ToolNode() : id( -1 ), visible( true ) {}; + ToolNode( const int _id ) : id( _id ), visible( true ) {}; - int id; - bool visible; + int id; //!< tool node ID + bool visible; //!< visibility status }; - typedef QList NodeList; + typedef QList NodeList; //!< toolbar nodes list protected: class ToolCreator; @@ -132,19 +119,15 @@ private: void triggerUpdate( const int ); private: - typedef struct { NodeList nodes; QToolBar* toolBar; } ToolBarInfo; - typedef QMap ToolBarMap; + typedef struct { NodeList nodes; QToolBar* toolBar; } ToolBarInfo; //!< toolbar info + typedef QMap ToolBarMap; //!< toolbars map private: - ToolBarMap myToolBars; - QMainWindow* myMainWindow; - QMap myUpdateIds; + ToolBarMap myToolBars; //!< toobars map + QMainWindow* myMainWindow; //!< parent main window + QMap myUpdateIds; //!< list of actions ID being updated }; -/*! - \class QtxActionToolMgr::ToolCreator - Allows to create automatically toolbar by data read from file -*/ class QtxActionToolMgr::ToolCreator : public QtxActionMgr::Creator { public: @@ -155,7 +138,7 @@ public: const ItemAttributes&, const int ); private: - QtxActionToolMgr* myMgr; + QtxActionToolMgr* myMgr; //!< toolbar manager }; #endif diff --git a/src/Qtx/QtxColorButton.cxx b/src/Qtx/QtxColorButton.cxx new file mode 100644 index 000000000..d921487ce --- /dev/null +++ b/src/Qtx/QtxColorButton.cxx @@ -0,0 +1,358 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxColorButton.cxx +// Author: Sergey TELKOV + +#include "QtxColorButton.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/*! + \class QtxColorButton + \brief The QtxColorButton class implements a widget for color + preference items editing. + + The color preference item is represented as the colored button with + assocoiated popup menu whihc is called when the user presses the small + arrow button near it. The popup menu allows selecting of the color + from the predefined set. In addition it contains the button which + invokes standard "Select color" dialog box. + + Initial color value can be set with setColor() method. Chosen color + can be retrieved with the color() method. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +QtxColorButton::QtxColorButton( QWidget* parent ) +: QToolButton( parent ) +{ + setCheckable( false ); + setPopupMode( MenuButtonPopup ); + + QMenu* pm = new QMenu( this ); + QGridLayout* grid = new QGridLayout( pm ); + grid->setMargin( 5 ); + grid->setSpacing( 0 ); + + QList cList = colorsList(); + int w = 8; + int h = cList.count() / w; + + for ( int y = 0; y < h; y++ ) + { + for ( int x = 0; x < w; x++ ) + { + QColor c = cList.at( x * h + y ).toRgb(); + QToolButton* btn = new QToolButton( pm ); + btn->setAutoRaise( true ); + btn->setCheckable( true ); + myColors.insert( btn, c ); + grid->addWidget( btn, y, x ); + + btn->installEventFilter( this ); + + connect( btn, SIGNAL( clicked( bool ) ), this, SLOT( onToggled( bool ) ) ); + + updateButton( btn ); + } + } + + QToolButton* other = new QToolButton( pm ); + other->setText( tr( "Other colors..." ) ); + other->setAutoRaise( true ); + other->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + grid->addWidget( other, grid->rowCount(), 0, 1, grid->columnCount() ); + connect( other, SIGNAL( clicked( bool ) ), this, SLOT( onDialogClicked( bool ) ) ); + + other->installEventFilter( this ); + + setMenu( pm ); + + connect( this, SIGNAL( clicked( bool ) ), this, SLOT( onClicked( bool ) ) ); + connect( pm, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) ); +} + +/*! + \brief Destructor. +*/ +QtxColorButton::~QtxColorButton() +{ +} + +/*! + \brief Get currently selected color. + + Returns null QColor if no color is selected. + + \return selected color + \sa setColor() +*/ +QColor QtxColorButton::color() const +{ + return myColors.contains( this ) ? myColors[this] : QColor(); +} + +/*! + \brief Set color. + \param c color to be set as current + \sa color() +*/ +void QtxColorButton::setColor( const QColor& c ) +{ + myColors.insert( this, c ); + updateState(); + update(); +} + +/*! + \brief Filter events for the child widgets. + \param o event receiver object + \param e event + \return \c true if the event should be filtered +*/ +bool QtxColorButton::eventFilter( QObject* o, QEvent* e ) +{ + if ( e->type() == QEvent::Leave ) + updateButton( qobject_cast( o ) ); + return QToolButton::eventFilter( o, e ); +} + +/*! + \brief Called when the popup menu is about to show. + + Updates the menu and child widgets state. +*/ +void QtxColorButton::onAboutToShow() +{ + updateState(); +} + +/*! + \brief Called when the button is clicked by the user. + + Emits the signal clicked( QColor ). + + \param on button state (not used) +*/ +void QtxColorButton::onClicked( bool /*on*/ ) +{ + emit clicked( color() ); +} + +/*! + \brief Called when any color selection button from popup menu + is clicked. + + Changes the currently selected color and emits the signal + changed( QColor ). + + \param on button state +*/ +void QtxColorButton::onToggled( bool on ) +{ + const QToolButton* tb = ::qobject_cast( sender() ); + if ( !tb ) + return; + + QColor old = color(); + + if ( on && myColors.contains( tb ) ) + { + myColors.insert( this, myColors[tb] ); + updateButton( this ); + } + + if ( menu() ) + menu()->hide(); + + updateState(); + + if ( old != color() ) + emit changed( color() ); +} + +/*! + \brief Called the "Other colors" child button from popup menu + is clicked. + + Invokes standard "Select color" dialog box allowing user to select + custom color. If the current color is changed by the user, emits + the signal changed( QColor ). + + \param on (not used) +*/ +void QtxColorButton::onDialogClicked( bool ) +{ + QColor c = QColorDialog::getColor( color(), this ); + if ( !c.isValid() ) + return; + + QColor old = color(); + + setColor( c ); + + if ( old != color() ) + emit changed( color() ); +} + +/*! + \brief Customize paint event for the widget. + \param e paint event +*/ +void QtxColorButton::paintEvent( QPaintEvent* e ) +{ + QToolButton::paintEvent( e ); + + if ( !color().isValid() ) + return; + + QStyleOptionToolButton opt; + opt.initFrom( this ); + opt.text = text(); + opt.icon = icon(); + opt.features = QStyleOptionToolButton::Menu; + + QRect r = style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton ); + r.setTopLeft( r.topLeft() + QPoint( 2, 2 ) ); + r.setBottomRight( r.bottomRight() - QPoint( 2, 2 ) ); + + QPixmap pix( r.size() ); + pix.fill( palette().color( backgroundRole() ) ); + drawColor( &pix, color() ); + + QPainter p( this ); + p.drawPixmap( r, pix ); + p.end(); +} + +/*! + \brief Update widget state. +*/ +void QtxColorButton::updateState() +{ + QList bList = qFindChildren( menu() ); + for ( QList::iterator cit = bList.begin(); cit != bList.end(); ++cit ) + updateButton( *cit ); +} + +/*! + \brief Update child button state. + \param btn child button +*/ +void QtxColorButton::updateButton( QToolButton* btn ) +{ + QColor c = color().toRgb(); + bool block = btn->signalsBlocked(); + btn->blockSignals( true ); + btn->setChecked( false ); + if ( myColors.contains( btn ) ) { + btn->setIcon( buttonIcon( myColors[btn] ) ); + btn->setChecked( myColors[btn].toRgb() == c ); + } + btn->setDown( false ); + btn->blockSignals( block ); +} + +/*! + \brief Generate (if necessary) or get the icon for the button. + \param c color to be used for the icon + \return icon pixmap for the button +*/ +QPixmap QtxColorButton::buttonIcon( const QColor& c ) const +{ + static QMap pixMap; + + if ( pixMap.contains( c.rgb() ) ) + return pixMap[c.rgb()]; + + QPixmap pix( 16, 16 ); + + QColor bg = Qt::white; + if ( bg == c ) + bg = Qt::gray; + pix.fill( bg ); + + drawColor( &pix, c ); + + pix.setMask( pix.createHeuristicMask() ); + + pixMap.insert( c.rgb(), pix ); + + return pix; +} + +/*! + \brief Draw pixmap. + \param pd paint device + \param c color + \param m margin +*/ +void QtxColorButton::drawColor( QPaintDevice* pd, const QColor& c, const int m ) const +{ + if ( !pd ) + return; + + QPainter p( pd ); + p.setPen( Qt::black ); + p.fillRect( m, m, pd->width() - 2 * m - 1, pd->height() - 2 * m - 1, QBrush( c ) ); + p.drawRect( m, m, pd->width() - 2 * m - 1, pd->height() - 2 * m - 1 ); + p.end(); +} + +/*! + \brief Get predefined list of colors to be used in the popup menu. + \return list of colors +*/ +QList QtxColorButton::colorsList() const +{ + QList lst; + + for ( int g = 0; g < 4; g++ ) + { + for ( int r = 0; r < 4; r++ ) + { + for ( int b = 0; b < 3; b++ ) + lst.append( QColor( qRgb( r * 255 / 3, g * 255 / 3, b * 255 / 2 ) ) ); + } + } + return lst; +} + +/*! + \fn void QtxColorButton::clicked( QColor color ); + \brief This signal is emitted when the widget button is clicked by + the user. + \param color current color +*/ + +/*! + \fn void QtxColorButton::changed( QColor color ); + \brief This signal is emitted when the current color is changed. + \param color new current color +*/ diff --git a/src/Qtx/QtxColorButton.h b/src/Qtx/QtxColorButton.h new file mode 100644 index 000000000..bb7a37eec --- /dev/null +++ b/src/Qtx/QtxColorButton.h @@ -0,0 +1,75 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxColorButton.h +// Author: Sergey TELKOV + +#ifndef QTXCOLORBUTTON_H +#define QTXCOLORBUTTON_H + +#include "Qtx.h" + +#include +#include +#include +#include + +class QPaintDevice; + +class QTX_EXPORT QtxColorButton : public QToolButton +{ + Q_OBJECT + +public: + QtxColorButton( QWidget* = 0 ); + virtual ~QtxColorButton(); + + QColor color() const; + void setColor( const QColor& ); + + bool eventFilter( QObject*, QEvent* ); + +signals: + void clicked( QColor ); + void changed( QColor ); + +private slots: + void onAboutToShow(); + void onClicked( bool ); + void onToggled( bool ); + void onDialogClicked( bool ); + +protected: + virtual void paintEvent( QPaintEvent* ); + +private: + QList colorsList() const; + + void updateState(); + void updateButton( QToolButton* ); + QPixmap buttonIcon( const QColor& ) const; + void drawColor( QPaintDevice*, const QColor&, const int = 1 ) const; + +private: + typedef QMap ColorMap; + +private: + ColorMap myColors; +}; + +#endif diff --git a/src/Qtx/QtxColorScale.cxx b/src/Qtx/QtxColorScale.cxx index 2a62d888e..97b61a2b3 100755 --- a/src/Qtx/QtxColorScale.cxx +++ b/src/Qtx/QtxColorScale.cxx @@ -21,969 +21,1072 @@ #include "QtxColorScale.h" -#include -#include -#include - -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include /*! - Constructor + \class QtxColorScale + \brief Color Scale widget. +*/ + +/*! + \brief Constructor. + \param parent parent widget + \param f widget flags */ QtxColorScale::QtxColorScale( QWidget* parent, Qt::WindowFlags f ) : QFrame( parent, f ), -myMin( 0.0 ), -myMax( 1.0 ), -myTitle( "" ), -myInterval( 10 ), -myFormat( "%.4g" ), -myColorMode( Auto ), -myLabelMode( Auto ), -myLabelPos( Right ), -myTitlePos( Center ), -myDumpMode( NoDump ), -myFlags( AtBorder | WrapTitle ) + myMin( 0.0 ), + myMax( 1.0 ), + myTitle( "" ), + myFormat( "%.4g" ), + myInterval( 10 ), + myDumpMode( NoDump ), + myColorMode( Auto ), + myLabelMode( Auto ), + myFlags( AtBorder | WrapTitle ), + myLabelPos( Right ), + myTitlePos( Center ) { - setWindowTitle( tr ( "Color scale" ) ); + setWindowTitle( tr ( "Color scale" ) ); } /*! - Constructor + \brief Constructor. + \param num number of color scale intervals + \param parent parent widget + \param f widget flags */ QtxColorScale::QtxColorScale( const int num, QWidget* parent, Qt::WindowFlags f ) : QFrame( parent, f ), -myMin( 0.0 ), -myMax( 1.0 ), -myTitle( "" ), -myInterval( num ), -myFormat( "%.4g" ), -myColorMode( Auto ), -myLabelMode( Auto ), -myLabelPos( Right ), -myTitlePos( Center ), -myDumpMode( NoDump ), -myFlags( AtBorder | WrapTitle ) + myMin( 0.0 ), + myMax( 1.0 ), + myTitle( "" ), + myFormat( "%.4g" ), + myInterval( num ), + myDumpMode( NoDump ), + myColorMode( Auto ), + myLabelMode( Auto ), + myFlags( AtBorder | WrapTitle ), + myLabelPos( Right ), + myTitlePos( Center ) { - setWindowTitle( tr ( "Color scale" ) ); + setWindowTitle( tr ( "Color scale" ) ); } /*! - Destructor + \brief Destructor. + + Does nothing for the moment. */ QtxColorScale::~QtxColorScale() { } /*! - \returns minimal limit of scale. + \brief Get color scale minimum value. + \return lower limit of the color scale */ double QtxColorScale::minimum() const { - return myMin; + return myMin; } /*! - \return maximal limit of scale. + \brief Get color scale maximum value. + \return upper limit of the color scale */ double QtxColorScale::maximum() const { - return myMax; + return myMax; } /*! - \return range (minimal and maximal limits) of scale. + \brief Get color scale range. + \param min returning lower limit of the color scale + \param max returning upper limit of the color scale */ void QtxColorScale::range( double& min, double& max ) const { - min = myMin; - max = myMax; + min = myMin; + max = myMax; } /*! - \return the current title string. + \brief Get color scale title. + \return current title */ QString QtxColorScale::title() const { - return myTitle; + return myTitle; } /*! - \returns the current format of number presentation in labels for Auto label mode (sprintf specification). + \brief Get current format of the number presentation. + + This format is used to output values in the color scale labels + in "Auto" label mode. The format uses sprintf specification. + + \return current format */ QString QtxColorScale::format() const { - return myFormat; + return myFormat; } /*! - \return dump mode. + \brief Get Color scale dump mode. + \return current dump mode (QtxColorScale::DumpMode) */ int QtxColorScale::dumpMode() const { - return myDumpMode; + return myDumpMode; } /*! - \return label mode. + \brief Get label mode. + \return current label mode (QtxColorScale::Mode) */ int QtxColorScale::labelMode() const { - return myLabelMode; + return myLabelMode; } /*! - \return color mode. + \brief Get color mode. + \return current color mode (QtxColorScale::Mode) */ int QtxColorScale::colorMode() const { - return myColorMode; + return myColorMode; } /*! - \return intervals number of color scale. + \brief Get number of color scale intervals. + \return number of intervals */ int QtxColorScale::intervalsNumber() const { - return myInterval; + return myInterval; } /*! - \return the user label of specified interval. + \brief Get user label for the specified color scale interval. + \param idx interval index + \return user label for specified interval */ QString QtxColorScale::label( const int idx ) const { - QString res; - if ( idx >= 0 && idx < (int)myLabels.count() ) - res = myLabels[idx]; - return res; + QString res; + if ( idx >= 0 && idx < (int)myLabels.count() ) + res = myLabels[idx]; + return res; } /*! - \return the user color of specified interval. + \brief Get user color for the specified color scale interval. + \param idx interval index + \return user color for specified interval */ QColor QtxColorScale::color( const int idx ) const { - QColor res; - if ( idx >= 0 && idx < (int)myColors.count() ) - res = myColors[idx]; - return res; + QColor res; + if ( idx >= 0 && idx < (int)myColors.count() ) + res = myColors[idx]; + return res; } /*! - \return the user labels. + \brief Get user labels for all color scale intervals. + \param list returning labels list */ void QtxColorScale::labels( QStringList& list ) const { - list = myLabels; + list = myLabels; } /*! - \return the user color. + \brief Get user colors for all color scale intervals. + \param list returning colors list */ void QtxColorScale::colors( QList& list ) const { - list = myColors; + list = myColors; } /*! - \return the label position. + \brief Get label position. + \return label position (QtxColorScale::Position) */ int QtxColorScale::labelPosition() const { - return myLabelPos; + return myLabelPos; } /*! - \return the title position. + \brief Get title position. + \return title position (QtxColorScale::Position) */ int QtxColorScale::titlePosition() const { - return myTitlePos; + return myTitlePos; } /*! - Sets the minimum limit. + \brief Set color scale minimum value. + \param val lower limit of the color scale */ void QtxColorScale::setMinimum( const double val ) { - setRange( val, maximum() ); + setRange( val, maximum() ); } /*! - Sets the maximum limit. + \brief Set color scale maximum value. + \param val upper limit of the color scale */ void QtxColorScale::setMaximum( const double val ) { - setRange( minimum(), val ); + setRange( minimum(), val ); } /*! - Sets the minimum and maximum limits. + \brief Set color scale range. + \param min lower limit of the color scale + \param max upper limit of the color scale */ void QtxColorScale::setRange( const double min, const double max ) { - if ( myMin == min && myMax == max ) - return; - - myMin = min; - myMax = max; - - myPrecise = QString::null; + if ( myMin == min && myMax == max ) + return; + + myMin = min; + myMax = max; + + myPrecise = QString::null; - if ( colorMode() == Auto || labelMode() == Auto ) - updateScale(); + if ( colorMode() == Auto || labelMode() == Auto ) + updateScale(); } /*! - Sets the title string. + \brief Set color scale title. + \param str new title */ void QtxColorScale::setTitle( const QString& str ) { - if ( myTitle == str ) - return; - - myTitle = str; - updateScale(); + if ( myTitle == str ) + return; + + myTitle = str; + updateScale(); } /*! - Sets the format of number presentation in labels for - Auto label mode (sprintf specification). + \brief Set current format of the number presentation. + \sa format() + \param format new number presentation format */ void QtxColorScale::setFormat( const QString& format ) { - if ( myFormat == format ) - return; + if ( myFormat == format ) + return; - myFormat = format; - myPrecise = QString::null; - if ( colorMode() == Auto ) - updateScale(); + myFormat = format; + myPrecise = QString::null; + if ( colorMode() == Auto ) + updateScale(); } /*! - Sets the number of intervals. + \brief Set number of color scale intervals. + \param num number of intervals */ void QtxColorScale::setIntervalsNumber( const int num ) { - if ( myInterval == num || num < 1 ) - return; - - myInterval = num; - myPrecise = QString::null; - - updateScale(); + if ( myInterval == num || num < 1 ) + return; + + myInterval = num; + myPrecise = QString::null; + + updateScale(); } /*! - Sets the user label for specified interval. If number - of interval is negative then user label will be added - as new at the end of list. + \brief Set user label for the specified color scale interval. + + If number of interval is negative then user label will be added + as new to the end of list. + + \param txt user label + \param idx interval index */ void QtxColorScale::setLabel( const QString& txt, const int idx ) { - bool changed = false; - uint i = idx < 0 ? myLabels.count() : idx; - if ( i < myLabels.count() ) - { - changed = myLabels[i] != txt; - myLabels[i] = txt; - } - else - { - changed = true; - while ( i >= myLabels.count() ) - myLabels.append( "" ); - myLabels[i] = txt; - } - if ( changed ) - updateScale(); -} - -/*! - Sets the user color for specified interval. If number - of interval is negative then user color will be added - as new at the end of list. + bool changed = false; + int i = idx < 0 ? myLabels.count() : idx; + if ( i < myLabels.count() ) + { + changed = myLabels[i] != txt; + myLabels[i] = txt; + } + else + { + changed = true; + while ( i >= myLabels.count() ) + myLabels.append( "" ); + myLabels[i] = txt; + } + if ( changed ) + updateScale(); +} + +/*! + \brief Set user color for the specified color scale interval. + + If number of interval is negative then user color will be added + as new to the end of list. + + \param clr user color + \param idx interval index */ void QtxColorScale::setColor( const QColor& clr, const int idx ) { - bool changed = false; - uint i = idx < 0 ? myColors.count() : idx; - if ( i < myColors.count() ) - { - changed = myColors[i] != clr; - myColors[i] = clr; - } - else - { - changed = true; - while ( i >= myColors.count() ) - myColors.append( QColor() ); - myColors[i] = clr; - } - if ( changed ) - updateScale(); + bool changed = false; + int i = idx < 0 ? myColors.count() : idx; + if ( i < myColors.count() ) + { + changed = myColors[i] != clr; + myColors[i] = clr; + } + else + { + changed = true; + while ( i >= myColors.count() ) + myColors.append( QColor() ); + myColors[i] = clr; + } + if ( changed ) + updateScale(); } /*! - Replace the all user label with specified list. + \brief Set user labels for all color scale intervals. + \param list new labels list */ void QtxColorScale::setLabels( const QStringList& list ) { - if ( list.isEmpty() ) - return; + if ( list.isEmpty() ) + return; - myLabels = list; - updateScale(); + myLabels = list; + updateScale(); } /*! - Replace the all user colors with specified list. + \brief Set user colors for all color scale intervals. + \param list new colors list */ void QtxColorScale::setColors( const QList& list ) { - if ( list.isEmpty() ) - return; + if ( list.isEmpty() ) + return; - myColors = list; - updateScale(); + myColors = list; + updateScale(); } /*! - Sets the color mode (Auto or User). + \brief Set color scale color mode. + \param mode new color mode (QtxColorScale::Mode) */ void QtxColorScale::setColorMode( const int mode ) { - if ( myColorMode == mode ) - return; - - myColorMode = mode; - updateScale(); + if ( myColorMode == mode ) + return; + + myColorMode = mode; + updateScale(); } /*! - Sets the dump mode. + \brief Set color scale dump mode. + \param mode new dump mode (QtxColorScale::DumpMode) */ void QtxColorScale::setDumpMode( const int mode ) { - myDumpMode = mode; + myDumpMode = mode; } /*! - Sets the label mode (Auto or User). + \brief Set color scale label mode. + \param mode new label mode (QtxColorScale::Mode) */ void QtxColorScale::setLabelMode( const int mode ) { - if ( myLabelMode != mode ) - { - myLabelMode = mode; - updateScale(); - } + if ( myLabelMode != mode ) + { + myLabelMode = mode; + updateScale(); + } } /*! - Sets the label position. + \brief Set label position. + \param pos new label position (QtxColorScale::Position) */ void QtxColorScale::setLabelPosition( const int pos ) { - if ( myLabelPos != pos && pos >= None && pos <= Center ) - { - myLabelPos = pos; - updateScale(); - } + if ( myLabelPos != pos && pos >= None && pos <= Center ) + { + myLabelPos = pos; + updateScale(); + } } /*! - Sets the title position. + \brief Set title position. + \param pos new title position (QtxColorScale::Position) */ void QtxColorScale::setTitlePosition( const int pos ) { - if ( myTitlePos != pos && pos >= None && pos <= Center ) - { - myTitlePos = pos; - updateScale(); - } + if ( myTitlePos != pos && pos >= None && pos <= Center ) + { + myTitlePos = pos; + updateScale(); + } } /*! - Set the specified flags. + \brief Set color scale flags. + \param flags new flags */ void QtxColorScale::setFlags( const int flags ) { - int prev = myFlags; - myFlags |= flags; - if ( prev != myFlags ) - updateScale(); + int prev = myFlags; + myFlags |= flags; + if ( prev != myFlags ) + updateScale(); } /*! - \return true if specified flags are setted. + \brief Test color scale flags. + \return \c true if specified flags are set */ bool QtxColorScale::testFlags( const int flags ) const { - return ( myFlags & flags ) == flags; + return ( myFlags & flags ) == flags; } /*! - Clear (reset) the specified flags. + \brief Clear (reset) color scale flags. + \param flags color scale flags to be cleared */ void QtxColorScale::clearFlags( const int flags ) { - int prev = myFlags; - myFlags &= ~flags; - if ( prev != myFlags ) - updateScale(); + int prev = myFlags; + myFlags &= ~flags; + if ( prev != myFlags ) + updateScale(); } /*! + \brief Get widget's minumum size hint. \return minimum size hint */ QSize QtxColorScale::minimumSizeHint() const { QSize sz = calculateSize( true, myFlags, titlePosition() != None, labelPosition() != None, true ); - return sz + QSize( frameWidth(), frameWidth() ); + return sz + QSize( frameWidth(), frameWidth() ); } /*! + \brief Get widget's default size hint. \return size hint */ QSize QtxColorScale::sizeHint() const { QSize sz = calculateSize( false, myFlags, titlePosition() != None, labelPosition() != None, true ); - return sz + QSize( frameWidth(), frameWidth() ); + return sz + QSize( frameWidth(), frameWidth() ); } /*! - Dump color scale into pixmap with current size. + \brief Calculate color scale size. + \param min if \c true, color scale size is calculated to be as smallest as possible + \param flags color scale flags + \param title color scale title + \param labels if \c true take into account labels + \param colors if \c true take into account colors + \return color scale size */ QSize QtxColorScale::calculateSize( const bool min, const int flags, const bool title, - const bool labels, const bool colors ) const + const bool labels, const bool colors ) const { - int num = intervalsNumber(); - - int spacer = 5; - int textWidth = 0; - int textHeight = fontMetrics().height(); - int colorWidth = 20; - - if ( labels && colors ) + int num = intervalsNumber(); + + int spacer = 5; + int textWidth = 0; + int textHeight = fontMetrics().height(); + int colorWidth = 20; + + if ( labels && colors ) { QtxColorScale* that = (QtxColorScale*)this; QString fmt = that->myFormat; - for ( int idx = 0; idx < num; idx++ ) - textWidth = qMax( textWidth, fontMetrics().width( getLabel( idx ) ) ); - + for ( int idx = 0; idx < num; idx++ ) + textWidth = qMax( textWidth, fontMetrics().width( getLabel( idx ) ) ); + if ( !min ) that->myFormat = that->myFormat.replace( QRegExp( "g" ), "f" ); - - for ( int index = 0; index < num; index++ ) - textWidth = qMax( textWidth, fontMetrics().width( getLabel( index ) ) ); - + + for ( int index = 0; index < num; index++ ) + textWidth = qMax( textWidth, fontMetrics().width( getLabel( index ) ) ); + that->myFormat = fmt; } + + int scaleWidth = 0; + int scaleHeight = 0; + + int titleWidth = 0; + int titleHeight = 0; + + if ( flags & AtBorder ) + { + num++; + if ( min && title && !myTitle.isEmpty() ) + titleHeight += 10; + } + + if ( colors ) + { + scaleWidth = colorWidth + textWidth + ( textWidth ? 3 : 2 ) * spacer; + if ( min ) + scaleHeight = qMax( 2 * num, 3 * textHeight ); + else + scaleHeight = (int)( 1.5 * ( num + 1 ) * textHeight ); + } - int scaleWidth = 0; - int scaleHeight = 0; - - int titleWidth = 0; - int titleHeight = 0; - - if ( flags & AtBorder ) - { - num++; - if ( min && title && !myTitle.isEmpty() ) - titleHeight += 10; - } - - if ( colors ) - { - scaleWidth = colorWidth + textWidth + ( textWidth ? 3 : 2 ) * spacer; - if ( min ) - scaleHeight = qMax( 2 * num, 3 * textHeight ); - else - scaleHeight = (int)( 1.5 * ( num + 1 ) * textHeight ); - } - - if ( title ) - { - QTextDocument* srt = textDocument( flags ); - if ( srt ) - { - QPainter p( (QtxColorScale*)this ); - if ( scaleWidth ) - srt->setTextWidth( scaleWidth ); - - titleHeight = srt->size().height() + spacer; - titleWidth = srt->size().width() + 10; - - } + if ( title ) + { + QTextDocument* srt = textDocument( flags ); + if ( srt ) + { + QPainter p( (QtxColorScale*)this ); + if ( scaleWidth ) + srt->setTextWidth( scaleWidth ); + + titleHeight = (int)srt->size().height() + spacer; + titleWidth = (int)srt->size().width() + 10; + + } delete srt; - } - - int W = qMax( titleWidth, scaleWidth ) + width() - contentsRect().width(); - int H = scaleHeight + titleHeight + height() - contentsRect().height(); + } - return QSize( W, H ); + int W = qMax( titleWidth, scaleWidth ) + width() - contentsRect().width(); + int H = scaleHeight + titleHeight + height() - contentsRect().height(); + + return QSize( W, H ); } /*! - Dump color scale into pixmap with current size. + \brief Dump color scale into pixmap with current size. + \return generated pixmap */ QPixmap QtxColorScale::dump() const { - QPixmap aPix; - - if ( dumpMode() != NoDump ) - { - aPix = QPixmap( size() ); - if ( !aPix.isNull() ) - { - bool scale = ( myDumpMode == ScaleDump || myDumpMode == FullDump ); - bool label = ( myDumpMode == ScaleDump || myDumpMode == FullDump ) && - labelPosition() != None; - bool title = ( myDumpMode == TitleDump || myDumpMode == FullDump ) && - titlePosition() != None; + QPixmap aPix; + + if ( dumpMode() != NoDump ) + { + aPix = QPixmap( size() ); + if ( !aPix.isNull() ) + { + bool scale = ( myDumpMode == ScaleDump || myDumpMode == FullDump ); + bool label = ( myDumpMode == ScaleDump || myDumpMode == FullDump ) && + labelPosition() != None; + bool title = ( myDumpMode == TitleDump || myDumpMode == FullDump ) && + titlePosition() != None; QColor bgc = palette().color( backgroundRole() ); - QPainter p; - p.begin( &aPix ); - p.fillRect( 0, 0, aPix.width(), aPix.height(), bgc ); - drawScale( &p, bgc, false, 0, 0, aPix.width(), aPix.height(), title, label, scale ); - p.end(); - } - } - - return aPix; + QPainter p; + p.begin( &aPix ); + p.fillRect( 0, 0, aPix.width(), aPix.height(), bgc ); + drawScale( &p, bgc, false, 0, 0, aPix.width(), aPix.height(), title, label, scale ); + p.end(); + } + } + + return aPix; } /*! - Dump color scale into pixmap with specified size. + \brief Dump color scale into pixmap with the specified size. + \param w pixmap width + \param h pixmap height + \return generated pixmap */ QPixmap QtxColorScale::dump( const int w, const int h ) const { - return dump( palette().color( backgroundRole() ), w, h ); + return dump( palette().color( backgroundRole() ), w, h ); } /*! - Dump color scale into pixmap with specified size and background color. + \brief Dump color scale into pixmap with the specified size and background color. + \param bg pixmap background color + \param w pixmap width + \param h pixmap height + \return generated pixmap */ QPixmap QtxColorScale::dump( const QColor& bg, const int w, const int h ) const { - QPixmap aPix; - if ( dumpMode() != NoDump ) - { - bool scale = ( myDumpMode == ScaleDump || myDumpMode == FullDump ); - bool label = ( myDumpMode == ScaleDump || myDumpMode == FullDump ) && - labelPosition() != None; - bool title = ( myDumpMode == TitleDump || myDumpMode == FullDump ) && - titlePosition() != None; - - int W = w; - int H = h; - if ( W < 0 || H < 0 ) - { - QSize sz = calculateSize( false, myFlags & ~WrapTitle, title, label, scale ); - - if ( W < 0 ) - W = sz.width(); - if ( H < 0 ) - H = sz.height(); - } - - aPix = QPixmap( W, H ); - if ( !aPix.isNull() ) - { - QPainter p; - p.begin( &aPix ); - p.fillRect( 0, 0, aPix.width(), aPix.height(), bg ); - drawScale( &p, bg, false, 0, 0, aPix.width(), aPix.height(), title, label, scale ); - p.end(); - } - } - - return aPix; + QPixmap aPix; + if ( dumpMode() != NoDump ) + { + bool scale = ( myDumpMode == ScaleDump || myDumpMode == FullDump ); + bool label = ( myDumpMode == ScaleDump || myDumpMode == FullDump ) && + labelPosition() != None; + bool title = ( myDumpMode == TitleDump || myDumpMode == FullDump ) && + titlePosition() != None; + + int W = w; + int H = h; + if ( W < 0 || H < 0 ) + { + QSize sz = calculateSize( false, myFlags & ~WrapTitle, title, label, scale ); + + if ( W < 0 ) + W = sz.width(); + if ( H < 0 ) + H = sz.height(); + } + + aPix = QPixmap( W, H ); + if ( !aPix.isNull() ) + { + QPainter p; + p.begin( &aPix ); + p.fillRect( 0, 0, aPix.width(), aPix.height(), bg ); + drawScale( &p, bg, false, 0, 0, aPix.width(), aPix.height(), title, label, scale ); + p.end(); + } + } + + return aPix; } /*! - Show the color scale. [Reimplemented] + \brief Show color scale (reimplemented from QFrame). */ void QtxColorScale::show() { - QFrame::show(); + QFrame::show(); } /*! - Hides the color scale. [Reimplemented] + \brief Hide color scale (reimplemented from QFrame). */ void QtxColorScale::hide() { - QFrame::hide(); + QFrame::hide(); } /*! - Draw color scale contents. [Reimplemented] + \brief Draw color scale (reimplemented from QFrame). + \param p painter */ void QtxColorScale::drawContents( QPainter* p ) { - if ( !updatesEnabled() ) - return; - - QRect aDrawRect = contentsRect(); - - drawScale( p, false/*testFlags( Transparent )*/, aDrawRect.x(), - aDrawRect.y(), aDrawRect.width(), aDrawRect.height(), - titlePosition() != None, labelPosition() != None, true ); + if ( !updatesEnabled() ) + return; + + QRect aDrawRect = contentsRect(); + + drawScale( p, false/*testFlags( Transparent )*/, aDrawRect.x(), + aDrawRect.y(), aDrawRect.width(), aDrawRect.height(), + titlePosition() != None, labelPosition() != None, true ); } /*! - Draw color scale contents. + \brief Draw color scale contents. + \param p painter + \param transp if \c true color scale is drawn on transparent background + \param X color scale x coordinate + \param Y color scale y coordinate + \param W color scale width + \param H color scale height + \param drawTitle if \c true, draw title + \param drawLabel if \c true, draw labels + \param drawColors if \c true, draw colors */ void QtxColorScale::drawScale( QPainter* p, const bool transp, const int X, const int Y, - const int W, const int H, const bool title, - const bool label, const bool scale ) const + const int W, const int H, const bool drawTitle, + const bool drawLabel, const bool drawColors ) const { - QPixmap cache( W, H ); - QPainter cp( &cache ); - - drawScale( &cp, palette().color( backgroundRole() ), transp, 0, 0, W, H, title, label, scale ); - cp.end(); - - p->drawPixmap( X, Y, cache ); + QPixmap cache( W, H ); + QPainter cp( &cache ); + + drawScale( &cp, palette().color( backgroundRole() ), transp, 0, 0, W, H, drawTitle, drawLabel, drawColors ); + cp.end(); + + p->drawPixmap( X, Y, cache ); } /*! - Draw color scale contents. + \brief Draw color scale contents. + \param p painter + \param bg background color + \param transp if \c true color scale is drawn on transparent background + \param X color scale x coordinate + \param Y color scale y coordinate + \param W color scale width + \param H color scale height + \param drawTitle if \c true, draw title + \param drawLabel if \c true, draw labels + \param drawColors if \c true, draw colors */ void QtxColorScale::drawScale( QPainter* p, const QColor& bg, const bool transp, const int X, const int Y, const int W, const int H, const bool drawTitle, const bool drawLabel, const bool drawColors ) const { - if ( !transp ) - p->fillRect( X, Y, W, H, bg ); - - int num = intervalsNumber(); - - int labPos = labelPosition(); - - int spacer = 5; - int textWidth = 0; - int textHeight = p->fontMetrics().height(); - - QString aTitle = title(); - - int titleWidth = 0; - int titleHeight = 0; - - if ( qGray( bg.rgb() ) < 128 ) - p->setPen( QColor( 255, 255, 255 ) ); - else + if ( !transp ) + p->fillRect( X, Y, W, H, bg ); + + int num = intervalsNumber(); + + int labPos = labelPosition(); + + int spacer = 5; + int textWidth = 0; + int textHeight = p->fontMetrics().height(); + + QString aTitle = title(); + + int titleWidth = 0; + int titleHeight = 0; + + if ( qGray( bg.rgb() ) < 128 ) + p->setPen( QColor( 255, 255, 255 ) ); + else p->setPen( QColor( 0, 0, 0 ) ); - - // Draw title - if ( drawTitle ) - { - QTextDocument* srt = textDocument( myFlags ); - if ( srt ) - { - srt->setTextWidth( W - 10 ); - titleHeight = srt->size().height() + spacer; - titleWidth = srt->size().width(); + + // Draw title + if ( drawTitle ) + { + QTextDocument* srt = textDocument( myFlags ); + if ( srt ) + { + srt->setTextWidth( W - 10 ); + titleHeight = (int)srt->size().height() + spacer; + titleWidth = (int)srt->size().width(); p->save(); p->translate( X + 5, Y ); - srt->drawContents( p ); + srt->drawContents( p ); p->restore(); - } + } delete srt; - } - - bool reverse = testFlags( Reverse ); - - QList colors; - QList labels; - for ( int idx = 0; idx < num; idx++ ) - { - if ( reverse ) - { - colors.append( getColor( idx ) ); - labels.append( getLabel( idx ) ); - } - else - { - colors.prepend( getColor( idx ) ); - labels.prepend( getLabel( idx ) ); - } - } - - if ( testFlags( AtBorder ) ) - { - if ( reverse ) - labels.append( getLabel( num ) ); - else - labels.prepend( getLabel( num ) ); - if ( drawLabel ) - textWidth = qMax( textWidth, p->fontMetrics().width( labels.last() ) ); - } - - if ( drawLabel ) - { - const QFontMetrics& fm = p->fontMetrics(); - for ( QStringList::ConstIterator it = labels.begin(); it != labels.end(); ++it ) - textWidth = qMax( textWidth, fm.width( *it) ); - } - - int lab = labels.count(); - - double spc = ( H - ( ( qMin( lab, 2 ) + qAbs( lab - num - 1 ) ) * textHeight ) - titleHeight ); - double val = spc != 0 ? 1.0 * ( lab - qMin( lab, 2 ) ) * textHeight / spc : 0; - double iPart; - double fPart = modf( val, &iPart ); - int filter = (int)iPart + ( fPart != 0 ? 1 : 0 ); - filter = qMax( filter, 1 ); - - double step = 1.0 * ( H - ( lab - num + qAbs( lab - num - 1 ) ) * textHeight - titleHeight ) / num; - - int ascent = p->fontMetrics().ascent(); - int colorWidth = qMax( 5, qMin( 20, W - textWidth - 3 * spacer ) ); - if ( labPos == Center || !drawLabel ) - colorWidth = W - 2 * spacer; - - // Draw colors - int x = X + spacer; - switch ( labPos ) - { - case Left: - x += textWidth + ( textWidth ? 1 : 0 ) * spacer; - break; - } - - double offset = 1.0 * textHeight / 2 * ( lab - num + qAbs( lab - num - 1 ) ) + titleHeight; - QList::Iterator cit = colors.begin(); + } + + bool reverse = testFlags( Reverse ); + + QList colors; + QList labels; + for ( int idx = 0; idx < num; idx++ ) + { + if ( reverse ) + { + colors.append( getColor( idx ) ); + labels.append( getLabel( idx ) ); + } + else + { + colors.prepend( getColor( idx ) ); + labels.prepend( getLabel( idx ) ); + } + } + + if ( testFlags( AtBorder ) ) + { + if ( reverse ) + labels.append( getLabel( num ) ); + else + labels.prepend( getLabel( num ) ); + if ( drawLabel ) + textWidth = qMax( textWidth, p->fontMetrics().width( labels.last() ) ); + } + + if ( drawLabel ) + { + const QFontMetrics& fm = p->fontMetrics(); + for ( QStringList::ConstIterator it = labels.begin(); it != labels.end(); ++it ) + textWidth = qMax( textWidth, fm.width( *it) ); + } + + int lab = labels.count(); + + double spc = ( H - ( ( qMin( lab, 2 ) + qAbs( lab - num - 1 ) ) * textHeight ) - titleHeight ); + double val = spc != 0 ? 1.0 * ( lab - qMin( lab, 2 ) ) * textHeight / spc : 0; + double iPart; + double fPart = modf( val, &iPart ); + int filter = (int)iPart + ( fPart != 0 ? 1 : 0 ); + filter = qMax( filter, 1 ); + + double step = 1.0 * ( H - ( lab - num + qAbs( lab - num - 1 ) ) * textHeight - titleHeight ) / num; + + int ascent = p->fontMetrics().ascent(); + int colorWidth = qMax( 5, qMin( 20, W - textWidth - 3 * spacer ) ); + if ( labPos == Center || !drawLabel ) + colorWidth = W - 2 * spacer; + + // Draw colors + int x = X + spacer; + switch ( labPos ) + { + case Left: + x += textWidth + ( textWidth ? 1 : 0 ) * spacer; + break; + } + + double offset = 1.0 * textHeight / 2 * ( lab - num + qAbs( lab - num - 1 ) ) + titleHeight; + QList::Iterator cit = colors.begin(); uint ci = 0; - for ( ci = 0; cit != colors.end() && drawColors; ++cit, ci++ ) - { - int y = (int)( Y + ci * step + offset ); - int h = (int)( Y + ( ci + 1 ) * step + offset ) - y; - p->fillRect( x, y, colorWidth, h, *cit ); - } - - if ( drawColors ) - p->drawRect( int( x - 1 ), int( Y + offset - 1 ), int( colorWidth + 2 ), int( ci * step + 2 ) ); - - // Draw labels - offset = 1.0 * qAbs( lab - num - 1 ) * ( step - textHeight ) / 2 + - 1.0 * qAbs( lab - num - 1 ) * textHeight / 2; - offset += titleHeight; - if ( drawLabel && !labels.isEmpty() ) - { - int i1 = 0; - int i2 = lab - 1; - int last1( i1 ), last2( i2 ); - int x = X + spacer; - switch ( labPos ) - { - case Center: - x += ( colorWidth - textWidth ) / 2; - break; - case Right: - x += colorWidth + spacer; - break; - } - while ( i2 - i1 >= filter || ( i2 == 0 && i1 == 0 ) ) - { - int pos1 = i1; - int pos2 = lab - 1 - i2; - if ( filter && !( pos1 % filter ) ) - { - p->drawText( x, (int)( Y + i1 * step + ascent + offset ), labels[i1] ); - last1 = i1; - } - if ( filter && !( pos2 % filter ) ) - { - p->drawText( x, (int)( Y + i2 * step + ascent + offset ), labels[i2] ); - last2 = i2; - } - i1++; - i2--; - } - int pos = i1; - int i0 = -1; - while ( pos <= i2 && i0 == -1 ) - { - if ( filter && !( pos % filter ) && - qAbs( pos - last1 ) >= filter && qAbs( pos - last2 ) >= filter ) - i0 = pos; - pos++; - } - - if ( i0 != -1 ) - p->drawText( x, (int)( Y + i0 * step + ascent + offset ), labels[i0] ); - } -} - -/*! - \return the format for number labels. + for ( ci = 0; cit != colors.end() && drawColors; ++cit, ci++ ) + { + int y = (int)( Y + ci * step + offset ); + int h = (int)( Y + ( ci + 1 ) * step + offset ) - y; + p->fillRect( x, y, colorWidth, h, *cit ); + } + + if ( drawColors ) + p->drawRect( int( x - 1 ), int( Y + offset - 1 ), int( colorWidth + 2 ), int( ci * step + 2 ) ); + + // Draw labels + offset = 1.0 * qAbs( lab - num - 1 ) * ( step - textHeight ) / 2 + + 1.0 * qAbs( lab - num - 1 ) * textHeight / 2; + offset += titleHeight; + if ( drawLabel && !labels.isEmpty() ) + { + int i1 = 0; + int i2 = lab - 1; + int last1( i1 ), last2( i2 ); + int x = X + spacer; + switch ( labPos ) + { + case Center: + x += ( colorWidth - textWidth ) / 2; + break; + case Right: + x += colorWidth + spacer; + break; + } + while ( i2 - i1 >= filter || ( i2 == 0 && i1 == 0 ) ) + { + int pos1 = i1; + int pos2 = lab - 1 - i2; + if ( filter && !( pos1 % filter ) ) + { + p->drawText( x, (int)( Y + i1 * step + ascent + offset ), labels[i1] ); + last1 = i1; + } + if ( filter && !( pos2 % filter ) ) + { + p->drawText( x, (int)( Y + i2 * step + ascent + offset ), labels[i2] ); + last2 = i2; + } + i1++; + i2--; + } + int pos = i1; + int i0 = -1; + while ( pos <= i2 && i0 == -1 ) + { + if ( filter && !( pos % filter ) && + qAbs( pos - last1 ) >= filter && qAbs( pos - last2 ) >= filter ) + i0 = pos; + pos++; + } + + if ( i0 != -1 ) + p->drawText( x, (int)( Y + i0 * step + ascent + offset ), labels[i0] ); + } +} + +/*! + \brief Generate number presentation format. + \return format for number labels */ QString QtxColorScale::getFormat() const { - QString aFormat = format(); - - if ( !testFlags( PreciseFormat ) || testFlags( Integer ) ) - return aFormat; - - if ( !myPrecise.isEmpty() ) - return myPrecise; - - if ( !aFormat.contains( QRegExp( "^(%[0-9]*.?[0-9]*[fegFEG])$" ) ) ) - return aFormat; - - int pos1 = aFormat.indexOf( '.' ); - int pos2 = aFormat.indexOf( QRegExp( "[fegFEG]") ); - - QString aLocFormat; - int precision = 1; - if ( pos1 > 0 ) - { - aLocFormat = aFormat.mid( 0, pos1 + 1 ); - precision = aFormat.mid( pos1 + 1, pos2 - pos1 - 1 ).toInt(); - if ( precision < 1 ) - precision = 1; - } - else - return aFormat; + QString aFormat = format(); - QtxColorScale* that = (QtxColorScale*)this; - - // calculate format, maximum precision limited - // to 7 digits after the decimal point. - while ( myPrecise.isEmpty() && precision < 7 ) - { - QString aTmpFormat = aLocFormat; - aTmpFormat += QString( "%1" ).arg( precision ); - aTmpFormat += aFormat.mid( pos2 ); - - QMap map; - bool isHasTwinz = false; - - for ( int idx = 0; idx < intervalsNumber() && !isHasTwinz; idx++ ) - { - double val = getNumber( idx ); - QString tmpname = QString().sprintf( aTmpFormat.toLatin1(), val ); - isHasTwinz = map.contains( tmpname ); - map.insert( tmpname, 1 ); - } - - if ( !isHasTwinz ) - that->myPrecise = aTmpFormat; - precision++; - } - - if ( !myPrecise.isEmpty() ) - aFormat = myPrecise; - - return aFormat; + if ( !testFlags( PreciseFormat ) || testFlags( Integer ) ) + return aFormat; + + if ( !myPrecise.isEmpty() ) + return myPrecise; + + if ( !aFormat.contains( QRegExp( "^(%[0-9]*.?[0-9]*[fegFEG])$" ) ) ) + return aFormat; + + int pos1 = aFormat.indexOf( '.' ); + int pos2 = aFormat.indexOf( QRegExp( "[fegFEG]") ); + + QString aLocFormat; + int precision = 1; + if ( pos1 > 0 ) + { + aLocFormat = aFormat.mid( 0, pos1 + 1 ); + precision = aFormat.mid( pos1 + 1, pos2 - pos1 - 1 ).toInt(); + if ( precision < 1 ) + precision = 1; + } + else + return aFormat; + + QtxColorScale* that = (QtxColorScale*)this; + + // calculate format, maximum precision limited + // to 7 digits after the decimal point. + while ( myPrecise.isEmpty() && precision < 7 ) + { + QString aTmpFormat = aLocFormat; + aTmpFormat += QString( "%1" ).arg( precision ); + aTmpFormat += aFormat.mid( pos2 ); + + QMap map; + bool isHasTwinz = false; + + for ( int idx = 0; idx < intervalsNumber() && !isHasTwinz; idx++ ) + { + double val = getNumber( idx ); + QString tmpname = QString().sprintf( aTmpFormat.toLatin1(), val ); + isHasTwinz = map.contains( tmpname ); + map.insert( tmpname, 1 ); + } + + if ( !isHasTwinz ) + that->myPrecise = aTmpFormat; + precision++; + } + + if ( !myPrecise.isEmpty() ) + aFormat = myPrecise; + + return aFormat; } /*! - \return the number for specified interval. + \brief Get color scale value corresponding to the specified interval. + \param idx interval index + \return color scale value */ double QtxColorScale::getNumber( const int idx ) const { - double val = 0; - if ( intervalsNumber() > 0 ) - val = minimum() + idx * ( qAbs( maximum() - minimum() ) / intervalsNumber() ); - return val; + double val = 0; + if ( intervalsNumber() > 0 ) + val = minimum() + idx * ( qAbs( maximum() - minimum() ) / intervalsNumber() ); + return val; } /*! - \return the label for specified interval according to the current label mode. + \brief Get color scale label text corresponding to the specified interval. + \param idx interval index + \return color scale label text */ QString QtxColorScale::getLabel( const int idx ) const { - QString res; - if ( labelMode() == User ) - res = label( idx ); - else - { - double val = getNumber( idx ); - res = QString().sprintf( getFormat().toLatin1(), testFlags( Integer ) ? (int)val : val ); - } - return res; + QString res; + if ( labelMode() == User ) + res = label( idx ); + else + { + double val = getNumber( idx ); + res = QString().sprintf( getFormat().toLatin1(), testFlags( Integer ) ? (int)val : val ); + } + return res; } /*! - \return the color for specified interval according to the current color mode. + \brief Get color scale color corresponding to the specified interval. + \param idx interval index + \return color scale color */ QColor QtxColorScale::getColor( const int idx ) const { - QColor res; - if ( colorMode() == User ) - res = color( idx ); - else + QColor res; + if ( colorMode() == User ) + res = color( idx ); + else res = Qtx::scaleColor( idx, 0, intervalsNumber() - 1 ); - return res; + return res; } /*! - Update color scale if it required. + \brief Update color scale. */ void QtxColorScale::updateScale() { update(); - updateGeometry(); + updateGeometry(); } /*! - \return QSimpleRichText object for title. If title - not defined (empty string) then return null pointer. - Object should be deleted by caller function. + \brief Get text document (rich text) for the color scale title representation. + + If title is not defined (empty string) then null pointer is returned. + The calling function is responsible for the returning object deleting. + + \param flags color scale flags (not used) + \return text document or 0 if title is not set */ -QTextDocument* QtxColorScale::textDocument( const int flags ) const +QTextDocument* QtxColorScale::textDocument( const int /*flags*/ ) const { - QTextDocument* doc = 0; - - QString aTitle; - switch ( titlePosition() ) - { - case Left: - aTitle = QString( "

%1

" ); - break; - case Right: - aTitle = QString( "

%1

" ); - break; - case Center: - aTitle = QString( "

%1

" ); - break; - case None: - default: - break; - } + QTextDocument* doc = 0; - if ( !aTitle.isEmpty() && !title().isEmpty() ) - { + QString aTitle; + switch ( titlePosition() ) + { + case Left: + aTitle = QString( "

%1

" ); + break; + case Right: + aTitle = QString( "

%1

" ); + break; + case Center: + aTitle = QString( "

%1

" ); + break; + case None: + default: + break; + } + + if ( !aTitle.isEmpty() && !title().isEmpty() ) + { /* - if ( !myStyleSheet ) - { - QtxColorScale* that = (QtxColorScale*)this; - that->myStyleSheet = new QStyleSheet( that ); - } - - if ( myStyleSheet ) - { - QStyleSheetItem* item = myStyleSheet->item( "p" ); - if ( item ) - item->setWhiteSpaceMode( flags & WrapTitle ? QStyleSheetItem::WhiteSpaceNormal : - QStyleSheetItem::WhiteSpaceNoWrap ); - } -*/ - aTitle = aTitle.arg( title() ); - doc = new QTextDocument( aTitle ); - } - - return doc; + if ( !myStyleSheet ) + { + QtxColorScale* that = (QtxColorScale*)this; + that->myStyleSheet = new QStyleSheet( that ); + } + + if ( myStyleSheet ) + { + QStyleSheetItem* item = myStyleSheet->item( "p" ); + if ( item ) + item->setWhiteSpaceMode( flags & WrapTitle ? QStyleSheetItem::WhiteSpaceNormal : + QStyleSheetItem::WhiteSpaceNoWrap ); + } + */ + aTitle = aTitle.arg( title() ); + doc = new QTextDocument( aTitle ); + } + + return doc; } diff --git a/src/Qtx/QtxColorScale.h b/src/Qtx/QtxColorScale.h index 364ac1e2e..ae9e985f2 100755 --- a/src/Qtx/QtxColorScale.h +++ b/src/Qtx/QtxColorScale.h @@ -24,8 +24,8 @@ #include "Qtx.h" -#include -#include +#include +#include class QTextDocument; @@ -33,20 +33,39 @@ class QTextDocument; #pragma warning( disable:4251 ) #endif -/*! - \class QtxColorScale - Color Scale widget. -*/ class QTX_EXPORT QtxColorScale : public QFrame { Q_OBJECT public: - typedef enum { Auto, User } Mode; - typedef enum { None, Left, Right, Center } Position; - typedef enum { NoDump, TitleDump, ScaleDump, FullDump } DumpMode; - typedef enum { AtBorder = 0x001, Reverse = 0x002, Integer = 0x004, - WrapTitle = 0x008, PreciseFormat = 0x010, Transparent = 0x020 } Flags; + //! Color scale color/label mode. + typedef enum { + Auto, //!< auto + User //!< user defined + } Mode; + //! Color scale title, label position. + typedef enum { + None, //!< do not draw + Left, //!< draw at the left + Right, //!< draw at the right + Center //!< draw at the center + } Position; + //! Dump mode. + typedef enum { + NoDump, //!< do not dump + TitleDump, //!< dump title + ScaleDump, //!< dump scale + FullDump //!< dump all + } DumpMode; + //! Color scale flags (bitwise). + typedef enum { + AtBorder = 0x001, + Reverse = 0x002, + Integer = 0x004, + WrapTitle = 0x008, + PreciseFormat = 0x010, + Transparent = 0x020 + } Flags; public: QtxColorScale( QWidget* = 0, Qt::WindowFlags = 0 ); @@ -114,34 +133,34 @@ private: double getNumber( const int ) const; QTextDocument* textDocument( const int ) const; void drawScale( QPainter*, const bool, const int, const int, - const int, const int, const bool, const bool, const bool ) const; + const int, const int, const bool, const bool, const bool ) const; void drawScale( QPainter*, const QColor&, const bool, - const int, const int, const int, const int, - const bool, const bool, const bool ) const; + const int, const int, const int, const int, + const bool, const bool, const bool ) const; QSize calculateSize( const bool, const int, - const bool, const bool, const bool ) const; + const bool, const bool, const bool ) const; private: - double myMin; - double myMax; - QString myTitle; - QString myFormat; - QString myPrecise; - int myInterval; - int myDumpMode; - int myColorMode; - int myLabelMode; - - QList myColors; - QList myLabels; - - int myFlags; - int myLabelPos; - int myTitlePos; + double myMin; //!< lower limit + double myMax; //!< upper limit + QString myTitle; //!< title + QString myFormat; //!< number presentation format + QString myPrecise; //!< double values precision format + int myInterval; //!< number of color scale intervals + int myDumpMode; //!< dump mode (QtxColorScale::DumpMode) + int myColorMode; //!< color mode (QtxColorScale::Mode) + int myLabelMode; //!< label mode (QtxColorScale::Mode) + + QList myColors; //!< list of colors + QList myLabels; //!< list of labels + + int myFlags; //!< color scale flags (QtxColorScale::Flags) + int myLabelPos; //!< label position (QtxColorScale::Position) + int myTitlePos; //!< title position (QtxColorScale::Position) }; #ifdef WIN32 #pragma warning( default:4251 ) #endif -#endif +#endif // QTXCOLORSCALE_H diff --git a/src/Qtx/QtxComboBox.cxx b/src/Qtx/QtxComboBox.cxx index b7ba7292a..eaffefbdf 100755 --- a/src/Qtx/QtxComboBox.cxx +++ b/src/Qtx/QtxComboBox.cxx @@ -21,30 +21,42 @@ #include "QtxComboBox.h" -#include -#include -#include +#include /*! - Constructor + \class QtxComboBox + \brief Enhanced version of Qt combo box class. + + In addition to the QComboBox class, QtxComboBox supports + adding/removing the items with the associated unique identifiers. + It also provides a way to set "cleared" state to the combo box - + when no item is selected. +*/ + +/*! + \brief Constructor. + \param parent parent widget */ QtxComboBox::QtxComboBox( QWidget* parent ) : QComboBox( parent ), -myCleared( false ) + myCleared( false ) { - connect( this, SIGNAL( activated( int ) ), this, SLOT( onActivated( int ) ) ); - connect( this, SIGNAL( activated( const QString& ) ), this, SLOT( onActivated( const QString& ) ) ); + connect( this, SIGNAL( activated( int ) ), this, SLOT( onActivated( int ) ) ); + connect( this, SIGNAL( activated( const QString& ) ), this, SLOT( onActivated( const QString& ) ) ); } /*! - Destructor + \brief Destructor. + + Does nothing currently. */ QtxComboBox::~QtxComboBox() { } /*! - \return true if combobox is cleared + \brief Check if the combo box is in the "cleared" state. + \return \c true if combobox is in the "cleared" state */ bool QtxComboBox::isCleared() const { @@ -52,8 +64,8 @@ bool QtxComboBox::isCleared() const } /*! - Sets cleared status - \param isClear - new status + \brief Set "cleared" state. + \param isClear new "cleared" state */ void QtxComboBox::setCleared( const bool isClear ) { @@ -74,8 +86,11 @@ void QtxComboBox::setCleared( const bool isClear ) } /*! - Sets currently selected item - \param idx - index of item + \brief Set current item. + + Does nothing if the item index is out of range. + + \param idx item index */ void QtxComboBox::setCurrentIndex( int idx ) { @@ -87,7 +102,8 @@ void QtxComboBox::setCurrentIndex( int idx ) } /*! - \return current selected id + \brief Get current item ID. + \return item id */ int QtxComboBox::currentId() const { @@ -95,7 +111,8 @@ int QtxComboBox::currentId() const } /*! - Sets current selected id + \brief Set current item by ID. + \param num item ID */ void QtxComboBox::setCurrentId( int num ) { @@ -103,7 +120,18 @@ void QtxComboBox::setCurrentId( int num ) } /*! - Custom paint event handler + \brief Set the identifier to specified item. + \param index - index of the item + \param id - identifier of the item +*/ +void QtxComboBox::setId( const int index, const int id ) +{ + setItemData( index, QVariant( id ), (Qt::ItemDataRole)IdRole ); +} + +/*! + \brief Customize paint event. + \param e paint event */ void QtxComboBox::paintEvent( QPaintEvent* e ) { @@ -114,35 +142,40 @@ void QtxComboBox::paintEvent( QPaintEvent* e ) } /*! - SLOT: called if some item is activated - \param idx - index of activated item + \brief Called when any item is activated by the user. + \param idx activated item index */ void QtxComboBox::onActivated( int idx ) { resetClear(); + + emit activatedId( id( idx ) ); } /*! - SLOT: called if some item is activated -*/void QtxComboBox::onActivated( const QString& ) + \brief Called when any item is activated by the user. + \param txt activated item text (not used) +*/ +void QtxComboBox::onActivated( const QString& /*txt*/ ) { - resetClear(); + resetClear(); } /*! - Strips "cleared" state and updates + \brief Reset "cleared" state and update the combo box. */ void QtxComboBox::resetClear() { - if ( !myCleared ) - return; - - myCleared = false; - update(); + if ( !myCleared ) + return; + + myCleared = false; + update(); } /*! - Draws combobox when it is cleared or isn't editable + \brief Draw combobox in the "cleared" state. + \param e paint event */ void QtxComboBox::paintClear( QPaintEvent* e ) { @@ -165,26 +198,53 @@ void QtxComboBox::paintClear( QPaintEvent* e ) } /*! - \return id by index + \brief Get item ID by the index. + \param idx item index + \return item ID or -1 if index is invalid. */ int QtxComboBox::id( const int idx ) const { int id = -1; - if ( myIndexId.contains( idx ) ) - id = myIndexId[idx]; + QVariant v = itemData( idx, (Qt::ItemDataRole)IdRole ); + if ( v.canConvert( QVariant::Int ) ) + id = v.toInt(); return id; } /*! - \return index by id + \brief Get item index by the ID. + \param id item ID + \return item index or -1 if ID is invalid. */ -int QtxComboBox::index( const int id ) const +int QtxComboBox::index( const int ident ) const { int idx = -1; - for ( IndexIdMap::ConstIterator it = myIndexId.begin(); it != myIndexId.end() && idx == -1; ++it ) + for ( int i = 0; i < (int)count() && idx == -1; i++ ) { - if ( it.value() == id ) - idx = it.key(); + if ( id( i ) == ident ) + idx = i; } return idx; } + +/*! + \brief Returns true if the item with index has ID. + \param idx item index +*/ +bool QtxComboBox::hasId( const int idx ) const +{ + QVariant v = itemData( idx, (Qt::ItemDataRole)IdRole ); + return v.canConvert( QVariant::Int ); +} + +/*! + \fn void QtxComboBox::activatedId( int id ) + \brief Emitted when the item with identificator \a id is activated. + \param id item ID +*/ + +/*! + \fn void QtxComboBox::highlightedId( int id ) + \brief Emitted when the item with identificator \a id is highlighted. + \param id item ID +*/ diff --git a/src/Qtx/QtxComboBox.h b/src/Qtx/QtxComboBox.h index 79f40d924..c821ffaed 100755 --- a/src/Qtx/QtxComboBox.h +++ b/src/Qtx/QtxComboBox.h @@ -24,8 +24,8 @@ #include "Qtx.h" -#include -#include +#include +#include #ifdef WIN32 #pragma warning( disable:4251 ) @@ -35,8 +35,6 @@ class QTX_EXPORT QtxComboBox : public QComboBox { Q_OBJECT - typedef QMap IndexIdMap; - public: QtxComboBox( QWidget* = 0 ); virtual ~QtxComboBox(); @@ -49,11 +47,17 @@ public: int currentId() const; void setCurrentId( int ); -Q_SIGNALS: + int id( const int ) const; + int index( const int ) const; + + bool hasId( const int ) const; + void setId( const int, const int ); + +signals: void activatedId( int ); void highlightedId( int ); -private Q_SLOTS: +private slots: void onActivated( int ); void onActivated( const QString& ); @@ -61,15 +65,14 @@ protected: virtual void paintEvent( QPaintEvent* ); private: - int id( const int ) const; - int index( const int ) const; - void resetClear(); void paintClear( QPaintEvent* ); private: - bool myCleared; - IndexIdMap myIndexId; + enum { IdRole = Qt::UserRole + 10 }; + +private: + bool myCleared; //!< "cleared" state }; #ifdef WIN32 diff --git a/src/Qtx/QtxDialog.cxx b/src/Qtx/QtxDialog.cxx index d11e8127e..64e43c854 100755 --- a/src/Qtx/QtxDialog.cxx +++ b/src/Qtx/QtxDialog.cxx @@ -21,18 +21,20 @@ #include "QtxDialog.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include /*! - Class: QtxDialog::Area - Level: Internal + \class QtxDialog::Area + \internal + \brief Area containing dialog box buttons. */ + class QtxDialog::Area : public QFrame { public: @@ -59,24 +61,27 @@ private: void updateBorder(); private: - QtxDialog* myDlg; - QLabel* myLine; - bool myBorder; - int myPolicy; - QList myButtons; - Qt::Orientation myOrientation; + QtxDialog* myDlg; //!< parent dialog box + QLabel* myLine; //!< border widget + bool myBorder; //!< "has border" flag + int myPolicy; //!< button layout type (QtxDialog::PlacePolicy) + QList myButtons; //!< buttons list + Qt::Orientation myOrientation; //!< buttons orientation (Qt::Orientation) }; /*! - Contructor + \brief Constructor. + \param o buttons orientation + \param dlg dialog box owning this area + \param parent parent widget */ QtxDialog::Area::Area( Qt::Orientation o, QtxDialog* dlg, QWidget* parent ) : QFrame( parent ), -myDlg( dlg ), -myLine( 0 ), -myBorder( false ), -myPolicy( Position ), -myOrientation( o ) + myDlg( dlg ), + myLine( 0 ), + myBorder( false ), + myPolicy( Position ), + myOrientation( o ) { if ( myOrientation == Qt::Horizontal ) setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Maximum ) ); @@ -87,15 +92,16 @@ myOrientation( o ) } /*! - Destructor + \brief Destructor. */ QtxDialog::Area::~Area() { } /*! - Inserts button to area - \param b - button + \brief Insert button to the area. + \param b button to be added + \sa removeButton() */ void QtxDialog::Area::insertButton( QAbstractButton* b ) { @@ -118,8 +124,9 @@ void QtxDialog::Area::insertButton( QAbstractButton* b ) } /*! - Removes button from area - \param b - button + \brief Remove button from the area. + \param b button to be removed + \sa insertButton() */ void QtxDialog::Area::removeButton( QAbstractButton* b ) { @@ -140,8 +147,9 @@ void QtxDialog::Area::removeButton( QAbstractButton* b ) } /*! - \return true if area contains button - \param b - button + \brief Check if area owns the button specified. + \param b button to be checked + \return \c true if area contains button */ bool QtxDialog::Area::contains( QAbstractButton* b ) const { @@ -149,7 +157,9 @@ bool QtxDialog::Area::contains( QAbstractButton* b ) const } /*! - \return policy of button layouting. + \brief Get buttons layout policy. + \return policy of button layouting (Qtx::PlacePolicy) + \sa setPolicy() */ int QtxDialog::Area::policy() const { @@ -157,8 +167,8 @@ int QtxDialog::Area::policy() const } /*! - Changes policy of button layouting. - \param p - new policy + \brief Set buttons layout policy. + \param p new policy */ void QtxDialog::Area::setPolicy( const int p ) { @@ -170,7 +180,9 @@ void QtxDialog::Area::setPolicy( const int p ) } /*! - \return true if border enabled + \brief Check of the border is enabled. + \return \c true if border is enabled + \sa setBorderEnabled(), setBorderWidget() */ bool QtxDialog::Area::isBorderEnabled() const { @@ -178,8 +190,8 @@ bool QtxDialog::Area::isBorderEnabled() const } /*! - Enables/disable separator between main frame and button frame - \param on - new state + \brief Enable/disable border (separator between main frame and button frame) + \param on new state */ void QtxDialog::Area::setBorderEnabled( const bool on ) { @@ -191,8 +203,8 @@ void QtxDialog::Area::setBorderEnabled( const bool on ) } /*! - Sets label as separator between main frame and button frame - \param line - new separator + \brief Set border widget (separator between main frame and button frame). + \param line new separator widget */ void QtxDialog::Area::setBorderWidget( QLabel* line ) { @@ -205,7 +217,8 @@ void QtxDialog::Area::setBorderWidget( QLabel* line ) } /*! - \return const reference to list of buttons + \brief Get all area buttons. + \return const reference to the list of buttons */ const QList& QtxDialog::Area::buttons() const { @@ -213,7 +226,7 @@ const QList& QtxDialog::Area::buttons() const } /*! - Updates visibility of border + \brief Update border visibility. */ void QtxDialog::Area::updateBorder() { @@ -227,7 +240,7 @@ void QtxDialog::Area::updateBorder() } /*! - Installs buttons into layout + \brief Layout buttons in the area. */ void QtxDialog::Area::layoutButtons() { @@ -329,9 +342,11 @@ void QtxDialog::Area::layoutButtons() /*! \class QtxDialog::Border - - Special label used as separator between main frame and button frame + \internal + \brief Special label used as border widget (separator + between main frame and button frame). */ + class QtxDialog::Border : public QLabel { public: @@ -345,7 +360,8 @@ public: }; /*! - Constructor + \brief Constructor. + \param parent parent widget */ QtxDialog::Border::Border( QWidget* parent ) : QLabel( parent ) @@ -354,15 +370,15 @@ QtxDialog::Border::Border( QWidget* parent ) } /*! - Destructor + \brief Destructor. */ QtxDialog::Border::~Border() { } /*! - Set line width of separator - \param lw - new line width + \brief Set separator line width. + \param lw new line width */ void QtxDialog::Border::setLineWidth( int lw ) { @@ -375,7 +391,8 @@ void QtxDialog::Border::setLineWidth( int lw ) } /*! - \return the recommended size for the widget + \brief Get recommended size for the widget. + \return recommended size for the widget */ QSize QtxDialog::Border::sizeHint() const { @@ -393,7 +410,8 @@ QSize QtxDialog::Border::sizeHint() const } /*! - \return the recommended minimum size for the widget + \brief Get recommended minimum size for the widget. + \return recommended minimum size for the widget */ QSize QtxDialog::Border::minimumSizeHint() const { @@ -401,12 +419,22 @@ QSize QtxDialog::Border::minimumSizeHint() const } /*! - Constructor + \class QtxDialog + \brief Generic dialog box class. +*/ + +/*! + \brief Constructor. + Construct a dialog with specified parent and name. - \param modal define modal status of dialog (default non modal dialog created). - \param allowResize - if it is true then dialog can be resize by user (default non resizable dialog created). - \param Button flags specified control buttons for dialog (default buttons is OK, Cancel and Help). - \param Widget flags used as in any widget. + By default non-modal, non-resizable with the OK, Cancel and Help buttons + dialog box is created. + + \param parent parent widget + \param modal if \c true dialog box is modal + \param allowResize if \c true then dialog can be resized by user + \param f specified control buttons for dialog box (QtxDialog::ButtonFlags) + \param wf dialog box flags (Qt::WindowFlags) */ QtxDialog::QtxDialog( QWidget* parent, bool modal, bool allowResize, const int f, Qt::WindowFlags wf ) : QDialog( parent, (Qt::WindowFlags)( wf | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::Dialog | @@ -419,10 +447,10 @@ QtxDialog::QtxDialog( QWidget* parent, bool modal, bool allowResize, const int f && !( wf & Qt::WindowContextHelpButtonHint ) #endif ) ? Qt::WindowMaximizeButtonHint : 0 ) ) ), -myInited( false ), -mySender( 0 ), -myAlignment( 0 ), -myDialogFlags( Accept | SetFocus ) + myInited( false ), + mySender( 0 ), + myAlignment( 0 ), + myDialogFlags( Accept | SetFocus ) { setModal( modal ); @@ -534,19 +562,17 @@ myDialogFlags( Accept | SetFocus ) } /*! - Name: ~QtxDialog [public] - Desc: Destructor + \brief Destructor. */ - QtxDialog::~QtxDialog() { } /*! - Name: setButtonFlags [public] - Desc: Allow to set specified control button(s) into dialog. + \brief Add specified control button(s) to the dialog box. + \param f ORed buttons flags (Qtx::ButtonFlags) + \sa clearButtonFlags(), testButtonFlags() */ - void QtxDialog::setButtonFlags( const int f ) { int old = myButtonFlags; @@ -556,10 +582,10 @@ void QtxDialog::setButtonFlags( const int f ) } /*! - Name: clearButtonFlags [public] - Desc: Allow to unset specified control button(s) from dialog. + \brief Remove specified control button(s) from the dialog box. + \param f ORed buttons flags (Qtx::ButtonFlags) + \sa setButtonFlags(), testButtonFlags() */ - void QtxDialog::clearButtonFlags( const int f ) { int old = myButtonFlags; @@ -569,68 +595,64 @@ void QtxDialog::clearButtonFlags( const int f ) } /*! - Name: testButtonFlags [public] - Desc: Return true if specified control button is used in dialog. + \brief Test specified buttons. + \return \c true if specified control buttons are used in the dialog box + \sa setButtonFlags(), clearButtonFlags() */ - bool QtxDialog::testButtonFlags( const int f ) const { return ( myButtonFlags & f ) == f; } /*! - Name: setDialogFlags [public] - Desc: Allow to set the dialog flags. - - Following flags can be used: - Accept - Allow to control dialog accepting. See also acceptData(). - Reject - Allow to control dialog rejecting. See also rejectData(). - AlignOnce - Allow to align dialog only when it first time shown. - SetFocus - Allow to set focus on dialog when it shown. User can use - setFocusProxy() and specify own initial focus widget. + \brief Set specified dialog box flags. + \param f dialog box flags (QtxDialog::DialogFlags) + \sa clearDialogFlags(), testDialogFlags(), acceptData(), rejectData() */ - void QtxDialog::setDialogFlags( const int f ) { myDialogFlags = myDialogFlags | f; } /*! - Name: clearDialogFlags [public] - Desc: Allow to clear the dialog flags. See also setDialogFlags(). + \brief Clear specified the dialog flags. + \param f dialog box flags (QtxDialog::DialogFlags) + \sa setDialogFlags(), testDialogFlags() */ - void QtxDialog::clearDialogFlags( const int f ) { myDialogFlags = myDialogFlags & ~f; } /*! - Name: testDialogFlags [public] - Desc: Returns true if specified dialog flag is setted (see setDialogFlags()). + \brief Test specified dialog flags. + \return \c true if specified dialog box falgs are set + \sa setDialogFlags(), clearDialogFlags() */ - bool QtxDialog::testDialogFlags( const int f ) const { return ( myDialogFlags & f ) == f; } /*! - Name: mainFrame [public] - Desc: Returns main frame of dialog. Main frame should contains all - elements of dialog except control buttons. -*/ + \brief Get dialog box main frame widget. + Main frame is an internal widget which should contains all + elements of dialog box except control buttons. + + \return main frame widget +*/ QFrame* QtxDialog::mainFrame() const { return myMainFrame; } /*! - Name: buttonPosition [public] - Desc: Returns position of specified button. + \brief Get specified control button position + \param id control button ID (QtxDialog::ButtonFlags) + \return button's position (QtxDialog::ButtonPosition) or -1 if it is not set or invalid \a id is given + \sa setButtonPosition() */ - int QtxDialog::buttonPosition( const int id ) const { int pos = -1; @@ -638,13 +660,11 @@ int QtxDialog::buttonPosition( const int id ) const pos = myPosition[id]; return pos; } - /*! - Name: setButtonPosition [public] - Desc: Sets the position for specified button(s). Following positions - may be used: Left, Right, Center, Top, Bottom. + \brief Set the specified control button(s) position. + \param id control button(s) ID (QtxDialog::ButtonFlags) + \param pos button(s) position (QtxDialog::ButtonPosition) */ - void QtxDialog::setButtonPosition( const int pos, const int id ) { ButtonMap map = buttons( id ); @@ -668,10 +688,11 @@ void QtxDialog::setButtonPosition( const int pos, const int id ) } /*! - Name: setPlacePosition [public] - Desc: Sets button position for all buttons in given place. + \brief Set button position for all buttons in specified \a area. + \param pos button(s) position (QtxDialog::ButtonPosition) + \param area buttons area (QtxDialog::ButtonArea) + \sa setButtonPosition() */ - void QtxDialog::setPlacePosition( const int pos, const int area ) { if ( !myArea.contains( area ) ) @@ -695,21 +716,10 @@ void QtxDialog::setPlacePosition( const int pos, const int area ) } /*! - Name: placePolicy [public] - Desc: Returns policy of button layouting for specified place. - - Following place may be used: - TopArea - Horizontal area in the top side of dialog. - BottomArea - Horizontal area in the bottom side of dialog. - LeftArea - Vertical area in the left side of dialog. - RightArea - Vertical area in the right side of dialog. - - Following policy may be used: - Position - Buttons placed according their position. - Expand - Buttons fills all available space. - Uniform - Buttons uniformly placed in area. + \brief Get buttons layouting policy for the specified \a area. + \param area buttons area (QtxDialog::ButtonArea) + \sa setPlacePolicy() */ - int QtxDialog::placePolicy( const int area ) const { int res = -1; @@ -719,11 +729,11 @@ int QtxDialog::placePolicy( const int area ) const } /*! - Name: setPlacePolicy [public] - Desc: Sets the policy of button layouting for specified place. - See also placePolicy(). + \brief set buttons layouting policy for the specified \a area. + \param policy buttons layouting policy (QtxDialog::PlacePolicy) + \param area buttons area (QtxDialog::ButtonArea) + \sa placePolicy() */ - void QtxDialog::setPlacePolicy( const int policy, const int area ) { if ( area < 0 ) @@ -736,17 +746,17 @@ void QtxDialog::setPlacePolicy( const int policy, const int area ) } /*! - Name: setButtonPlace [public] - Desc: Move given button(s) into specified place. + \brief Move specified button(s) into specified area. + \param area buttons area (QtxDialog::ButtonArea) + \param id control button(s) ID (QtxDialog::ButtonFlags) */ - -void QtxDialog::setButtonPlace( const int area, const int ids ) +void QtxDialog::setButtonPlace( const int area, const int id ) { if ( !myArea.contains( area ) ) return; Area* anArea = myArea[area]; - ButtonMap map = buttons( ids ); + ButtonMap map = buttons( id ); QMap areaMap; for ( AreaMap::ConstIterator aIt = myArea.begin(); aIt != myArea.end(); ++aIt ) areaMap.insert( aIt.value(), 0 ); @@ -764,10 +774,11 @@ void QtxDialog::setButtonPlace( const int area, const int ids ) } /*! - Name: isBorderEnabled [public] - Desc: Returns true if border is shown for specified button area. + \brief Check if border is enabled. + \param area buttons area (QtxDialog::ButtonArea) + \return \c true if border is enabled for specified button area. + \sa setBorderEnabled() */ - bool QtxDialog::isBorderEnabled( const int area ) const { bool res = false; @@ -777,11 +788,14 @@ bool QtxDialog::isBorderEnabled( const int area ) const } /*! - Name: setBorderEnabled [public] - Desc: Show/hide border for specified button area. Border are - line which separate main frame and control buttons. -*/ + \brief Show/hide border for the specified button area. + Border is a line which separate main frame and control buttons. + + \param area buttons area (QtxDialog::ButtonArea) + \param on enable border flag + \sa isBorderEnabled() +*/ void QtxDialog::setBorderEnabled( const bool on, const int area ) { if ( !myArea.contains( area ) ) @@ -800,13 +814,14 @@ void QtxDialog::setBorderEnabled( const bool on, const int area ) } /*! - Name: isButtonEnabled [public] - Desc: Returns true if all specified button(s) is enabled. + \brief Get "enabled" status of the specified button(s). + \param id control button(s) ID (QtxDialog::ButtonFlags) + \return \c true if all specified buttons are enabled. + \sa setButtonEnabled() */ - -bool QtxDialog::isButtonEnabled( const int f ) const +bool QtxDialog::isButtonEnabled( const int id ) const { - ButtonMap map = buttons( f ); + ButtonMap map = buttons( id ); bool result = !map.isEmpty(); for ( ButtonMap::Iterator it = map.begin(); it != map.end(); ++it ) result = result && it.value()->isEnabled(); @@ -814,22 +829,24 @@ bool QtxDialog::isButtonEnabled( const int f ) const } /*! - Name: setButtonEnabled [public] - Desc: Enable/disable specified button(s). + \brief Enable/disable specified button(s). + \param on enable button(s) flag + \param id control button(s) ID (QtxDialog::ButtonFlags) + \sa isButtonEnabled() */ - -void QtxDialog::setButtonEnabled( const bool on, const int ids ) +void QtxDialog::setButtonEnabled( const bool on, const int id ) { - ButtonMap map = buttons( ids ); + ButtonMap map = buttons( id ); for ( ButtonMap::Iterator it = map.begin(); it != map.end(); ++it ) it.value()->setEnabled( on ); } /*! - Name: hasButtonFocus [public] - Desc: Retruns true if specified button has keyboard focus. + \brief Check if specified button has keyboard focus. + \param id control button ID (QtxDialog::ButtonFlags) + \return \c true if specified button has keyboard focus + \sa setButtonFocus() */ - bool QtxDialog::hasButtonFocus( const int id ) const { bool res = false; @@ -840,10 +857,10 @@ bool QtxDialog::hasButtonFocus( const int id ) const } /*! - Name: setButtonFocus [public] - Desc: Sets the keyboard focus on specified button. + \brief Sets the keyboard focus to the specified button. + \param id control button ID (QtxDialog::ButtonFlags) + \sa hasButtonFocus() */ - void QtxDialog::setButtonFocus( const int id ) { QAbstractButton* pb = button( id ); @@ -852,10 +869,11 @@ void QtxDialog::setButtonFocus( const int id ) } /*! - Name: buttonText [public] - Desc: Return text of specified button. + \brief Get specified button's text. + \param id control button ID (QtxDialog::ButtonFlags) + \return button's text + \sa setButtonText() */ - QString QtxDialog::buttonText( const int id ) { QString retval; @@ -866,10 +884,11 @@ QString QtxDialog::buttonText( const int id ) } /*! - Name: setButtonText [public] - Desc: Sets text to specified button. + \brief Set specified button's text. + \param id control button ID (QtxDialog::ButtonFlags) + \param text button's text + \sa buttonText() */ - void QtxDialog::setButtonText( const int id, const QString& text ) { QAbstractButton* but = button( id ); @@ -881,28 +900,19 @@ void QtxDialog::setButtonText( const int id, const QString& text ) } /*! - Name: setAlignment [public] - Desc: Sets alignment policy. Returns the previous alignment. - Use the function before the first show of the dialog. - If dialog flag AlignOnce is setted then align will performed - only one time otherwise dialog will be aligned every time - when it shown. Dialog will be aligned relative to it parent. + \brief Sets alignment policy. - Following align flags may be used: - Qtx::AlignAuto - Align to center of desktop (default). - Qtx::AlignLeft - Align left side of dialog to left side of parent. - Qtx::AlignRight - Align right side of dialog to right side of parent. - Qtx::AlignTop - Align top side of dialog to top side of parent. - Qtx::AlignBottom - Align bottom side of dialog to bottom side of parent. - Qtx::AlignHCenter - Align dialog to center of parent in horizontal dimension. - Qtx::AlignVCenter - Align dialog to center of parent in vertical dimension. - Qtx::AlignCenter - Align dialog to center of parent in both dimensions. - Qtx::AlignOutLeft - Align right side of dialog to left side of parent. - Qtx::AlignOutRight - Align left side of dialog to right side of parent. - Qtx::AlignOutTop - Align bottom side of dialog to top side of parent. - Qtx::AlignOutBottom - Align top side of dialog to bottom side of parent. + Use the function before the the dialog is first time shown. + If dialog flag AlignOnce is set then alignment is performed + only once, otherwise the dialog is aligned each time when it + is shown. + Dialog box is aligned relatively to its parent. + By default, dialog box is aligned to the center of the parent + widget (usually desktop or another dialog box). + + \param align alignment flag(s) (Qtx::AlignmentFlags) + \return previous alignment policy */ - uint QtxDialog::setAlignment( uint align ) { uint oldAlign = myAlignment; @@ -911,10 +921,8 @@ uint QtxDialog::setAlignment( uint align ) } /*! - Name: update [virtual public slot] - Desc: Updates dialog, show selected buttons and hide unselected. + \brief Update dialog box. */ - void QtxDialog::update() { for ( ButtonMap::Iterator it = myButton.begin(); it != myButton.end(); ++it ) @@ -930,12 +938,16 @@ void QtxDialog::update() } /*! - Name: show [virtual public] - Desc: Show dialog, set keyboard focus on dialog. + \brief Show/hide dialog box, set keyboard focus to the dialog. + + Re-implemented from Qt. + + \param on show/hide flag */ - void QtxDialog::setVisible( bool on ) { + resize( sizeHint() ); + QDialog::setVisible( on ); if ( on ) @@ -949,10 +961,11 @@ void QtxDialog::setVisible( bool on ) } /*! - Name: userButton [public] - Desc: Return user dialog button using specified identificator. + \brief Get user button by the specified \a id. + \param id user button ID + \return user button or 0 if it is not found + \sa insertButton(), removeButton(), userButtonIds() */ - QAbstractButton* QtxDialog::userButton( const int id ) const { QAbstractButton* b = 0; @@ -962,10 +975,10 @@ QAbstractButton* QtxDialog::userButton( const int id ) const } /*! - Name: userButtonIds [public] - Desc: Return list of user dialog button identificators. + \brief Get all user button IDs. + \return list of user buttons identificators + \sa insertButton(), removeButton(), userButton() */ - QIntList QtxDialog::userButtonIds() const { QIntList retlist; @@ -976,11 +989,17 @@ QIntList QtxDialog::userButtonIds() const } /*! - Name: insertButton [public] - Desc: Add new user dialog button. Function return identificator of - newly added button in successfull case otherwise -1 will be returned. -*/ + \brief Add user button to the dialog box. + The button is inserted to the specified dialog box area. + if the button is added successfully, the unique identificator of + the added button is returned, otherwise -1 is returned. + + \param text text of the added button + \param area buttons area (QtxDialog::ButtonArea) + \return button ID + \sa removeButton(), userButton(), userButtonIds() +*/ int QtxDialog::insertButton( const QString& text, const int area ) { if ( !myArea.contains( area ) ) @@ -1011,11 +1030,13 @@ int QtxDialog::insertButton( const QString& text, const int area ) } /*! - Name: removeButton [public] - Desc: Remove user dialog button with specified identificator. If - identificator equal -1 then method will remove all user dialog buttons. -*/ + \brief Remove user button. + + If \c id is -1, all user buttons are removed. + \param id user button ID + \sa insertButton(), userButton(), userButtonIds() +*/ void QtxDialog::removeButton( const int id ) { if ( id >= 0 ) @@ -1047,18 +1068,31 @@ void QtxDialog::removeButton( const int id ) } /*! - Name: setUnits [static public] - Desc: Sets specified measure units in given label. Measure units close - in braces. If measure units not exist then they will be added. - For example: - 1. Label contains text 'Radius'. - setUnits( aLabel, "mm" ) => aLabel contains 'Radius (mm)' - setUnits( aLabel, "cm" ) => aLabel contains 'Radius (cm)' - 2. Label "aLabel" contains text 'Radius ():'. - setUnits( aLabel, "mm" ) => aLabel contains 'Radius (mm):' - setUnits( aLabel, "cm" ) => aLabel contains 'Radius (cm):' -*/ + \brief Set measure units to the specified label. + In the dialog box label the measure units are closed in braces. + If measure units do not exist they will be added. + + For example: + \code + // create label "Radius" + QLabel* aLabel = new QLabel( "Radius", mainFrame() ); + // set measure units to "mm" + setUnits( aLabel, "mm" ) // => aLabel contains 'Radius (mm)' + // set measure units to "cm" + setUnits( aLabel, "cm" ) // => aLabel contains 'Radius (cm)' + + // create label "Radius" with initially not set measure units + QLabel* aLabel = new QLabel( "Radius ():", mainFrame() ); + // set measure units to "mm" + setUnits( aLabel, "mm" ) // => aLabel contains 'Radius (mm):' + // set measure units to "cm" + setUnits( aLabel, "cm" ) // => aLabel contains 'Radius (cm):' + \endcode + + \param aLabel label widget + \param aUnits measure units +*/ void QtxDialog::setUnits( QLabel* aLabel, const QString& aUnits ) { QString label = aLabel->text(); @@ -1095,32 +1129,49 @@ void QtxDialog::setUnits( QLabel* aLabel, const QString& aUnits ) } /*! - Name: acceptData [virtual protected] - Desc: If returns true dialog will be accepted and closed. This method - called if dialog flag Accept is setted. -*/ + \brief Check if data entered by the user is valid. + + This method can be re-implemented in the successor class if it + requires to check user input consistency. + Default implementation returns \c true. + This method is called if dialog flag QtxDialog::Accept is set. + If this method returns \c true, then dialog will be accepted and closed. + + \return \c true if user input is valid + \sa accept() +*/ bool QtxDialog::acceptData() const { return true; } /*! - Name: rejectData [virtual protected] - Desc: If returns true dialog will be rejected and closed. This method - called if dialog flag Reject is setted. -*/ + \brief Check if dialog box can be cancelled. + + This method can be re-implemented in the successor class if it + requires to check possibility to cancel dialog box safely. + Default implementation returns \c true. + + This method is called if dialog flag QtxDialog::Reject is set. + If this method returns \c true, then dialog will be rejected and closed. + \return \c true if dialog box can be cancelled + \sa reject() +*/ bool QtxDialog::rejectData() const { return true; } /*! - Name: createButton [virtual protected] - Desc: Create new user button. Invoked from method "insertButton". -*/ + \brief Create new user button. + This method is invoked from method insertButton(). + + \param parent parent widget + \return new user button +*/ QAbstractButton* QtxDialog::createButton( QWidget* parent ) { QPushButton* pb = new QPushButton( parent ); @@ -1129,11 +1180,10 @@ QAbstractButton* QtxDialog::createButton( QWidget* parent ) } /*! - Name: button [protected] - Desc: Return pointer on control button specified by identifier. - If identifier is wrong then null pointer will returned. + \brief Get button by the specified ID. + \param f control button ID (QtxDialog::ButtonFlags) + \return button or 0 if \a id is invalid */ - QAbstractButton* QtxDialog::button( const int f ) const { QAbstractButton* retval = 0; @@ -1143,10 +1193,10 @@ QAbstractButton* QtxDialog::button( const int f ) const } /*! - Name: buttons [protected] - Desc: Return map with control dialog buttons accordance to given button flags. + \brief Get buttons by the specified IDs. + \param f control button(s) ID(s) (QtxDialog::ButtonFlags) + \return button map */ - QtxDialog::ButtonMap QtxDialog::buttons( const int f ) const { ButtonMap retmap; @@ -1165,10 +1215,10 @@ QtxDialog::ButtonMap QtxDialog::buttons( const int f ) const } /*! - Name: buttonId [protected] - Desc: Return identifier of specified button. + \brief Get specified button's identifier. + \param b button + \return button ID */ - int QtxDialog::buttonId( const QAbstractButton* b ) const { int id = -1; @@ -1179,21 +1229,23 @@ int QtxDialog::buttonId( const QAbstractButton* b ) const } /*! - Name: buttonPosition - Desc: Returns position of specified button. [protected] + \brief Get position of specified button. + \param b button + \return button position (QtxDialog::ButtonPosition) */ - int QtxDialog::buttonPosition( QAbstractButton* b ) const { return buttonPosition( buttonId( b ) ); } /*! - Name: showEvent [virtual protected] - Desc: Aligns this dialog according the parent widget and alignment - policy before the show. -*/ + \brief Align this dialog according to the parent widget and alignment + policy before the dialog box is shown. + + Re-implemented from Qt. + \param e show event +*/ void QtxDialog::showEvent( QShowEvent* e ) { if ( !testDialogFlags( AlignOnce ) || !myInited ) @@ -1202,10 +1254,12 @@ void QtxDialog::showEvent( QShowEvent* e ) } /*! - Name: hideEvent [virtual protected] - Desc: Process all existing events when dialog is closed. -*/ + \brief Process all existing events when dialog box is hidden. + Re-implemented from Qt. + + \param e hide event +*/ void QtxDialog::hideEvent( QHideEvent* e ) { QApplication::instance()->processEvents(); @@ -1213,10 +1267,12 @@ void QtxDialog::hideEvent( QHideEvent* e ) } /*! - Name: childEvent [virtual protected] - Desc: Setting up layout when size grip is added. -*/ + \brief Update dialog box layout when the size grip is added. + + Re-implemented from Qt. + \param e child event +*/ void QtxDialog::childEvent( QChildEvent* e ) { QDialog::childEvent( e ); @@ -1228,13 +1284,18 @@ void QtxDialog::childEvent( QChildEvent* e ) } /*! - Name: keyPressEvent [virtual protected] - Desc: Calls reject() if key Escape is pressed. - Calls accept() if key "Ctrl+Enter" is pressed. - Process key "F1" and emit signal dlgHelp(). - Transfer key "Ctrl+(Shift+)Tab" press event to Tab Widget. -*/ + \brief Process key pressing event. + Re-implemented from Qt. + + Call reject() if "Escape" key is pressed. + Call accept() if "Ctrl+Enter" key-sequence is pressed. + Process "F1" key and emit signal dlgHelp(). + Transfer "Ctrl+(Shift+)Tab" key-sequence press event + to the child Tab widget (if there is any). + + \param e key press event +*/ void QtxDialog::keyPressEvent( QKeyEvent* e ) { QDialog::keyPressEvent( e ); @@ -1269,22 +1330,37 @@ void QtxDialog::keyPressEvent( QKeyEvent* e ) } /*! - Name: closeEvent [virtual protected] - Desc: Reject the dialog. + \brief Called when user closes dialog box. + + Call reject() method. + + \param e close event (not used) */ - -void QtxDialog::closeEvent( QCloseEvent* ) +void QtxDialog::closeEvent( QCloseEvent* /*e*/ ) { reject(); } /*! - Name: accept [virtual protected slot] - Desc: Invoke function acceptData() if it needed and if acceptData() return - false does nothing. Otherwise hides the dialog and sets the result code - to Accepted. Emit signal according to the pressed control button. -*/ + \brief Accept the dialog box. + + This method is used when any accept button is pressed (usually + "OK", "Yes", etc). + If dialog flag QtxDialog::Accept is set, this function invokes + acceptData() method, which should in this case return \c true to + allow further processing. + + If acceptData() returns \c false, this function just returns. + + If acceptData() returns \c true, the Accepted result is set + and signal according to the pressed control button is emitted. + Then the default implementation of accept() method is called + (which hides the dialog box and, depending on the dialog box flags, + can close and destroy it). + + \sa acceptData() +*/ void QtxDialog::accept() { if ( !mySender ) @@ -1310,14 +1386,25 @@ void QtxDialog::accept() } /*! - Name: reject [virtual protected slot] - Desc: Invoke function rejectData() if it needed and if rejectData() return - false does nothing. Otherwise hides the dialog and sets the result code - to Rejected. Emit signal according to the pressed control button. (If - dialog was closed by key Escape or by close event emit signal dlgCancel(), - or dlgClose(), or dlgNo(). -*/ + \brief Reject the dialog box. + This method is used when any reject button is pressed (usually + "Close", "Cancel", "No", etc). + + If dialog flag QtxDialog::Reject is set, this function invokes + rejectData() method, which should in this case return \c true to + allow further processing. + + If rejectData() returns \c false, this function just returns. + + If rejectData() returns \c true, the Rejected result is set + and signal according to the pressed control button is emitted. + Then the default implementation of reject() method is called + (which hides the dialog box and, depending on the dialog box flags, + can close and destroy it). + + \sa rejectData() +*/ void QtxDialog::reject() { if ( testDialogFlags( Reject ) && !rejectData() ) @@ -1343,10 +1430,8 @@ void QtxDialog::reject() } /*! - Name: reject [private] - Desc: Emit signal appropriate to control button. + \brief Emit signal correspondingly to the control button. */ - void QtxDialog::emitSignal() { QApplication::instance()->processEvents(); @@ -1376,10 +1461,11 @@ void QtxDialog::emitSignal() } /*! - Name: onAccept [private slot] - Desc: Process signals "clicked()" from control buttons "OK", "Yes". Invoke accept(). -*/ + \brief This slot is called when user presses on of the buttons + "OK", "Yes", etc. + Call accept() method. +*/ void QtxDialog::onAccept() { const QObject* obj = sender(); @@ -1388,9 +1474,10 @@ void QtxDialog::onAccept() } /*! - Name: onReject [private slot] - Desc: Process signals "clicked()" from control buttons "Cancel", "No", "Close". - Invoke reject(). + \brief This slot is called when user presses on of the buttons + "Cancel", "No", "Close". + + Call reject() method. */ void QtxDialog::onReject() @@ -1401,11 +1488,12 @@ void QtxDialog::onReject() } /*! - Name: onButton [private slot] - Desc: Receive signal "clicked()" from user buttons and emit signal - "dlgButton( int )" with identificator of clicked user button. + \brief Process user button click event. + + This method is called when user presses one of custom user buttons. + Emits signal dlgButton(int) with identificator of the clicked user + button passed as parameter. */ - void QtxDialog::onButton() { int id = buttonId( (QAbstractButton*)sender() ); @@ -1414,10 +1502,9 @@ void QtxDialog::onButton() } /*! - Name: onDestroyed [private slot] - Desc: Remove user button if it was destroyed. + \brief Watch for the user button destroying. + \param obj button being destroyed */ - void QtxDialog::onDestroyed( QObject* obj ) { QAbstractButton* b = (QAbstractButton*)obj; @@ -1432,10 +1519,8 @@ void QtxDialog::onDestroyed( QObject* obj ) } /*! - Name: onSizeGripDestroyed [private slot] - Desc: Setting up layout when size grip is destroyed. + \brief Update dialog box layout when the size grip is destroyed. */ - void QtxDialog::onSizeGripDestroyed() { if ( layout() ) @@ -1443,10 +1528,8 @@ void QtxDialog::onSizeGripDestroyed() } /*! - Name: adjustButtons [private] - Desc: Setting the equal with for all buttons. + \brief Adjust buttons (set equal size for all buttons). */ - void QtxDialog::adjustButtons() { int minWidth = 0; @@ -1466,3 +1549,42 @@ void QtxDialog::adjustButtons() (*bItr)->setMinimumWidth( minWidth ); } } + +/*! + \fn void QtxDialog::dlgButton( int id ) + \brief Emitted when the user button is clicked. + \param id user button identificator +*/ +/*! + \fn void QtxDialog::dlgParamChanged() + \brief This signal can be used in successor classes to signalize about + some dialog parameter changing. +*/ +/*! + \fn void QtxDialog::dlgHelp() + \brief Emitted when the "Help" button is clicked. +*/ +/*! + \fn void QtxDialog::dlgApply() + \brief Emitted when the "Apply" button is clicked. +*/ +/*! + \fn void QtxDialog::dlgOk() + \brief Emitted when the "OK" button is clicked. +*/ +/*! + \fn void QtxDialog::dlgNo() + \brief Emitted when the "No" button is clicked. +*/ +/*! + \fn void QtxDialog::dlgYes() + \brief Emitted when the "Yes" button is clicked. +*/ +/*! + \fn void QtxDialog::dlgClose() + \brief Emitted when the "Close" button is clicked. +*/ +/*! + \fn void QtxDialog::dlgCancel() + \brief Emitted when the "Cancel" button is clicked. +*/ diff --git a/src/Qtx/QtxDialog.h b/src/Qtx/QtxDialog.h index 9ab34e770..86006f547 100755 --- a/src/Qtx/QtxDialog.h +++ b/src/Qtx/QtxDialog.h @@ -1,22 +1,22 @@ // Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D -// +// // 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 +// License as published by the Free Software Foundation; either // version 2.1 of the License. -// -// 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 +// +// 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 +// 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: QtxDialog.hxx +// File: QtxDialog.h // Author: Sergey TELKOV #ifndef QTXDIALOG_H @@ -24,10 +24,8 @@ #include "Qtx.h" -#include -#include - -#include +#include +#include class QFrame; class QLabel; @@ -45,140 +43,157 @@ class QTX_EXPORT QtxDialog : public QDialog class Border; public: - typedef enum { Position, Expand, Uniform } PlacePolicy; - typedef enum { TopArea, BottomArea, LeftArea, RightArea } ButtonArea; - typedef enum { Left, Right, Center, Top = Left, Bottom = Right } ButtonPosition; - - typedef enum { None = 0x00000000, - OK = 0x00000001, - Apply = 0x00000002, - Cancel = 0x00000004, - Yes = 0x00000008, - No = 0x00000010, - Close = 0x00000020, - Help = 0x00000040, - OKCancel = OK | Cancel, - YesNo = Yes | No, - Standard = OK | Cancel | Help, - All = Standard | YesNo | Apply | Close } ButtonFlags; - - typedef enum { Accept = 0x000001, - Reject = 0x000002, - AlignOnce = 0x000004, - SetFocus = 0x000008 } DialogFlags; - + //! Buttons alignment type + typedef enum { Position, //!< buttons are placed according their position + Expand, //!< buttons occupy all available space + Uniform //!< buttons are uniformly placed in the area + } PlacePolicy; + //! Buttons area + typedef enum { TopArea, //!< horizontal area at the top side of the dialog box + BottomArea, //!< horizontal area at the bottom side of the dialog box + LeftArea, //!< vertical area at the left side of the dialog box + RightArea //!< vertical area at the right side of the dialog box + } ButtonArea; + //! Button position + typedef enum { Left, //!< set button left-most + Right, //!< set button right-most + Center, //!< place button in the center + Top = Left, //!< set button top-most + Bottom = Right //!< set button bottom-most + } ButtonPosition; + //! Button ID flags + typedef enum { None = 0x00000000, //!< no button used + OK = 0x00000001, //!< OK button + Apply = 0x00000002, //!< Apply button + Cancel = 0x00000004, //!< Cancel button + Yes = 0x00000008, //!< Yes button + No = 0x00000010, //!< No button + Close = 0x00000020, //!< Close button + Help = 0x00000040, //!< Help button + OKCancel = OK | Cancel, //!< OK & Cancel button + YesNo = Yes | No, //!< Yes & No buttons + Standard = OK | Cancel | Help, //!< OK, Cancel & Help buttons + All = Standard | YesNo | Apply | Close //!< all buttons + } ButtonFlags; + //! Dialog box flags + typedef enum { Accept = 0x000001, //!< allow dialog box accepting control + Reject = 0x000002, //!< allow dialog box rejecting control + AlignOnce = 0x000004, //!< align dialog box only when it is first time shown + SetFocus = 0x000008 //!< allow to set focus on dialog box when it is shown (user can use setFocusProxy() and specify own initial focus widget) + } DialogFlags; + public: - QtxDialog( QWidget* = 0, bool = false, bool = false, const int = Standard, Qt::WindowFlags = 0 ); - virtual ~QtxDialog(); - - void setDialogFlags( const int ); - void clearDialogFlags( const int ); - bool testDialogFlags( const int ) const; - - void setButtonFlags( const int ); - void clearButtonFlags( const int ); - bool testButtonFlags( const int ) const; - - int buttonPosition( const int ) const; - void setButtonPosition( const int, const int = -1 ); - void setPlacePosition( const int, const int ); - - int placePolicy( const int ) const; - void setPlacePolicy( const int, const int ); - void setButtonPlace( const int, const int ); - - QString buttonText( const int ); - void setButtonText( const int, const QString& text ); - - void setButtonFocus( const int ); - bool hasButtonFocus( const int ) const; - - bool isButtonEnabled( const int ) const; - void setButtonEnabled( const bool, const int ); - - bool isBorderEnabled( const int ) const; - void setBorderEnabled( const bool, const int ); - - void removeButton( const int ); - int insertButton( const QString&, const int = BottomArea ); - - QIntList userButtonIds() const; - QAbstractButton* userButton( const int ) const; - - uint setAlignment( uint align ); - static void setUnits( QLabel*, const QString& ); - -Q_SIGNALS: - void dlgButton( int ); - void dlgParamChanged(); - - void dlgHelp(); - void dlgApply(); - - void dlgOk(); - void dlgNo(); - void dlgYes(); - void dlgClose(); - void dlgCancel(); - -public Q_SLOTS: - void update(); - virtual void setVisible( bool ); - -protected Q_SLOTS: - virtual void accept(); - virtual void reject(); - -private Q_SLOTS: - void onAccept(); - void onReject(); - void onButton(); - void onSizeGripDestroyed(); - void onDestroyed( QObject* ); + QtxDialog( QWidget* = 0, bool = false, bool = false, const int = Standard, Qt::WindowFlags = 0 ); + virtual ~QtxDialog(); + + void setDialogFlags( const int ); + void clearDialogFlags( const int ); + bool testDialogFlags( const int ) const; + + void setButtonFlags( const int ); + void clearButtonFlags( const int ); + bool testButtonFlags( const int ) const; + + int buttonPosition( const int ) const; + void setButtonPosition( const int, const int = -1 ); + void setPlacePosition( const int, const int ); + + int placePolicy( const int ) const; + void setPlacePolicy( const int, const int ); + void setButtonPlace( const int, const int ); + + QString buttonText( const int ); + void setButtonText( const int, const QString& text ); + + void setButtonFocus( const int ); + bool hasButtonFocus( const int ) const; + + bool isButtonEnabled( const int ) const; + void setButtonEnabled( const bool, const int ); + + bool isBorderEnabled( const int ) const; + void setBorderEnabled( const bool, const int ); + + void removeButton( const int ); + int insertButton( const QString&, const int = BottomArea ); + + QIntList userButtonIds() const; + QAbstractButton* userButton( const int ) const; + + uint setAlignment( uint align ); + static void setUnits( QLabel*, const QString& ); + +signals: + void dlgButton( int ); + void dlgParamChanged(); + + void dlgHelp(); + void dlgApply(); + + void dlgOk(); + void dlgNo(); + void dlgYes(); + void dlgClose(); + void dlgCancel(); + +public slots: + void update(); + virtual void setVisible( bool ); + +protected slots: + virtual void accept(); + virtual void reject(); + +private slots: + void onAccept(); + void onReject(); + void onButton(); + void onSizeGripDestroyed(); + void onDestroyed( QObject* ); protected: - typedef QMap ButtonMap; + typedef QMap ButtonMap; //!< button map protected: - QFrame* mainFrame() const; - - virtual bool acceptData() const; - virtual bool rejectData() const; - - virtual QAbstractButton* createButton( QWidget* ); - - QAbstractButton* button( const int ) const; - ButtonMap buttons( const int = All ) const; - int buttonId( const QAbstractButton* ) const; - int buttonPosition( QAbstractButton* ) const; - - virtual void showEvent( QShowEvent* ); - virtual void hideEvent( QHideEvent* ); - virtual void closeEvent( QCloseEvent* ); - virtual void childEvent( QChildEvent* ); - virtual void keyPressEvent( QKeyEvent* ); - + QFrame* mainFrame() const; + + virtual bool acceptData() const; + virtual bool rejectData() const; + + virtual QAbstractButton* createButton( QWidget* ); + + QAbstractButton* button( const int ) const; + ButtonMap buttons( const int = All ) const; + int buttonId( const QAbstractButton* ) const; + int buttonPosition( QAbstractButton* ) const; + + virtual void showEvent( QShowEvent* ); + virtual void hideEvent( QHideEvent* ); + virtual void closeEvent( QCloseEvent* ); + virtual void childEvent( QChildEvent* ); + virtual void keyPressEvent( QKeyEvent* ); + private: - void adjustButtons(); - void emitSignal(); - + void adjustButtons(); + void emitSignal(); + private: - typedef QMap AreaMap; - typedef QMap PositionMap; - - friend class Area; + typedef QMap AreaMap; //!< button area map + typedef QMap PositionMap; //!< button position map + + friend class Area; private: - AreaMap myArea; - ButtonMap myButton; - PositionMap myPosition; - - bool myInited; - const QObject* mySender; - uint myAlignment; - QFrame* myMainFrame; - int myButtonFlags; - int myDialogFlags; + AreaMap myArea; //!< buttons areas map + ButtonMap myButton; //!< buttons map + PositionMap myPosition; //!< buttons position map + + bool myInited; //!< dialog's "initialized" flag + const QObject* mySender; //!< signal sender + uint myAlignment; //!< dialog box alignment type + QFrame* myMainFrame; //!< main frame + int myButtonFlags; //!< button flags + int myDialogFlags; //!< dialog flags }; #ifdef WIN32 diff --git a/src/Qtx/QtxDockAction.cxx b/src/Qtx/QtxDockAction.cxx index 49b22b89c..8f40092d3 100755 --- a/src/Qtx/QtxDockAction.cxx +++ b/src/Qtx/QtxDockAction.cxx @@ -21,88 +21,101 @@ #include "QtxDockAction.h" -#include -#include -#include -#include +#include +#include +#include +#include /*! - Name: QtxDockAction [public] - Desc: Constructs an Dock action with given main window and name. + \class QtxDockAction + \brief Dockable windows & toolbars list action. + + Implements the action which provides the popup menu with the list + of toolbars and/or dockable windows list owned by the main window. + This action can be used, for example, in the menu "Windows". */ +/*! + \brief Constructor. + \param mw parent main window +*/ QtxDockAction::QtxDockAction( QMainWindow* mw ) : QtxAction( "Windows and Toolbars", "Windows and Toolbars", 0, mw ), -myMain( mw ), -myType( Both ) + myType( Both ), + myMain( mw ) { initialize(); } /*! - Name: QtxDockAction [public] - Desc: This constructor creates an action with the following properties: the - description text, the menu text and. It is a child of given main window - and named specified name. + \brief Constructor. + \param text description (tooltip) text + \param menuText menu text + \param mw parent main window */ - QtxDockAction::QtxDockAction( const QString& text, const QString& menuText, QMainWindow* mw ) : QtxAction( text, menuText, 0, mw ), -myMain( mw ), -myType( Both ) + myType( Both ), + myMain( mw ) { initialize(); } /*! - Name: QtxDockAction [public] - Desc: This constructor creates an action with the following properties: the - description text, the menu text, the icon or iconset icon and keyboard - accelerator. It is a child of given main window and named specified name. + \brief Constructor. + \param text description (tooltip) text + \param icon action icon + \param menuText menu text + \param mw parent main window */ - QtxDockAction::QtxDockAction( const QString& text, const QIcon& icon, const QString& menuText, QMainWindow* mw ) : QtxAction( text, icon, menuText, 0, mw ), -myMain( mw ), -myType( Both ) + myType( Both ), + myMain( mw ) { initialize(); } /*! - Name: ~QtxDockAction [public] - Desc: Removes all added popup items. + \brief Desctructor + + Does nothing currently. */ - QtxDockAction::~QtxDockAction() { } /*! - Name: mainWindow [public] - Desc: Returns the main window which contains managed dock windows. + \brief Get parent main window. + \return main window pointer. */ - QMainWindow* QtxDockAction::mainWindow() const { return myMain; } +/*! + \brief Get dock action type. + \return dock type (QtxDockAction::DockType) +*/ int QtxDockAction::dockType() const { return myType; } +/*! + \brief Set dock action type. + \param type dock type (QtxDockAction::DockType) +*/ void QtxDockAction::setDockType( const int type ) { myType = type; } /*! - Name: onAboutToShow [private slots] - Desc: Prepare sub popup with dock windows list when parent popup is shown. + \brief Prepare popup menu with dock windows list when + parent popup menu is shown. */ - void QtxDockAction::onAboutToShow() { updateMenu(); @@ -110,10 +123,9 @@ void QtxDockAction::onAboutToShow() } /*! - Name: toolBars [private] - Desc: Returns all toolbars of the main window. + \brief Get all toolbars owned by parent main window. + \param lst returned list of all toolbars owned by main window */ - void QtxDockAction::toolBars( QList& lst ) const { lst.clear(); @@ -132,10 +144,9 @@ void QtxDockAction::toolBars( QList& lst ) const } /*! - Name: dockWidgets [private] - Desc: Returns all dock widgets of the main window. + \brief Get all dockable windows owned by parent main window. + \param lst returned list of all dockable windows owned by main window */ - void QtxDockAction::dockWidgets( QList& lst ) const { lst.clear(); @@ -153,10 +164,6 @@ void QtxDockAction::dockWidgets( QList& lst ) const } } -/*! - Name: updateInfo [private] - Desc: Updates icon and caption info of dock window in the corresponded action. -*/ /* void QtxDockAction::updateInfo( QDockWindow* dw ) { @@ -178,12 +185,28 @@ void QtxDockAction::updateInfo( QDockWindow* dw ) } */ +/*! + \brief Customize action adding to the widget operation. + + Called when the action is added to the widget. + Reimplemented from QtxAction class. + + \param w widget this action is added to (menu or toolbar) +*/ void QtxDockAction::addedTo( QWidget* w ) { if ( w->inherits( "QMenu" ) ) connect( w, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) ); } +/*! + \brief Customize action removing from the widget operation. + + Called when the action is removed from the widget. + Reimplemented from QtxAction class. + + \param w widget this action is removed from to (menu or toolbar) +*/ void QtxDockAction::removedFrom( QWidget* w ) { if ( w->inherits( "QMenu" ) ) @@ -191,17 +214,15 @@ void QtxDockAction::removedFrom( QWidget* w ) } /*! - Name: initialize [private] - Desc: Initialisation of the object. + \brief Initialize the action. */ - void QtxDockAction::initialize() { setMenu( new QMenu( 0 ) ); } /*! - Updates menu of action + \brief Update action child popup menu. */ void QtxDockAction::updateMenu() { diff --git a/src/Qtx/QtxDockAction.h b/src/Qtx/QtxDockAction.h index 8fd83e6fb..293e3351d 100755 --- a/src/Qtx/QtxDockAction.h +++ b/src/Qtx/QtxDockAction.h @@ -19,12 +19,12 @@ // File: QtxDockAction.h // Author: Sergey TELKOV -#ifndef QTX_DOCKACTION_H -#define QTX_DOCKACTION_H +#ifndef QTXDOCKACTION_H +#define QTXDOCKACTION_H #include "QtxAction.h" -#include +#include class QIcon; class QString; @@ -41,7 +41,11 @@ class QTX_EXPORT QtxDockAction : public QtxAction Q_OBJECT public: - enum { ToolBar, DockWidget, Both }; + //! Dock windows type. + enum { ToolBar, //!< list toolbars only + DockWidget, //!< list dockable windows only + Both //!< list toolbars and dockable windows + } DockType; public: QtxDockAction( QMainWindow* ); @@ -54,7 +58,7 @@ public: QMainWindow* mainWindow() const; -private Q_SLOTS: +private slots: void onAboutToShow(); protected: @@ -69,12 +73,12 @@ private: void dockWidgets( QList& ) const; private: - int myType; - QMainWindow* myMain; + int myType; //!< dock action type + QMainWindow* myMain; //!< parent main window }; #ifdef WIN32 #pragma warning( default:4251 ) #endif -#endif +#endif // QTXDOCKACTION_H diff --git a/src/Qtx/QtxDockWidget.cxx b/src/Qtx/QtxDockWidget.cxx index 7b16f4247..fd6f00371 100644 --- a/src/Qtx/QtxDockWidget.cxx +++ b/src/Qtx/QtxDockWidget.cxx @@ -28,16 +28,18 @@ #include /*! - \class QtxDockWidget::Watcher [Internal] - Internal object with event filter. + \class QtxDockWidget::Watcher + \internal + \brief Internal class which goal is to watch parent dockable widget state changing. */ + class QtxDockWidget::Watcher : public QObject { public: Watcher( QtxDockWidget* ); void shown( QtxDockWidget* ); - void hided( QtxDockWidget* ); + void hidden( QtxDockWidget* ); virtual bool eventFilter( QObject*, QEvent* ); @@ -62,12 +64,13 @@ private: }; /*! - Constructor + \brief Constructor. + \param cont dockable widget to be watched */ QtxDockWidget::Watcher::Watcher( QtxDockWidget* cont ) : QObject( cont ), myCont( cont ), -myState( true ), -myEmpty( false ) + myState( true ), + myEmpty( false ) { myCont->installEventFilter( this ); myVisible = myCont->isVisibleTo( myCont->parentWidget() ); @@ -76,7 +79,10 @@ myEmpty( false ) } /*! - Custom event filter + \brief Custom event filter. + \param o event receiver object + \param e event sent to object + \return \c true if further event processing should be stopped */ bool QtxDockWidget::Watcher::eventFilter( QObject* o, QEvent* e ) { @@ -111,7 +117,8 @@ bool QtxDockWidget::Watcher::eventFilter( QObject* o, QEvent* e ) } /*! - Sets internal status to shown + \brief Set internal status to "shown" + \param dw dockable widget */ void QtxDockWidget::Watcher::shown( QtxDockWidget* dw ) { @@ -122,9 +129,10 @@ void QtxDockWidget::Watcher::shown( QtxDockWidget* dw ) } /*! - Sets internal status to hidden + \brief Set internal status to "hidden" + \param dw dockable widget */ -void QtxDockWidget::Watcher::hided( QtxDockWidget* dw ) +void QtxDockWidget::Watcher::hidden( QtxDockWidget* dw ) { if ( dw != myCont ) return; @@ -133,7 +141,7 @@ void QtxDockWidget::Watcher::hided( QtxDockWidget* dw ) } /*! - Shows corresponding dock window + \brief Show the dock window being watched */ void QtxDockWidget::Watcher::showContainer() { @@ -147,7 +155,7 @@ void QtxDockWidget::Watcher::showContainer() } /*! - Hides corresponding dock window + \brief Hide the dock window being watched */ void QtxDockWidget::Watcher::hideContainer() { @@ -161,9 +169,10 @@ void QtxDockWidget::Watcher::hideContainer() } /*! - Event filter of custom events + \brief Proces custom events. + \param e custom event (not used) */ -void QtxDockWidget::Watcher::customEvent( QEvent* ) +void QtxDockWidget::Watcher::customEvent( QEvent* /*e*/ ) { updateIcon(); updateCaption(); @@ -171,7 +180,8 @@ void QtxDockWidget::Watcher::customEvent( QEvent* ) } /*! - Installs this object as event filter to all widgets inside corresponding main window + \brief Install this object as event filter to all children widgets + of the dockable widget being watched. */ void QtxDockWidget::Watcher::installFilters() { @@ -190,7 +200,8 @@ void QtxDockWidget::Watcher::installFilters() } /*! - Updates visibility of all widgets inside corresponding main window + \brief Update visibility state of all children widgets of the dockable widget + being watched. */ void QtxDockWidget::Watcher::updateVisibility() { @@ -223,7 +234,7 @@ void QtxDockWidget::Watcher::updateVisibility() } /*! - Updates icon of corresponding main window + \brief Update the icon of dockable window being watched */ void QtxDockWidget::Watcher::updateIcon() { @@ -234,7 +245,7 @@ void QtxDockWidget::Watcher::updateIcon() } /*! - Updates caption of corresponding main window + \brief Update the title of dockable window being watched */ void QtxDockWidget::Watcher::updateCaption() { @@ -243,7 +254,15 @@ void QtxDockWidget::Watcher::updateCaption() } /*! - Constructor + \class QtxDockWidget + \brief Enhanced dockable widget class. +*/ + +/*! + \brief Constructor. + \param title dockable widget title + \param parent parent widget + \param f widget flags */ QtxDockWidget::QtxDockWidget( const QString& title, QWidget* parent, Qt::WindowFlags f ) : QDockWidget( title, parent, f ), @@ -254,7 +273,11 @@ QtxDockWidget::QtxDockWidget( const QString& title, QWidget* parent, Qt::WindowF } /*! - Constructor + \brief Constructor. + \param watch if \c true the event filter is installed to watch wigdet state changes + to update it properly + \param parent parent widget + \param f widget flags */ QtxDockWidget::QtxDockWidget( const bool watch, QWidget* parent, Qt::WindowFlags f ) : QDockWidget( parent, f ), @@ -268,7 +291,9 @@ QtxDockWidget::QtxDockWidget( const bool watch, QWidget* parent, Qt::WindowFlags } /*! - Constructor + \brief Constructor. + \param parent parent widget + \param f widget flags */ QtxDockWidget::QtxDockWidget( QWidget* parent, Qt::WindowFlags f ) : QDockWidget( parent, f ), @@ -277,14 +302,15 @@ myWatcher( 0 ) } /*! - Destructor + \brief Destructor. */ QtxDockWidget::~QtxDockWidget() { } /*! - \return the recommended size for the widget + \brief Get the recommended size for the widget. + \return recommended dockable widget size */ QSize QtxDockWidget::sizeHint() const { @@ -302,7 +328,8 @@ QSize QtxDockWidget::sizeHint() const } /*! - \return the recommended minimum size for the widget + \brief Get the recommended minimum size for the widget. + \return recommended dockable widget minimum size */ QSize QtxDockWidget::minimumSizeHint() const { @@ -325,7 +352,8 @@ QSize QtxDockWidget::minimumSizeHint() const } /*! - Shows/hides the window + \brief Show/hide the dockable window. + \param on new visibility state */ void QtxDockWidget::setVisible( bool on ) { @@ -334,7 +362,7 @@ void QtxDockWidget::setVisible( bool on ) if ( on ) myWatcher->shown( this ); else - myWatcher->hided( this ); + myWatcher->hidden( this ); } updateGeometry(); @@ -344,12 +372,20 @@ void QtxDockWidget::setVisible( bool on ) QDockWidget::setVisible( on ); } +/*! + \brief Process resize event + \param e event +*/ void QtxDockWidget::resizeEvent( QResizeEvent* e ) { QDockWidget::resizeEvent( e ); updateState(); } +/*! + \brief Get dockable window orientation. + \return orientation type +*/ Qt::Orientation QtxDockWidget::orientation() const { QMainWindow* mw = 0; @@ -383,6 +419,9 @@ Qt::Orientation QtxDockWidget::orientation() const return res; } +/*! + \brief Update dockable window state. +*/ void QtxDockWidget::updateState() { Qt::Orientation o = orientation(); @@ -393,3 +432,9 @@ void QtxDockWidget::updateState() emit orientationChanged( myOrientation ); } + +/*! + \fn QtxDockWidget::orientationChanged(Qt::Orientation o) + \brief Emitted when the dockable window orientation is changed. + \param o new window orientation +*/ diff --git a/src/Qtx/QtxDockWidget.h b/src/Qtx/QtxDockWidget.h index 3554f05f7..f94756ebf 100644 --- a/src/Qtx/QtxDockWidget.h +++ b/src/Qtx/QtxDockWidget.h @@ -19,6 +19,9 @@ // File: QtxDockWidget.h // Author: Sergey TELKOV +#ifndef QTXDOCKWIDGET_H +#define QTXDOCKWIDGET_H + #include "Qtx.h" #include @@ -40,10 +43,10 @@ public: Qt::Orientation orientation() const; -Q_SIGNALS: +signals: void orientationChanged( Qt::Orientation ); -public Q_SLOTS: +public slots: virtual void setVisible( bool ); protected: @@ -53,6 +56,8 @@ private: void updateState(); private: - Watcher* myWatcher; - Qt::Orientation myOrientation; + Watcher* myWatcher; //!< watcher object + Qt::Orientation myOrientation; //!< dockable window orientation }; + +#endif // QTXDOCKWIDGET_H diff --git a/src/Qtx/QtxDoubleSpinBox.cxx b/src/Qtx/QtxDoubleSpinBox.cxx new file mode 100644 index 000000000..c79e581c0 --- /dev/null +++ b/src/Qtx/QtxDoubleSpinBox.cxx @@ -0,0 +1,152 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxDoubleSpinBox.cxx +// Author: Sergey TELKOV + +#include "QtxDoubleSpinBox.h" + +#include + +/*! + \class QtxDoubleSpinBox + \brief Enhanced version of the Qt's double spin box. + + The QtxDoubleSpinBox class represents the widget for entering the + floating point values. In addition to the functionality provided by + QDoubleSpinBox, this class supports "cleared" state - this is the + state corresponding to "None" (or empty) entered value. + + To set "cleared" state use setCleared() method. To check if the spin + box stores "cleared" state, use isCleared() method. + For example: + \code + if (myDblSpinBox->isCleared()) { + ... // process "None" state + } + else { + double value = myDblSpinBox->value(); + ... // process entered value + } + \endcode +*/ + +/*! + \brief Constructor. + + Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value, + a step value of 1.0 and a precision of 2 decimal places. + The value is initially set to 0.00. + + \param parent parent object +*/ +QtxDoubleSpinBox::QtxDoubleSpinBox( QWidget* parent ) +: QDoubleSpinBox( parent ), + myCleared( false ) +{ + connect( lineEdit(), SIGNAL( textChanged( const QString& ) ), + this, SLOT( onTextChanged( const QString& ) ) ); +} + +/*! + \brief Constructor. + + Constructs a spin box with specified minimum, maximum and step value. + The precision is set to 2 decimal places. + The value is initially set to the minimum value. + + \param min spin box minimum possible value + \param max spin box maximum possible value + \param step spin box increment/decrement value + \param parent parent object +*/ +QtxDoubleSpinBox::QtxDoubleSpinBox( double min, double max, double step, QWidget* parent ) +: QDoubleSpinBox( parent ), + myCleared( false ) +{ + setMinimum( min ); + setMaximum( max ); + setSingleStep( step ); + + connect( lineEdit(), SIGNAL( textChanged( const QString& ) ), + this, SLOT( onTextChanged( const QString& ) ) ); +} + +/*! + \brief Destructor. +*/ +QtxDoubleSpinBox::~QtxDoubleSpinBox() +{ +} + +/*! + \brief Check if spin box is in the "cleared" state. + \return \c true if spin box is cleared +*/ +bool QtxDoubleSpinBox::isCleared() const +{ + return myCleared; +} + +/*! + \brief Change "cleared" status of the spin box. + \param on new "cleared" status +*/ +void QtxDoubleSpinBox::setCleared( const bool on ) +{ + if ( myCleared == on ) + return; + + myCleared = on; + setSpecialValueText( specialValueText() ); +} + +/*! + \brief Convert value to the text. + \param val value being converted + \return string containing the converted value +*/ +QString QtxDoubleSpinBox::textFromValue( double val ) const +{ + return myCleared ? QString() : QDoubleSpinBox::textFromValue( val ); +} + +/*! + \brief Perform \a steps increment/decrement steps. + + The \a steps value can be any integer number. If it is > 0, + the value incrementing is done, otherwise value is decremented + \a steps times. + + \param steps number of increment/decrement steps +*/ +void QtxDoubleSpinBox::stepBy( int steps ) +{ + myCleared = false; + + QDoubleSpinBox::stepBy( steps ); +} + +/*! + \brief Called when user enters the text in the spin box. + \param txt current spin box text (not used) +*/ +void QtxDoubleSpinBox::onTextChanged( const QString& /*txt*/ ) +{ + myCleared = false; +} diff --git a/src/Qtx/QtxDoubleSpinBox.h b/src/Qtx/QtxDoubleSpinBox.h new file mode 100644 index 000000000..45ef5434b --- /dev/null +++ b/src/Qtx/QtxDoubleSpinBox.h @@ -0,0 +1,53 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxDoubleSpinBox.h +// Author: Sergey TELKOV + +#ifndef QTXDOUBLESPINBOX_H +#define QTXDOUBLESPINBOX_H + +#include "Qtx.h" + +#include + +class QTX_EXPORT QtxDoubleSpinBox : public QDoubleSpinBox +{ + Q_OBJECT + +public: + QtxDoubleSpinBox( QWidget* = 0 ); + QtxDoubleSpinBox( double, double, double = 1, QWidget* = 0 ); + virtual ~QtxDoubleSpinBox(); + + bool isCleared() const; + virtual void setCleared( const bool ); + + virtual void stepBy( int ); + +private slots: + virtual void onTextChanged( const QString& ); + +protected: + virtual QString textFromValue( double ) const; + +private: + bool myCleared; +}; + +#endif diff --git a/src/Qtx/QtxEvalExpr.cxx b/src/Qtx/QtxEvalExpr.cxx new file mode 100644 index 000000000..75bcb7c43 --- /dev/null +++ b/src/Qtx/QtxEvalExpr.cxx @@ -0,0 +1,2435 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxEvalExpr.cxx +// Author: Alexander SOLOVYOV, Sergey TELKOV + +#include "QtxEvalExpr.h" + +#include + +#include + +/*! + \class QtxEvalExpr + \brief String expression evaluator. +*/ + +/*! + \brief Constructor. + + The evaluator is initalized by standard operations. Use another constructor with parameter + \a stdSets = \c false to avoid initialization of evaluator with standard operations. + + \param expr expression to be evaluated +*/ +QtxEvalExpr::QtxEvalExpr( const QString& expr ) +{ + intialize( true, expr ); +} + +/*! + \brief Constructor. + \param stdSets if \c true, the evaluator is initalized by standard operations + \param expr expression to be evaluated +*/ +QtxEvalExpr::QtxEvalExpr( const bool stdSets, const QString& expr ) +{ + intialize( stdSets, expr ); +} + +/*! + \brief Destructor. +*/ +QtxEvalExpr::~QtxEvalExpr() +{ + delete myParser; +} + +/*! + \brief Initialize the evaluator. + \param stdSets if \c true, the evaluator is initalized by standard operations + \param expr expression to be evaluated +*/ +void QtxEvalExpr::intialize( const bool stdSets, const QString& expr ) +{ + myParser = new QtxEvalParser(); + if ( stdSets ) + { + myParser->setAutoDeleteOperationSets( true ); + myParser->insertOperationSet( new QtxEvalSetArithmetic() ); + myParser->insertOperationSet( new QtxEvalSetLogic() ); + myParser->insertOperationSet( new QtxEvalSetString() ); + myParser->insertOperationSet( new QtxEvalSetMath() ); + myParser->insertOperationSet( new QtxEvalSetSets() ); + myParser->insertOperationSet( new QtxEvalSetConst() ); + } + setExpression( expr ); +} + +/*! + \brief Evaluate the expression. + \param expr expression to be evaluated + \return result of the evaluation +*/ +QVariant QtxEvalExpr::calculate( const QString& expr ) +{ + if ( !expr.isEmpty() ) + setExpression( expr ); + return myParser->calculate(); +} + +/*! + \brief Get the expression. + \return expression string +*/ +QString QtxEvalExpr::expression() const +{ + return myExpr; +} + +/*! + \brief Set the expression. + \param expr expression string +*/ +void QtxEvalExpr::setExpression( const QString& expr ) +{ + if ( expr == expression() ) + return; + + myExpr = expr; + myParser->setExpression( myExpr ); +} + +/*! + \brief Get the code of latest parsing error. + \return the code of the last error +*/ +QtxEvalExpr::Error QtxEvalExpr::error() const +{ + return myParser->error(); +} + +/*! + \brief Get the expression parser. + \return expression parser +*/ +QtxEvalParser* QtxEvalExpr::parser() const +{ + return myParser; +} + +/*! + \brief Get current set of operations. + \return operations set + \sa insertOperationSet(), removeOperationSet(), operationSet() +*/ +QList QtxEvalExpr::operationSets() const +{ + return myParser->operationSets(); +} + +/*! + \brief Install the operation. + \param operation to be added + \param idx index in the list at which the operation shoud be inserted + \sa operationSets(), removeOperationSet(), operationSet() +*/ +void QtxEvalExpr::insertOperationSet( QtxEvalSet* set, const int idx ) +{ + myParser->insertOperationSet( set, idx ); +} + +/*! + \brief Remove the operation. + \param operation to be removed + \sa operationSets(), insertOperationSet(), operationSet() +*/ +void QtxEvalExpr::removeOperationSet( QtxEvalSet* set ) +{ + myParser->removeOperationSet( set ); +} + +/*! + \brief Get the operation by name. + \param name operation name + \return operation of 0 if not found + \sa operationSets(), insertOperationSet(), removeOperationSet() +*/ +QtxEvalSet* QtxEvalExpr::operationSet( const QString& name ) const +{ + return myParser->operationSet( name ); +} + +/*! + \brief Get the 'auto-delete operations' flag value. + \return \c true if all operations shoud be automatically deleted when the evaluator is destroyed + \sa setAutoDeleteOperationSets() +*/ +bool QtxEvalExpr::autoDeleteOperationSets() const +{ + return myParser->autoDeleteOperationSets(); +} + +/*! + \brief Set the 'auto-delete operations' flag value. + \param on if \c true, all operations shoud be automatically deleted when the evaluator is destroyed + \sa autoDeleteOperationSets() +*/ +void QtxEvalExpr::setAutoDeleteOperationSets( const bool on ) +{ + myParser->setAutoDeleteOperationSets( on ); +} + +/*! + \class QtxEvalParser + \brief Expression parser. + + This class provides the functionality to calculate value of the expression using defined set of operations. + Standard operations (arithmetics, logic, strings, etc) are implemented in the corresponding successors of the + QtxEvalSet class: QtxEvalSetArithmetic, QtxEvalSetLogic, QtxEvalSetMath, QtxEvalSetString, ... + + The parser allows using parameters with help of methods has(), set(), remove(), value(). It uses + postfix representation of expressions and uses class QtxEvalSet in order to make certain operation. + + Every instance of parser contains only one postfix - thus, if the expression is changed, the postfix + must be rebuilt. In order to increase performance of frequent calculations for many of expressions it is + recommended to use different instances of the parser for each expression. +*/ + +/*! + \brief Constructor. +*/ +QtxEvalParser::QtxEvalParser() +: myAutoDel( false ) +{ + setError( QtxEvalExpr::OK ); +} + +/*! + \brief Destructor. +*/ +QtxEvalParser::~QtxEvalParser() +{ + if ( autoDeleteOperationSets() ) + qDeleteAll( mySets ); +} + +/*! + \brief Get current operations set. + \return current operations set +*/ +QList QtxEvalParser::operationSets() const +{ + return mySets; +} + +/*! + \brief Get the operations set by \a name. + \param name the name of the operation set + \return operation set or 0 if not found +*/ +QtxEvalSet* QtxEvalParser::operationSet( const QString& name ) const +{ + QtxEvalSet* set = 0; + for ( SetList::const_iterator it = mySets.begin(); it != mySets.end() && !set; ++it ) + { + if ( (*it)->name() == name ) + set = *it; + } + return set; +} + +/*! + \brief Install the operations set. + \param operations set to be added + \param idx index in the list at which the operations set shoud be inserted + \sa operationSets(), removeOperationSet(), operationSet() +*/ +void QtxEvalParser::insertOperationSet( QtxEvalSet* set, const int idx ) +{ + if ( mySets.contains( set ) ) + return; + + int index = idx < 0 ? mySets.count() - 1 : idx; + index = qMin( index, mySets.count() - 1 ); + mySets.insert( index, set ); +} + +/*! + \brief Remove the operations set. + \param operations set to be removed + \sa operationSets(), insertOperationSet(), operationSet() +*/ +void QtxEvalParser::removeOperationSet( QtxEvalSet* set ) +{ + mySets.removeAll( set ); +} + +/*! + \brief Get the 'auto-delete operations' flag value. + \return \c true if all operations shoud be automatically deleted when the parser is destroyed + \sa setAutoDeleteOperationSets() +*/ +bool QtxEvalParser::autoDeleteOperationSets() const +{ + return myAutoDel; +} + +/*! + \brief Set the 'auto-delete operations' flag value. + \param on if \c true, all operations shoud be automatically deleted when the parser is destroyed + \sa autoDeleteOperationSets() +*/ +void QtxEvalParser::setAutoDeleteOperationSets( const bool on ) +{ + myAutoDel = on; +} + +/*! + \brief Search elements of the list as substrings starting from \a offset. + \param list list of substrings + \param str string in which the searching is performed + \param offset starting index for search + \param matchLen returning matching length of any substring + \param listind returning index of the found substring in the \a list + \return position of first found substring inside the \a str or -1 if no matches is found +*/ +int QtxEvalParser::search( const QStringList& list, const QString& str, + int offset, int& matchLen, int& listind ) +{ + int min = -1; + QStringList::const_iterator anIt = list.begin(), aLast = list.end(); + for ( int ind = 0; anIt != aLast; anIt++, ind++ ) + { + int pos = str.indexOf( *anIt, offset ); + if ( pos >= 0 && ( min < 0 || min > pos || + ( min == pos && matchLen < (int)(*anIt).length() ) ) ) + { + min = pos; + listind = ind; + matchLen = (*anIt).length(); + } + } + if ( min < 0 ) + matchLen = 0; + return min; +} + +/*! + \brief Get the substring field from the string \a str. + \param str source string + \param pos start position of the substring + \param len length of the substring + \return substring (leading and trailing spaces are truncated) +*/ +QString QtxEvalParser::note( const QString& str, int pos, int len ) +{ + return str.mid( pos, len ).trimmed(); +} + +/*! + \brief Prepare to the parsing. + + Performs the first step of the parsing: + - find tokens + - determine tokens types + - create unsorted pseudo-postfix (with brackets) + + \param expr string expression + \param post postfix to be created + \return \c true on success and \c false if error is found +*/ +bool QtxEvalParser::prepare( const QString& expr, Postfix& post ) +{ + int pos = 0; + int len = expr.length(); + QStack aBracketStack; + QStringList anOpers, anOpenBr, aCloseBr; + if ( !checkOperations() ) + return false; + + bracketsList( anOpenBr, true ); + bracketsList( aCloseBr, false ); + operationList( anOpers ); + + while ( pos < len && error() == QtxEvalExpr::OK ) + { + PostfixItem item; + while ( expr[pos].isSpace() && pos < len ) + pos++; + if ( pos >= len ) + break; + + int mBrLen = 0, mLen = 0, br_ind = -1, op_ind = -1; + int oPos = search( anOpenBr, expr, pos, mBrLen, br_ind ); + int cPos = oPos == pos ? -1 : search( aCloseBr, expr, pos, mBrLen, br_ind ); + int opPos = search( anOpers, expr, pos, mLen, op_ind ); + + if ( expr[pos] == QChar( '\'' ) ) + { + int vpos = pos + 1; + while ( vpos < (int)expr.length() && expr[vpos] != QChar( '\'' ) ) + vpos++; + + mLen = vpos - pos + 1; + + int res = createValue( note( expr, pos, mLen ), item.myValue ); + item.myType = res ? Value : Param; + post.append( item ); + pos = vpos + 1; + continue; + } + + if ( oPos == pos ) + { + aBracketStack.push( br_ind ); + item.myValue = note( expr, pos, mBrLen ); + item.myType = Open; + post.append( item ); + } + else if ( cPos == pos ) + { + if ( aBracketStack.count() == 0 ) + { + setError( QtxEvalExpr::ExcessClose ); + break; + } + if ( br_ind != aBracketStack.top() ) + { + setError( QtxEvalExpr::BracketsNotMatch ); + break; + } + else + { + aBracketStack.pop(); + item.myValue = note( expr, pos, mBrLen ); + item.myType = Close; + post.append( item ); + } + } + else + mBrLen = 0; + + if ( opPos == pos ) + { + mBrLen = 0; + item.myValue = note( expr, pos, mLen ); + item.myType = Binary; + + if ( oPos == pos ) + post.insert( post.count() - 1, item ); + else + post.append( item ); + } + else + { + mLen = 0; + if ( oPos != pos && cPos != pos ) + { + int i; + for ( i = pos + 1; i < (int)expr.length(); i++ ) + { + if ( expr[i].isSpace() ) + break; + } + + int vpos = i; + if ( oPos >= 0 && oPos < vpos ) + vpos = oPos; + if ( cPos >= 0 && cPos < vpos ) + vpos = cPos; + if ( opPos >= 0 && opPos < vpos ) + vpos = opPos; + + while( vpos < (int)expr.length() && + ( expr[vpos].isLetter() || expr[vpos].isDigit() || expr[vpos]=='_' ) ) + vpos++; + + mLen = vpos - pos; + bool res = createValue( note( expr, pos, mLen ), item.myValue ); + item.myType = res ? Value : Param; + post.append( item ); + } + } + + pos += mBrLen + mLen; + } + + //Bracket checking + int brValue = 0; + for ( Postfix::iterator anIt = post.begin(); anIt != post.end(); ++anIt ) + { + if ( (*anIt).myType == Open ) + brValue++; + else if ( (*anIt).myType == Close ) + { + if ( brValue > 0 ) + brValue--; + else + { + setError( QtxEvalExpr::ExcessClose ); + break; + } + } + } + + if ( brValue > 0 ) + setError( QtxEvalExpr::CloseExpected ); + + return error() == QtxEvalExpr::OK; +} + +/*! + \brief Analyze the operations used. + + Second step of the parsing: analyze the types of the operations used in the expression. + + \param post unsorted postfix + \return \c true on success and \c false if error is found +*/ +bool QtxEvalParser::setOperationTypes( Postfix& post ) +{ + if ( !checkOperations() ) + return false; + + QStringList anOpen, aClose; + bracketsList( anOpen, true ); + bracketsList( aClose, false ); + + Postfix::iterator aPrev, aNext; + for ( Postfix::iterator anIt = post.begin(); anIt != post.end(); ++anIt ) + { + aPrev = anIt; + aPrev--; + aNext = anIt; + aNext++; + if ( (*anIt).myType != Binary ) + continue; + + if ( ( anIt == post.begin() || (*aPrev).myType == Open || + (*aPrev).myType == Pre || (*aPrev).myType == Binary ) && aNext != post.end() && + ( (*aNext).myType == Value || (*aNext).myType == Param || + (*aNext).myType == Open || (*aNext).myType == Binary ) ) + (*anIt).myType = Pre; + else if ( anIt != post.begin() && ( (*aPrev).myType == Close || (*aPrev).myType == Param || + (*aPrev).myType == Value || (*aPrev).myType == Pre || + (*aPrev).myType == Post || (*aPrev).myType == Binary ) && + ( aNext == post.end() || (*aNext).myType == Close ) ) + (*anIt).myType = Post; + + if ( anOpen.contains( (*anIt).myValue.toString() ) ) + (*anIt).myType = Pre; + else if ( aClose.contains( (*anIt).myValue.toString() ) ) + (*anIt).myType = Post; + } + + return error() == QtxEvalExpr::OK; +} + +/*! + \brief Get the number of the globar brackets pairs. + + For example, the expression '((2+3))' has 2 global brackets pairs. + + \param post postfix to be checked + \param f starting position for the search + \param l last position for the search + \return number of brackets pairs +*/ +int QtxEvalParser::globalBrackets( const QtxEvalParser::Postfix& post, int f, int l ) +{ + int i; + int start_br = 0; + int fin_br = 0; + int br = 0; + int br_num = 0; + int min_br_num = (l-f+1)*5; + + for( i=f; i<=l; i++ ) + if( post[ i ].myType==QtxEvalParser::Open ) + start_br++; + else + break; + for( i=l; i>=f; i-- ) + if( post[ i ].myType==QtxEvalParser::Close ) + fin_br++; + else + break; + + br = start_br= 0 ) + res.append( post[f] ); + + if ( l <= f ) + return true; + + if ( !checkOperations() ) + return false; + + int min = -1; + QIntList argmin; + QList min_types; + + for ( int i = 0, j = f; j <= l; i++, j++ ) + { + const PostfixItem& item = post[j]; + PostfixItemType tt = item.myType; + if ( tt == Binary || tt == Pre || tt == Post ) + { + int cur_pr = priority( item.myValue.toString(), tt == Binary ); + if ( cur_pr > 0 ) + { + if ( min < 0 || min >= cur_pr ) + { + if ( min == cur_pr ) + { + argmin.append( f + i ); + min_types.append( tt ); + } + else + { + min = cur_pr; + argmin.clear(); + argmin.append( f + i ); + min_types.clear(); min_types.append( tt ); + } + } + } + else + { + setError( QtxEvalExpr::InvalidOperation ); + break; + } + } + else if ( tt == Open ) + { + QString opBr = item.myValue.toString(); + int ind = anOpen.indexOf( opBr ), brValue = 0; + while ( j <= l ) + { + const PostfixItem& anItem = post[j]; + if ( anItem.myType == Open ) + brValue++; + + if ( anItem.myType == Close ) + { + brValue--; + QString clBr = anItem.myValue.toString(); + if ( aClose.indexOf( clBr ) == ind && brValue == 0 ) + break; + } + i++; j++; + } + + if ( brValue > 0 ) + { + setError( QtxEvalExpr::CloseExpected ); + break; + } + } + } + + if ( error() == QtxEvalExpr::OK ) + { + if ( min >= 0 ) + { + Postfix one; + QList parts; + QIntList::const_iterator anIt = argmin.begin(), aLast = argmin.end(); + bool ok = sort( post, one, anOpen, aClose, f, *anIt - 1 ); + parts.append( one ); + one.clear(); + for ( ; anIt != aLast && ok; anIt++ ) + { + QIntList::const_iterator aNext = anIt; aNext++; + ok = sort( post, one, anOpen, aClose, *anIt + 1, aNext == aLast ? l : *aNext - 1 ); + parts.append( one ); + one.clear(); + } + + if ( !ok ) + return false; + + QStack aStack; + QList::const_iterator aPIt = parts.begin(); + QList::const_iterator aTIt = min_types.begin(); + res += (*aPIt); + aPIt++; + anIt = argmin.begin(); + for ( ; anIt != aLast; anIt++, aPIt++, aTIt++ ) + { + if ( *aTIt == Pre ) + { + if ( anOpen.contains( post[*anIt].myValue.toString() ) == 0 ) + { + res += (*aPIt); + aStack.push( post[ *anIt ] ); + } + else + { + res.append( post[*anIt] ); + res += *aPIt; + } + } + else + { + res += *aPIt; + while ( !aStack.isEmpty() ) + { + res.append( aStack.top() ); + aStack.pop(); + } + res.append( post[*anIt] ); + } + } + while ( !aStack.isEmpty() ) + { + res.append( aStack.top() ); + aStack.pop(); + } + } + else + { //there are no operations + for ( int k = f; k <= l; k++ ) + { + if ( post.at( k ).myType==Value || post.at( k ).myType == Param ) + res.append( post.at( k ) ); + } + } + } + + return error() == QtxEvalExpr::OK; +} + +/*! + \brief Parse the expression and build the posfix. + + If by parsing error is found, the function returns \c false. In this case the code of the error + can be retrieved with error() method. + + \param expr string expression + \return \c true on success and \c false if error is found +*/ +bool QtxEvalParser::parse( const QString& expr ) +{ + myPostfix.clear(); + + if ( !checkOperations() ) + return false; + + Postfix p; + QStringList opens, closes; + + setError( QtxEvalExpr::OK ); + bracketsList( opens, true ); + bracketsList( closes, false ); + + return prepare( expr, p ) && setOperationTypes( p ) && sort( p, myPostfix, opens, closes ); +} + +/*! + \brief Calculate the operation. + + The result of the operation is returned in the parameter \a v1. + + \param op operation name + \param v1 first argument (not valid for unary prefix operations) + \param v2 second argument (not valid for unary postfix operations) + \return \c true on success and \c false if error is found +*/ +bool QtxEvalParser::calculate( const QString& op, QVariant& v1, QVariant& v2 ) +{ + QtxEvalExpr::Error err = isValid( op, v1.type(), v2.type() ); + if ( err == QtxEvalExpr::OK ) + setError( calculation( op, v1, v2 ) ); + else + setError( err ); + + return error() == QtxEvalExpr::OK; +} + +/*! + \brief Calculate the expression without postfix rebuilding. + \return QVariant as result (it is invalid if there were errors during calculation) +*/ +QVariant QtxEvalParser::calculate() +{ + if ( !checkOperations() ) + return QVariant(); + + setError( QtxEvalExpr::OK ); + + QStringList anOpen, aClose; + bracketsList( anOpen, true ); + bracketsList( aClose, false ); + + QStack aStack; + Postfix::iterator anIt = myPostfix.begin(), aLast = myPostfix.end(); + for ( ; anIt != aLast && error() == QtxEvalExpr::OK; anIt++ ) + { + QString nn = (*anIt).myValue.toString(); + if ( (*anIt).myType == Param ) + { + if ( hasParameter( nn ) ) + { + QVariant& v = myParams[nn]; + if ( v.isValid() ) + aStack.push( v ); + else + setError( QtxEvalExpr::InvalidToken ); + } + else + setError( QtxEvalExpr::InvalidToken ); + } + else if ( (*anIt).myType == Value ) + aStack.push( (*anIt).myValue ); + else if ( (*anIt).myType == Pre || (*anIt).myType == Post ) + { + if ( anOpen.contains( nn ) ) + { + QVariant inv; + if ( calculate( nn, inv, inv ) ) + aStack.push( QVariant() ); + } + else if ( aClose.contains( nn ) ) + { + QList set; + while ( true ) + { + if ( aStack.isEmpty() ) + { + setError( QtxEvalExpr::StackUnderflow ); + break; + } + if ( aStack.top().isValid() ) + { + set.append( aStack.top() ); + aStack.pop(); + } + else + { + aStack.pop(); + break; + } + } + + QVariant qSet = set, inv; + if ( calculate( nn, qSet, inv ) ) + aStack.push( set ); + } + else if ( aStack.count() >= 1 ) + { + QVariant inv; + QVariant* v1 = &aStack.top(), *v2 = &inv; //"post-" case + if ( (*anIt).myType == Pre ) + { + v2 = &aStack.top(); + v1 = &inv; + } + calculate( nn, *v1, *v2 ); + } + else + setError( QtxEvalExpr::StackUnderflow ); + } + else if ( (*anIt).myType == Binary ) + { + if ( aStack.count() >= 2 ) + { + QVariant v2 = aStack.top(); + aStack.pop(); + calculate( nn, aStack.top(), v2 ); + } + else + setError( QtxEvalExpr::StackUnderflow ); + } + } + + QVariant res; + if ( error() == QtxEvalExpr::OK ) + { + int count = aStack.count(); + if ( count == 0 ) + setError( QtxEvalExpr::StackUnderflow ); + else if( count == 1 ) + res = aStack.top(); + else + setError( QtxEvalExpr::ExcessData ); + } + return res; +} + +/*! + \brief Change the expression, rebuild the postfix and calculate it. + \param expr new expression + \return QVariant as result (it is invalid if there were errors during calculation) +*/ +QVariant QtxEvalParser::calculate( const QString& expr ) +{ + setExpression( expr ); + return calculate(); +} + +/*! + \brief Change the expression and rebuild the postfix. + \param expr new expression + \return \c true on success and \c false if error is found +*/ +bool QtxEvalParser::setExpression( const QString& expr ) +{ + return parse( expr ); +} + +/*! + \brief Check if the parser contains specified parameter. + \param name parameter name + \return \c true, if the parser contains parameter +*/ +bool QtxEvalParser::hasParameter( const QString& name ) const +{ + return myParams.contains( name.trimmed() ); +} + +/*! + \brief Set parameters value. + \param name parameter name + \param value parameter value +*/ +void QtxEvalParser::setParameter( const QString& name, const QVariant& value ) +{ + myParams.insert( name.trimmed(), value ); +} + +/*! + \brief Remove parameter. + \param name parameter name + \return \c true on success +*/ +bool QtxEvalParser::removeParameter( const QString& name ) +{ + return myParams.remove( name.trimmed() ); +} + +/*! + \brief Get the parameter value. + \param name parameter name + \return parameter value or invalud QVariant if there is no such parameter +*/ +QVariant QtxEvalParser::parameter( const QString& name ) const +{ + QVariant res; + if ( myParams.contains( name.trimmed() ) ) + res = myParams[name.trimmed()].toString(); + return res; +} + +/*! + \brief Search first parameter with assigned invalid value. + \param name used to retrieve the name of the parameter if it is found + \return \c true if parameter is found +*/ +bool QtxEvalParser::firstInvalid( QString& name ) const +{ + for ( ParamMap::const_iterator anIt = myParams.begin(); anIt != myParams.end(); anIt++ ) + { + if ( !anIt.value().isValid() ) + { + name = anIt.key(); + return true; + } + } + return false; +} + +/*! + \brief Remove all parameters with assigned invalid values. +*/ +void QtxEvalParser::removeInvalids() +{ + QStringList toDelete; + for ( ParamMap::const_iterator anIt = myParams.begin(); anIt != myParams.end(); anIt++ ) + { + if ( !anIt.value().isValid() ) + toDelete.append( anIt.key() ); + } + + for ( QStringList::const_iterator aLIt = toDelete.begin(); aLIt != toDelete.end(); aLIt++ ) + myParams.remove( *aLIt ); +} + +/*! + \brief Get the code of the latest parsing error. + \return last error code +*/ +QtxEvalExpr::Error QtxEvalParser::error() const +{ + return myError; +} + +/*! + \brief Set the error vode. + \internal + \param err error code +*/ +void QtxEvalParser::setError( QtxEvalExpr::Error err ) +{ + myError = err; +} + +/*! + \brief Dump the current postfix contents to the string. + \return string representation of the internal parser postfix +*/ +QString QtxEvalParser::dump() const +{ + return dump( myPostfix ); +} + +/*! + \brief Dump the postfix contents to the string. + \param post postfix to be dumped + \return string representation of the postfix +*/ +QString QtxEvalParser::dump( const Postfix& post ) const +{ + QString res; + + if ( !checkOperations() ) + return res; + + for ( Postfix::const_iterator anIt = post.begin(); anIt != post.end(); anIt++ ) + { + if ( (*anIt).myType == Value && (*anIt).myValue.type() == QVariant::String ) + res += "'" + (*anIt).myValue.toString() + "'"; + else + res += (*anIt).myValue.toString(); + + if ( (*anIt).myType == Pre ) + res += "(pre)"; + else if ( (*anIt).myType == Post ) + res += "(post)"; + else if ( (*anIt).myType == Binary ) + res += "(bin)"; + + res += "_"; + } + + return res; +} + +/*! + \brief Get the list of the parameters names. + \return parameters names +*/ +QStringList QtxEvalParser::parameters() const +{ + QStringList lst; + for ( Postfix::const_iterator anIt = myPostfix.begin(); anIt != myPostfix.end(); anIt++ ) + { + if ( (*anIt).myType == Param ) + { + QString name = (*anIt).myValue.toString(); + if ( !lst.contains( name ) ) + lst.append( name ); + } + } + return lst; +} + +/*! + \brief Remove all parameters. +*/ +void QtxEvalParser::clearParameters() +{ + myParams.clear(); +} + +/*! + \brief Get the string representation for the list of QVariant values. + \param list list to be converted + \return string representation for the list +*/ +QString QtxEvalParser::toString( const QList& list ) +{ + QString res = "set : [ "; + for ( QList::const_iterator anIt = list.begin(); anIt != list.end(); anIt++ ) + res += (*anIt).toString() + " "; + res += "]"; + return res; +} + +/*! + \brief Get names of all operations used in the expression. + \param list returning list of the operations names +*/ +void QtxEvalParser::operationList( QStringList& list ) const +{ + for ( SetList::const_iterator it = mySets.begin(); it != mySets.end(); ++it ) + { + QStringList custom; + QtxEvalSet* set = *it; + set->operationList( custom ); + for ( QStringList::const_iterator sIt = custom.begin(); sIt != custom.end(); ++sIt ) + { + if ( !list.contains( *sIt ) ) + list.append( *sIt ); + } + } +} + +/*! + \brief Get list of brackets. + \param list returning list of brackets + \param open if \c true, collect opening brackets, or closing brackets otherwise +*/ +void QtxEvalParser::bracketsList( QStringList& list, bool open ) const +{ + for ( SetList::const_iterator it = mySets.begin(); it != mySets.end(); ++it ) + { + QStringList custom; + QtxEvalSet* set = *it; + set->bracketsList( custom, open ); + for ( QStringList::const_iterator sIt = custom.begin(); sIt != custom.end(); ++sIt ) + { + if ( !list.contains( *sIt ) ) + list.append( *sIt ); + } + } +} + +/*! + \brief Create value. + \param str parsed string + \param val returning value + \return \c true on success +*/ +bool QtxEvalParser::createValue( const QString& str, QVariant& val ) const +{ + bool ok = false; + for ( SetList::const_iterator it = mySets.begin(); it != mySets.end() && !ok; ++it ) + ok = (*it)->createValue( str, val ); + return ok; +} + +/*! + \brief Get the operation priority level. + \param op operation + \param isBin \c true if the operation is binary and \c false if it is unary + \return operation priority +*/ +int QtxEvalParser::priority( const QString& op, bool isBin ) const +{ + int i = 0; + int priority = 0; + for ( SetList::const_iterator it = mySets.begin(); it != mySets.end() && priority <= 0; ++it, i++ ) + priority = (*it)->priority( op, isBin ); + + return priority > 0 ? priority + i * 10 : 0; +} + +/*! + \brief Check operation validity. + + If the operation is valid, QtxEvalExpr::OK is returned. + + \param op operation + \param t1 first operand type + \param t2 second operand type + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalParser::isValid( const QString& op, + const QVariant::Type t1, const QVariant::Type t2 ) const +{ + QtxEvalExpr::Error err = QtxEvalExpr::OK; + for ( SetList::const_iterator it = mySets.begin(); it != mySets.end(); ++it ) + { + err = (*it)->isValid( op, t1, t2 ); + if ( err == QtxEvalExpr::OK ) + break; + } + return err; +} + +/*! + \brief Perform calculation + + The result of the operation is returned in the parameter \a v1. + If the operation is calculated correctly, the function returns QtxEvalExpr::OK. + + \param op operation name + \param v1 first argument (not valid for unary prefix operations) + \param v2 second argument (not valid for unary postfix operations) + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalParser::calculation( const QString& op, QVariant& v1, QVariant& v2 ) const +{ + QVariant nv1, nv2; + for ( SetList::const_iterator it = mySets.begin(); it != mySets.end(); ++it ) + { + nv1 = v1; + nv2 = v2; + if ( (*it)->isValid( op, v1.type(), v2.type() ) == QtxEvalExpr::OK ) + { + QtxEvalExpr::Error err = (*it)->calculate( op, nv1, nv2 ); + if ( err == QtxEvalExpr::OK || err == QtxEvalExpr::InvalidResult ) + { + v1 = nv1; + v2 = nv2; + return err; + } + } + } + return QtxEvalExpr::InvalidOperation; +} + +/*! + \brief Check current operations set. + \return \c false if current set of operations is empty +*/ +bool QtxEvalParser::checkOperations() const +{ + if ( !mySets.isEmpty() ) + return true; + + QtxEvalParser* that = (QtxEvalParser*)this; + that->setError( QtxEvalExpr::OperationsNull ); + return false; +} + +/*! + \class QtxEvalSet + \brief Generic class for all the operations sets used in expressions. +*/ + +/*! + \brief Constructor. +*/ +QtxEvalSet::QtxEvalSet() +{ +} + +/*! + \brief Destructor. +*/ +QtxEvalSet::~QtxEvalSet() +{ +} + +/*! + \fn void QtxEvalSet::operationList( QStringList& list ) const; + \brief Get the list of possible operations. + \param list returning list of operations supported by the class +*/ + +/*! + \fn void QtxEvalSet::bracketsList( QStringList& list, bool open ) const; + \brief Get list of brackets. + \param list returning list of brackets + \param open if \c true, collect opening brackets, or closing brackets otherwise +*/ + +/*! + \brief Create value from its string representation. + + By default, the string value is set, that corresponds to the parameter. + Base implementation always returns \c false (it means that string + is evaluated to the parameter). + Successor class can re-implement this method to return \c true + if the argument being parsed can be evaluated as custom value. + + \param str string representration of the value + \param val returning value + \return \c true if \a str can be evaluated as custom value and \c false + otherwise (parameter) +*/ +bool QtxEvalSet::createValue( const QString& str, QVariant& val ) const +{ + val = str; + return false; +} + +/*! + \fn int QtxEvalSet::priority( const QString& op, bool isBin ) const; + \brief Get the operation priority. + + Operation priority counts from 1. + If the operation is impossible, this function should return value <= 0. + + \param op operation + \param isBin \c true if the operation is binary and \c false if it is unary + \return operation priority +*/ + +/*! + \fn QtxEvalExpr::Error QtxEvalSet::isValid( const QString& op, const QVariant::Type t1, + const QVariant::Type t2 ) const; + \brief Check operation validity. + + If the operation is valid, QtxEvalExpr::OK is returned. + If types of operands are invalid, the function returns QtxEvalExpr::OperandsNotMatch + or QtxEvalExpr::InvalidOperation. + + \param op operation + \param t1 first operand type + \param t2 second operand type + \return error code (QtxEvalExpr::Error) +*/ + +/*! + \fn QtxEvalExpr::Error QtxEvalSet::calculate( const QString& op, QVariant& v1, + QVariant& v2 ) const; + \brief Calculate the operation. + + Process binary operation with values \a v1 and \a v2. + For unary operation the \v2 is invalid. + The result of the operation is returned in the parameter \a v1. + + \param op operation name + \param v1 first argument (not valid for unary prefix operations) + \param v2 second argument (not valid for unary postfix operations) + \return error code (QtxEvalExpr::Error) +*/ + +/*! + \fn QString QtxEvalSet::name() const; + \brief Get unique operations set name. + + Should be redefined in the successor classes. + + \return operations set name +*/ + +/*! + \class QtxEvalSetBase + \brief Generic class. Provides functionality for standard operations sets. +*/ + +/*! + \brief Constructor. +*/ +QtxEvalSetBase::QtxEvalSetBase() +{ +} + +/*! + \brief Destructor. +*/ +QtxEvalSetBase::~QtxEvalSetBase() +{ +} + +/*! + \brief Get list of brackets. + \param list returning list of brackets + \param open if \c true, collect opening brackets, or closing brackets otherwise +*/ +void QtxEvalSetBase::bracketsList( QStringList& list, bool open ) const +{ + list.append( open ? "(" : ")" ); +} + +/*! + \brief Get the list of possible operations. + \param list returning list of operations supported by the class +*/ +void QtxEvalSetBase::operationList( QStringList& list ) const +{ + list += myOpers; +} + +/*! + \brief Add operation names to the internal list of operations. + \param list operations to be added +*/ +void QtxEvalSetBase::addOperations( const QStringList& list ) +{ + for ( QStringList::const_iterator anIt = list.begin(); anIt != list.end(); ++anIt ) + { + if ( !myOpers.contains( *anIt ) ) + myOpers.append( *anIt ); + } +} + +/*! + \brief Add operand types. + \param list operand types to be added +*/ +void QtxEvalSetBase::addTypes( const ListOfTypes& list ) +{ + for ( ListOfTypes::const_iterator anIt = list.begin(); anIt != list.end(); ++anIt ) + { + if ( !myTypes.contains( *anIt ) ) + myTypes.append( *anIt ); + } +} + +/*! + \brief Check operation validity. + + If the operation is valid, QtxEvalExpr::OK is returned. + If types of operands are invalid, the function returns QtxEvalExpr::OperandsNotMatch + or QtxEvalExpr::InvalidOperation. + + \param op operation + \param t1 first operand type + \param t2 second operand type + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalSetBase::isValid( const QString& op, + const QVariant::Type t1, const QVariant::Type t2 ) const +{ + if ( ( t1 == QVariant::Invalid || myTypes.contains( t1 ) ) && + ( t2 == QVariant::Invalid || myTypes.contains( t2 ) ) && + ( t1 != QVariant::Invalid || t2 != QVariant::Invalid ) ) + { + if ( priority( op, t1 != QVariant::Invalid && t2 != QVariant::Invalid ) > 0 ) + return QtxEvalExpr::OK; + else + return QtxEvalExpr::InvalidOperation; + } + else + return QtxEvalExpr::OperandsNotMatch; +} + +/*! + \class QtxEvalSetArithmetic + \brief Provides set of arithmetical operations for the parser. +*/ + +/*! + \brief Constructor. +*/ +QtxEvalSetArithmetic::QtxEvalSetArithmetic() +: QtxEvalSetBase() +{ + addOperations( QString( "+;-;*;/;=;<;>;<=;>=;<>;!=" ).split( ";" ) ); + + ListOfTypes aTypes; + aTypes.append( QVariant::Int ); + aTypes.append( QVariant::UInt ); + aTypes.append( QVariant::Double ); + addTypes( aTypes ); +} + +/*! + \brief Destructor. +*/ +QtxEvalSetArithmetic::~QtxEvalSetArithmetic() +{ +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetArithmetic::Name() +{ + return "Arithmetic"; +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetArithmetic::name() const +{ + return Name(); +} + +/*! + \brief Create value from its string representation. + + Creates numbers from string representation. + + \param str string representration of the value + \param val returning value + \return \c true if \a str can be evaluated as custom value and \c false + otherwise (parameter) +*/ +bool QtxEvalSetArithmetic::createValue( const QString& str, QVariant& val ) const +{ + bool ok = false; + val = str.toInt( &ok ); + + if ( !ok ) + { + val = str.toDouble( &ok ); + if ( !ok ) + ok = QtxEvalSetBase::createValue( str, val ); + } + return ok; +} + +/*! + \brief Get the operation priority. + + Operation priority counts from 1. + If the operation is impossible, this function returns value <= 0. + + \param op operation + \param isBin \c true if the operation is binary and \c false if it is unary + \return operation priority +*/ +int QtxEvalSetArithmetic::priority( const QString& op, bool isBin ) const +{ + if ( isBin ) + { + if ( op == "<" || op == ">" || op == "=" || + op == "<=" || op == ">=" || op == "<>" || op == "!=" ) + return 1; + else if ( op == "+" || op == "-" ) + return 2; + else if( op == "*" || op == "/" ) + return 3; + else + return 0; + } + else if ( op == "+" || op == "-" ) + return 5; + else + return 0; +} + +/*! + \brief Calculate the operation. + + Process binary operation with values \a v1 and \a v2. + For unary operation the \v2 is invalid. + The result of the operation is returned in the parameter \a v1. + + \param op operation name + \param v1 first argument (not valid for unary prefix operations) + \param v2 second argument (not valid for unary postfix operations) + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalSetArithmetic::calculate( const QString& op, QVariant& v1, QVariant& v2 ) const +{ + QtxEvalExpr::Error err = QtxEvalExpr::OK; + + if ( v1.isValid() && v2.isValid() ) + { + // binary operations + if ( ( v1.type() == QVariant::Int || v1.type() == QVariant::UInt ) && + ( v2.type() == QVariant::Int || v2.type() == QVariant::UInt ) ) + { + int _v1 = v1.toInt(); + int _v2 = v2.toInt(); + + if ( op == "+" ) + v1 = _v1 + _v2; + else if ( op == "-" ) + v1 = _v1 - _v2; + else if ( op == "*" ) + v1 = _v1 * _v2; + else if ( op == "/" ) + { + if ( _v2 != 0 ) + { + if ( _v1 % _v2 == 0 ) + v1 = _v1 / _v2; + else + v1 = double( _v1 ) / double( _v2 ); + } + else + err = QtxEvalExpr::InvalidResult; + } + else if ( op == "<" ) + v1 = _v1 < _v2; + else if ( op == ">" ) + v1 = _v1 > _v2; + else if ( op == "=" ) + v1 = _v1 == _v2; + else if ( op == "<=" ) + v1 = _v1 <= _v2; + else if ( op == ">=" ) + v1 = _v1 >= _v2; + else if ( op == "<>" || op == "!=" ) + v1 = _v1 != _v2; + } + else if ( ( v1.type() == QVariant::Int || v1.type() == QVariant::Double ) && + ( v2.type() == QVariant::Int || v2.type() == QVariant::Double ) ) + { + double _v1 = v1.toDouble(); + double _v2 = v2.toDouble(); + + if ( op == "+" ) + v1 = _v1 + _v2; + else if ( op == "-" ) + v1 = _v1 - _v2; + else if ( op == "*" ) + v1 = _v1 * _v2; + else if ( op == "/" ) + { + if ( _v2 != 0 ) + v1 = _v1 / _v2; + else + err = QtxEvalExpr::InvalidResult; + } + else if ( op == "<" ) + v1 = _v1 < _v2; + else if ( op == ">" ) + v1 = _v1 > _v2; + else if ( op == "=" ) + v1 = _v1 == _v2; + else if ( op == "<=" ) + v1 = _v1 <= _v2; + else if ( op == ">=" ) + v1 = _v1 >= _v2; + else if ( op == "<>" || op == "!=" ) + v1 = _v1 != _v2; + } + else // prefix operations + { + if ( op == "-" ) + { + if ( v2.type() == QVariant::Int ) + v2 = -v2.toInt(); + else if ( v2.type() == QVariant::Double ) + v2 = -v2.toDouble(); + } + } + } + + return err; +} + +/*! + \class QtxEvalSetLogic + \brief Provides set of logical operations for the parser. +*/ + +/*! + \brief Constructor. +*/ +QtxEvalSetLogic::QtxEvalSetLogic() +: QtxEvalSetBase() +{ + addOperations( QString( "and;&&;or;||;xor;not;!;imp;=" ).split( ";" ) ); + + ListOfTypes aTypes; + aTypes.append( QVariant::Bool ); + aTypes.append( QVariant::Int ); + aTypes.append( QVariant::UInt ); + addTypes( aTypes ); +} + +/*! + \brief Destructor. +*/ +QtxEvalSetLogic::~QtxEvalSetLogic() +{ +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetLogic::Name() +{ + return "Logic"; +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetLogic::name() const +{ + return Name(); +} + +/*! + \brief Create value from its string representation. + + Create \c true or \c false value from string representation. + + \param str string representration of the value + \param val returning value + \return \c true if \a str can be evaluated as custom value and \c false + otherwise (parameter) +*/ +bool QtxEvalSetLogic::createValue( const QString& str, QVariant& val ) const +{ + bool ok = true; + QString valStr = str.toLower(); + if ( valStr == "true" || valStr == "yes" ) + val = QVariant( true ); + else if ( valStr == "false" || valStr == "no" ) + val = QVariant( false ); + else + ok = QtxEvalSetBase::createValue( str, val ); + + return ok; +} + +/*! + \brief Get the operation priority. + + Operation priority counts from 1. + If the operation is impossible, this function returns value <= 0. + + \param op operation + \param isBin \c true if the operation is binary and \c false if it is unary + \return operation priority +*/ +int QtxEvalSetLogic::priority( const QString& op, bool isBin ) const +{ + if ( isBin ) + { + if ( op == "and" || op == "or" || op == "xor" || op == "&&" || op == "||" || op == "imp" ) + return 1; + else if ( op == "=" ) + return 2; + else + return 0; + } + else if ( op == "not" || op == "!" ) + return 5; + else + return 0; +} + +/*! + \brief Calculate the operation. + + Process binary operation with values \a v1 and \a v2. + For unary operation the \v2 is invalid. + The result of the operation is returned in the parameter \a v1. + + \param op operation name + \param v1 first argument (not valid for unary prefix operations) + \param v2 second argument (not valid for unary postfix operations) + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalSetLogic::calculate( const QString& op, QVariant& v1, QVariant& v2 ) const +{ + QtxEvalExpr::Error err = QtxEvalExpr::OK; + bool val1 = booleanValue( v1 ); + bool val2 = booleanValue( v2 ); + if ( v1.isValid() && v2.isValid() ) + { + if ( op == "and" || op == "&&" ) + v1 = val1 && val2; + else if ( op == "or" || op == "||" ) + v1 = val1 || val2; + else if ( op == "xor" ) + v1 = ( !val1 && val2 ) || ( val1 && !val2 ); + else if ( op == "imp" ) + v1 = !val1 || val2; + else if ( op == "=" ) + v1 = val1 == val2; + } + else if ( op == "not" || op == "!" ) + v2 = !val2; + + return err; +} + +/*! + \brief Convert value to the boolean. + \param v value being converted + \return converted value +*/ +bool QtxEvalSetLogic::booleanValue( const QVariant& v ) const +{ + bool res = false; + switch ( v.type() ) + { + case QVariant::Bool: + res = v.toBool(); + break; + case QVariant::Int: + res = v.toInt() != 0; + break; + case QVariant::UInt: + res = v.toUInt() != 0; + break; + default: + res = false; + break; + } + return res; +} + +/*! + \class QtxEvalSetMath + \brief Provides a set of more complex operations (mathematical functions) + for the parser (sqrt, sin, cos, etc). +*/ + +/*! + \brief Constructor. +*/ +QtxEvalSetMath::QtxEvalSetMath() +: QtxEvalSetBase() +{ + addOperations( QString( "sqrt;abs;sin;cos;rad2grad;grad2rad" ).split( ";" ) ); + + ListOfTypes aTypes; + aTypes.append( QVariant::Int ); + aTypes.append( QVariant::Double ); + addTypes( aTypes ); +} + +/*! + \brief Destructor. +*/ +QtxEvalSetMath::~QtxEvalSetMath() +{ +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetMath::Name() +{ + return "Math"; +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetMath::name() const +{ + return Name(); +} + +/*! + \brief Create value from its string representation. + + Creates numbers from string representation. + + \param str string representration of the value + \param val returning value + \return \c true if \a str can be evaluated as custom value and \c false + otherwise (parameter) +*/ +bool QtxEvalSetMath::createValue( const QString& str, QVariant& val ) const +{ + bool ok = false; + val = str.toInt( &ok ); + + if ( !ok ) + { + val = str.toDouble( &ok ); + if ( !ok ) + ok = QtxEvalSetBase::createValue( str, val ); + } + return ok; +} + +/*! + \brief Get the operation priority. + + Operation priority counts from 1. + If the operation is impossible, this function returns value <= 0. + + \param op operation + \param isBin \c true if the operation is binary and \c false if it is unary + \return operation priority +*/ +int QtxEvalSetMath::priority( const QString& op, bool isBin ) const +{ + if ( isBin ) + return 0; + else if ( op == "sqrt" || op == "abs" || op == "sin" || + op == "cos" || op == "rad2grad" || op == "grad2rad" ) + return 1; + else + return 0; +} + +/*! + \brief Calculate the operation. + + Process binary operation with values \a v1 and \a v2. + For unary operation the \v2 is invalid. + The result of the operation is returned in the parameter \a v1. + + \param op operation name + \param v1 first argument (not valid for unary prefix operations) + \param v2 second argument (not valid for unary postfix operations) + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalSetMath::calculate( const QString& op, QVariant&, QVariant& v2 ) const +{ + QtxEvalExpr::Error err = QtxEvalExpr::OK; + double val = v2.toDouble(); + if ( op == "sqrt" ) + { + if ( val >= 0 ) + v2 = sqrt( val ); + else + err = QtxEvalExpr::InvalidResult; + } + else if ( op == "abs" ) + { + if ( v2.type() == QVariant::Int ) + v2 = abs( v2.toInt() ); + else + v2 = fabs( v2.toDouble() ); + } + else if ( op == "sin" ) + v2 = sin( val ); + else if ( op == "cos" ) + v2 = cos( val ); + else if ( op == "grad2rad" ) + v2 = val * 3.14159256 / 180.0; + else if ( op == "rad2grad" ) + v2 = val * 180.0 / 3.14159256; + + return err; +} + +/*! + \class QtxEvalSetString + \brief Provides set of string operations for the parser. +*/ + +/*! + \brief Constructor. +*/ +QtxEvalSetString::QtxEvalSetString() +: QtxEvalSetBase() +{ + addOperations( QString( "+;=;<;>;<=;>=;<>;!=;length;lower;upper" ).split( ";" ) ); + + ListOfTypes aTypes; + aTypes.append( QVariant::Int ); + aTypes.append( QVariant::Double ); + aTypes.append( QVariant::String ); + addTypes( aTypes ); +} + +/*! + \brief Destructor. +*/ +QtxEvalSetString::~QtxEvalSetString() +{ +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetString::Name() +{ + return "String"; +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetString::name() const +{ + return Name(); +} + +/*! + \brief Create value from its string representation. + + Creates string value from Qt string representation. + + \param str string representration of the value + \param val returning value + \return \c true if \a str can be evaluated as custom value and \c false + otherwise (parameter) +*/ +bool QtxEvalSetString::createValue( const QString& str, QVariant& val ) const +{ + bool ok = false; + if ( str.length() > 1 && str[0] == '\'' && str[str.length() - 1] == '\'' ) + { + val = str.mid( 1, str.length() - 2 ); + ok = true; + } + else + ok = QtxEvalSetBase::createValue( str, val ); + return ok; +} + +/*! + \brief Get the operation priority. + + Operation priority counts from 1. + If the operation is impossible, this function returns value <= 0. + + \param op operation + \param isBin \c true if the operation is binary and \c false if it is unary + \return operation priority +*/ +int QtxEvalSetString::priority( const QString& op, bool isBin ) const +{ + if ( isBin ) + { + if ( op == "+" ) + return 2; + else if ( op == "=" || op == "<" || op == ">" || + op == "<=" || op == ">=" || op == "<>" || op == "!=" ) + return 1; + else + return 0; + } + else if ( op == "length" || op == "lower" || op=="upper" ) + return 5; + else + return 0; +} + +/*! + \brief Calculate the operation. + + Process binary operation with values \a v1 and \a v2. + For unary operation the \v2 is invalid. + The result of the operation is returned in the parameter \a v1. + + \param op operation name + \param v1 first argument (not valid for unary prefix operations) + \param v2 second argument (not valid for unary postfix operations) + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalSetString::calculate( const QString& op, QVariant& v1, QVariant& v2 ) const +{ + QtxEvalExpr::Error err = QtxEvalExpr::OK; + if ( v1.isValid() && v2.isValid() ) + { + QString _v1 = v1.toString(); + QString _v2 = v2.toString(); + if ( op == "+" ) + v1 = _v1 + _v2; + else if ( op == "=" ) + v1 = _v1 ==_v2; + else if ( op == "<" ) + v1 = _v1 < _v2; + else if ( op == ">" ) + v1 = _v1 > _v2; + else if ( op == "<>" || op == "!=" ) + v1 = _v1 != _v2; + else if ( op == "<=" ) + v1 = _v1 < _v2 || _v1 == _v2; + else if ( op == ">=" ) + v1 = _v1 > _v2 || _v1 == _v2; + } + else if ( !v1.isValid() && v2.isValid() ) + { + QString val = v2.toString(); + if ( op == "length" ) + v2 = (int)val.length(); + else if ( op == "lower" ) + v2 = val.toLower(); + else if ( op == "upper" ) + v2 = val.toUpper(); + } + return err; +} + +/*! + \class QtxEvalSetSets + \brief Provides set of operations with sequences for the parser. +*/ + +/*! + \brief Constructor. +*/ +QtxEvalSetSets::QtxEvalSetSets() +: QtxEvalSetBase() +{ + addOperations( QString( "{;};=;<>;!=;+;-;*;in;count" ).split( ";" ) ); + + ListOfTypes aTypes; + aTypes.append( QVariant::List ); + addTypes( aTypes ); +} + +/*! + \brief Destructor. +*/ +QtxEvalSetSets::~QtxEvalSetSets() +{ +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetSets::Name() +{ + return "Sets"; +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetSets::name() const +{ + return Name(); +} + +/*! + \brief Get list of brackets. + \param list returning list of brackets + \param open if \c true, collect opening brackets, or closing brackets otherwise +*/ +void QtxEvalSetSets::bracketsList( QStringList& list, bool open ) const +{ + list.append( open ? "{" : "}" ); + QtxEvalSetBase::bracketsList( list, open ); +} + +/*! + \brief Get the operation priority. + + Operation priority counts from 1. + If the operation is impossible, this function returns value <= 0. + + \param op operation + \param isBin \c true if the operation is binary and \c false if it is unary + \return operation priority +*/ +int QtxEvalSetSets::priority( const QString& op, bool isBin ) const +{ + if ( isBin ) + { + if ( op == "=" || op == "<>" || op == "!=" ) + return 1; + else if ( op == "+" || op == "-" || op == "*" ) + return 2; + else if ( op == "in" ) + return 3; + else + return 0; + } + else if ( op == "{" || op == "}" ) + return 5; + else if ( op == "count" ) + return 4; + else + return 0; +} + +/*! + \brief Check operation validity. + + If the operation is valid, QtxEvalExpr::OK is returned. + If types of operands are invalid, the function returns QtxEvalExpr::OperandsNotMatch + or QtxEvalExpr::InvalidOperation. + + \param op operation + \param t1 first operand type + \param t2 second operand type + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalSetSets::isValid( const QString& op, + const QVariant::Type t1, const QVariant::Type t2 ) const +{ + if ( op == "{" ) + return QtxEvalExpr::OK; + + if ( op != "in" ) + return QtxEvalSetBase::isValid( op, t1, t2 ); + + if ( t1 != QVariant::Invalid && t2 == QVariant::List ) + return QtxEvalExpr::OK; + else + return QtxEvalExpr::OperandsNotMatch; +} + +/*! + \brief Add new value \a v to the sequence \a set. + \param set sequence + \param v value to be added +*/ +void QtxEvalSetSets::add( ValueSet& set, const QVariant& v ) +{ + if ( v.isValid() && !set.contains( v ) ) + set.append( v ); +} + +/*! + \brief Add all values from sequence \a s2 to the sequence \a s1. + \param s1 destination sequence + \param s2 source sequence +*/ +void QtxEvalSetSets::add( ValueSet& s1, const ValueSet& s2 ) +{ + for ( ValueSet::const_iterator anIt = s2.begin(); anIt != s2.end(); ++anIt ) + add( s1, *anIt ); +} + +/*! + \brief Remove value \a v from sequence \a set. + \param set sequence + \param v value to be removed +*/ +void QtxEvalSetSets::remove( ValueSet& set, const QVariant& v ) +{ + set.removeAll( v ); +} + +/*! + \brief Remove all values listed in the sequence \a s2 from the sequence \a s1. + \param s1 sequence from which items are removed + \param s2 sequence which items are removed +*/ +void QtxEvalSetSets::remove( ValueSet& s1, const ValueSet& s2 ) +{ + for ( ValueSet::const_iterator anIt = s2.begin(); anIt != s2.end(); ++anIt ) + s1.removeAll( *anIt ); +} + +/*! + \brief Calculate the operation. + + Process binary operation with values \a v1 and \a v2. + For unary operation the \v2 is invalid. + The result of the operation is returned in the parameter \a v1. + + \param op operation name + \param v1 first argument (not valid for unary prefix operations) + \param v2 second argument (not valid for unary postfix operations) + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalSetSets::calculate( const QString& op, QVariant& v1, QVariant& v2 ) const +{ + QtxEvalExpr::Error err = QtxEvalExpr::OK; + + if ( op != "{" ) + { + if ( op == "}" ) + { + ValueSet aNewList; + add( aNewList, v1.toList() ); + v1 = aNewList; + } + else if ( op == "=" || op == "<>" || op == "!=" || op == "+" || op == "-" || op == "*" ) + { + ValueSet aNewList; + add( aNewList, v1.toList() ); + if ( op == "=" || op == "<>" || op == "!=" || op == "-" ) + { + remove( aNewList, v2.toList() ); + if ( op == "=" ) + v1 = aNewList.isEmpty() && v1.toList().count() == v2.toList().count(); + else if ( op == "<>" || op == "!=" ) + v1 = !aNewList.isEmpty() || v1.toList().count() != v2.toList().count(); + else + v1 = aNewList; + } + else if ( op == "+" ) + { + add( aNewList, v2.toList() ); + v1 = aNewList; + } + else if ( op == "*" ) + { + ValueSet toDelete; + add( toDelete, aNewList ); + remove( toDelete, v2.toList() ); + remove( aNewList, toDelete ); + v1 = aNewList; + } + } + else if ( op== "count" ) + v2 = (int)v2.toList().count(); + else if ( op == "in" ) + { + if ( v1.type() == QVariant::List ) + { + bool res = true; + ValueSet lst1 = v1.toList(); + ValueSet lst2 = v2.toList(); + for ( ValueSet::const_iterator anIt = lst1.begin(); anIt != lst1.end() && res; ++anIt ) + res = lst2.contains( *anIt ); + + v1 = res; + } + else + v1 = QVariant( v2.toList().contains( v1 ) ); + } + } + return err; +} + +/*! + \class QtxEvalSetConst + \brief Provides different standard constants. +*/ +QtxEvalSetConst::QtxEvalSetConst() +: QtxEvalSet() +{ +} + +/*! + \brief Destructor. +*/ +QtxEvalSetConst::~QtxEvalSetConst() +{ +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetConst::Name() +{ + return "Const"; +} + +/*! + \brief Get operations set name. + \return operations set name +*/ +QString QtxEvalSetConst::name() const +{ + return Name(); +} + +/*! + \brief Create value from its string representation. + + Convert constant name to its value. + + \param str string representration of the constant + \param val returning value + \return \c true if \a str can be evaluated as custom value and \c false + otherwise (parameter) +*/ +bool QtxEvalSetConst::createValue( const QString& str, QVariant& val ) const +{ + bool ok = true; + if ( str == "pi" ) // PI number + val = QVariant( 3.141593 ); + else if ( str == "exp" ) // Exponent value (e) + val = QVariant( 2.718282 ); + else if ( str == "g" ) // Free fall acceleration (g) + val = QVariant( 9.80665 ); + else + ok = false; + + return ok; +} + +/*! + \brief Get the list of possible operations. + \param list returning list of operations supported by the class (not used) +*/ +void QtxEvalSetConst::operationList( QStringList& /*list*/ ) const +{ +} + +/*! + \brief Get list of brackets. + \param list returning list of brackets (not used) + \param open if \c true, collect opening brackets, or closing brackets otherwise (not used) +*/ +void QtxEvalSetConst::bracketsList( QStringList& /*list*/, bool /*open*/ ) const +{ +} + +/*! + \brief Get the operation priority. + + Operation priority counts from 1. + If the operation is impossible, this function returns value <= 0. + + \param op operation (not used) + \param isBin \c true if the operation is binary and \c false if it is unary (not used) + \return operation priority +*/ +int QtxEvalSetConst::priority( const QString& /*op*/, bool /*isBin*/ ) const +{ + return 0; +} + +/*! + \brief Check operation validity. + + Always returns QtxEvalExpr::InvalidOperation. + + \param op operation (not used) + \param t1 first operand type (not used) + \param t2 second operand type (not used) + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalSetConst::isValid( const QString& /*op*/, + const QVariant::Type /*t1*/, + const QVariant::Type /*t2*/ ) const +{ + return QtxEvalExpr::InvalidOperation; +} + +/*! + \brief Calculate the operation. + + Always returns QtxEvalExpr::InvalidOperation. + + \param op operation name (not used) + \param v1 first argument (not valid for unary prefix operations) (not used) + \param v2 second argument (not valid for unary postfix operations) (not used) + \return error code (QtxEvalExpr::Error) +*/ +QtxEvalExpr::Error QtxEvalSetConst::calculate( const QString&, QVariant&, QVariant& ) const +{ + return QtxEvalExpr::InvalidOperation; +} diff --git a/src/Qtx/QtxEvalExpr.h b/src/Qtx/QtxEvalExpr.h new file mode 100644 index 000000000..34acd4747 --- /dev/null +++ b/src/Qtx/QtxEvalExpr.h @@ -0,0 +1,324 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxEvalExpr.h +// Author: Alexander SOLOVYOV, Sergey TELKOV + +#ifndef QTXEVALEXPR_H +#define QTXEVALEXPR_H + +#include "Qtx.h" + +#include +#include + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +class QtxEvalSet; +class QtxEvalParser; + +class QTX_EXPORT QtxEvalExpr +{ +public: + //! Parsing error type + typedef enum + { + OK, //!< No errors found + OperandsNotMatch, //!< Types of arguments are invalid for this operation + InvalidResult, //!< Operation cannot find result (for example, division by zero) + InvalidOperation, //!< Unknown operation + OperationsNull, //!< Internal operations pointer of parser is null + InvalidToken, //!< Invalid token (neither operation, nor parameter of value) + CloseExpected, //!< Closing bracket is expected + ExcessClose, //!< Extra closing bracket is found + BracketsNotMatch, //!< Opening and closing brackets are of different type, e.g. [) + StackUnderflow, //!< There are no arguments in the stack for the operation + ExcessData //!< The parsing is finished, but there are more then one value in the stack + } Error; + +public: + QtxEvalExpr( const QString& = QString() ); + QtxEvalExpr( const bool, const QString& = QString() ); + ~QtxEvalExpr(); + + QVariant calculate( const QString& = QString() ); + + QString expression() const; + void setExpression( const QString& ); + + Error error() const; + QtxEvalParser* parser() const; + + bool autoDeleteOperationSets() const; + void setAutoDeleteOperationSets( const bool ); + + QList operationSets() const; + QtxEvalSet* operationSet( const QString& ) const; + void removeOperationSet( QtxEvalSet* ); + void insertOperationSet( QtxEvalSet*, const int = -1 ); + +private: + void intialize( const bool, const QString& ); + +private: + QString myExpr; + QtxEvalParser* myParser; +}; + +class QTX_EXPORT QtxEvalParser +{ +public: + QtxEvalParser(); + virtual ~QtxEvalParser(); + + QVariant calculate(); + QVariant calculate( const QString& ); + bool setExpression( const QString& ); + + QList operationSets() const; + QtxEvalSet* operationSet( const QString& ) const; + void removeOperationSet( QtxEvalSet* ); + void insertOperationSet( QtxEvalSet*, const int = -1 ); + + bool autoDeleteOperationSets() const; + void setAutoDeleteOperationSets( const bool ); + + virtual void clearParameters(); + virtual bool removeParameter( const QString& name ); + virtual QVariant parameter( const QString& name ) const; + virtual bool hasParameter( const QString& name ) const; + virtual void setParameter( const QString& name, const QVariant& value ); + QStringList parameters() const; + + QtxEvalExpr::Error error() const; + + bool firstInvalid( QString& ) const; + void removeInvalids(); + QString dump() const; + + static QString toString( const QList& ); + +protected: + //! Types of postfix representation elements + typedef enum + { + Value, //!< Value (number, string, etc.) + Param, //!< Parameter + Open, //!< Open bracket + Close, //!< Close bracket + Pre, //!< Unary prefix operation + Post, //!< Unary postfix operation + Binary //!< Binary operation + } PostfixItemType; + + //! Postfix representation element + typedef struct + { + QVariant myValue; + PostfixItemType myType; + } PostfixItem; + + typedef QList Postfix; //!< postfix representation + typedef QList SetList; //!< list of operations + typedef QMap ParamMap; //!< parameter-to-value map + +protected: + QString dump( const Postfix& ) const; + virtual bool prepare( const QString&, Postfix& ); + virtual bool setOperationTypes( Postfix& ); + virtual bool sort( const Postfix&, Postfix&, const QStringList&, + const QStringList&, int f = -1, int l = -1 ); + + virtual bool parse( const QString& ); + virtual void setError( const QtxEvalExpr::Error ); + + bool calculate( const QString&, QVariant&, QVariant& ); + + static int search( const QStringList&, const QString&, + int offset, int& matchLen, int& listind ); + static QString note( const QString& str, int pos, int len ); + static int globalBrackets( const Postfix&, int, int ); + +private: + void operationList( QStringList& ) const; + void bracketsList( QStringList&, bool ) const; + bool createValue( const QString&, QVariant& ) const; + int priority( const QString&, bool isBin ) const; + QtxEvalExpr::Error isValid( const QString&, + const QVariant::Type, const QVariant::Type ) const; + QtxEvalExpr::Error calculation( const QString&, QVariant&, QVariant& ) const; + + bool checkOperations() const; + +private: + SetList mySets; + QtxEvalExpr::Error myError; + ParamMap myParams; + Postfix myPostfix; + bool myAutoDel; +}; + +class QTX_EXPORT QtxEvalSet +{ +public: + QtxEvalSet(); + virtual ~QtxEvalSet(); + + virtual QString name() const = 0; + + virtual void operationList( QStringList& ) const = 0; + + virtual void bracketsList( QStringList&, bool open ) const = 0; + + virtual bool createValue( const QString&, QVariant& ) const; + + virtual int priority( const QString&, bool isBin ) const = 0; + + virtual QtxEvalExpr::Error isValid( const QString&, const QVariant::Type, + const QVariant::Type ) const = 0; + + virtual QtxEvalExpr::Error calculate( const QString&, QVariant&, QVariant& ) const = 0; +}; + +class QTX_EXPORT QtxEvalSetBase : public QtxEvalSet +{ +public: + QtxEvalSetBase(); + virtual ~QtxEvalSetBase(); + + virtual void operationList( QStringList& ) const; + virtual void bracketsList( QStringList&, bool open ) const; + + virtual QtxEvalExpr::Error isValid( const QString&, const QVariant::Type, + const QVariant::Type ) const; +protected: + typedef QList ListOfTypes; + + void addTypes( const ListOfTypes& ); + void addOperations( const QStringList& ); + +private: + QStringList myOpers; + ListOfTypes myTypes; +}; + +class QTX_EXPORT QtxEvalSetArithmetic : public QtxEvalSetBase +{ +public: + QtxEvalSetArithmetic(); + virtual ~QtxEvalSetArithmetic(); + + virtual bool createValue( const QString&, QVariant& ) const; + virtual int priority( const QString&, bool isBin ) const; + virtual QtxEvalExpr::Error calculate( const QString&, QVariant&, QVariant& ) const; + + static QString Name(); + virtual QString name() const; +}; + +class QTX_EXPORT QtxEvalSetLogic : public QtxEvalSetBase +{ +public: + QtxEvalSetLogic(); + virtual ~QtxEvalSetLogic(); + + virtual bool createValue( const QString&, QVariant& ) const; + virtual int priority( const QString&, bool isBin ) const; + virtual QtxEvalExpr::Error calculate( const QString&, QVariant&, QVariant& ) const; + + static QString Name(); + virtual QString name() const; + +private: + bool booleanValue( const QVariant& v ) const; +}; + +class QTX_EXPORT QtxEvalSetMath : public QtxEvalSetBase +{ +public: + QtxEvalSetMath(); + virtual ~QtxEvalSetMath(); + + virtual bool createValue( const QString&, QVariant& ) const; + virtual int priority( const QString&, bool isBin ) const; + virtual QtxEvalExpr::Error calculate( const QString&, QVariant&, QVariant& ) const; + + static QString Name(); + virtual QString name() const; +}; + +class QTX_EXPORT QtxEvalSetString : public QtxEvalSetBase +{ +public: + QtxEvalSetString(); + virtual ~QtxEvalSetString(); + + virtual bool createValue( const QString&, QVariant& ) const; + virtual int priority( const QString&, bool isBin ) const; + virtual QtxEvalExpr::Error calculate( const QString&, QVariant&, QVariant& ) const; + + static QString Name(); + virtual QString name() const; +}; + +class QTX_EXPORT QtxEvalSetSets : public QtxEvalSetBase +{ +public: + typedef QList ValueSet; + +public: + QtxEvalSetSets(); + virtual ~QtxEvalSetSets(); + + virtual void bracketsList( QStringList&, bool open ) const; + virtual int priority( const QString&, bool isBin ) const; + virtual QtxEvalExpr::Error isValid( const QString&, const QVariant::Type, + const QVariant::Type ) const; + virtual QtxEvalExpr::Error calculate( const QString&, QVariant&, QVariant& ) const; + + static void add( ValueSet&, const QVariant& ); + static void add( ValueSet&, const ValueSet& ); + static void remove( ValueSet&, const QVariant& ); + static void remove( ValueSet&, const ValueSet& ); + + static QString Name(); + virtual QString name() const; +}; + +class QTX_EXPORT QtxEvalSetConst : public QtxEvalSet +{ +public: + QtxEvalSetConst(); + virtual ~QtxEvalSetConst(); + + static QString Name(); + virtual QString name() const; + + virtual bool createValue( const QString&, QVariant& ) const; + + virtual void operationList( QStringList& ) const; + virtual void bracketsList( QStringList&, bool open ) const; + virtual int priority( const QString&, bool isBin ) const; + virtual QtxEvalExpr::Error isValid( const QString&, const QVariant::Type, + const QVariant::Type ) const; + virtual QtxEvalExpr::Error calculate( const QString&, QVariant&, QVariant& ) const; +}; + +#endif // QTXEVALEXPR_H diff --git a/src/Qtx/QtxFontEdit.cxx b/src/Qtx/QtxFontEdit.cxx new file mode 100644 index 000000000..30970d8f1 --- /dev/null +++ b/src/Qtx/QtxFontEdit.cxx @@ -0,0 +1,298 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxFontEdit.cxx +// Author: Sergey TELKOV + +#include "QtxFontEdit.h" + +#include "QtxComboBox.h" + +#include +#include +#include +#include +#include + +/*! + \class QtxFontEdit + \brief The QtxFontEdit class represents a widget for font + preference items editing. + + The font preference item is represented as the drop-down combo box + filled with the list of available fonts. Additional controls for + modifying font properties ('bold', 'italic', font size, etc) are also + available for use. + + Initial font value can be set with setCurrentFont() method. Chosen font + can be retrieved with the currentFont() method. + + Font properties can be set with the setFontSize(), setFontFamily(), + setFontScripting() methods and retrieved with fontSize(), fontFamily(), + fontScripting() methods. + + Additional widgets for direct modyfing font properties are available + with use of setFeatures() method. +*/ + +/*! + \brief Constructor + \param feat font widget features (ORed QtxFontEdit::Features flags) + \param parent parent widget +*/ +QtxFontEdit::QtxFontEdit( const int feat, QWidget* parent ) +: QFrame( parent ), + myFeatures( feat ) +{ + initialize(); +} + +/*! + \brief Constructor + \param parent parent widget + + All font widget features are enabled. +*/ +QtxFontEdit::QtxFontEdit( QWidget* parent ) +: QFrame( parent ), + myFeatures( All ) +{ + initialize(); +} + +/*! + \brief Destructor +*/ +QtxFontEdit::~QtxFontEdit() +{ +} + +/*! + \brief Get font widget features. + \return font widget features (ORed QtxFontEdit::Features flags) + \sa setFeatures() +*/ +int QtxFontEdit::features() const +{ + return myFeatures; +} + +/*! + \brief Set font widget features. + \param f font widget features (ORed QtxFontEdit::Features flags) + \sa features() +*/ +void QtxFontEdit::setFeatures( const int f ) +{ + if ( myFeatures == f ) + return; + + myFeatures = f; + updateState(); +} + +/*! + \brief Get currently selected font. + \return current font + \sa setCurrentFont() +*/ +QFont QtxFontEdit::currentFont() const +{ + QFont fnt( fontFamily(), fontSize() ); + + int script = fontScripting(); + fnt.setBold( script & Bold ); + fnt.setItalic( script & Italic ); + fnt.setUnderline( script & Underline ); + + return fnt; +} + +/*! + \brief Set currently selected font. + \param fnt current font + \sa currentFont() +*/ +void QtxFontEdit::setCurrentFont( const QFont& fnt ) +{ + setFontFamily( fnt.family() ); + setFontSize( fnt.pointSize() ); + setFontScripting( ( fnt.bold() ? Bold : 0 ) | + ( fnt.italic() ? Italic : 0 ) | + ( fnt.underline() ? Underline : 0 ) ); +} + +/*! + \brief Get selected font family name. + \return current font family name + \sa setFontFamily() +*/ +QString QtxFontEdit::fontFamily() const +{ + return myFamily->currentFont().family(); +} + +/*! + \brief Get selected font size. + \return current font size + \sa setFontSize() +*/ +int QtxFontEdit::fontSize() const +{ + bool ok; + int pSize = mySize->currentText().toInt( &ok ); + return ok ? pSize : 0; +} + +/*! + \brief Get selected font scripting. + \return current font scripting + \sa setFontScripting() +*/ +int QtxFontEdit::fontScripting() const +{ + return ( myB->isChecked() ? Bold : 0 ) | + ( myI->isChecked() ? Italic : 0 ) | + ( myU->isChecked() ? Underline : 0 ); +} + +/*! + \brief Set font family name. + \param fam new font family name + \sa fontFamily() +*/ +void QtxFontEdit::setFontFamily( const QString& fam ) +{ + myFamily->setCurrentFont( QFont( fam ) ); + onFontChanged( myFamily->currentFont() ); +} + +/*! + \brief Set font size. + \param fam new font size + \sa fontSize() +*/ +void QtxFontEdit::setFontSize( const int s ) +{ + if ( s <= 0 ) + return; + + int idx = mySize->findText( QString::number( s ) ); + if ( idx != -1 ) + mySize->setCurrentIndex( idx ); + else if ( mySize->isEditable() ) + mySize->setEditText( QString::number( s ) ); +} + +/*! + \brief Set font scripting. + \param fam new font scripting + \sa fontScripting() +*/ +void QtxFontEdit::setFontScripting( const int script ) +{ + myB->setChecked( script & Bold ); + myI->setChecked( script & Italic ); + myU->setChecked( script & Underline ); +} + +/*! + \brief Update widget state +*/ +void QtxFontEdit::updateState() +{ + int feat = features(); + + myFamily->setVisible( feat & Family ); + mySize->setVisible( feat & Size ); + myB->setVisible( feat & Bold ); + myI->setVisible( feat & Italic ); + myU->setVisible( feat & Underline ); + myPreview->setVisible( feat & Preview ); + + mySize->setEditable( feat & UserSize ); +} + +/*! + \brief Called when current font is changed. + \param f (not used) +*/ +void QtxFontEdit::onFontChanged( const QFont& /*f*/ ) +{ + int s = fontSize(); + mySize->clear(); + + QList szList = QFontDatabase().pointSizes( fontFamily() ); + QStringList sizes; + for ( QList::const_iterator it = szList.begin(); it != szList.end(); ++it ) + sizes.append( QString::number( *it ) ); + mySize->addItems( sizes ); + + setFontSize( s ); +} + +/*! + \brief Called when "Preview" button is clicked. + \param on (not used) +*/ +void QtxFontEdit::onPreview( bool /*on*/ ) +{ + bool ok; + QFont fnt = QFontDialog::getFont( &ok, currentFont() ); + + if ( ok ) + setCurrentFont( fnt ); +} + +/* + \brief Perform internal intialization. +*/ +void QtxFontEdit::initialize() +{ + QHBoxLayout* base = new QHBoxLayout( this ); + base->setMargin( 0 ); + base->setSpacing( 5 ); + + base->addWidget( myFamily = new QFontComboBox( this ) ); + base->addWidget( mySize = new QtxComboBox( this ) ); + mySize->setInsertPolicy( QComboBox::NoInsert ); + mySize->setValidator( new QIntValidator( 1, 250, mySize ) ); + + base->addWidget( myB = new QToolButton( this ) ); + myB->setText( tr( "B" ) ); + myB->setCheckable( true ); + + base->addWidget( myI = new QToolButton( this ) ); + myI->setText( tr( "I" ) ); + myI->setCheckable( true ); + + base->addWidget( myU = new QToolButton( this ) ); + myU->setText( tr( "U" ) ); + myU->setCheckable( true ); + + base->addWidget( myPreview = new QToolButton( this ) ); + myPreview->setText( "..." ); + + myFamily->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred ); + + connect( myPreview, SIGNAL( clicked( bool ) ), this, SLOT( onPreview( bool ) ) ); + connect( myFamily, SIGNAL( currentFontChanged( const QFont& ) ), this, SLOT( onFontChanged( const QFont& ) ) ); + + updateState(); + onFontChanged( currentFont() ); +} diff --git a/src/Qtx/QtxFontEdit.h b/src/Qtx/QtxFontEdit.h new file mode 100644 index 000000000..b0ef25eef --- /dev/null +++ b/src/Qtx/QtxFontEdit.h @@ -0,0 +1,86 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxFontEdit.h +// Author: Sergey TELKOV + +#ifndef QTXFONTEDIT_H +#define QTXFONTEDIT_H + +#include "Qtx.h" + +#include + +class QtxComboBox; +class QToolButton; +class QFontComboBox; + +class QTX_EXPORT QtxFontEdit : public QFrame +{ + Q_OBJECT + +public: + //! Font widget features + typedef enum { + Family = 0x01, //!< show font family selection widget + Size = 0x02, //!< show font size widget + UserSize = 0x04, //!< allow font size direct change + Bold = 0x08, //!< show 'bold' widget + Italic = 0x10, //!< show 'italic' widget + Underline = 0x20, //!< show 'underline' widget + Preview = 0x40, //!< show font preview widget + Scripting = Bold | Italic | Underline, //!< show font scripting widgets ('bold','italic','underline') + All = Family | Size | UserSize | Scripting | Preview //!< show all font widgets + } Features; + +public: + QtxFontEdit( const int, QWidget* = 0 ); + QtxFontEdit( QWidget* = 0 ); + virtual ~QtxFontEdit(); + + QFont currentFont() const; + void setCurrentFont( const QFont& ); + + int fontSize() const; + QString fontFamily() const; + int fontScripting() const; + + void setFontSize( const int ); + void setFontFamily( const QString& ); + void setFontScripting( const int ); + + int features() const; + void setFeatures( const int ); + +private slots: + void onPreview( bool ); + void onFontChanged( const QFont& ); + +private: + void initialize(); + void updateState(); + +private: + QtxComboBox* mySize; + QFontComboBox* myFamily; + QToolButton* myPreview; + int myFeatures; + QToolButton *myB, *myI, *myU; +}; + +#endif // QTXFONTEDIT_H diff --git a/src/Qtx/QtxGridBox.cxx b/src/Qtx/QtxGridBox.cxx new file mode 100644 index 000000000..bb2d33623 --- /dev/null +++ b/src/Qtx/QtxGridBox.cxx @@ -0,0 +1,362 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxGridBox.cxx +// Author: Sergey TELKOV + +#include "QtxGridBox.h" + +#include +#include + +/*! + \class QtxGridBox::Space + \internal + \brief Represents a space in the grid box. +*/ + +class QtxGridBox::Space : public QWidget +{ +public: + Space( const int, QtxGridBox* ); + virtual ~Space(); + + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + +private: + int mySize; + QtxGridBox* myGrid; +}; + +/*! + \brief Constructor. + \param sz size + \param gb parent grid box +*/ +QtxGridBox::Space::Space( const int sz, QtxGridBox* gb ) +: QWidget( gb ), + mySize( sz ), + myGrid( gb ) +{ + setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); +} + +/*! + \brief Destructor. +*/ +QtxGridBox::Space::~Space() +{ +} + +/*! + \brief Get recommended size for the widget. + \return recommended size for the widget +*/ +QSize QtxGridBox::Space::sizeHint() const +{ + return minimumSizeHint(); +} + +/*! + \brief Get recommended minimum size for the widget. + \return recommended minimum size for the widget +*/ +QSize QtxGridBox::Space::minimumSizeHint() const +{ + QSize sz( 0, 0 ); + if ( myGrid && myGrid->orientation() == Qt::Horizontal ) + sz.setWidth( mySize ); + else + sz.setHeight( mySize ); + return sz; +} + +/*! + \class QtxGridBox + \brief A container widget with possibility to automatically layout + child widgets. +*/ + +/*! + \brief Constructor. + \param parent parent widget + \param m grid box margin + \param s grid box spacing +*/ +QtxGridBox::QtxGridBox( QWidget* parent, const int m, const int s ) +: QWidget( parent ), + myCols( 1 ), + mySkip( false ), + myOrient( Qt::Vertical ), + myCol( 0 ), + myRow( 0 ) +{ + myLayout = new QGridLayout( this ); + myLayout->setMargin( m ); + myLayout->setSpacing( s ); +} + +/*! + \brief Constructor. + \param cols number of grid box columns or rows (depending on the orientation) + \param o grid box orientation + \param parent parent widget + \param m grid box margin + \param s grid box spacing +*/ +QtxGridBox::QtxGridBox( const int cols, Qt::Orientation o, QWidget* parent, const int m, const int s ) +: QWidget( parent ), + myCols( cols ), + mySkip( false ), + myOrient( o ), + myLayout( 0 ), + myCol( 0 ), + myRow( 0 ) +{ + myLayout = new QGridLayout( this ); + myLayout->setMargin( m ); + myLayout->setSpacing( s ); +} + +/*! + \brief Destructor. +*/ +QtxGridBox::~QtxGridBox() +{ +} + +/*! + \brief Get number of grid box columns/rows (depending on the orientation). + \return number of columns (rows) +*/ +int QtxGridBox::columns() const +{ + return myCols; +} + +/*! + \brief Get the grid box orientation. + \return orientation +*/ +Qt::Orientation QtxGridBox::orientation() const +{ + return myOrient; +} + +/*! + \brief Set number of grid box columns/rows (depending on the orientation). + \param cols number of columns (rows) +*/ +void QtxGridBox::setColumns( const int cols ) +{ + setLayout( cols, orientation() ); +} + +/*! + \brief Set the grid box orientation. + \param o orientation +*/ +void QtxGridBox::setOrientation( Qt::Orientation o ) +{ + setLayout( columns(), o ); +} + +/*! + \brief Initialize internal layout. + \param cols number of columns (rows) + \param o orientation +*/ +void QtxGridBox::setLayout( const int cols, Qt::Orientation o ) +{ + if ( myCols == cols && myOrient == o ) + return; + + myCols = cols; + myOrient = o; + + arrangeWidgets(); +} + +/*! + \brief Get "skip invisible widgets" flags. + \return current flag state +*/ +bool QtxGridBox::skipInvisible() const +{ + return mySkip; +} + +/*! + \brief Set "skip invisible widgets" flags. + + If this flag is set to \c false, invisible widgets + are not taken into account when layouting widgets. + + \param on new flag state +*/ +void QtxGridBox::setSkipInvisible( const bool on ) +{ + if ( mySkip == on ) + return; + + mySkip = on; + arrangeWidgets(); +} + +/*! + \brief Add space (empty cell) to the grid box. + \param sp requied space size +*/ +void QtxGridBox::addSpace( const int sp ) +{ + new Space( sp, this ); +} + +/*! + \brief Get grid box's inside margin size. + \return inside margin size +*/ +int QtxGridBox::insideMargin() const +{ + return myLayout->margin(); +} + +/*! + \brief Get grid box's inside spacing size. + \return inside spacing size +*/ +int QtxGridBox::insideSpacing() const +{ + return myLayout->spacing(); +} + +/*! + \brief Set grid box's inside margin size. + \param m new inside margin size +*/ +void QtxGridBox::setInsideMargin( const int m ) +{ + myLayout->setMargin( m ); +} + +/*! + \brief Set grid box's inside spacing size. + \param s new inside spacing size +*/ +void QtxGridBox::setInsideSpacing( const int s ) +{ + myLayout->setSpacing( s ); +} + +/*! + \brief Custom event filter. + \param o event receiver object. + \param e event + \return \c true if the event processing should be stopped +*/ +bool QtxGridBox::eventFilter( QObject* o, QEvent* e ) +{ + if ( skipInvisible() && ( e->type() == QEvent::Show || e->type() == QEvent::ShowToParent || + e->type() == QEvent::Hide || e->type() == QEvent::HideToParent ) ) + arrangeWidgets(); + + return QWidget::eventFilter( o, e ); +} + +/*! + \brief Customize child event. + \param e child event +*/ +void QtxGridBox::childEvent( QChildEvent* e ) +{ + if ( e->child()->isWidgetType() ) + { + QWidget* wid = (QWidget*)e->child(); + if ( e->type() == QEvent::ChildAdded ) + { + placeWidget( wid ); + wid->installEventFilter( this ); + } + else if ( e->type() == QEvent::ChildRemoved ) + wid->removeEventFilter( this ); + } + QWidget::childEvent( e ); +} + +/*! + \brief Increment the grid box current cell. +*/ +void QtxGridBox::skip() +{ + if ( orientation() == Qt::Horizontal ) + { + myCol++; + if ( myCol >= columns() ) + { + myRow++; + myCol = 0; + } + } + else + { + myRow++; + if ( myRow >= columns() ) + { + myCol++; + myRow = 0; + } + } +} + +/*! + \brief Arrange child widgets. +*/ +void QtxGridBox::arrangeWidgets() +{ + myRow = myCol = 0; + int m = myLayout ? myLayout->margin() : 0; + int s = myLayout ? myLayout->spacing() : 0; + delete myLayout; + myLayout = new QGridLayout( this ); + myLayout->setMargin( m ); + myLayout->setSpacing( s ); + + QObjectList list = children(); + for ( QObjectList::iterator it = list.begin(); it != list.end(); ++it ) + { + if ( !(*it)->isWidgetType() ) + continue; + + QWidget* wid = (QWidget*)(*it); + if ( !skipInvisible() || wid->isVisibleTo( this ) ) + placeWidget( wid ); + } + updateGeometry(); +} + +/*! + \brief Place new widget to the current grid box cell. + \param wid widget being inserted +*/ +void QtxGridBox::placeWidget( QWidget* wid ) +{ + myLayout->addWidget( wid, myRow, myCol ); + + skip(); +} diff --git a/src/Qtx/QtxGridBox.h b/src/Qtx/QtxGridBox.h new file mode 100644 index 000000000..4ca39aa08 --- /dev/null +++ b/src/Qtx/QtxGridBox.h @@ -0,0 +1,79 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxGridBox.h +// Author: Sergey TELKOV + +#ifndef QTXGRIDBOX_H +#define QTXGRIDBOX_H + +#include "Qtx.h" + +#include + +class QGridLayout; + +class QTX_EXPORT QtxGridBox : public QWidget +{ + Q_OBJECT + + class Space; + +public: + QtxGridBox( QWidget* = 0, const int = 5, const int = 5 ); + QtxGridBox( const int, Qt::Orientation, QWidget* = 0, const int = 5, const int = 5 ); + virtual ~QtxGridBox(); + + int columns() const; + Qt::Orientation orientation() const; + + void setColumns( const int ); + void setOrientation( Qt::Orientation ); + + void setLayout( const int, Qt::Orientation ); + + bool skipInvisible() const; + void setSkipInvisible( const bool ); + + void addSpace( const int ); + + int insideMargin() const; + int insideSpacing() const; + void setInsideMargin( const int ); + void setInsideSpacing( const int ); + + virtual bool eventFilter( QObject*, QEvent* ); + +protected: + void childEvent( QChildEvent* ); + +private: + void skip(); + void arrangeWidgets(); + void placeWidget( QWidget* ); + +private: + int myCols; + bool mySkip; + Qt::Orientation myOrient; + QGridLayout* myLayout; + + int myCol, myRow; +}; + +#endif diff --git a/src/Qtx/QtxGroupBox.cxx b/src/Qtx/QtxGroupBox.cxx new file mode 100644 index 000000000..e99532ed4 --- /dev/null +++ b/src/Qtx/QtxGroupBox.cxx @@ -0,0 +1,345 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxGroupBox.cxx +// Author: Sergey TELKOV + +#include "QtxGroupBox.h" + +#include +#include +#include +#include +#include + +/*! + \class QtxGroupBox + \brief Enhanced group box widget. + + The QtxGroupBox class allows inserting custom widgets in the + group box title. Use insertTitleWidget() method to add + custom widget to the title and removeTitleWidget() to remove it. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +QtxGroupBox::QtxGroupBox( QWidget* parent ) +: QGroupBox( parent ), + myContainer( 0 ) +{ + initialize(); +} + +/*! + \brief Constructor. + \param title group box title text + \param parent parent widget +*/ +QtxGroupBox::QtxGroupBox( const QString& title, QWidget* parent ) +: QGroupBox( title, parent ), + myContainer( 0 ) +{ + initialize(); +} + +/*! + \brief Destructor. +*/ +QtxGroupBox::~QtxGroupBox() +{ +} + +/*! + \brief Initialize the group box. + + Creates horizontal box as container for title widgets. +*/ +void QtxGroupBox::initialize() +{ + myContainer = new QWidget( this ); + QHBoxLayout* base = new QHBoxLayout( myContainer ); + base->setMargin( 0 ); + base->setSpacing( 0 ); + + updateTitle(); +} + +/*! + \brief Add widget to the group box title. + \param wid widget being added to the title +*/ +void QtxGroupBox::insertTitleWidget( QWidget* wid ) +{ + if ( !myContainer ) + return; + + myContainer->layout()->addWidget( wid ); + wid->installEventFilter( this ); + + updateTitle(); +} + +/*! + \brief Remove widget from the group box title. + \param wid widget to be removed from the title +*/ +void QtxGroupBox::removeTitleWidget( QWidget* wid ) +{ + if ( !myContainer || wid->parentWidget() != myContainer ) + return; + + myContainer->layout()->removeWidget( wid ); + wid->setParent( 0 ); + wid->removeEventFilter( this ); + wid->hide(); + + updateTitle(); +} + +/*! + \brief Show/hide group box. + \param on if \c true, show group box, otherwise, hide it +*/ +void QtxGroupBox::setVisible( bool on ) +{ + if ( on ) + updateTitle(); + + QGroupBox::setVisible( on ); +} + +/*! + \brief Get recommended size for the widget. + \return recommended size for the widget +*/ +QSize QtxGroupBox::sizeHint() const +{ + return expandTo( QGroupBox::sizeHint() ); +} + +/*! + \brief Get recommended minimum size for the widget. + \return recommended minimum size for the widget +*/ +QSize QtxGroupBox::minimumSizeHint() const +{ + return expandTo( QGroupBox::minimumSizeHint() ); +} + +/*! + \brief Custom event filter. + \param obj event receiver + \param e event + \return \c true if event processing should be stopped +*/ +bool QtxGroupBox::eventFilter( QObject* obj, QEvent* e ) +{ + QEvent::Type type = e->type(); + if ( myContainer && obj->parent() == myContainer && + ( type == QEvent::Show || type == QEvent::ShowToParent || + type == QEvent::Hide || type == QEvent::HideToParent ) ) + QApplication::postEvent( this, new QEvent( QEvent::User ) ); + + return QGroupBox::eventFilter( obj, e ); +} +/*! + \brief Get central widget (or first found one). + \return widget +*/ +QWidget* QtxGroupBox::widget() const +{ + if ( !layout() ) + return 0; + + QWidget* w = 0; + for ( int i = 0; i < (int)layout()->count() && !w; i++ ) + w = layout()->itemAt( i )->widget(); + return w; +} + +/*! + \brief Set central widget to the group box. + \param wid widget being added to the group box +*/ +void QtxGroupBox::setWidget( QWidget* wid ) +{ + QWidget* w = widget(); + if ( w == wid ) + return; + + if ( layout() ) + layout()->removeWidget( w ); + + if ( !wid ) + delete layout(); + else if ( !layout() ) + { + QLayout* bl = new QVBoxLayout( this ); + bl->setMargin( 0 ); + bl->setSpacing( 0 ); + } + + if ( layout() ) + layout()->addWidget( wid ); + + if ( wid ) + wid->updateGeometry(); +} + +/*! + \brief Customize resize event. + \param e resize event +*/ +void QtxGroupBox::resizeEvent( QResizeEvent* e ) +{ + QGroupBox::resizeEvent( e ); + + updateTitle(); +} + +/*! + \brief Customize child event. + \param e child event +*/ +void QtxGroupBox::childEvent( QChildEvent* e ) +{ +/* + if ( e->type() == QEvent::ChildAdded && e->child() == myContainer ) + return; +*/ + QGroupBox::childEvent( e ); +} + +/*! + \brief Process custom events. + \param e custom event (not used) +*/ +void QtxGroupBox::customEvent( QEvent* /*e*/ ) +{ + updateTitle(); +} + +/*! + \brief Get the group box title size. + \return title size +*/ +QSize QtxGroupBox::titleSize() const +{ + return QSize( fontMetrics().width( title() ), fontMetrics().height() ); +} + +/*! + \brief Update the group box title. +*/ +void QtxGroupBox::updateTitle() +{ + if ( !myContainer ) + return; + + int align = alignment(); + + if ( title().isEmpty() ) + align = Qt::AlignRight; + + QSize ts = titleSize(); + + int m = 5; + + int w = width() - ts.width(); + if ( align == Qt::AlignCenter ) + w = w / 2; + + w -= m; + + myContainer->resize( myContainer->minimumSizeHint() ); + + bool vis = false; + const QObjectList list = myContainer->children(); + for ( QObjectList::const_iterator it = list.begin(); it != list.end() && !vis; ++it ) + vis = (*it)->isWidgetType() && ((QWidget*)(*it))->isVisibleTo( myContainer ); + + if ( !vis ) + myContainer->hide(); + else + { + int x = 0; + if ( align == Qt::AlignRight ) + x = rect().left() + m; + else + x = rect().right() - myContainer->width() - m; + + int y = rect().top() - ( myContainer->height() - ts.height() ) / 2; + + QPoint pos( x, qMax( 0, y ) ); + myContainer->move( pos ); + myContainer->show(); + } + + if ( layout() ) + { + if ( myContainer && myContainer->isVisibleTo( this ) ) + setInsideMargin( qMax( 0, myContainer->height() - ts.height() ) ); + else + setInsideMargin( 0 ); + } + + updateGeometry(); +} + +/*! + \brief Expand group box to the specified size. + \param sz new size +*/ +QSize QtxGroupBox::expandTo( const QSize& sz ) const +{ + int sh = 0; + int sw = titleSize().width(); + if ( myContainer && myContainer->isVisibleTo( (QWidget*)this ) ) + { + if ( alignment() == Qt::AlignCenter ) + sw += 2 * ( myContainer->width() + 5 ); + else + sw += 1 * ( myContainer->width() + 5 ); + sw += 20; + sh = myContainer->height() + 5; + } + return QSize( qMax( sz.width(), sw ), qMax( sz.height(), sh ) ); +} + +/*! + \brief Set group box's inside margin size. + \param m new inside margin size +*/ +void QtxGroupBox::setInsideMargin( const int m ) +{ + QVBoxLayout* bl = ::qobject_cast( layout() ); + + if ( !bl ) + return; + + QSpacerItem* spacer = 0; + if ( bl->count() ) + spacer = bl->itemAt( 0 )->spacerItem(); + + if ( !spacer ) + bl->insertSpacing( 0, m ); + else + spacer->changeSize( 0, m ); +} diff --git a/src/Qtx/QtxGroupBox.h b/src/Qtx/QtxGroupBox.h new file mode 100644 index 000000000..c2aa4e65b --- /dev/null +++ b/src/Qtx/QtxGroupBox.h @@ -0,0 +1,68 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxGroupBox.h +// Author: Sergey TELKOV + +#ifndef QTXGROUPBOX_H +#define QTXGROUPBOX_H + +#include "Qtx.h" + +#include + +class QTX_EXPORT QtxGroupBox : public QGroupBox +{ + Q_OBJECT + +public: + QtxGroupBox( QWidget* = 0 ); + QtxGroupBox( const QString&, QWidget* = 0 ); + virtual ~QtxGroupBox(); + + virtual void insertTitleWidget( QWidget* ); + virtual void removeTitleWidget( QWidget* ); + + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + + virtual bool eventFilter( QObject*, QEvent* ); + + QWidget* widget() const; + void setWidget( QWidget* ); + +public slots: + virtual void setVisible( bool ); + +protected: + virtual void childEvent( QChildEvent* ); + virtual void resizeEvent( QResizeEvent* ); + virtual void customEvent( QEvent* ); + +private: + void initialize(); + void updateTitle(); + QSize titleSize() const; + void setInsideMargin( const int ); + QSize expandTo( const QSize& ) const; + +private: + QWidget* myContainer; +}; + +#endif diff --git a/src/Qtx/QtxIntSpinBox.cxx b/src/Qtx/QtxIntSpinBox.cxx new file mode 100755 index 000000000..175a297ae --- /dev/null +++ b/src/Qtx/QtxIntSpinBox.cxx @@ -0,0 +1,149 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxIntSpinBox.cxx +// Author: Sergey TELKOV + +#include "QtxIntSpinBox.h" + +#include +/*! + \class QtxIntSpinBox + \brief Enhanced version of the Qt's spin box. + + The QtxIntSpinBox class represents the widget for entering the + integer values. In addition to the functionality provided by + QSpinBox, this class supports "cleared" state - this is the + state corresponding to "None" (or empty) entered value. + + To set "cleared" state use setCleared() method. To check if the spin + box stores "cleared" state, use isCleared() method. + For example: + \code + if (mySpinBox->isCleared()) { + ... // process "None" state + } + else { + int value = mySpinBox->value(); + ... // process entered value + } + \endcode +*/ + +/*! + \brief Constructor. + + Constructs a spin box with 0 as minimum value and 99 as maximum value, + a step value of 1. The value is initially set to 0. + + \param parent parent object +*/ +QtxIntSpinBox::QtxIntSpinBox( QWidget* parent ) +: QSpinBox( parent ), + myCleared( false ) +{ + connect( lineEdit(), SIGNAL( textChanged( const QString& ) ), + this, SLOT( onTextChanged( const QString& ) ) ); +} + +/*! + \brief Constructor. + + Constructs a spin box with specified minimum, maximum and step value. + The value is initially set to the minimum value. + + \param min spin box minimum possible value + \param max spin box maximum possible value + \param step spin box increment/decrement value + \param parent parent object +*/ +QtxIntSpinBox::QtxIntSpinBox( int min, int max, int step, QWidget* parent ) +: QSpinBox( parent ), + myCleared( false ) +{ + setMinimum( min ); + setMaximum( max ); + setSingleStep( step ); + + connect( lineEdit(), SIGNAL( textChanged( const QString& ) ), + this, SLOT( onTextChanged( const QString& ) ) ); +} + +/*! + \brief Destructor. +*/ +QtxIntSpinBox::~QtxIntSpinBox() +{ +} + +/*! + \brief Check if spin box is in the "cleared" state. + \return \c true if spin box is cleared +*/ +bool QtxIntSpinBox::isCleared() const +{ + return myCleared; +} + +/*! + \brief Change "cleared" status of the spin box. + \param on new "cleared" status +*/ +void QtxIntSpinBox::setCleared( const bool on ) +{ + if ( myCleared == on ) + return; + + myCleared = on; + setSpecialValueText( specialValueText() ); +} + +/*! + \brief Convert value to the text. + \param val value being converted + \return string containing the converted value +*/ +QString QtxIntSpinBox::textFromValue( int val ) const +{ + return myCleared ? QString() : QSpinBox::textFromValue( val ); +} + +/*! + \brief Perform \a steps increment/decrement steps. + + The \a steps value can be any integer number. If it is > 0, + the value incrementing is done, otherwise value is decremented + \a steps times. + + \param steps number of increment/decrement steps +*/ +void QtxIntSpinBox::stepBy( int steps ) +{ + myCleared = false; + + QSpinBox::stepBy( steps ); +} + +/*! + \brief Called when user enters the text in the spin box. + \param txt current spin box text (not used) +*/ +void QtxIntSpinBox::onTextChanged( const QString& ) +{ + myCleared = false; +} diff --git a/src/Qtx/QtxIntSpinBox.h b/src/Qtx/QtxIntSpinBox.h new file mode 100755 index 000000000..31580a1d8 --- /dev/null +++ b/src/Qtx/QtxIntSpinBox.h @@ -0,0 +1,53 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxIntSpinBox.h +// Author: Sergey TELKOV + +#ifndef QTXINTSPINBOX_H +#define QTXINTSPINBOX_H + +#include "Qtx.h" + +#include + +class QTX_EXPORT QtxIntSpinBox : public QSpinBox +{ + Q_OBJECT + +public: + QtxIntSpinBox( QWidget* = 0 ); + QtxIntSpinBox( int, int, int = 1, QWidget* = 0 ); + virtual ~QtxIntSpinBox(); + + bool isCleared() const; + virtual void setCleared( const bool ); + + virtual void stepBy( int ); + +protected slots: + virtual void onTextChanged( const QString& ); + +protected: + virtual QString textFromValue( int ) const; + +private: + bool myCleared; +}; + +#endif diff --git a/src/Qtx/QtxListAction.cxx b/src/Qtx/QtxListAction.cxx new file mode 100755 index 000000000..813d052ee --- /dev/null +++ b/src/Qtx/QtxListAction.cxx @@ -0,0 +1,927 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxListAction.cxx +// Author: Sergey TELKOV + +#include "QtxListAction.h" + +#include +#include +#include +#include +#include +#include +#include + +/*! + \class QtxListAction::ScrollEvent + \internal + \brief Event for the scrolling in the list of actions. +*/ + +class QtxListAction::ScrollEvent : public QEvent +{ +public: + enum { Scroll = User + 1 }; + + ScrollEvent( bool down ) : QEvent( (QEvent::Type)Scroll ), myDown( down ) {} + virtual ~ScrollEvent() {} + + bool isDown() const { return myDown; } + +private: + bool myDown; +}; + +/*! + \class QtxListAction::ListWidget + \internal + \brief List of actions. +*/ + +class QtxListAction::ListWidget : public QListWidget +{ +public: + ListWidget( QWidget* parent = 0 ) : QListWidget( parent ) {} + virtual ~ListWidget() {} + +protected: + virtual void scrollContentsBy( int dx, int dy ) + { + QListWidget::scrollContentsBy( dx, dy ); + if ( dy != 0 ) + QApplication::postEvent( viewport(), new ScrollEvent( dy <= 0 ) ); + } +}; + +/*! + \class QtxListAction::ListFrame + \internal + \brief Expanding frame with action list and comment. +*/ + +class QtxListAction::ListFrame: public QMenu +{ +public: + ListFrame( QtxListAction*, QWidget* parent ); + virtual ~ListFrame(); + + void clear(); + const QStringList names() const; + void addNames( const QStringList& ); + + void setSingleComment( const QString& ); + void setMultipleComment( const QString& ); + + int selected() const; + void setSelected( const int ); + + int linesNumber() const; + int charsNumber() const; + + void setLinesNumber( const int ); + void setCharsNumber( const int ); + + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + + virtual bool eventFilter( QObject*, QEvent* ); + + virtual void setVisible( bool ); + +protected: + virtual void keyPressEvent( QKeyEvent* ); + +private: + void accept(); + void updateComment(); + void setNames( const QStringList& ); + void removePostedEvens( QObject*, int ); + +private: + QListWidget* myList; + QStringList myNames; + QtxListAction* myAction; + QLabel* myComment; + + int myLines; + int myChars; + + QString mySingleComment; + QString myMultipleComment; +}; + +/*! + \brief Constructor. + \param a list action + \param parent parent widget +*/ +QtxListAction::ListFrame::ListFrame( QtxListAction* a, QWidget* parent ) +: QMenu( parent ), + myList( 0 ), + myAction( a ), + myComment( 0 ), + myLines( 5 ), + myChars( 5 ) +{ + QVBoxLayout* top = new QVBoxLayout( this ); + top->setMargin( 0 ); + QFrame* main = new QFrame( this ); + main->setFrameStyle( QFrame::Panel | QFrame::Raised ); + top->addWidget( main ); + + QVBoxLayout* base = new QVBoxLayout( main ); + base->setMargin( 3 ); + base->setSpacing( 2 ); + + myList = new ListWidget( main ); + myList->setSelectionMode( QListWidget::MultiSelection ); + myList->setVerticalScrollMode( QListWidget::ScrollPerItem ); + myList->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded ); + myList->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + myList->viewport()->installEventFilter( this ); + myList->viewport()->setMouseTracking( true ); + myList->setFocusPolicy( Qt::NoFocus ); + + myComment = new QLabel( main ); + myComment->setFrameStyle( QFrame::Panel | QFrame::Sunken ); + myComment->setAlignment( Qt::AlignCenter ); + myMultipleComment = "%1"; + + base->addWidget( myList ); + base->addWidget( myComment ); +} + +/*! + \brief Destructor. +*/ +QtxListAction::ListFrame::~ListFrame() +{ +} + +/*! + \brief Clear list of names. +*/ +void QtxListAction::ListFrame::clear() +{ + myNames.clear(); + setNames( myNames ); +} + +/*! + \brief Add names to the list. + + Truncates each name to fit the frame width. + Method QtxListAction::setCharsNumber(int) can be used to change + the frame width (in characters). + + \param names list of names to be added + \sa setNames(), QtxListAction::setCharsNumber(int) +*/ +void QtxListAction::ListFrame::addNames( const QStringList& names ) +{ + for ( QStringList::ConstIterator it = names.begin(); it != names.end(); ++it ) + myNames.append( *it ); + setNames( myNames ); +} + +/*! + \brief Set names to the list. + + Truncates each name to fit the frame width. + Method QtxListAction::setCharsNumber(int) can be used to change + the frame width (in characters). + + \param names list of names to be set + \sa addNames(), QtxListAction::setCharsNumber(int) +*/ +void QtxListAction::ListFrame::setNames( const QStringList& names ) +{ + if ( !myList ) + return; + + myList->clear(); + QStringList strList; + for ( QStringList::const_iterator it = names.begin(); it != names.end(); ++it ) + { + QString s = *it; + QFontMetrics fm = myList->fontMetrics(); + int maxW = charsNumber() * fm.maxWidth(); + int w = fm.width( s ); + if ( w > maxW ) + { + QString extra( "..." ); + int len = s.length(); + int extraLen = fm.width( extra ) + 1; + while ( true ) + { + w = fm.width( s, --len ); + if ( w + extraLen < maxW ) + { + s = s.left( len ); + break; + } + } + s += extra; + } + strList.append( s ); + } + myList->addItems( strList ); +} + +/*! + \brief Get list of names. + \return list of names +*/ +const QStringList QtxListAction::ListFrame::names() const +{ + return myNames; +} + +/*! + \brief Get maximum numer of lines shown without activation of vertical scroll bar. + \return number of lines + \sa setLinesNumber(), charsNumber(), setCharsNumber() +*/ +int QtxListAction::ListFrame::linesNumber() const +{ + return myLines; +} + +/*! + \brief Get maximum numer of characters in the line. + + If the name length is greater than this value, it will be truncated. + + \return number of characters + \sa setCharsNumber(), linesNumber(), setLinesNumber() +*/ +int QtxListAction::ListFrame::charsNumber() const +{ + return myChars; +} + +/*! + \brief Set maximum numer of lines shown without activation of vertical scroll bar. + \param maxLines number of lines + \sa linesNumber(), charsNumber(), setCharsNumber() +*/ +void QtxListAction::ListFrame::setLinesNumber( const int maxLines ) +{ + myLines = maxLines; +} + +/*! + \brief Set maximum numer of characters in the line. + + If the name length is greater than this value, it will be truncated. + + \param maxChars number of characters + \sa charsNumber(), linesNumber(), setLinesNumber() +*/ +void QtxListAction::ListFrame::setCharsNumber( const int maxChars ) +{ + if ( myChars == maxChars ) + return; + + myChars = maxChars; + setNames( myNames ); +} + +/*! + \brief Set comment which is displayed when single name is selected. + \param comment comment format +*/ +void QtxListAction::ListFrame::setSingleComment( const QString& comment ) +{ + mySingleComment = comment; + setNames( myNames ); + updateComment(); +} + +/*! + \brief Set comment which is displayed when multiple names are selected. + \param comment comment format +*/ +void QtxListAction::ListFrame::setMultipleComment( const QString& comment ) +{ + myMultipleComment = comment; + setNames( myNames ); + updateComment(); +} + +/*! + \brief Update displayed comment. +*/ +void QtxListAction::ListFrame::updateComment() +{ + QString com; + int selNum = selected(); + if ( selNum > 1 ) + com = myMultipleComment; + else if ( selNum > 0 && !mySingleComment.isEmpty() ) + com = mySingleComment; + + if ( !com.isEmpty() ) + com = com.arg( selNum ); + + myComment->setText( com ); +} + +/*! + \brief Get preferable size for the list widget. + \return preferable size +*/ +QSize QtxListAction::ListFrame::sizeHint() const +{ + return QSize( myList->fontMetrics().maxWidth() * charsNumber() + 10, + qMax( 1, linesNumber() ) * ( myList->fontMetrics().height() + 2 ) + + myComment->sizeHint().height() ); +} + +/*! + \brief Get preferable minimum size for the list widget. + \return preferable minimum size +*/ +QSize QtxListAction::ListFrame::minimumSizeHint() const +{ + return QSize( myList->fontMetrics().maxWidth() * charsNumber() + 10, + qMax( 1, linesNumber() ) * ( myList->fontMetrics().height() + 2 ) + + myComment->sizeHint().height() ); +} + +/*! + \brief Validate the action. +*/ +void QtxListAction::ListFrame::accept() +{ + int sel = selected(); + if ( sel && myAction ) + myAction->onMultiple( sel ); +} + +/*! + \brief Called when list widget is shown/hidden. + \param on if \c true, widget is shown, otherswise it is hidden +*/ +void QtxListAction::ListFrame::setVisible( bool on ) +{ + if ( on ) + { + myList->setFocus(); + myList->scrollToItem( myList->item( 0 ), QListWidget::PositionAtTop ); + setSelected( 0 ); + updateComment(); + } + + QMenu::setVisible( on ); +} + +/*! + \brief Process key press event. + + The following keys are supported: + - Up/Down + - PageUp/PageDown + - Enter + - Escape + + \param e key press event +*/ +void QtxListAction::ListFrame::keyPressEvent( QKeyEvent* e ) +{ + if ( e->type() == QEvent::KeyRelease ) + return; + + e->accept(); + + int selNum = selected(); + switch( e->key() ) + { + case Qt::Key_Up: + setSelected( qMax( 1, selNum - 1 ) ); + break; + case Qt::Key_Down: + setSelected( qMax( 1, selNum + 1 ) ); + break; + case Qt::Key_PageUp: + setSelected( qMax( 1, selNum - linesNumber() ) ); + break; + case Qt::Key_PageDown: + setSelected( selNum += linesNumber() ); + break; + case Qt::Key_Home: + setSelected( 1 ); + break; + case Qt::Key_End: + setSelected( myList->count() ); + break; + case Qt::Key_Return: + accept(); + break; + case Qt::Key_Escape: + hide(); + break; + } +} + +/*! + \brief Process mouse events on the viewport of the list widget. + \param o object recieving event (viewport) + \param e event + \return \c true if further event processing should be stopped. +*/ +bool QtxListAction::ListFrame::eventFilter( QObject* o, QEvent* e ) +{ + bool res = true; + + switch( e->type() ) + { + case QEvent::MouseMove: + { + QMouseEvent* me = (QMouseEvent*)e; + if ( !myList->viewport()->rect().contains( me->pos() ) ) + setSelected( 0 ); + else if ( myList->itemAt( me->pos() ) ) + setSelected( myList->row( myList->itemAt( me->pos() ) ) + 1 ); + } + break; + case QEvent::MouseButtonRelease: + accept(); + case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: + break; + case ScrollEvent::Scroll: + { + ScrollEvent* se = (ScrollEvent*)e; + QPoint pos = myList->viewport()->mapFromGlobal( QCursor::pos() ); + if ( myList->viewport()->rect().contains( pos ) ) + { + if ( myList->itemAt( pos ) ) + setSelected( myList->row( myList->itemAt( pos ) ) + 1 ); + } + else if ( se->isDown() ) + setSelected( myList->row( myList->itemAt( myList->viewport()->rect().bottomLeft() - + QPoint( 0, myList->fontMetrics().height() / 2 ) ) ) + 1 ); + else + setSelected( myList->row( myList->itemAt( myList->viewport()->rect().topLeft() + + QPoint( 0, myList->fontMetrics().height() / 2 ) ) ) + 1 ); + } + break; + default: + res = false; + break; + } + + if ( res ) + return true; + else + return QMenu::eventFilter( o, e ); +} + +/*! + \brief Get number of selected names. + \return number of selected items +*/ +int QtxListAction::ListFrame::selected() const +{ + int sel = 0; + QModelIndexList indexes = myList->selectionModel()->selectedRows(); + for ( QModelIndexList::const_iterator it = indexes.begin(); it != indexes.end(); ++it ) + sel = qMax( sel, (*it).row() + 1 ); + + return sel; +} + +/*! + \brief Set number of selected names. + \param lastSel number of items to be selected +*/ +void QtxListAction::ListFrame::setSelected( const int lastSel ) +{ + int last = qMin( lastSel, (int)myList->count() ); + + QItemSelection selection; + QItemSelectionModel* selModel = myList->selectionModel(); + + for ( int i = 0; i < last; i++ ) + selection.select( selModel->model()->index( i, 0 ), selModel->model()->index( i, 0 ) ); + + selModel->select( selection, QItemSelectionModel::ClearAndSelect ); + + int item = last - 1; + + myList->scrollToItem( myList->item( item ) ); + myList->clearFocus(); + + removePostedEvens( myList->viewport(), ScrollEvent::Scroll ); + + updateComment(); +} + +/*! + \brief Filter all events of specified type sent to specified object. + \param o object + \param type event type to be filtered +*/ +void QtxListAction::ListFrame::removePostedEvens( QObject* o, int type ) +{ + class Filter : public QObject + { + public: + Filter() : QObject( 0 ) {} + virtual bool eventFilter( QObject*, QEvent* ) + { + return true; + } + }; + + Filter f; + o->installEventFilter( &f ); + QApplication::sendPostedEvents( o, type ); +} + +/*! + \class QtxListAction + \brief Action with associated list of items. + + This class can be helpuful, for example, for creation of Undo/Redo + toolbar items which show list of available commands in the popup list box. +*/ + +/*! + \brief Constructor. + \param parent parent object +*/ +QtxListAction::QtxListAction( QObject* parent ) +: QWidgetAction( parent ), + myFrame( 0 ) +{ + initialize(); +} + +/*! + \brief Constructor. + \param icon action icon + \param menuText menu text + \param accel key accelerator + \param parent parent object +*/ +QtxListAction::QtxListAction( const QIcon& icon, const QString& menuText, + int accel, QObject* parent ) +: QWidgetAction( parent ), + myFrame( 0 ) +{ + setIcon( icon ); + setText( menuText ); + setShortcut( accel ); + + initialize(); +} + +/*! + \brief Constructor. + \param menuText menu text + \param accel key accelerator + \param parent parent object +*/ +QtxListAction::QtxListAction( const QString& menuText, int accel, QObject* parent ) +: QWidgetAction( parent ), + myFrame( 0 ) +{ + setText( menuText ); + setShortcut( accel ); + + initialize(); +} + +/*! + \brief Constructor. + \param text action description text (tooltip) + \param menuText menu text + \param accel key accelerator + \param parent parent object +*/ +QtxListAction::QtxListAction( const QString& text, const QString& menuText, + int accel, QObject* parent ) +: QWidgetAction( parent ), + myFrame( 0 ) +{ + setText( menuText ); + setShortcut( accel ); + setToolTip( text ); + + initialize(); +} + +/*! + \brief Constructor. + \param text action description text (tooltip) + \param icon action icon + \param menuText menu text + \param accel key accelerator + \param parent parent object +*/ +QtxListAction::QtxListAction( const QString& text, const QIcon& icon, + const QString& menuText, int accel, QObject* parent ) +: QWidgetAction( parent ), + myFrame( 0 ) +{ + setIcon( icon ); + setText( menuText ); + setShortcut( accel ); + setToolTip( text ); + + initialize(); +} + +/*! + \brief Destructor. +*/ +QtxListAction::~QtxListAction() +{ + delete myFrame; + myFrame = 0; +} + +/*! + \brief Get popup mode. + \return current popup mode (QtxListAction::PopupMode) + \sa setPopupMode() +*/ +int QtxListAction::popupMode() const +{ + return menu() ? SubMenu : Item; +} + +/*! + \brief Set popup mode. + \param mode new popup mode (QtxListAction::PopupMode) + \sa popupMode() +*/ +void QtxListAction::setPopupMode( const int mode ) +{ + if ( mode == popupMode() ) + return; + + if ( mode == Item ) + { + delete menu(); + setMenu( 0 ); + } + else + setMenu( new QMenu( 0 ) ); + + onChanged(); +} + +/*! + \brief Get current list of names. + \return list of names +*/ +QStringList QtxListAction::names() const +{ + QStringList lst; + if ( myFrame ) + lst = myFrame->names(); + return lst; +} + +/*! + \brief Add names to the list. + + Truncates each name to fit the frame width. + Method setCharsNumber() can be used to change + the frame width (in characters). + + \param names list of names to be added + \param clear if \c true, remove the old contents from the list + \sa setCharsNumber() +*/ +void QtxListAction::addNames( const QStringList& names, bool clear ) +{ + if ( !myFrame ) + return; + + if ( clear ) + myFrame->clear(); + + myFrame->addNames( names ); + + onChanged(); +} + +/*! + \brief Get maximum numer of lines shown without activation of vertical scroll bar. + \return number of lines + \sa setLinesNumber(), charsNumber(), setCharsNumber() +*/ +int QtxListAction::linesNumber() const +{ + return myFrame->linesNumber(); +} + +/*! + \brief Get maximum numer of characters in the line. + + If the name length is greater than this value, it will be truncated. + + \return number of characters + \sa setCharsNumber(), linesNumber(), setLinesNumber() +*/ +int QtxListAction::charsNumber() const +{ + return myFrame->charsNumber(); +} + +/*! + \brief Set maximum numer of lines shown without activation of vertical scroll bar. + \param nlines number of lines (5 by default) + \sa linesNumber(), charsNumber(), setCharsNumber() +*/ +void QtxListAction::setLinesNumber( const int nlines ) +{ + myFrame->setLinesNumber( nlines ); +} + +/*! + \brief Set maximum numer of characters in the line. + + If the name length is greater than this value, it will be truncated. + + \param maxChars number of characters (5 by default) + \sa charsNumber(), linesNumber(), setLinesNumber() +*/ + +void QtxListAction::setCharsNumber( const int nchars ) +{ + myFrame->setCharsNumber( nchars ); +} + +/*! + \brief Set the format Qt string for comments displayed under the list + of actions for one action and for several actions. + + Example: "Undo %1 actions" format string will work as "Undo 3 actions" + when 3 actions are selected. The default format string is "%1". + + \param c single action comment format + \param c multiple actions comment format +*/ +void QtxListAction::setComment( const QString& c, const QString& sc ) +{ + if ( !myFrame ) + return; + + myFrame->setSingleComment( sc.isEmpty() ? c : sc ); + myFrame->setMultipleComment( c ); +} + +/*! + \brief Create action widget. + + This function is called whenever the action is added + to a container widget that supports custom widgets like menu or toolbar. + + \param parent container widget the action is added to + \return tool button for toolbar and 0 otherwise +*/ +QWidget* QtxListAction::createWidget( QWidget* parent ) +{ + if ( parent && parent->inherits( "QMenu" ) ) + return 0; + + QToolButton* tb = new QToolButton( parent ); + tb->setText( text() ); + tb->setIcon( icon() ); + tb->setPopupMode( QToolButton::MenuButtonPopup ); + tb->setMenu( myFrame ); + tb->setEnabled( isEnabled() && !names().isEmpty() ); + tb->setToolTip( toolTip() ); + connect( tb, SIGNAL( clicked( bool ) ), this, SLOT( onSingle( bool ) ) ); + + return tb; +} + +/*! + \brief Destroy action widget. + + This function is called whenever the action is removed + from a container widget that supports custom widgets like menu or toolbar. + + \param widget container widget the action is removed from +*/ +void QtxListAction::deleteWidget( QWidget* widget ) +{ + delete widget; +} + +/*! + \brief Initialize the action. +*/ +void QtxListAction::initialize() +{ + setPopupMode( Item ); + + myFrame = new QtxListAction::ListFrame( this, 0 ); + myFrame->setLinesNumber( 7 ); + myFrame->setCharsNumber( 5 ); + + myFrame->hide(); + + connect( this, SIGNAL( changed() ), this, SLOT( onChanged() ) ); + connect( this, SIGNAL( triggered( bool ) ), this, SLOT( onSingle( bool ) ) ); +} + +/*! + \brief Called the action contents is changed. +*/ +void QtxListAction::onChanged() +{ + QStringList lst = myFrame->names(); + + if ( menu() ) + { + menu()->clear(); + for ( QStringList::iterator iter = lst.begin(); iter != lst.end(); ++iter ) + { + QAction* a = new QAction( *iter, menu() ); + menu()->addAction( a ); + connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onTriggered( bool ) ) ); + } + } + + QList widList = createdWidgets(); + for ( QList::iterator it = widList.begin(); it != widList.end(); ++it ) + { + (*it)->setEnabled( isEnabled() && !lst.isEmpty() ); + QToolButton* tb = ::qobject_cast( *it ); + if ( tb ) + { + tb->setText( text() ); + tb->setIcon( icon() ); + tb->setToolTip( toolTip() ); + } + } +} + +/*! + \brief Called when a user click action button. + \param on (not used) +*/ + +void QtxListAction::onSingle( bool /*on*/ ) +{ + onMultiple( 1 ); +} + +/*! + \brief Called when multiple items are selected. +*/ +void QtxListAction::onMultiple( const int numActions ) +{ + if ( myFrame ) + myFrame->hide(); + + if ( numActions > 0 ) + emit activated( numActions ); +} + +/*! + \brief Called when user activates an items in the popup sub menu. + \param on (not used) +*/ +void QtxListAction::onTriggered( bool /*on*/ ) +{ + if ( !menu() ) + return; + + QList actionList = menu()->actions(); + int idx = actionList.indexOf( ::qobject_cast( sender() ) ); + if ( idx < 0 ) + return; + + emit activated( idx + 1 ); +} + +/*! + \fn QtxListAction::activated(int numItems ); + \brief This signal is emitted when an action is activated. + \param numItems number of items being selected in the action list. +*/ diff --git a/src/Qtx/QtxListAction.h b/src/Qtx/QtxListAction.h new file mode 100755 index 000000000..182698551 --- /dev/null +++ b/src/Qtx/QtxListAction.h @@ -0,0 +1,96 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxListAction.h +// Author: Sergey TELKOV + +#ifndef QTXLISTACTION_H +#define QTXLISTACTION_H + +#include "Qtx.h" + +#include +#include + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +class QTX_EXPORT QtxListAction : public QWidgetAction +{ + Q_OBJECT + + class ListFrame; + class ListWidget; + class ScrollEvent; + +public: + //! Popup mode + enum { + Item, //!< action is added to popup menu as menu item + SubMenu //!< action is added to popup menu as sub menu with list of items + } PopupMode; + +public: + QtxListAction( QObject* = 0 ); + QtxListAction( const QString&, int, QObject* ); + QtxListAction( const QString&, const QString&, int, QObject* ); + QtxListAction( const QIcon&, const QString&, int, QObject* ); + QtxListAction( const QString&, const QIcon&, const QString&, int, QObject* ); + virtual ~QtxListAction(); + + int popupMode() const; + void setPopupMode( const int ); + + QStringList names() const; + void addNames( const QStringList&, bool = true ); + void setComment( const QString&, const QString& = QString() ); + + int linesNumber() const; + int charsNumber() const; + + void setLinesNumber( const int ); + void setCharsNumber( const int ); + +signals: + void activated( int ); + +private slots: + void onChanged(); + void onMultiple( const int ); + void onSingle( bool = false ); + void onTriggered( bool = false ); + +protected: + virtual QWidget* createWidget( QWidget* ); + virtual void deleteWidget( QWidget* ); + +private: + void initialize(); + +private: + ListFrame* myFrame; //!< list of actions shown as submenu + + friend class QtxListAction::ListFrame; +}; + +#ifdef WIN32 +#pragma warning( default:4251 ) +#endif + +#endif diff --git a/src/Qtx/QtxLogoMgr.cxx b/src/Qtx/QtxLogoMgr.cxx index 47a8d5628..e04d32fdf 100644 --- a/src/Qtx/QtxLogoMgr.cxx +++ b/src/Qtx/QtxLogoMgr.cxx @@ -16,6 +16,9 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// File: QtxLogoMgr.cxx +// Author: Sergey TELKOV + #include "QtxLogoMgr.h" #include @@ -153,12 +156,12 @@ void QtxLogoMgr::LogoBox::updateContents() base->setMargin( 0 ); base->setSpacing( 3 ); - if ( myCornWid ) - base->addWidget( myCornWid ); - for ( QList::const_iterator it = myLabels.begin(); it != myLabels.end(); ++it ) base->addWidget( *it ); + if ( myCornWid ) + base->addWidget( myCornWid ); + QApplication::sendPostedEvents(); } @@ -406,7 +409,7 @@ void QtxLogoMgr::generate() int QtxLogoMgr::find( const QString& id ) const { int idx = -1; - for ( uint i = 0; i < myLogos.count() && idx < 0; i++ ) + for ( int i = 0; i < myLogos.count() && idx < 0; i++ ) { if ( myLogos.at( i ).id == id ) idx = i; diff --git a/src/Qtx/QtxLogoMgr.h b/src/Qtx/QtxLogoMgr.h index ff43fddaa..73b49ee5a 100644 --- a/src/Qtx/QtxLogoMgr.h +++ b/src/Qtx/QtxLogoMgr.h @@ -16,8 +16,11 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#ifndef QTX_LOGOMGR_H -#define QTX_LOGOMGR_H +// File: QtxLogoMgr.h +// Author: Sergey TELKOV + +#ifndef QTXLOGOMGR_H +#define QTXLOGOMGR_H #include "Qtx.h" @@ -66,12 +69,12 @@ private: void movies( const QString&, QList& ) const; private: - LogoBox* myBox; - LogoList myLogos; + LogoBox* myBox; //!< widget containing logox + LogoList myLogos; //!< list of logo data }; #ifdef WIN32 #pragma warning( default : 4251 ) #endif -#endif +#endif // QTXLOGOMGR_H diff --git a/src/Qtx/QtxMRUAction.h b/src/Qtx/QtxMRUAction.h index bb4dca638..f8a5dd9b0 100755 --- a/src/Qtx/QtxMRUAction.h +++ b/src/Qtx/QtxMRUAction.h @@ -24,7 +24,6 @@ #include "QtxAction.h" -#include #include class QtxResourceMgr; @@ -37,10 +36,13 @@ class QTX_EXPORT QtxMRUAction : public QtxAction { Q_OBJECT - Q_PROPERTY( int visibleCount READ visibleCount WRITE setVisibleCount ) - public: - enum { MoveFirst, MoveLast, AddFirst, AddLast }; + //! Items insertion policy + typedef enum { MoveFirst, //!< put the specified item to the beginning + MoveLast, //!< put the specified item to the end + AddFirst, //!< if specified item doesn't exist, add it to the beginning + AddLast //!< if specified item doesn't exist, add it to the end + } InsertionMode; public: QtxMRUAction( QObject* = 0 ); @@ -68,7 +70,7 @@ public: virtual void loadLinks( QtxResourceMgr*, const QString&, const bool = true ); virtual void saveLinks( QtxResourceMgr*, const QString&, const bool = true ) const; -Q_SIGNALS: +signals: void activated( const QString& ); private slots: @@ -79,9 +81,9 @@ private: void updateMenu(); private: - QStringList myLinks; - int myVisCount; - int myInsertMode; + QStringList myLinks; //!< most recent used items + int myVisCount; //!< number of visible MRU items + int myInsertMode; //!< items insertion policy }; #endif diff --git a/src/Qtx/QtxMainWindow.cxx b/src/Qtx/QtxMainWindow.cxx index 8ecc6e96c..7ca329ac2 100644 --- a/src/Qtx/QtxMainWindow.cxx +++ b/src/Qtx/QtxMainWindow.cxx @@ -24,16 +24,17 @@ #include "QtxToolBar.h" #include "QtxResourceMgr.h" -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include /*! - Class: QtxMainWindow::Filter [Internal] - Descr: Internal object with event filter for QtxMainWindow. + \class QtxMainWindow::Filter + \internal + \brief Internal object used to filter child removal events for + specified widget from parent widget. */ class QtxMainWindow::Filter : public QObject @@ -45,30 +46,39 @@ public: virtual bool eventFilter( QObject*, QEvent* ); private: - QMainWindow* myMain; - QWidget* myWidget; + QMainWindow* myMain; //!< parent main window + QWidget* myWidget; //!< widget being watched }; /*! - Constructor + \brief Constructor. + \param wid widget to be watched + \param mw parent main window + \param parent parent object (in terms of QObject) */ QtxMainWindow::Filter::Filter( QWidget* wid, QtxMainWindow* mw, QObject* parent ) : QObject( parent ), -myMain( mw ), -myWidget( wid ) + myMain( mw ), + myWidget( wid ) { QApplication::instance()->installEventFilter( this ); }; /*! - Destructor + \brief Destructor. */ QtxMainWindow::Filter::~Filter() { } /*! - Custom event filter + \brief Event filter. + + Watches for the specified widget and prevents its removal from the + parent main window. + + \param o recevier object + \param e event */ bool QtxMainWindow::Filter::eventFilter( QObject* o, QEvent* e ) { @@ -79,21 +89,27 @@ bool QtxMainWindow::Filter::eventFilter( QObject* o, QEvent* e ) return QObject::eventFilter( o, e ); } + +/*! + \class QtxMainWindow + \brief Enhanced main window which supports dockable menubar and status bar + plus geometry saving/restoring. +*/ + /*! - Class: QtxMainWindow [Public] - Descr: Main window with support of dockable menubar/status bar - and geometry store/retrieve. + \brief Constructor. + \param parent parent widget + \param f widget flags (Qt::WindowFlags) */ QtxMainWindow::QtxMainWindow( QWidget* parent, Qt::WindowFlags f ) : QMainWindow( parent, f ), -myMode( -1 ), -myMenuBar( 0 ), -myStatusBar( 0 ) + myMenuBar( 0 ), + myStatusBar( 0 ) { } /*! - Destructor + \brief Destructor. */ QtxMainWindow::~QtxMainWindow() { @@ -102,16 +118,18 @@ QtxMainWindow::~QtxMainWindow() } /*! - \return true if menu bar exists + \brief Check if the menu bar is dockable. + \return \c true if dockable menu bar exists */ bool QtxMainWindow::isDockableMenuBar() const { - return myMenuBar; + return myMenuBar != 0; } /*! - Creates or deletes menu bar - \param on - if it is true, then to create, otherwise - to delete + \brief Set menu bar dockable/undockable. + \param on if \c true, make menu bar dockable, otherwise + make menu bar undockable */ void QtxMainWindow::setDockableMenuBar( const bool on ) { @@ -147,7 +165,8 @@ void QtxMainWindow::setDockableMenuBar( const bool on ) } /*! - \return true if status bar exists + \brief Check if the status bar is dockable. + \return \c true if dockable status bar exists */ bool QtxMainWindow::isDockableStatusBar() const { @@ -155,8 +174,9 @@ bool QtxMainWindow::isDockableStatusBar() const } /*! - Creates or deletes status bar - \param on - if it is true, then to create, otherwise - to delete + \brief Set status bar dockable/undockable. + \param on if \c true, make status bar dockable, otherwise + make status bar undockable */ void QtxMainWindow::setDockableStatusBar( const bool on ) { @@ -193,7 +213,11 @@ void QtxMainWindow::setDockableStatusBar( const bool on ) } } -QString QtxMainWindow::saveGeometry() const +/*! + \brief Dump main window geometry to the string. + \return string represenation of the window geometry +*/ +QString QtxMainWindow::storeGeometry() const { QRect frame = frameGeometry(); QRect screen = QApplication::desktop()->availableGeometry( this ); @@ -236,7 +260,11 @@ QString QtxMainWindow::saveGeometry() const return geom; } -void QtxMainWindow::loadGeometry( const QString& str ) +/*! + \brief Restore main window geometry from the string. + \param str string represenation of the window geometry +*/ +void QtxMainWindow::retrieveGeometry( const QString& str ) { QString geom = str; geom.remove( '\t' ); @@ -268,7 +296,7 @@ void QtxMainWindow::loadGeometry( const QString& str ) rect.setSize( QSize( w, h ) ); } - QRegExp posRx( "([+|-]\\d+\%?)\\s*([+|-]\\d+\%?)" ); + QRegExp posRx( "([+|-]\\d+%?)\\s*([+|-]\\d+%?)" ); if ( posRx.indexIn( geom ) != -1 ) { int x = -1; @@ -316,6 +344,19 @@ void QtxMainWindow::loadGeometry( const QString& str ) setWindowState( state ); } +/*! + \brief Retrieve numerical value from the string. + + Numerical value in the string have the structure [+|-]\d*[%], + that is one or more digits which can start from "+" or "-" and + can end with "%" symbol. + + \param str string being converted + \param num returning value (> 0) + \param percent if string ends with "%" this parameter is equal to \c true after + returning from the function + \return -1 if value < 0, 1 if value > 0 and 0 in case of error +*/ int QtxMainWindow::geometryValue( const QString& str, int& num, bool& percent ) const { num = -1; @@ -340,158 +381,11 @@ int QtxMainWindow::geometryValue( const QString& str, int& num, bool& percent ) } /*! - Retrieve the geometry information from the specified resource manager section. - \param resMgr - instance of ersource manager - \param section - section name -*/ -void QtxMainWindow::loadGeometry( QtxResourceMgr* resMgr, const QString& section ) -{ - QString sec = section.trimmed(); - if ( !resMgr || sec.isEmpty() ) - return; - /* - int winState = -1; - if ( !resMgr->value( sec, "state", winState ) ) - { - QString stateStr; - if ( resMgr->value( sec, "state", stateStr ) ) - winState = windowState( stateStr ); - } - - int win_w = resMgr->integerValue( sec, "width", width() ); - int win_h = resMgr->integerValue( sec, "height", height() ); - - int winPosX = windowPosition( resMgr->stringValue( sec, QString( "pos_x" ), QString::null ) ); - int winPosY = windowPosition( resMgr->stringValue( sec, QString( "pos_y" ), QString::null ) ); - - QWidget* desk = QApplication::desktop(); - - int win_x = 0; - if ( winPosX == WP_Absolute ) - win_x = resMgr->integerValue( sec, "pos_x", x() ); - else if ( desk ) - win_x = relativeCoordinate( winPosX, desk->width(), win_w ); - - int win_y = 0; - if ( winPosX == WP_Absolute ) - win_y = resMgr->integerValue( sec, "pos_y", y() ); - else if ( desk ) - win_y = relativeCoordinate( winPosY, desk->height(), win_h ); - - bool vis = isVisibleTo( parentWidget() ); - - resize( win_w, win_h ); - move( win_x, win_y ); - - myMode = -1; - */ -/* - if ( vis ) - QApplication::postEvent( this, new QEvent( QEvent::User, (void*)winState ) ); - else - myMode = winState; -*/ -} - -/*! - Shows main window -*/ -void QtxMainWindow::show() -{ -/* - if ( myMode != -1 ) - QApplication::postEvent( this, new QCustomEvent( QEvent::User, (void*)myMode ) ); -*/ - myMode = -1; - - QMainWindow::show(); -} - -/*! - Handler of custom events -*/ -void QtxMainWindow::customEvent( QEvent* e ) -{ - QMainWindow::customEvent( e ); - - int mode = WS_Normal; -// int mode = (int)e->data(); - switch ( mode ) - { - case WS_Normal: - showNormal(); - break; - case WS_Minimized: - showMinimized(); - break; - case WS_Maximized: - showMaximized(); - break; - } -} - -/*! - \return relative co-ordinate by two points - \param type - type of result: WP_Center (center), WP_Left (left), WP_Right (right) - \param wh - left point - \param WH - right point -*/ -/* -int QtxMainWindow::relativeCoordinate( const int type, const int WH, const int wh ) const -{ - int res = 0; - switch ( type ) - { - case WP_Center: - res = ( WH - wh ) / 2; - break; - case WP_Left: - res = 0; - break; - case WP_Right: - res = WH - wh; - break; - } - return res; -} -*/ - -/*! - Store the geometry information into the specified resource manager section. - \param resMgr - instance of ersource manager - \param section - section name -*/ -void QtxMainWindow::saveGeometry( QtxResourceMgr* resMgr, const QString& section ) const -{ - QString sec = section.trimmed(); - if ( !resMgr || sec.isEmpty() ) - return; - /* - resMgr->setValue( sec, "pos_x", pos().x() ); - resMgr->setValue( sec, "pos_y", pos().y() ); - resMgr->setValue( sec, "width", width() ); - resMgr->setValue( sec, "height", height() ); - - int winState = WS_Normal; - if ( isMinimized() ) - winState = WS_Minimized; - else if ( isMaximized() ) - winState = WS_Maximized; - - resMgr->setValue( sec, "state", winState ); - */ -} + \brief Called when child object (menu bar, status bar) is destroyed. + + Clears internal pointer to prevent crashes. -/*! - Custom event filter -*/ -bool QtxMainWindow::eventFilter( QObject* o, QEvent* e ) -{ - return QMainWindow::eventFilter( o, e ); -} - -/*! - SLOT: called on object destroyed, clears internal fields in case of deletion of menu bar or status bar + \param obj signal sender (object being destroyed) */ void QtxMainWindow::onDestroyed( QObject* obj ) { @@ -514,58 +408,3 @@ void QtxMainWindow::onDestroyed( QObject* obj ) } } -/*! - \return flag of window state by it's name - \param str - name of flag -*/ -/* -int QtxMainWindow::windowState( const QString& str ) const -{ - static QMap winStateMap; - if ( winStateMap.isEmpty() ) - { - winStateMap["normal"] = WS_Normal; - winStateMap["min"] = WS_Minimized; - winStateMap["mini"] = WS_Minimized; - winStateMap["minimized"] = WS_Minimized; - winStateMap["max"] = WS_Maximized; - winStateMap["maxi"] = WS_Maximized; - winStateMap["maximized"] = WS_Maximized; - winStateMap["hidden"] = WS_Hidden; - winStateMap["hided"] = WS_Hidden; - winStateMap["hide"] = WS_Hidden; - winStateMap["invisible"] = WS_Hidden; - } - - int res = -1; - QString stateStr = str.trimmed().toLower(); - if ( winStateMap.contains( stateStr ) ) - res = winStateMap[stateStr]; - return res; -} -*/ - -/*! - \return flag of position by it's name - \param str - name of position -*/ -/* -int QtxMainWindow::windowPosition( const QString& str ) const -{ - static QMap winPosMap; - if ( winPosMap.isEmpty() ) - { - winPosMap["center"] = WP_Center; - winPosMap["left"] = WP_Left; - winPosMap["right"] = WP_Right; - winPosMap["top"] = WP_Top; - winPosMap["bottom"] = WP_Bottom; - } - - int res = WP_Absolute; - QString posStr = str.trimmed().toLower(); - if ( winPosMap.contains( posStr ) ) - res = winPosMap[posStr]; - return res; -} -*/ diff --git a/src/Qtx/QtxMainWindow.h b/src/Qtx/QtxMainWindow.h index 833a95e71..10accc407 100644 --- a/src/Qtx/QtxMainWindow.h +++ b/src/Qtx/QtxMainWindow.h @@ -24,9 +24,8 @@ #include "Qtx.h" -#include +#include -class QDockWindow; class QtxResourceMgr; class QTX_EXPORT QtxMainWindow : public QMainWindow @@ -35,9 +34,6 @@ class QTX_EXPORT QtxMainWindow : public QMainWindow class Filter; - enum { WS_Normal, WS_Minimized, WS_Maximized, WS_Hidden }; - enum { WP_Absolute, WP_Center, WP_Left, WP_Right, WP_Top = WP_Left, WP_Bottom = WP_Right }; - public: QtxMainWindow( QWidget* = 0, Qt::WindowFlags = 0 ); virtual ~QtxMainWindow(); @@ -48,33 +44,18 @@ public: bool isDockableStatusBar() const; void setDockableStatusBar( const bool ); - QString saveGeometry() const; - void loadGeometry( const QString& ); - - void loadGeometry( QtxResourceMgr*, const QString& ); - void saveGeometry( QtxResourceMgr*, const QString& ) const; - - virtual bool eventFilter( QObject*, QEvent* ); - -public slots: - virtual void show(); - -protected: - virtual void customEvent( QEvent* ); + QString storeGeometry() const; + void retrieveGeometry( const QString& ); private slots: void onDestroyed( QObject* ); private: int geometryValue( const QString&, int&, bool& ) const; -// int windowState( const QString& ) const; -// int windowPosition( const QString& ) const; -// int relativeCoordinate( const int, const int, const int ) const; private: - int myMode; - QToolBar* myMenuBar; - QToolBar* myStatusBar; + QToolBar* myMenuBar; //!< dockable menu bar + QToolBar* myStatusBar; //!< dockable status bar }; -#endif +#endif // QTXMAINWINDOW_H diff --git a/src/Qtx/QtxMap.h b/src/Qtx/QtxMap.h new file mode 100644 index 000000000..403fc3284 --- /dev/null +++ b/src/Qtx/QtxMap.h @@ -0,0 +1,210 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxMap.h +// Author: Vadim SANDLER + +#ifndef QTXMAP_H +#define QTXMAP_H + +template class IMap; +template class IMapIterator; +template class IMapConstIterator; + +/*! + \brief Indexed map template class. +*/ +template class IMap +{ +public: + typedef IMapIterator Iterator; + typedef IMapConstIterator ConstIterator; + +public: + IMap() {} + IMap( const IMap& m ) : myKeys( m.myKeys ), myData( m.myData ) {} + IMap& operator=( const IMap& m ) { myKeys = m.myKeys; myData = m.myData; return *this; } + + int count() const { return myData.count(); } + int size() const { return myData.count(); } + bool empty() const { return myData.empty(); } + bool isEmpty() const { return myData.empty(); } + + void clear() { myKeys.clear(); myData.clear(); } + + QList keys() const { return myKeys; } + QList values() const { QList l; for ( int i = 0; i < count(); i++ ) l.append( value( i ) ); return l; } + bool contains ( const Key& key ) const { return myData.contains( key ); } + + Iterator begin() { return Iterator( this ); } + Iterator end() { return Iterator( this, count() ); } + ConstIterator begin() const { return ConstIterator( this ); } + ConstIterator end() const { return ConstIterator( this, count() ); } + + Iterator insert( const Key& key, const Value& value, bool overwrite = true ) + { + if ( myData.find( key ) == myData.end() || overwrite ) + { + if ( myData.find( key ) != myData.end() && overwrite ) + myKeys.removeAt( myKeys.indexOf( key ) ); + myKeys.append( key ); + myData[key] = value; + } + return Iterator( this, index( key ) ); + } + + Iterator replace( const Key& key, const Value& value ) + { + if ( myData.find( key ) == myData.end() ) + myKeys.append( key ); + myData[ key ] = value; + return Iterator( this, index( key ) ); + } + + int index( const Key& key ) const { return myKeys.indexOf( key ); } + Iterator at( const int index ) { return Iterator( this, index ); } + ConstIterator at( const int index ) const { return ConstIterator( this, index ); } + + Key& key( const int index ) + { + if ( index < 0 || index >= (int)myKeys.count() ) + return dummyKey; + return myKeys[index]; + } + + Value value( const int index ) + { + if ( index < 0 || index >= (int)myKeys.count() ) + return dummyValue; + return myData[ myKeys[index] ]; + } + + Value operator[]( const Key& key ) + { + if ( myData.find( key ) == myData.end() ) + insert( key, Value() ); + return myData[ key ]; + } + + const Value operator[]( const Key& key ) const + { + if ( myData.find( key ) == myData.end() ) + return dummyValue; + return myData[key]; + } + + void erase( Iterator it ) { remove( it ); } + void erase( const Key& key ) { remove( key ); } + void erase( const int index ) { remove( index ); } + void remove( Iterator it ) { if ( it.myMap != this ) return; remove( it.myIndex ); } + void remove( const Key& key ) { remove( index( key ) ); } + void remove( const int index ) + { + if ( index >= 0 && index < (int)myKeys.count() ) + { + myData.remove( myKeys[index] ); + myKeys.removeAt( index ); + } + } + +private: + QList myKeys; + QMap myData; + Key dummyKey; + Value dummyValue; + + friend class IMapIterator; + friend class IMapConstIterator; +}; + +/*! + \brief Indexed map iterator template class. +*/ +template class IMapIterator +{ +public: + IMapIterator() : myMap( 0 ), myIndex( 0 ) { init(); } + IMapIterator( const IMap* m ) : myMap( const_cast< IMap* >( m ) ), myIndex( 0 ) { init(); } + IMapIterator( const IMapIterator& i ) : myMap( i.myMap ), myIndex( i.myIndex ) { init(); } + + bool operator==( const IMapIterator& i ) { return !operator!=( i ); } + bool operator!=( const IMapIterator& i ) { return !myMap || myMap != i.myMap || myIndex != i.myIndex; } + + operator bool() const { return myIndex >= 0; } + + const Key& key() const { return myMap->key( myIndex ); } + Value& value() { return myMap->value( myIndex ); } + const Value& value() const { return myMap->value( myIndex ); } + + Value& operator*() { return value(); } + + IMapIterator& operator++() { myIndex++; init(); return *this; } + IMapIterator operator++( int ) { IMapIterator i = *this; myIndex++; init(); return i; } + IMapIterator& operator--() { myIndex--; init(); return *this; } + IMapIterator operator--( int ) { IMapIterator i = *this; myIndex--; init(); return i; } + +private: + IMapIterator( const IMap* m, const int index ) : myMap( const_cast< IMap* >( m ) ), myIndex( index ) { init(); } + void init() { if ( !myMap || myIndex >= myMap->count() ) myIndex = -1; } + +private: + IMap* myMap; + int myIndex; + + friend class IMap; + friend class IMapConstIterator; +}; + +/*! + \brief Indexed map const iterator template class. +*/ +template class IMapConstIterator +{ +public: + IMapConstIterator() : myMap( 0 ), myIndex( 0 ) { init(); } + IMapConstIterator( const IMap* m ) : myMap( const_cast< IMap* >( m ) ), myIndex( 0 ) { init(); } + IMapConstIterator( const IMapConstIterator& i ) : myMap( i.myMap ), myIndex( i.myIndex ) { init(); } + IMapConstIterator( const IMapIterator& i ) : myMap( i.myMap ), myIndex( i.myIndex ) { init(); } + + bool operator==( const IMapConstIterator& i ) { return !operator!=( i ); } + bool operator!=( const IMapConstIterator& i ) { return !myMap || myMap != i.myMap || myIndex != i.myIndex; } + + operator bool() const { return myIndex >= 0; } + + const Key& key() const { return myMap->key( myIndex ); } + const Value value() const { return myMap->value( myIndex ); } + + const Value operator*() const { return value(); } + + IMapConstIterator& operator++() { myIndex++; init(); return *this; } + IMapConstIterator operator++( int ) { IMapConstIterator i = *this; myIndex++; init(); return i; } + IMapConstIterator& operator--() { myIndex--; init(); return *this; } + IMapConstIterator operator--( int ) { IMapConstIterator i = *this; myIndex--; init(); return i; } + +private: + IMapConstIterator( const IMap* m, const int index ): myMap( const_cast< IMap* >( m ) ), myIndex( index ) { init(); } + void init() { if ( !myMap || myIndex >= myMap->count() ) myIndex = -1; } + +private: + IMap* myMap; + int myIndex; + + friend class IMap; +}; + +#endif // QTXMAP_H diff --git a/src/Qtx/QtxPagePrefMgr.cxx b/src/Qtx/QtxPagePrefMgr.cxx new file mode 100644 index 000000000..5697e4415 --- /dev/null +++ b/src/Qtx/QtxPagePrefMgr.cxx @@ -0,0 +1,3316 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPagePrefMgr.cxx +// Author: Sergey TELKOV + +#include "QtxPagePrefMgr.h" + +#include "QtxGridBox.h" +#include "QtxFontEdit.h" +#include "QtxGroupBox.h" +#include "QtxComboBox.h" +#include "QtxIntSpinBox.h" +#include "QtxColorButton.h" +#include "QtxDoubleSpinBox.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*! + \class QtxPagePrefMgr + \brief GUI implementation of the QtxPreferenceMgr class: preferences manager. +*/ + +/*! + \brief Constructor. + \param resMgr resource manager + \param parent parent widget +*/ +QtxPagePrefMgr::QtxPagePrefMgr( QtxResourceMgr* resMgr, QWidget* parent ) +: QFrame( parent ), + QtxPreferenceMgr( resMgr ), + myInit( false ) +{ + myBox = new QtxGridBox( 1, Qt::Horizontal, this, 0 ); + QVBoxLayout* base = new QVBoxLayout( this ); + base->setMargin( 0 ); + base->setSpacing( 0 ); + base->addWidget( myBox ); +} + +/*! + \brief Destructor +*/ +QtxPagePrefMgr::~QtxPagePrefMgr() +{ +} + +/*! + \brief Get recommended size for the widget. + \return recommended widget size +*/ +QSize QtxPagePrefMgr::sizeHint() const +{ + initialize(); + + return QFrame::sizeHint(); +} + +/*! + \brief Get recommended minimum size for the widget. + \return recommended minimum widget size +*/ +QSize QtxPagePrefMgr::minimumSizeHint() const +{ + initialize(); + + return QFrame::minimumSizeHint(); +} + +/*! + \brief Customize show/hide widget operation. + \param on if \c true the widget is being shown, otherswise + it is being hidden +*/ +void QtxPagePrefMgr::setVisible( bool on ) +{ + if ( on && !myInit ) + updateContents(); + + QFrame::setVisible( on ); +} + +/*! + \brief Update widget contents. +*/ +void QtxPagePrefMgr::updateContents() +{ + QtxPreferenceMgr::updateContents(); + + QList lst = childItems(); + for ( QList::const_iterator it = lst.begin(); it != lst.end(); ++it ) + { + if ( (*it)->rtti() == QtxPagePrefItem::RTTI() ) + { + QtxPagePrefItem* item = (QtxPagePrefItem*)(*it); + if ( item->widget() && item->widget()->parent() != myBox ) + item->widget()->setParent( myBox ); + } + } + + setWindowIcon( icon() ); +} + +/*! + \brief Callback function which is called when the child + preference item is added. + \param item child item being added + \sa itemRemoved(), itemChanged() +*/ +void QtxPagePrefMgr::itemAdded( QtxPreferenceItem* /*item*/ ) +{ + triggerUpdate(); +} + +/*! + \brief Callback function which is called when the child + preference item is removed. + \param item child item being removed + \sa itemAdded(), itemChanged() +*/ +void QtxPagePrefMgr::itemRemoved( QtxPreferenceItem* /*item*/ ) +{ + triggerUpdate(); +} + +/*! + \brief Callback function which is called when the child + preference item is modified. + \param item child item being modified + \sa itemAdded(), itemRemoved() +*/ +void QtxPagePrefMgr::itemChanged( QtxPreferenceItem* /*item*/ ) +{ + triggerUpdate(); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefMgr::optionValue( const QString& name ) const +{ + if ( name == "orientation" ) + return myBox->orientation() == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal; + else + return QtxPreferenceMgr::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefMgr::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "orientation" ) + { + if ( val.canConvert( QVariant::Int ) ) + myBox->setOrientation( val.toInt() == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal ); + } + else + QtxPreferenceMgr::setOptionValue( name, val ); +} + +/*! + \brief Perform internal initialization. +*/ +void QtxPagePrefMgr::initialize() const +{ + if ( myInit ) + return; + + QtxPagePrefMgr* that = (QtxPagePrefMgr*)this; + + that->updateContents(); + + QList lst = childItems( true ); + for ( QList::iterator it = lst.begin(); it != lst.end(); ++it ) + (*it)->updateContents(); + + that->myInit = true; +} + +/*! + \class QtxPagePrefItem + \brief Base class for implementation of all the widget-based + preference items. +*/ + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefItem::QtxPagePrefItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPreferenceItem( title, sect, param, parent ), + myWidget( 0 ) +{ +} + +/*! + \brief Destructor. +*/ +QtxPagePrefItem::~QtxPagePrefItem() +{ + delete myWidget; +} + +/*! + \brief Get unique item type identifier. + \return item type ID +*/ +int QtxPagePrefItem::rtti() const +{ + return QtxPagePrefItem::RTTI(); +} + +/*! + \brief Get preference item editor widget. + \return editor widget + \sa setWidget() +*/ +QWidget* QtxPagePrefItem::widget() const +{ + return myWidget; +} + +/*! + \brief Specify unique item class identifier. + \return item class ID +*/ +int QtxPagePrefItem::RTTI() +{ + return 1000; +} + +/*! + \brief Set preference item editor widget. + \param wid editor widget + \sa widget() +*/ +void QtxPagePrefItem::setWidget( QWidget* wid ) +{ + myWidget = wid; + sendItemChanges(); +} + +/*! + \brief Callback function which is called when the child + preference item is added. + \param item child item being added + \sa itemRemoved(), itemChanged() +*/ +void QtxPagePrefItem::itemAdded( QtxPreferenceItem* /*item*/ ) +{ + contentChanged(); +} + +/*! + \brief Callback function which is called when the child + preference item is removed. + \param item child item being removed + \sa itemAdded(), itemChanged() +*/ +void QtxPagePrefItem::itemRemoved( QtxPreferenceItem* /*item*/ ) +{ + contentChanged(); +} + +/*! + \brief Callback function which is called when the child + preference item is modified. + \param item child item being modified + \sa itemAdded(), itemRemoved() +*/ +void QtxPagePrefItem::itemChanged( QtxPreferenceItem* /*item*/ ) +{ + contentChanged(); +} + +/*! + \brief Store preference item to the resource manager. + + This method should be reimplemented in the subclasses. + Base implementation does nothing. + + \sa retrieve() +*/ +void QtxPagePrefItem::store() +{ +} + +/*! + \brief Retrieve preference item from the resource manager. + + This method should be reimplemented in the subclasses. + Base implementation does nothing. + + \sa store() +*/ +void QtxPagePrefItem::retrieve() +{ +} + +/*! + \brief Find all child items of the QtxPagePrefItem type. + \param list used to return list of child items + \param rec if \c true, perform recursive search +*/ +void QtxPagePrefItem::pageChildItems( QList& list, const bool rec ) const +{ + QList lst = childItems( rec ); + for ( QList::const_iterator it = lst.begin(); it != lst.end(); ++it ) + { + if ( (*it)->rtti() == QtxPagePrefItem::RTTI() ) + list.append( (QtxPagePrefItem*)*it ); + } +} + +/*! + \brief Called when contents is changed (item is added, removed or modified). + + Triggers the item update. +*/ +void QtxPagePrefItem::contentChanged() +{ + triggerUpdate(); +} + +/*! + \class QtxPageNamedPrefItem + \brief Base class for implementation of the named preference items + (items with text labels). +*/ + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPageNamedPrefItem::QtxPageNamedPrefItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPagePrefItem( title, parent, sect, param ), + myControl( 0 ) +{ + QWidget* main = new QWidget(); + QHBoxLayout* base = new QHBoxLayout( main ); + base->setMargin( 0 ); + base->setSpacing( 5 ); + + myLabel = new QLabel( title, main ); + base->addWidget( myLabel ); + + setWidget( main ); + + myLabel->setVisible( !title.isEmpty() ); +} + +/*! + \brief Destructor. +*/ +QtxPageNamedPrefItem::~QtxPageNamedPrefItem() +{ +} + +/*! + \brief Set preference title. + \param txt new preference title. +*/ +void QtxPageNamedPrefItem::setTitle( const QString& txt ) +{ + QtxPagePrefItem::setTitle( txt ); + + label()->setText( title() ); + if ( !title().isEmpty() ) + label()->setVisible( true ); +} + +/*! + \brief Get label widget corresponding to the preference item. + \return label widget +*/ +QLabel* QtxPageNamedPrefItem::label() const +{ + return myLabel; +} + +/*! + \brief Get control widget corresponding to the preference item. + \return control widget + \sa setControl() +*/ +QWidget* QtxPageNamedPrefItem::control() const +{ + return myControl; +} + +/*! + \brief Set control widget corresponding to the preference item. + \param wid control widget + \sa control() +*/ +void QtxPageNamedPrefItem::setControl( QWidget* wid ) +{ + if ( myControl == wid ) + return; + + delete myControl; + myControl = wid; + + if ( myControl ) + widget()->layout()->addWidget( myControl ); +} + +/*! + \class QtxPagePrefListItem + \brief GUI implementation of the list container preference item. +*/ + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefListItem::QtxPagePrefListItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPagePrefItem( title, parent, sect, param ), + myFix( false ) +{ + QSplitter* main = new QSplitter( Qt::Horizontal ); + main->setChildrenCollapsible( false ); + + main->addWidget( myList = new QListWidget( main ) ); + main->addWidget( myStack = new QStackedWidget( main ) ); + + myList->setSelectionMode( QListWidget::SingleSelection ); + + myStack->addWidget( myInfLabel = new QLabel( myStack ) ); + myInfLabel->setAlignment( Qt::AlignCenter ); + + connect( myList, SIGNAL( itemSelectionChanged() ), this, SLOT( onItemSelectionChanged() ) ); + + setWidget( main ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefListItem::~QtxPagePrefListItem() +{ +} + +/*! + \brief Get message text which is shown if the container is empty. + \return message text + \sa setEmptyInfo() +*/ +QString QtxPagePrefListItem::emptyInfo() const +{ + return myInfText; +} + +/*! + \brief Set message text which is shown if the container is empty. + \param new message text + \sa emptyInfo() +*/ +void QtxPagePrefListItem::setEmptyInfo( const QString& inf ) +{ + if ( myInfText == inf ) + return; + + myInfText = inf; + + updateVisible(); +} + +/*! + \brief Check if the preference item widget is of fixed size. + \return \c true if the widget has the fixed size + \sa setFixedSize() +*/ +bool QtxPagePrefListItem::isFixedSize() const +{ + return myFix; +} + +/*! + \brief Set the preference item widget to be of fixed size. + \param on if \c true, the widget will have the fixed size + \sa isFixedSize() +*/ +void QtxPagePrefListItem::setFixedSize( const bool on ) +{ + if ( myFix == on ) + return; + + myFix = on; + + updateGeom(); +} + +/*! + \brief Update widget contents. +*/ +void QtxPagePrefListItem::updateContents() +{ + updateVisible(); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefListItem::optionValue( const QString& name ) const +{ + if ( name == "fixed_size" ) + return isFixedSize(); + else if ( name == "empty_info" || name == "info" ) + return emptyInfo(); + else + return QtxPagePrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefListItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "fixed_size" ) + { + if ( val.canConvert( QVariant::Bool ) ) + setFixedSize( val.toBool() ); + } + else if ( name == "empty_info" || name == "info" ) + { + if ( val.canConvert( QVariant::String ) ) + setEmptyInfo( val.toString() ); + } + else + QtxPagePrefItem::setOptionValue( name, val ); +} + +/*! + \brief Called when the selection in the list box is changed. +*/ +void QtxPagePrefListItem::onItemSelectionChanged() +{ + updateState(); +} + +/*! + \brief Update information label widget. +*/ +void QtxPagePrefListItem::updateInfo() +{ + QString infoText; + QtxPagePrefItem* item = selectedItem(); + if ( item ) + { + infoText = emptyInfo(); + QRegExp rx( "%([%|N])" ); + + int idx = 0; + while ( ( idx = rx.indexIn( infoText ) ) != -1 ) + { + if ( rx.cap() == QString( "%%" ) ) + infoText.replace( idx, rx.matchedLength(), "%" ); + else if ( rx.cap() == QString( "%N" ) ) + infoText.replace( idx, rx.matchedLength(), item->title() ); + } + } + myInfLabel->setText( infoText ); +} + +/*! + \brief Update widget state. +*/ +void QtxPagePrefListItem::updateState() +{ + QtxPagePrefItem* item = selectedItem(); + QWidget* wid = item && !item->isEmpty() ? item->widget() : myInfLabel; + if ( wid ) + myStack->setCurrentWidget( wid ); + + updateInfo(); +} + +/*! + \brief Update visibile child widgets. +*/ +void QtxPagePrefListItem::updateVisible() +{ + QList items; + pageChildItems( items ); + + QMap map; + for ( int i = 0; i < (int)myStack->count(); i++ ) + map.insert( myStack->widget( i ), 0 ); + + int selId = selected(); + myList->clear(); + for ( QList::const_iterator it = items.begin(); it != items.end(); ++it ) + { + if ( (*it)->isEmpty() && myInfText.isEmpty() ) + continue; + + myList->addItem( (*it)->title() ); + myList->item( myList->count() - 1 )->setIcon( (*it)->icon() ); + myList->item( myList->count() - 1 )->setData( Qt::UserRole, (*it)->id() ); + + QWidget* wid = (*it)->widget(); + if ( !map.contains( wid ) ) + myStack->addWidget( wid ); + + map.remove( wid ); + } + + map.remove( myInfLabel ); + + for ( QMap::const_iterator it = map.begin(); it != map.end(); ++it ) + myStack->removeWidget( it.key() ); + + setSelected( selId ); + if ( selected() == -1 && myList->count() ) + setSelected( myList->item( 0 )->data( Qt::UserRole ).toInt() ); + + //myList->setVisible( myList->count() > 1 ); + + updateState(); + updateGeom(); +} + +/*! + \brief Update widget geometry. +*/ +void QtxPagePrefListItem::updateGeom() +{ + if ( myFix ) + myList->setFixedWidth( myList->minimumSizeHint().width() + 10 ); + else + { + myList->setMinimumWidth( 0 ); + myList->setMaximumWidth( 16777215 ); + + QSplitter* s = ::qobject_cast( widget() ); + if ( s ) + { + int w = myList->minimumSizeHint().width() + 30; + QList szList; + szList.append( w ); + szList.append( s->width() - w ); + s->setSizes( szList ); + } + } +} + +/*! + \brief Get identifier of the currently selected preference item. + \return identifier of the currently selected item or -1 if no item is selected + \sa setSelected() +*/ +int QtxPagePrefListItem::selected() const +{ + QList selList = myList->selectedItems(); + if ( selList.isEmpty() ) + return -1; + + QVariant v = selList.first()->data( Qt::UserRole ); + return v.canConvert( QVariant::Int ) ? v.toInt() : -1; +} + +/*! + \brief Get currently selected preference item. + \return currently selected item or 0 if no item is selected + \sa setSelected() +*/ +QtxPagePrefItem* QtxPagePrefListItem::selectedItem() const +{ + int selId = selected(); + + QList items; + pageChildItems( items ); + + QtxPagePrefItem* item = 0; + for ( QList::const_iterator it = items.begin(); it != items.end() && !item; ++it ) + { + if ( (*it)->id() == selId ) + item = *it; + } + return item; +} + +/*! + \brief Set currently selected preference item. + \param id identifier of the preference item to make selected +*/ +void QtxPagePrefListItem::setSelected( const int id ) +{ + int idx = -1; + for ( int i = 0; i < (int)myList->count() && idx < 0; i++ ) + { + QVariant v = myList->item( i )->data( Qt::UserRole ); + if ( v.canConvert( QVariant::Int ) && v.toInt() == id ) + idx = i; + } + + QItemSelection sel; + QItemSelectionModel* selModel = myList->selectionModel(); + + if ( idx >= 0 ) + sel.select( myList->model()->index( idx, 0 ), myList->model()->index( idx, 0 ) ); + + selModel->select( sel, QItemSelectionModel::ClearAndSelect ); +} + +/*! + \class QtxPagePrefToolBoxItem +*/ + +QtxPagePrefToolBoxItem::QtxPagePrefToolBoxItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPagePrefItem( title, parent, sect, param ) +{ + setWidget( myToolBox = new QToolBox( 0 ) ); +} + +QtxPagePrefToolBoxItem::~QtxPagePrefToolBoxItem() +{ +} + +void QtxPagePrefToolBoxItem::updateContents() +{ + updateToolBox(); +} + +void QtxPagePrefToolBoxItem::updateToolBox() +{ + QList items; + pageChildItems( items ); + + QWidget* cur = myToolBox->currentWidget(); + + int i = 0; + QMap map; + for ( QList::const_iterator it = items.begin(); it != items.end(); ++it ) + { + QWidget* wid = (*it)->widget(); + if ( !wid ) + continue; + + if ( myToolBox->widget( i ) != wid ) + { + if ( myToolBox->indexOf( wid ) != -1 ) + myToolBox->removeItem( myToolBox->indexOf( wid ) ); + + myToolBox->insertItem( i, wid, (*it)->title() ); + } + else + myToolBox->setItemText( i, (*it)->title() ); + + myToolBox->setItemIcon( i, (*it)->icon() ); + + i++; + map.insert( wid, 0 ); + } + + QList del; + for ( int idx = 0; idx < (int)myToolBox->count(); idx++ ) + { + QWidget* w = myToolBox->widget( idx ); + if ( !map.contains( w ) ) + del.append( w ); + } + + for ( QList::const_iterator itr = del.begin(); itr != del.end(); ++itr ) + myToolBox->removeItem( myToolBox->indexOf( *itr ) ); + + if ( cur ) + myToolBox->setCurrentWidget( cur ); +} + +/*! + \class QtxPagePrefTabsItem + \brief GUI implementation of the tab widget container. +*/ + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefTabsItem::QtxPagePrefTabsItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPagePrefItem( title, parent, sect, param ) +{ + setWidget( myTabs = new QTabWidget( 0 ) ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefTabsItem::~QtxPagePrefTabsItem() +{ +} + +/*! + \brief Update widget contents. +*/ +void QtxPagePrefTabsItem::updateContents() +{ + updateTabs(); +} + +/*! + \brief Get tabs position. + \return current tabs position (QTabWidget::TabPosition) + \sa setTabPosition() +*/ +int QtxPagePrefTabsItem::tabPosition() const +{ + return myTabs->tabPosition(); +} + +/*! + \brief Set tabs position. + \param tp new tabs position (QTabWidget::TabPosition) + \sa tabPosition() +*/ +void QtxPagePrefTabsItem::setTabPosition( const int tp ) +{ + myTabs->setTabPosition( (QTabWidget::TabPosition)tp ); +} + +/*! + \brief Get tabs shape. + \return current tabs shape (QTabWidget::TabShape) + \sa setTabShape() +*/ +int QtxPagePrefTabsItem::tabShape() const +{ + return myTabs->tabShape(); +} + +/*! + \brief Set tabs shape. + \param ts new tabs shape (QTabWidget::TabShape) + \sa tabShape() +*/ +void QtxPagePrefTabsItem::setTabShape( const int ts ) +{ + myTabs->setTabShape( (QTabWidget::TabShape)ts ); +} + +/*! + \brief Get tabs icon size. + \return current tabs icon size + \sa setTabIconSize() +*/ +QSize QtxPagePrefTabsItem::tabIconSize() const +{ + return myTabs->iconSize(); +} + +/*! + \brief Set tabs icon size. + \param sz new tabs icon size + \sa tabIconSize() +*/ +void QtxPagePrefTabsItem::setTabIconSize( const QSize& sz ) +{ + myTabs->setIconSize( sz ); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefTabsItem::optionValue( const QString& name ) const +{ + if ( name == "position" ) + return tabPosition(); + else if ( name == "shape" ) + return tabShape(); + else if ( name == "icon_size" ) + return tabIconSize(); + else + return QtxPagePrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefTabsItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "position" ) + { + if ( val.canConvert( QVariant::Int ) ) + setTabPosition( val.toInt() ); + } + else if ( name == "shape" ) + { + if ( val.canConvert( QVariant::Int ) ) + setTabShape( val.toInt() ); + } + else if ( name == "icon_size" ) + { + if ( val.canConvert( QVariant::Size ) ) + setTabIconSize( val.toSize() ); + } + else + QtxPagePrefItem::setOptionValue( name, val ); +} + +/*! + \brief Update tabs. +*/ +void QtxPagePrefTabsItem::updateTabs() +{ + QList items; + pageChildItems( items ); + + QWidget* cur = myTabs->currentWidget(); + + int i = 0; + QMap map; + for ( QList::const_iterator it = items.begin(); it != items.end(); ++it ) + { + QWidget* wid = (*it)->widget(); + if ( !wid ) + continue; + + if ( myTabs->widget( i ) != wid ) + { + if ( myTabs->indexOf( wid ) != -1 ) + myTabs->removeTab( myTabs->indexOf( wid ) ); + + myTabs->insertTab( i, wid, (*it)->title() ); + } + else + myTabs->setTabText( i, (*it)->title() ); + + myTabs->setTabIcon( i, (*it)->icon() ); + + i++; + map.insert( wid, 0 ); + } + + QList del; + for ( int idx = 0; idx < (int)myTabs->count(); idx++ ) + { + QWidget* w = myTabs->widget( idx ); + if ( !map.contains( w ) ) + del.append( w ); + } + + for ( QList::const_iterator itr = del.begin(); itr != del.end(); ++itr ) + myTabs->removeTab( myTabs->indexOf( *itr ) ); + + if ( cur ) + myTabs->setCurrentWidget( cur ); +} + +/*! + \class QtxPagePrefFrameItem + \brief GUI implementation of the frame widget container. +*/ + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefFrameItem::QtxPagePrefFrameItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPagePrefItem( title, parent, sect, param ) +{ + QWidget* main = new QWidget(); + QVBoxLayout* base = new QVBoxLayout( main ); + base->setMargin( 0 ); + base->setSpacing( 0 ); + + base->addWidget( myBox = new QtxGridBox( 1, Qt::Horizontal, main, 5, 5 ) ); + base->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding ) ); + + setWidget( main ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefFrameItem::~QtxPagePrefFrameItem() +{ +} + +/*! + \brief Update widget contents. +*/ +void QtxPagePrefFrameItem::updateContents() +{ + updateFrame(); +} + +/*! + \brief Get frame margin. + \return current frame margin + \sa setMargin() +*/ +int QtxPagePrefFrameItem::margin() const +{ + return myBox->insideMargin(); +} + +/*! + \brief Get frame margin. + \param m new frame margin + \sa margin() +*/ +void QtxPagePrefFrameItem::setMargin( const int m ) +{ + myBox->setInsideMargin( m ); +} + +/*! + \brief Get frame spacing. + \return current frame spacing + \sa setSpacing() +*/ +int QtxPagePrefFrameItem::spacing() const +{ + return myBox->insideSpacing(); +} + +/*! + \brief Set frame spacing. + \param s new frame spacing + \sa spacing() +*/ +void QtxPagePrefFrameItem::setSpacing( const int s ) +{ + myBox->setInsideSpacing( s ); +} + +/*! + \brief Get number of frame columns. + \return current columns number + \sa setColumns() +*/ +int QtxPagePrefFrameItem::columns() const +{ + return myBox->columns(); +} + +/*! + \brief Set number of frame columns. + \param c new columns number + \sa columns() +*/ +void QtxPagePrefFrameItem::setColumns( const int c ) +{ + myBox->setColumns( c ); +} + +/*! + \brief Get frame box orientation. + \return current frame orientation + \sa setOrientation() +*/ +Qt::Orientation QtxPagePrefFrameItem::orientation() const +{ + return myBox->orientation(); +} + +/*! + \brief Set frame box orientation. + \param o new frame orientation + \sa orientation() +*/ +void QtxPagePrefFrameItem::setOrientation( const Qt::Orientation o ) +{ + myBox->setOrientation( o ); +} + +bool QtxPagePrefFrameItem::stretch() const +{ + QSpacerItem* s = 0; + QLayout* l = widget() ? widget()->layout() : 0; + for ( int i = 0; l && i < l->count() && !s; i++ ) + s = l->itemAt( i )->spacerItem(); + + return s ? ( s->expandingDirections() & Qt::Vertical ) != 0 : false; +} + +void QtxPagePrefFrameItem::setStretch( const bool on ) +{ + QSpacerItem* s = 0; + QLayout* l = widget() ? widget()->layout() : 0; + for ( int i = 0; l && i < l->count() && !s; i++ ) + s = l->itemAt( i )->spacerItem(); + + if ( s ) + s->changeSize( 0, 0, QSizePolicy::Minimum, on ? QSizePolicy::Expanding : QSizePolicy::Minimum ); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefFrameItem::optionValue( const QString& name ) const +{ + if ( name == "margin" ) + return margin(); + else if ( name == "spacing" ) + return spacing(); + else if ( name == "columns" ) + return columns(); + else if ( name == "orientation" ) + return orientation(); + else if ( name == "stretch" ) + return stretch(); + else + return QtxPagePrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefFrameItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "margin" ) + { + if ( val.canConvert( QVariant::Int ) ) + setMargin( val.toInt() ); + } + else if ( name == "spacing" ) + { + if ( val.canConvert( QVariant::Int ) ) + setSpacing( val.toInt() ); + } + else if ( name == "columns" ) + { + if ( val.canConvert( QVariant::Int ) ) + setColumns( val.toInt() ); + } + else if ( name == "orientation" ) + { + if ( val.canConvert( QVariant::Int ) ) + setOrientation( (Qt::Orientation)val.toInt() ); + } + else if ( name == "stretch" ) + { + if ( val.canConvert( QVariant::Bool ) ) + setStretch( val.toBool() ); + } + else + QtxPagePrefItem::setOptionValue( name, val ); +} + +/*! + \brief Update frame widget. +*/ +void QtxPagePrefFrameItem::updateFrame() +{ + QList items; + pageChildItems( items ); + + for ( QList::const_iterator it = items.begin(); it != items.end(); ++it ) + { + QWidget* wid = (*it)->widget(); + if ( !wid ) + continue; + + if ( wid->parent() != myBox ) + wid->setParent( myBox ); + } +} + +/*! + \class QtxPagePrefGroupItem + \brief GUI implementation of the group widget container. +*/ + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefGroupItem::QtxPagePrefGroupItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPagePrefItem( title, parent, sect, param ) +{ + myGroup = new QtxGroupBox( title, 0 ); + myBox = new QtxGridBox( 1, Qt::Horizontal, myGroup, 5, 5 ); + myGroup->setWidget( myBox ); + + setWidget( myGroup ); +} + +/*! + \brief Constructor. + \param cols columns number + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefGroupItem::QtxPagePrefGroupItem( const int cols, const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPagePrefItem( title, parent, sect, param ) +{ + myGroup = new QtxGroupBox( title, 0 ); + myBox = new QtxGridBox( cols, Qt::Horizontal, myGroup, 5, 5 ); + myGroup->setWidget( myBox ); + + setWidget( myGroup ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefGroupItem::~QtxPagePrefGroupItem() +{ +} + +/*! + \brief Assign resource file settings to the preference item. + \param sect resource file section name + \param param resource file parameter name + \sa resource() +*/ +void QtxPagePrefGroupItem::setResource( const QString& sect, const QString& param ) +{ + QtxPagePrefItem::setResource( sect, param ); + updateState(); +} + +/*! + \brief Update widget contents. +*/ +void QtxPagePrefGroupItem::updateContents() +{ + myGroup->setTitle( title() ); + + updateState(); + updateGroup(); +} + +/*! + \brief Get group box margin. + \return current group box margin + \sa setMargin() +*/ +int QtxPagePrefGroupItem::margin() const +{ + return myBox->insideMargin(); +} + +/*! + \brief Get group box margin. + \param m new group box margin + \sa margin() +*/ +void QtxPagePrefGroupItem::setMargin( const int m ) +{ + myBox->setInsideMargin( m ); +} + +/*! + \brief Get group box spacing. + \return current group box spacing + \sa setSpacing() +*/ +int QtxPagePrefGroupItem::spacing() const +{ + return myBox->insideSpacing(); +} + +/*! + \brief Set group box spacing. + \param s new group box spacing + \sa spacing() +*/ +void QtxPagePrefGroupItem::setSpacing( const int s ) +{ + myBox->setInsideSpacing( s ); +} + +/*! + \brief Get number of group box columns. + \return current columns number + \sa setColumns() +*/ +int QtxPagePrefGroupItem::columns() const +{ + return myBox->columns(); +} + +/*! + \brief Set number of group box columns. + \param c new columns number + \sa columns() +*/ +void QtxPagePrefGroupItem::setColumns( const int c ) +{ + myBox->setColumns( c ); +} + +/*! + \brief Get group box orientation. + \return current group box orientation + \sa setOrientation() +*/ +Qt::Orientation QtxPagePrefGroupItem::orientation() const +{ + return myBox->orientation(); +} + +/*! + \brief Set group box orientation. + \param o new group box orientation + \sa orientation() +*/ +void QtxPagePrefGroupItem::setOrientation( const Qt::Orientation o ) +{ + myBox->setOrientation( o ); +} + +/*! + \brief Get 'flat' flag of the group box widget. + \return \c true if the group box is flat +*/ +bool QtxPagePrefGroupItem::isFlat() const +{ + return myGroup->isFlat(); +} + +/*! + \brief Get 'flat' flag of the group box widget. + \param on if \c true the group box will be made flat +*/ +void QtxPagePrefGroupItem::setFlat( const bool on ) +{ + myGroup->setFlat( on ); +} + +/*! + \brief Store preference item to the resource manager. + \sa retrieve() +*/ +void QtxPagePrefGroupItem::store() +{ + if ( myGroup->isCheckable() ) + setBoolean( myGroup->isChecked() ); +} + +/*! + \brief Retrieve preference item from the resource manager. + \sa store() +*/ +void QtxPagePrefGroupItem::retrieve() +{ + if ( myGroup->isCheckable() ) + myGroup->setChecked( getBoolean() ); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefGroupItem::optionValue( const QString& name ) const +{ + if ( name == "margin" ) + return margin(); + else if ( name == "spacing" ) + return spacing(); + else if ( name == "columns" ) + return columns(); + else if ( name == "orientation" ) + return orientation(); + else if ( name == "flat" ) + return isFlat(); + else + return QtxPagePrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefGroupItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "margin" ) + { + if ( val.canConvert( QVariant::Int ) ) + setMargin( val.toInt() ); + } + else if ( name == "spacing" ) + { + if ( val.canConvert( QVariant::Int ) ) + setSpacing( val.toInt() ); + } + else if ( name == "columns" ) + { + if ( val.canConvert( QVariant::Int ) ) + setColumns( val.toInt() ); + } + else if ( name == "orientation" ) + { + if ( val.canConvert( QVariant::Int ) ) + setOrientation( (Qt::Orientation)val.toInt() ); + } + else if ( name == "flat" ) + { + if ( val.canConvert( QVariant::Bool ) ) + setFlat( val.toBool() ); + } + else + QtxPagePrefItem::setOptionValue( name, val ); +} + +/*! + \brief Update widget state. +*/ +void QtxPagePrefGroupItem::updateState() +{ + QString section, param; + resource( section, param ); + myGroup->setCheckable( !title().isEmpty() && !section.isEmpty() && !param.isEmpty() ); +} + +/*! + \brief Update group box widget. +*/ +void QtxPagePrefGroupItem::updateGroup() +{ + QList items; + pageChildItems( items ); + + for ( QList::const_iterator it = items.begin(); it != items.end(); ++it ) + { + QWidget* wid = (*it)->widget(); + if ( !wid ) + continue; + + if ( wid->parent() != myBox ) + wid->setParent( myBox ); + } +} + +/*! + \class QtxPagePrefSpaceItem + \brief Simple spacer item which can be used in the preferences + editor dialog box. +*/ + +/*! + \brief Constructor. + + Creates spacer item with zero width and height and expanding + on both directions (by height and width). + + \param parent parent preference item +*/ +QtxPagePrefSpaceItem::QtxPagePrefSpaceItem( QtxPreferenceItem* parent ) +: QtxPagePrefItem( QString(), parent ) +{ + initialize( 0, 0, 1, 1 ); +} + +/*! + \brief Constructor. + + Creates spacer item with zero width and height and expanding + according to the specified orientation. + + \param o spacer orientation + \param parent parent preference item +*/ +QtxPagePrefSpaceItem::QtxPagePrefSpaceItem( Qt::Orientation o, QtxPreferenceItem* parent ) +: QtxPagePrefItem( QString(), parent ) +{ + if ( o == Qt::Horizontal ) + initialize( 0, 0, 1, 0 ); + else + initialize( 0, 0, 0, 1 ); +} + +/*! + \brief Constructor. + + Creates spacer item with specified width and height. The spacing + item is expanding horizontally if \a w <= 0 and vertically + if \a h <= 0. + + \param w spacer width + \param h spacer height + \param parent parent preference item +*/ +QtxPagePrefSpaceItem::QtxPagePrefSpaceItem( const int w, const int h, QtxPreferenceItem* parent ) +: QtxPagePrefItem( QString(), parent ) +{ + initialize( w, h, w > 0 ? 0 : 1, h > 0 ? 0 : 1 ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefSpaceItem::~QtxPagePrefSpaceItem() +{ +} + +/*! + \brief Get spacer item size for the specified direction. + \param o direction + \return size for the specified direction + \sa setSize() +*/ +int QtxPagePrefSpaceItem::size( Qt::Orientation o ) const +{ + return o == Qt::Horizontal ? widget()->minimumWidth() : widget()->minimumHeight(); +} + +/*! + \brief Set spacer item size for the specified direction. + \param o direction + \param sz new size for the specified direction + \sa size() +*/ +void QtxPagePrefSpaceItem::setSize( Qt::Orientation o, const int sz ) +{ + if ( o == Qt::Horizontal ) + widget()->setMinimumWidth( sz ); + else + widget()->setMinimumHeight( sz ); +} + +/*! + \brief Get spacer item stretch factor for the specified direction. + \param o direction + \return stretch factor for the specified direction + \sa setStretch() +*/ +int QtxPagePrefSpaceItem::stretch( Qt::Orientation o ) const +{ + QSizePolicy sp = widget()->sizePolicy(); + return o == Qt::Horizontal ? sp.horizontalStretch() : sp.verticalStretch(); +} + +/*! + \brief Set spacer item stretch factor for the specified direction. + \param o direction + \param sf new stretch factor for the specified direction + \sa stretch() +*/ +void QtxPagePrefSpaceItem::setStretch( Qt::Orientation o, const int sf ) +{ + QSizePolicy sp = widget()->sizePolicy(); + if ( o == Qt::Horizontal ) + { + sp.setHorizontalStretch( sf ); + sp.setHorizontalPolicy( sf > 0 ? QSizePolicy::Expanding : QSizePolicy::Fixed ); + } + else + { + sp.setVerticalStretch( sf ); + sp.setVerticalPolicy( sf > 0 ? QSizePolicy::Expanding : QSizePolicy::Fixed ); + } + + widget()->setSizePolicy( sp ); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefSpaceItem::optionValue( const QString& name ) const +{ + if ( name == "horizontal_size" || name == "hsize" ) + return size( Qt::Horizontal ); + else if ( name == "vertical_size" || name == "vsize" ) + return size( Qt::Vertical ); + else if ( name == "horizontal_stretch" || name == "hstretch" ) + return stretch( Qt::Horizontal ); + else if ( name == "vertical_stretch" || name == "vstretch" ) + return stretch( Qt::Vertical ); + else + return QtxPagePrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefSpaceItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "horizontal_size" || name == "hsize" ) + { + if ( val.canConvert( QVariant::Int ) ) + setSize( Qt::Horizontal, val.toInt() ); + } + else if ( name == "vertical_size" || name == "vsize" ) + { + if ( val.canConvert( QVariant::Int ) ) + setSize( Qt::Vertical, val.toInt() ); + } + else if ( name == "horizontal_stretch" || name == "hstretch" ) + { + if ( val.canConvert( QVariant::Int ) ) + setStretch( Qt::Horizontal, val.toInt() ); + } + else if ( name == "vertical_stretch" || name == "vstretch" ) + { + if ( val.canConvert( QVariant::Int ) ) + setStretch( Qt::Vertical, val.toInt() ); + } + else + QtxPagePrefItem::setOptionValue( name, val ); +} + +/*! + \brief Perform internal initialization. + \param w spacer item width + \param h spacer item height + \param ws spacer item horizontal stretch factor + \param hs spacer item vertical stretch factor +*/ +void QtxPagePrefSpaceItem::initialize( const int w, const int h, const int hs, const int vs ) +{ + QSizePolicy sp; + sp.setHorizontalPolicy( hs > 0 ? QSizePolicy::Expanding : QSizePolicy::Fixed ); + sp.setVerticalPolicy( vs > 0 ? QSizePolicy::Expanding : QSizePolicy::Fixed ); + + sp.setHorizontalStretch( hs ); + sp.setVerticalStretch( vs ); + + QWidget* wid = new QWidget(); + wid->setSizePolicy( sp ); + + wid->setMinimumSize( w, h ); + + setWidget( wid ); +} + +/*! + \class QtxPagePrefCheckItem + \brief GUI implementation of the resources check box item (boolean). +*/ + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefCheckItem::QtxPagePrefCheckItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) + +: QtxPagePrefItem( title, parent, sect, param ) +{ + myCheck = new QCheckBox( title ); + myCheck->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + setWidget( myCheck ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefCheckItem::~QtxPagePrefCheckItem() +{ +} + +/*! + \brief Set preference item title. + \param txt new preference title. +*/ +void QtxPagePrefCheckItem::setTitle( const QString& txt ) +{ + QtxPagePrefItem::setTitle( txt ); + + myCheck->setText( title() ); +} + +/*! + \brief Store preference item to the resource manager. + \sa retrieve() +*/ +void QtxPagePrefCheckItem::store() +{ + setBoolean( myCheck->isChecked() ); +} + +/*! + \brief Retrieve preference item from the resource manager. + \sa store() +*/ +void QtxPagePrefCheckItem::retrieve() +{ + myCheck->setChecked( getBoolean() ); +} + +/*! + \class QtxPagePrefEditItem + \brief GUI implementation of the resources line edit box item + for string, integer and double values. +*/ + +/*! + \brief Constructor. + + Creates preference item for string value editing. + + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefEditItem::QtxPagePrefEditItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ), + myType( String ) +{ + setControl( myEditor = new QLineEdit() ); + updateEditor(); +} + +/*! + \brief Constructor. + + Creates preference item for editing of the value which type + is specified by parameter \a type. + + \param type preference item input type (QtxPagePrefEditItem::InputType) + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefEditItem::QtxPagePrefEditItem( const int type, const QString& title, + QtxPreferenceItem* parent, const QString& sect, + const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ), + myType( type ) +{ + setControl( myEditor = new QLineEdit() ); + updateEditor(); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefEditItem::~QtxPagePrefEditItem() +{ +} + +/*! + \brief Get edit box preference item input type. + \return preference item input type (QtxPagePrefEditItem::InputType) + \sa setInputType() +*/ +int QtxPagePrefEditItem::inputType() const +{ + return myType; +} + +/*! + \brief Set edit box preference item input type. + \param type new preference item input type (QtxPagePrefEditItem::InputType) + \sa inputType() +*/ +void QtxPagePrefEditItem::setInputType( const int type ) +{ + if ( myType == type ) + return; + + myType = type; + updateEditor(); +} + +/*! + \brief Store preference item to the resource manager. + \sa retrieve() +*/ +void QtxPagePrefEditItem::store() +{ + setString( myEditor->text() ); +} + +/*! + \brief Retrieve preference item from the resource manager. + \sa store() +*/ +void QtxPagePrefEditItem::retrieve() +{ + QString txt = getString(); + if ( myEditor->validator() ) + { + int pos = 0; + if ( myEditor->validator()->validate( txt, pos ) == QValidator::Invalid ) + txt.clear(); + } + myEditor->setText( txt ); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefEditItem::optionValue( const QString& name ) const +{ + if ( name == "input_type" || name == "type" ) + return inputType(); + else + return QtxPageNamedPrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefEditItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "input_type" || name == "type" ) + { + if ( val.canConvert( QVariant::Int ) ) + setInputType( val.toInt() ); + } + else + QtxPageNamedPrefItem::setOptionValue( name, val ); +} + +/*! + \brief Update edit box widget. +*/ +void QtxPagePrefEditItem::updateEditor() +{ + QValidator* val = 0; + switch ( inputType() ) + { + case Integer: + val = new QIntValidator( myEditor ); + break; + case Double: + val = new QDoubleValidator( myEditor ); + break; + default: + break; + } + + if ( !myEditor->text().isEmpty() && val ) + { + int pos = 0; + QString str = myEditor->text(); + if ( val->validate( str, pos ) == QValidator::Invalid ) + myEditor->clear(); + } + + delete myEditor->validator(); + myEditor->setValidator( val ); +} + +/*! + \class QtxPagePrefSelectItem + \brief GUI implementation of the resources selector item + (string, integer or double values list). + + All items in the list (represented as combo box) should be specified + by the unique identifier which is stored to the resource file instead + of the value itself. +*/ + +/*! + \brief Constructor. + + Creates preference item with combo box widget which is not editable + (direct value entering is disabled). + + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefSelectItem::QtxPagePrefSelectItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ), + myType( NoInput ) +{ + setControl( mySelector = new QtxComboBox() ); + mySelector->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + mySelector->setDuplicatesEnabled( false ); + updateSelector(); +} + +/*! + \brief Constructor. + + Creates preference item with combo box widget which is editable + according to the specified input type (integer, double or string values). + + \param type input type (QtxPagePrefSelectItem::InputType) + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefSelectItem::QtxPagePrefSelectItem( const int type, const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ), + myType( type ) +{ + setControl( mySelector = new QtxComboBox() ); + mySelector->setDuplicatesEnabled( false ); + updateSelector(); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefSelectItem::~QtxPagePrefSelectItem() +{ +} + +/*! + \brief Get edit box preference item input type. + \return preference item input type (QtxPagePrefSelectItem::InputType) + \sa setInputType() +*/ +int QtxPagePrefSelectItem::inputType() const +{ + return myType; +} + +/*! + \brief Set edit box preference item input type. + \param type new preference item input type (QtxPagePrefSelectItem::InputType) + \sa inputType() +*/ +void QtxPagePrefSelectItem::setInputType( const int type ) +{ + if ( myType == type ) + return; + + myType = type; + updateSelector(); +} + +/*! + \brief Get the list of the values from the selection widget. + \return list of values + \sa numbers(), setStrings() +*/ +QStringList QtxPagePrefSelectItem::strings() const +{ + QStringList res; + for ( int i = 0; i < mySelector->count(); i++ ) + res.append( mySelector->itemText( i ) ); + return res; +} + +/*! + \brief Get the list of the values identifiers from the selection widget. + \return list of values IDs + \sa strings(), setNumbers() +*/ +QList QtxPagePrefSelectItem::numbers() const +{ + QList res; + for ( int i = 0; i < mySelector->count(); i++ ) + { + if ( mySelector->hasId( i ) ) + res.append( mySelector->id( i ) ); + } + return res; +} + +/*! + \brief Set the list of the values to the selection widget. + \param lst new list of values + \sa strings(), setNumbers() +*/ +void QtxPagePrefSelectItem::setStrings( const QStringList& lst ) +{ + mySelector->clear(); + mySelector->addItems( lst ); +} + +/*! + \brief Set the list of the values identifiers to the selection widget. + \param ids new list of values IDs + \sa numbers(), setStrings() +*/ +void QtxPagePrefSelectItem::setNumbers( const QList& ids ) +{ + int i = 0; + for ( QList::const_iterator it = ids.begin(); it != ids.end() && i < mySelector->count(); ++it, i++ ) + mySelector->setId( i, *it ); +} + +/*! + \brief Store preference item to the resource manager. + \sa retrieve() +*/ +void QtxPagePrefSelectItem::store() +{ + if ( mySelector->isCleared() ) + return; + + int idx = mySelector->currentIndex(); + + if ( mySelector->hasId( idx ) ) + setInteger( mySelector->id( idx ) ); + else if ( idx >= 0 ) + setString( mySelector->itemText( idx ) ); +} + +/*! + \brief Retrieve preference item from the resource manager. + \sa store() +*/ +void QtxPagePrefSelectItem::retrieve() +{ + QString txt = getString(); + + int idx = -1; + + bool ok = false; + int num = txt.toInt( &ok ); + if ( ok ) + idx = mySelector->index( num ); + else + { + for ( int i = 0; i < mySelector->count() && idx == -1; i++ ) + { + if ( mySelector->itemText( i ) == txt ) + idx = i; + } + } + + if ( idx != -1 ) + mySelector->setCurrentIndex( idx ); + else if ( mySelector->isEditable() ) + { + int pos = 0; + if ( mySelector->validator() && + mySelector->validator()->validate( txt, pos ) == QValidator::Invalid ) + mySelector->setCleared( true ); + else + { + mySelector->setCleared( false ); + mySelector->addItem( txt ); + mySelector->setCurrentIndex( mySelector->count() - 1 ); + } + } +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefSelectItem::optionValue( const QString& name ) const +{ + if ( name == "input_type" || name == "type" ) + return inputType(); + else if ( name == "strings" || name == "labels" ) + return strings(); + else if ( name == "numbers" || name == "ids" || name == "indexes" ) + { + QList lst; + QList nums = numbers(); + for ( QList::const_iterator it = nums.begin(); it != nums.end(); ++it ) + lst.append( *it ); + return lst; + } + else + return QtxPageNamedPrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefSelectItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "input_type" || name == "type" ) + { + if ( val.canConvert( QVariant::Int ) ) + setInputType( val.toInt() ); + } + else if ( name == "strings" || name == "labels" ) + setStrings( val ); + else if ( name == "numbers" || name == "ids" || name == "indexes" ) + setNumbers( val ); + else + QtxPageNamedPrefItem::setOptionValue( name, val ); +} + +/*! + \brief Set the list of the values from the resource manager. + \param var new values list + \internal +*/ +void QtxPagePrefSelectItem::setStrings( const QVariant& var ) +{ + if ( var.type() != QVariant::StringList ) + return; + + setStrings( var.toStringList() ); +} + +/*! + \brief Set the list of the values identifiers from the resource manager. + \param var new values IDs list + \internal +*/ +void QtxPagePrefSelectItem::setNumbers( const QVariant& var ) +{ + if ( var.type() != QVariant::List ) + return; + + QList lst; + QList varList = var.toList(); + for ( QList::const_iterator it = varList.begin(); it != varList.end(); ++it ) + { + if ( (*it).canConvert( QVariant::Int ) ) + lst.append( (*it).toInt() ); + } + setNumbers( lst ); +} + +/*! + \brief Update selector widget. +*/ +void QtxPagePrefSelectItem::updateSelector() +{ + QValidator* val = 0; + switch ( inputType() ) + { + case Integer: + val = new QIntValidator( mySelector ); + break; + case Double: + val = new QDoubleValidator( mySelector ); + break; + default: + break; + } + + mySelector->setEditable( inputType() != NoInput ); + + if ( mySelector->isEditable() && !mySelector->currentText().isEmpty() && val ) + { + int pos = 0; + QString str = mySelector->currentText(); + if ( val->validate( str, pos ) == QValidator::Invalid ) + mySelector->clearEditText(); + } + + delete mySelector->validator(); + mySelector->setValidator( val ); +} + +/*! + \class QtxPagePrefSpinItem + \brief GUI implementation of the resources spin box item + (for integer or double value). +*/ + +/*! + \brief Constructor. + + Creates spin box preference item for the entering integer values. + + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefSpinItem::QtxPagePrefSpinItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ), + myType( Integer ) +{ + updateSpinBox(); +} + +/*! + \brief Constructor. + + Creates spin box preference item for the entering values which type + is specified by the parameter \a type. + + \param type input type (QtxPagePrefSpinItem::InputType). + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefSpinItem::QtxPagePrefSpinItem( const int type, const QString& title, + QtxPreferenceItem* parent, const QString& sect, + const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ), + myType( type ) +{ + updateSpinBox(); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefSpinItem::~QtxPagePrefSpinItem() +{ +} + +/*! + \brief Get spin box preference item input type. + \return preference item input type (QtxPagePrefSpinItem::InputType) + \sa setInputType() +*/ +int QtxPagePrefSpinItem::inputType() const +{ + return myType; +} + +/*! + \brief Set spin box preference item input type. + \param type new preference item input type (QtxPagePrefSpinItem::InputType) + \sa inputType() +*/ +void QtxPagePrefSpinItem::setInputType( const int type ) +{ + if ( myType == type ) + return; + + myType = type; + updateSpinBox(); +} + +/*! + \brief Get spin box preference item step value. + \return spin box single step value + \sa setStep() +*/ +QVariant QtxPagePrefSpinItem::step() const +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + return isb->singleStep(); + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + return dsb->singleStep(); + else + return QVariant(); +} + +/*! + \brief Get spin box preference item minimum value. + \return spin box minimum value + \sa setMinimum() +*/ +QVariant QtxPagePrefSpinItem::minimum() const +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + return isb->minimum(); + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + return dsb->minimum(); + else + return QVariant(); +} + +/*! + \brief Get spin box preference item maximum value. + \return spin box maximum value + \sa setMaximum() +*/ +QVariant QtxPagePrefSpinItem::maximum() const +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + return isb->maximum(); + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + return dsb->maximum(); + else + return QVariant(); +} + +/*! + \brief Get spin box preference item prefix string. + \return spin box prefix string + \sa setPrefix() +*/ +QString QtxPagePrefSpinItem::prefix() const +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + return isb->prefix(); + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + return dsb->prefix(); + else + return QString(); +} + +/*! + \brief Get spin box preference item suffix string. + \return spin box suffix string + \sa setSuffix() +*/ +QString QtxPagePrefSpinItem::suffix() const +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + return isb->suffix(); + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + return dsb->suffix(); + else + return QString(); +} + +/*! + \brief Get spin box preference item special value text (which is shown + when the spin box reaches minimum value). + \return spin box special value text + \sa setSpecialValueText() +*/ +QString QtxPagePrefSpinItem::specialValueText() const +{ + QAbstractSpinBox* sb = ::qobject_cast( control() ); + if ( sb ) + return sb->specialValueText(); + else + return QString(); +} + +/*! + \brief Set spin box preference item step value. + \param step new spin box single step value + \sa step() +*/ +void QtxPagePrefSpinItem::setStep( const QVariant& step ) +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + { + if ( step.canConvert( QVariant::Int ) ) + isb->setSingleStep( step.toInt() ); + } + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + { + if ( step.canConvert( QVariant::Double ) ) + dsb->setSingleStep( step.toDouble() ); + } +} + +/*! + \brief Set spin box preference item minimum value. + \param min new spin box minimum value + \sa minimum() +*/ +void QtxPagePrefSpinItem::setMinimum( const QVariant& min ) +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + { + if ( min.canConvert( QVariant::Int ) ) + isb->setMinimum( min.toInt() ); + } + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + { + if ( min.canConvert( QVariant::Double ) ) + dsb->setMinimum( min.toDouble() ); + } +} + +/*! + \brief Set spin box preference item maximum value. + \param min new spin box maximum value + \sa maximum() +*/ +void QtxPagePrefSpinItem::setMaximum( const QVariant& max ) +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + { + if ( max.canConvert( QVariant::Int ) ) + isb->setMaximum( max.toInt() ); + } + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + { + if ( max.canConvert( QVariant::Double ) ) + dsb->setMaximum( max.toDouble() ); + } +} + +/*! + \brief Set spin box preference item prefix string. + \param txt new spin box prefix string + \sa prefix() +*/ +void QtxPagePrefSpinItem::setPrefix( const QString& txt ) +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + isb->setPrefix( txt ); + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + dsb->setPrefix( txt ); +} + +/*! + \brief Set spin box preference item suffix string. + \param txt new spin box suffix string + \sa suffix() +*/ +void QtxPagePrefSpinItem::setSuffix( const QString& txt ) +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + isb->setSuffix( txt ); + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + dsb->setSuffix( txt ); +} + +/*! + \brief Set spin box preference item special value text (which is shown + when the spin box reaches minimum value). + \param txt new spin box special value text + \sa specialValueText() +*/ +void QtxPagePrefSpinItem::setSpecialValueText( const QString& txt ) +{ + QAbstractSpinBox* sb = ::qobject_cast( control() ); + if ( sb ) + sb->setSpecialValueText( txt ); +} + +/*! + \brief Store preference item to the resource manager. + \sa retrieve() +*/ +void QtxPagePrefSpinItem::store() +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + setInteger( isb->value() ); + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + setDouble( dsb->value() ); +} + +/*! + \brief Retrieve preference item from the resource manager. + \sa store() +*/ +void QtxPagePrefSpinItem::retrieve() +{ + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + isb->setValue( getInteger( isb->value() ) ); + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + dsb->setValue( getDouble( dsb->value() ) ); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefSpinItem::optionValue( const QString& name ) const +{ + if ( name == "input_type" || name == "type" ) + return inputType(); + else if ( name == "minimum" || name == "min" ) + return minimum(); + else if ( name == "maximum" || name == "max" ) + return maximum(); + else if ( name == "step" ) + return step(); + else if ( name == "prefix" ) + return prefix(); + else if ( name == "suffix" ) + return suffix(); + else if ( name == "special" ) + return specialValueText(); + else + return QtxPageNamedPrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefSpinItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "input_type" || name == "type" ) + { + if ( val.canConvert( QVariant::Int ) ) + setInputType( val.toInt() ); + } + else if ( name == "minimum" || name == "min" ) + setMinimum( val ); + else if ( name == "maximum" || name == "max" ) + setMaximum( val ); + else if ( name == "step" ) + setStep( val ); + else if ( name == "prefix" ) + { + if ( val.canConvert( QVariant::String ) ) + setPrefix( val.toString() ); + } + else if ( name == "suffix" ) + { + if ( val.canConvert( QVariant::String ) ) + setSuffix( val.toString() ); + } + else if ( name == "special" ) + { + if ( val.canConvert( QVariant::String ) ) + setSpecialValueText( val.toString() ); + } + else + QtxPageNamedPrefItem::setOptionValue( name, val ); +} + +/*! + \brief Update spin box widget. +*/ +void QtxPagePrefSpinItem::updateSpinBox() +{ + QVariant val; + QVariant stp = step(); + QVariant min = minimum(); + QVariant max = maximum(); + + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + val = isb->value(); + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + val = dsb->value(); + + switch ( inputType() ) + { + case Integer: + setControl( new QtxIntSpinBox() ); + break; + case Double: + setControl( new QtxDoubleSpinBox() ); + break; + default: + break; + } + + control()->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + + setStep( stp ); + setMinimum( min ); + setMaximum( max ); + + if ( QtxIntSpinBox* isb = ::qobject_cast( control() ) ) + { + if ( val.canConvert( QVariant::Int ) ) + isb->setValue( val.toInt() ); + } + else if ( QtxDoubleSpinBox* dsb = ::qobject_cast( control() ) ) + { + if ( val.canConvert( QVariant::Double ) ) + dsb->setValue( val.toDouble() ); + } +} + +/*! + \class QtxPagePrefTextItem + \brief GUI implementation of the resources text box edit item + (for large text data). +*/ + +/*! + \brief Constructor. + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefTextItem::QtxPagePrefTextItem( QtxPreferenceItem* parent, const QString& sect, + const QString& param ) +: QtxPageNamedPrefItem( QString(), parent, sect, param ) +{ + myEditor = new QTextEdit(); + myEditor->setAcceptRichText( false ); + + setControl( myEditor ); +} + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefTextItem::QtxPagePrefTextItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ) +{ + myEditor = new QTextEdit(); + myEditor->setAcceptRichText( false ); + + setControl( myEditor ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefTextItem::~QtxPagePrefTextItem() +{ +} + +/*! + \brief Store preference item to the resource manager. + \sa retrieve() +*/ +void QtxPagePrefTextItem::store() +{ + setString( myEditor->toPlainText() ); +} + +/*! + \brief Retrieve preference item from the resource manager. + \sa store() +*/ +void QtxPagePrefTextItem::retrieve() +{ + myEditor->setPlainText( getString() ); +} + +/*! + \class QtxPagePrefColorItem + \brief GUI implementation of the resources color item. +*/ + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefColorItem::QtxPagePrefColorItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ) +{ + setControl( myColor = new QtxColorButton() ); + myColor->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefColorItem::~QtxPagePrefColorItem() +{ +} + +/*! + \brief Store preference item to the resource manager. + \sa retrieve() +*/ +void QtxPagePrefColorItem::store() +{ + setColor( myColor->color() ); +} + +/*! + \brief Retrieve preference item from the resource manager. + \sa store() +*/ +void QtxPagePrefColorItem::retrieve() +{ + myColor->setColor( getColor() ); +} + +/*! + \class QtxPagePrefFontItem + \brief GUI implementation of the resources font item. +*/ + +/*! + \brief Constructor. + \param feat font editor widget features (QtxFontEdit::Features) + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefFontItem::QtxPagePrefFontItem( const int feat, const QString& title, + QtxPreferenceItem* parent, const QString& sect, + const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ) +{ + setControl( myFont = new QtxFontEdit( feat ) ); +} + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefFontItem::QtxPagePrefFontItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ) +{ + setControl( myFont = new QtxFontEdit() ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefFontItem::~QtxPagePrefFontItem() +{ +} + +/*! + \brief Get font widget features. + \return font widget features (ORed QtxFontEdit::Features flags) + \sa setFeatures() +*/ +int QtxPagePrefFontItem::features() const +{ + return myFont->features(); +} + +/*! + \brief Set font widget features. + \param f new font widget features (ORed QtxFontEdit::Features flags) + \sa features() +*/ +void QtxPagePrefFontItem::setFeatures( const int f ) +{ + myFont->setFeatures( f ); +} + +/*! + \brief Store preference item to the resource manager. + \sa retrieve() +*/ +void QtxPagePrefFontItem::store() +{ + setFont( myFont->currentFont() ); +} + +/*! + \brief Retrieve preference item from the resource manager. + \sa store() +*/ +void QtxPagePrefFontItem::retrieve() +{ + myFont->setCurrentFont( getFont() ); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefFontItem::optionValue( const QString& name ) const +{ + if ( name == "features" ) + return features(); + else + return QtxPageNamedPrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefFontItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "features" ) + { + if ( val.canConvert( QVariant::Int ) ) + setFeatures( val.toInt() ); + } + else + QtxPageNamedPrefItem::setOptionValue( name, val ); +} + +/*! + \class QtxPagePrefPathItem + \brief GUI implementation of the resources file/directory path item. +*/ + +/*! + \brief Constructor. + \param type path widget mode (Qtx::PathType ) + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefPathItem::QtxPagePrefPathItem( const Qtx::PathType type, const QString& title, + QtxPreferenceItem* parent, const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ) +{ + setControl( myPath = new QtxPathEdit( type ) ); +} + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefPathItem::QtxPagePrefPathItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ) +{ + setControl( myPath = new QtxPathEdit() ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefPathItem::~QtxPagePrefPathItem() +{ +} + +/*! + \brief Get path widget mode. + \return current path widget mode (Qtx::PathType) + \sa setPathType() +*/ +Qtx::PathType QtxPagePrefPathItem::pathType() const +{ + return myPath->pathType(); +} + +/*! + \brief Set path widget mode. + \param type new path widget mode (Qtx::PathType) + \sa pathType() +*/ +void QtxPagePrefPathItem::setPathType( const Qtx::PathType type ) +{ + myPath->setPathType( type ); +} + +/*! + \brief Get currently used path widget filters. + \return file or directory path filters + \sa setPathFilter() +*/ +QString QtxPagePrefPathItem::pathFilter() const +{ + return myPath->pathFilter(); +} + +/*! + \brief Set path widget filters. + \param f new file or directory path filters + \sa pathFilter() +*/ +void QtxPagePrefPathItem::setPathFilter( const QString& f ) +{ + myPath->setPathFilter( f ); +} + +/*! + \brief Store preference item to the resource manager. + \sa retrieve() +*/ +void QtxPagePrefPathItem::store() +{ + setString( myPath->path() ); +} + +/*! + \brief Retrieve preference item from the resource manager. + \sa store() +*/ +void QtxPagePrefPathItem::retrieve() +{ + myPath->setPath( getString() ); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefPathItem::optionValue( const QString& name ) const +{ + if ( name == "path_type" ) + return pathType(); + else if ( name == "path_filter" ) + return pathFilter(); + else + return QtxPageNamedPrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefPathItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "path_type" ) + { + if ( val.canConvert( QVariant::Int ) ) + setPathType( (Qtx::PathType)val.toInt() ); + } + else if ( name == "path_filter" ) + { + if ( val.canConvert( QVariant::String ) ) + setPathFilter( val.toString() ); + } + else + QtxPageNamedPrefItem::setOptionValue( name, val ); +} + +/*! + \class QtxPagePrefPathListItem + \brief GUI implementation of resources directory list item. +*/ + +/*! + \brief Constructor. + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefPathListItem::QtxPagePrefPathListItem( QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( QString(), parent, sect, param ) +{ + setControl( myPaths = new QtxPathListEdit() ); +} + +/*! + \brief Constructor. + \param type path list widget mode (Qtx::PathType) + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefPathListItem::QtxPagePrefPathListItem( const Qtx::PathType type, const QString& title, + QtxPreferenceItem* parent, const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ) +{ + setControl( myPaths = new QtxPathListEdit( type ) ); +} + +/*! + \brief Constructor. + \param title preference item title + \param parent parent preference item + \param sect resource file section associated with the preference item + \param param resource file parameter associated with the preference item +*/ +QtxPagePrefPathListItem::QtxPagePrefPathListItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ) +{ + setControl( myPaths = new QtxPathListEdit() ); +} + +/*! + \brief Destructor. +*/ +QtxPagePrefPathListItem::~QtxPagePrefPathListItem() +{ +} + +/*! + \brief Get path list widget mode. + \return currently used path list widget mode (Qtx::PathType) + \sa setPathType() +*/ +Qtx::PathType QtxPagePrefPathListItem::pathType() const +{ + return myPaths->pathType(); +} + +/*! + \brief Set path list widget mode. + \param type new path list widget mode (Qtx::PathType) + \sa pathType() +*/ +void QtxPagePrefPathListItem::setPathType( const Qtx::PathType type ) +{ + myPaths->setPathType( type ); +} + +/*! + \brief Store preference item to the resource manager. + \sa retrieve() +*/ +void QtxPagePrefPathListItem::store() +{ + setString( myPaths->pathList().join( ";" ) ); +} + +/*! + \brief Retrieve preference item from the resource manager. + \sa store() +*/ +void QtxPagePrefPathListItem::retrieve() +{ + myPaths->setPathList( getString().split( ";" ) ); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPagePrefPathListItem::optionValue( const QString& name ) const +{ + if ( name == "path_type" ) + return pathType(); + else + return QtxPageNamedPrefItem::optionValue( name ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPagePrefPathListItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "path_type" ) + { + if ( val.canConvert( QVariant::Int ) ) + setPathType( (Qtx::PathType)val.toInt() ); + } + else + QtxPageNamedPrefItem::setOptionValue( name, val ); +} + +/*! + \class QtxPagePrefDateTimeItem + \brief GUI implementation of resources date/time item. +*/ + +QtxPagePrefDateTimeItem::QtxPagePrefDateTimeItem( const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ), +myType( DateTime ) +{ + setControl( myDateTime = new QDateTimeEdit() ); + myDateTime->setCalendarPopup( true ); + myDateTime->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + updateDateTime(); +} + +QtxPagePrefDateTimeItem::QtxPagePrefDateTimeItem( const int type, const QString& title, QtxPreferenceItem* parent, + const QString& sect, const QString& param ) +: QtxPageNamedPrefItem( title, parent, sect, param ), +myType( type ) +{ + setControl( myDateTime = new QDateTimeEdit() ); + myDateTime->setCalendarPopup( true ); + myDateTime->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + updateDateTime(); +} + +QtxPagePrefDateTimeItem::~QtxPagePrefDateTimeItem() +{ +} + +int QtxPagePrefDateTimeItem::inputType() const +{ + return myType; +} + +void QtxPagePrefDateTimeItem::setInputType( const int type ) +{ + if ( myType == type ) + return; + + myType = type; + updateDateTime(); +} + +bool QtxPagePrefDateTimeItem::calendar() const +{ + return myDateTime->calendarPopup(); +} + +void QtxPagePrefDateTimeItem::setCalendar( const bool on ) +{ + myDateTime->setCalendarPopup( on ); +} + +QDate QtxPagePrefDateTimeItem::maximumDate() const +{ + return myDateTime->maximumDate(); +} + +QTime QtxPagePrefDateTimeItem::maximumTime() const +{ + return myDateTime->maximumTime(); +} + +QDate QtxPagePrefDateTimeItem::minimumDate() const +{ + return myDateTime->minimumDate(); +} + +QTime QtxPagePrefDateTimeItem::minimumTime() const +{ + return myDateTime->minimumTime(); +} + +void QtxPagePrefDateTimeItem::setMaximumDate( const QDate& d ) +{ + if ( d.isValid() ) + myDateTime->setMaximumDate( d ); + else + myDateTime->clearMaximumDate(); +} + +void QtxPagePrefDateTimeItem::setMaximumTime( const QTime& t ) +{ + if ( t.isValid() ) + myDateTime->setMaximumTime( t ); + else + myDateTime->clearMaximumTime(); +} + +void QtxPagePrefDateTimeItem::setMinimumDate( const QDate& d ) +{ + if ( d.isValid() ) + myDateTime->setMinimumDate( d ); + else + myDateTime->clearMinimumDate(); +} + +void QtxPagePrefDateTimeItem::setMinimumTime( const QTime& t ) +{ + if ( t.isValid() ) + myDateTime->setMinimumTime( t ); + else + myDateTime->clearMinimumTime(); +} + +void QtxPagePrefDateTimeItem::store() +{ + QString str; + switch ( inputType() ) + { + case Date: + str = myDateTime->date().toString( Qt::ISODate ); + break; + case Time: + str = myDateTime->time().toString( Qt::ISODate ); + break; + case DateTime: + str = myDateTime->dateTime().toString( Qt::ISODate ); + break; + } + + setString( str ); +} + +void QtxPagePrefDateTimeItem::retrieve() +{ + QString str = getString(); + switch ( inputType() ) + { + case Date: + myDateTime->setDate( QDate::fromString( str, Qt::ISODate ) ); + break; + case Time: + myDateTime->setTime( QTime::fromString( str, Qt::ISODate ) ); + break; + case DateTime: + myDateTime->setDateTime( QDateTime::fromString( str, Qt::ISODate ) ); + break; + } +} + +QVariant QtxPagePrefDateTimeItem::optionValue( const QString& name ) const +{ + if ( name == "input_type" || name == "type" ) + return inputType(); + else if ( name == "minimum_date" || name == "min_date" ) + return minimumDate(); + else if ( name == "maximum_date" || name == "max_date" ) + return maximumDate(); + else if ( name == "minimum_time" || name == "min_time" ) + return minimumTime(); + else if ( name == "maximum_time" || name == "max_time" ) + return maximumTime(); + else + return QtxPageNamedPrefItem::optionValue( name ); +} + +void QtxPagePrefDateTimeItem::setOptionValue( const QString& name, const QVariant& val ) +{ + if ( name == "input_type" || name == "type" ) + { + if ( val.canConvert( QVariant::Int ) ) + setInputType( val.toInt() ); + } + else if ( name == "minimum_date" || name == "min_date" ) + { + if ( val.canConvert( QVariant::Date ) ) + setMinimumDate( val.toDate() ); + } + else if ( name == "maximum_date" || name == "max_date" ) + { + if ( val.canConvert( QVariant::Date ) ) + setMaximumDate( val.toDate() ); + } + else if ( name == "minimum_time" || name == "min_time" ) + { + if ( val.canConvert( QVariant::Time ) ) + setMinimumTime( val.toTime() ); + } + else if ( name == "maximum_time" || name == "max_time" ) + { + if ( val.canConvert( QVariant::Time ) ) + setMaximumTime( val.toTime() ); + } + else + QtxPageNamedPrefItem::setOptionValue( name, val ); +} + +void QtxPagePrefDateTimeItem::updateDateTime() +{ + QString dispFmt; + switch ( inputType() ) + { + case Date: + dispFmt = QDateEdit().displayFormat(); + break; + case Time: + dispFmt = QTimeEdit().displayFormat(); + break; + case DateTime: + dispFmt = QDateTimeEdit().displayFormat(); + break; + } + + myDateTime->setDisplayFormat( dispFmt ); +} diff --git a/src/Qtx/QtxPagePrefMgr.h b/src/Qtx/QtxPagePrefMgr.h new file mode 100644 index 000000000..67ceee71e --- /dev/null +++ b/src/Qtx/QtxPagePrefMgr.h @@ -0,0 +1,607 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPagePrefMgr.h +// Author: Sergey TELKOV + +#ifndef QTXPAGEPREFMGR_H +#define QTXPAGEPREFMGR_H + +#include "QtxPreferenceMgr.h" + +#include "QtxPathEdit.h" +#include "QtxPathListEdit.h" + +#include +#include +#include + +class QtxGridBox; +class QtxFontEdit; +class QtxGroupBox; +class QtxComboBox; +class QtxColorButton; + +class QToolBox; +class QLineEdit; +class QTextEdit; +class QCheckBox; +class QTabWidget; +class QToolButton; +class QListWidget; +class QFileDialog; +class QDateTimeEdit; +class QStackedWidget; + +class QTX_EXPORT QtxPagePrefMgr : public QFrame, public QtxPreferenceMgr +{ + Q_OBJECT + +public: + QtxPagePrefMgr( QtxResourceMgr*, QWidget* = 0 ); + virtual ~QtxPagePrefMgr(); + + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + + virtual void updateContents(); + +signals: + void resourceChanged( int ); + void resourceChanged( QString&, QString& ); + void resourcesChanged( const QMap& ); + +public slots: + virtual void setVisible( bool ); + +protected: + virtual void itemAdded( QtxPreferenceItem* ); + virtual void itemRemoved( QtxPreferenceItem* ); + virtual void itemChanged( QtxPreferenceItem* ); + + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + void initialize() const; + +private: + QtxGridBox* myBox; + bool myInit; +}; + +class QTX_EXPORT QtxPagePrefItem : public QtxPreferenceItem +{ +public: + QtxPagePrefItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefItem(); + + virtual int rtti() const; + + QWidget* widget() const; + + static int RTTI(); + +protected: + void setWidget( QWidget* ); + + virtual void itemAdded( QtxPreferenceItem* ); + virtual void itemRemoved( QtxPreferenceItem* ); + virtual void itemChanged( QtxPreferenceItem* ); + + void pageChildItems( QList&, const bool = false ) const; + + virtual void store(); + virtual void retrieve(); + +private: + virtual void contentChanged(); + +private: + QPointer myWidget; +}; + +class QTX_EXPORT QtxPageNamedPrefItem : public QtxPagePrefItem +{ +public: + QtxPageNamedPrefItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPageNamedPrefItem(); + + virtual void setTitle( const QString& ); + +protected: + QLabel* label() const; + QWidget* control() const; + + void setControl( QWidget* ); + +private: + QPointer myLabel; + QPointer myControl; +}; + +class QTX_EXPORT QtxPagePrefListItem : public QObject, public QtxPagePrefItem +{ + Q_OBJECT + +public: + QtxPagePrefListItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefListItem(); + + virtual void updateContents(); + + QString emptyInfo() const; + void setEmptyInfo( const QString& ); + + bool isFixedSize() const; + void setFixedSize( const bool ); + +private slots: + void onItemSelectionChanged(); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + void updateInfo(); + void updateGeom(); + void updateState(); + void updateVisible(); + + int selected() const; + QtxPagePrefItem* selectedItem() const; + void setSelected( const int ); + +private: + bool myFix; + QListWidget* myList; + QStackedWidget* myStack; + + QString myInfText; + QLabel* myInfLabel; +}; + +class QTX_EXPORT QtxPagePrefToolBoxItem : public QtxPagePrefItem +{ +public: + QtxPagePrefToolBoxItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefToolBoxItem(); + + virtual void updateContents(); + +private: + void updateToolBox(); + +private: + QToolBox* myToolBox; +}; + +class QTX_EXPORT QtxPagePrefTabsItem : public QtxPagePrefItem +{ +public: + QtxPagePrefTabsItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefTabsItem(); + + virtual void updateContents(); + + int tabPosition() const; + void setTabPosition( const int ); + + int tabShape() const; + void setTabShape( const int ); + + QSize tabIconSize() const; + void setTabIconSize( const QSize& ); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + void updateTabs(); + +private: + QTabWidget* myTabs; +}; + +class QTX_EXPORT QtxPagePrefFrameItem : public QtxPagePrefItem +{ +public: + QtxPagePrefFrameItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefFrameItem(); + + virtual void updateContents(); + + bool stretch() const; + void setStretch( const bool ); + + int margin() const; + void setMargin( const int ); + + int spacing() const; + void setSpacing( const int ); + + int columns() const; + void setColumns( const int ); + + Qt::Orientation orientation() const; + void setOrientation( const Qt::Orientation ); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + void updateFrame(); + +private: + QtxGridBox* myBox; +}; + +class QTX_EXPORT QtxPagePrefGroupItem : public QtxPagePrefItem +{ +public: + QtxPagePrefGroupItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + QtxPagePrefGroupItem( const int, const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefGroupItem(); + + virtual void updateContents(); + + int margin() const; + void setMargin( const int ); + + int spacing() const; + void setSpacing( const int ); + + int columns() const; + void setColumns( const int ); + + Qt::Orientation orientation() const; + void setOrientation( const Qt::Orientation ); + + bool isFlat() const; + void setFlat( const bool ); + + virtual void setResource( const QString&, const QString& ); + + virtual void store(); + virtual void retrieve(); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + void updateState(); + void updateGroup(); + +private: + QtxGridBox* myBox; + QtxGroupBox* myGroup; +}; + +class QTX_EXPORT QtxPagePrefSpaceItem : public QtxPagePrefItem +{ +public: + QtxPagePrefSpaceItem( QtxPreferenceItem* = 0 ); + QtxPagePrefSpaceItem( Qt::Orientation, QtxPreferenceItem* = 0 ); + QtxPagePrefSpaceItem( const int, const int, QtxPreferenceItem* = 0 ); + virtual ~QtxPagePrefSpaceItem(); + + int size( Qt::Orientation ) const; + void setSize( Qt::Orientation, const int ); + + int stretch( Qt::Orientation ) const; + void setStretch( Qt::Orientation, const int ); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + void initialize( const int, const int, const int, const int ); +}; + +class QTX_EXPORT QtxPagePrefCheckItem : public QtxPagePrefItem +{ +public: + QtxPagePrefCheckItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefCheckItem(); + + virtual void setTitle( const QString& ); + + virtual void store(); + virtual void retrieve(); + +private: + QCheckBox* myCheck; +}; + +class QTX_EXPORT QtxPagePrefEditItem : public QtxPageNamedPrefItem +{ +public: + typedef enum { String, Integer, Double } InputType; + +public: + QtxPagePrefEditItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + QtxPagePrefEditItem( const int, const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefEditItem(); + + int inputType() const; + void setInputType( const int ); + + virtual void store(); + virtual void retrieve(); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + void updateEditor(); + +private: + int myType; + QLineEdit* myEditor; +}; + +class QTX_EXPORT QtxPagePrefSelectItem : public QtxPageNamedPrefItem +{ +public: + typedef enum { NoInput, String, Integer, Double } InputType; + +public: + QtxPagePrefSelectItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + QtxPagePrefSelectItem( const int, const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefSelectItem(); + + int inputType() const; + void setInputType( const int ); + + QStringList strings() const; + QList numbers() const; + + void setStrings( const QStringList& ); + void setNumbers( const QList& ); + + virtual void store(); + virtual void retrieve(); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + void updateSelector(); + void setStrings( const QVariant& ); + void setNumbers( const QVariant& ); + +private: + int myType; + QtxComboBox* mySelector; +}; + +class QTX_EXPORT QtxPagePrefSpinItem : public QtxPageNamedPrefItem +{ +public: + typedef enum { Integer, Double } InputType; + +public: + QtxPagePrefSpinItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + QtxPagePrefSpinItem( const int, const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefSpinItem(); + + QVariant step() const; + QVariant minimum() const; + QVariant maximum() const; + + QString prefix() const; + QString suffix() const; + QString specialValueText() const; + + void setStep( const QVariant& ); + void setMinimum( const QVariant& ); + void setMaximum( const QVariant& ); + + void setPrefix( const QString& ); + void setSuffix( const QString& ); + void setSpecialValueText( const QString& ); + + int inputType() const; + void setInputType( const int ); + + virtual void store(); + virtual void retrieve(); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + void updateSpinBox(); + +private: + int myType; +}; + +class QTX_EXPORT QtxPagePrefTextItem : public QtxPageNamedPrefItem +{ +public: + QtxPagePrefTextItem( QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + QtxPagePrefTextItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefTextItem(); + + virtual void store(); + virtual void retrieve(); + +private: + QTextEdit* myEditor; +}; + +class QTX_EXPORT QtxPagePrefColorItem : public QtxPageNamedPrefItem +{ +public: + QtxPagePrefColorItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefColorItem(); + + virtual void store(); + virtual void retrieve(); + +private: + QtxColorButton* myColor; +}; + +class QTX_EXPORT QtxPagePrefFontItem : public QObject, public QtxPageNamedPrefItem +{ + Q_OBJECT + +public: + QtxPagePrefFontItem( const int, const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + QtxPagePrefFontItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefFontItem(); + + int features() const; + void setFeatures( const int ); + + virtual void store(); + virtual void retrieve(); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + QtxFontEdit* myFont; +}; + +class QTX_EXPORT QtxPagePrefPathItem : public QtxPageNamedPrefItem +{ +public: + QtxPagePrefPathItem( const Qtx::PathType, const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + QtxPagePrefPathItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefPathItem(); + + Qtx::PathType pathType() const; + void setPathType( const Qtx::PathType ); + + QString pathFilter() const; + void setPathFilter( const QString& ); + + virtual void store(); + virtual void retrieve(); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + QtxPathEdit* myPath; +}; + +class QTX_EXPORT QtxPagePrefPathListItem : public QtxPageNamedPrefItem +{ +public: + QtxPagePrefPathListItem( QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + QtxPagePrefPathListItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + QtxPagePrefPathListItem( const Qtx::PathType, const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefPathListItem(); + + Qtx::PathType pathType() const; + void setPathType( const Qtx::PathType ); + + virtual void store(); + virtual void retrieve(); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + QtxPathListEdit* myPaths; +}; + +class QTX_EXPORT QtxPagePrefDateTimeItem : public QtxPageNamedPrefItem +{ +public: + typedef enum { Date, Time, DateTime } InputType; + +public: + QtxPagePrefDateTimeItem( const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + QtxPagePrefDateTimeItem( const int, const QString&, QtxPreferenceItem* = 0, + const QString& = QString(), const QString& = QString() ); + virtual ~QtxPagePrefDateTimeItem(); + + int inputType() const; + void setInputType( const int ); + + bool calendar() const; + void setCalendar( const bool ); + + QDate maximumDate() const; + QTime maximumTime() const; + QDate minimumDate() const; + QTime minimumTime() const; + + void setMaximumDate( const QDate& ); + void setMaximumTime( const QTime& ); + void setMinimumDate( const QDate& ); + void setMinimumTime( const QTime& ); + + virtual void store(); + virtual void retrieve(); + +protected: + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +private: + void updateDateTime(); + +private: + int myType; + QDateTimeEdit* myDateTime; +}; + +#endif diff --git a/src/Qtx/QtxPathDialog.cxx b/src/Qtx/QtxPathDialog.cxx new file mode 100755 index 000000000..d6989e6b6 --- /dev/null +++ b/src/Qtx/QtxPathDialog.cxx @@ -0,0 +1,740 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPathDialog.cxx +// Author: Sergey TELKOV + +#include "QtxPathDialog.h" + +#include "QtxGridBox.h" +#include "QtxGroupBox.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char* open_icon[] = { +"16 16 5 1", +" c none", +". c #ffff00", +"# c #848200", +"a c #ffffff", +"b c #000000", +" ", +" bbb ", +" b b b", +" bb", +" bbb bbb", +" ba.abbbbbbb ", +" b.a.a.a.a.b ", +" ba.a.a.a.ab ", +" b.a.abbbbbbbbbb", +" ba.ab#########b", +" b.ab#########b ", +" bab#########b ", +" bb#########b ", +" bbbbbbbbbbb ", +" ", +" " +}; + +/*! + \class QtxPathDialog + \brief The QtxPathDialog class provides a simple convenience dialog to + enter a path to the file or to the directory. + + The QtxPathDialog class adds possibility to browse the file system + with help of standard Open/Save dialog boxes or enter the file/directory + path manually. + + Default implementation provides only one "standard" file entry. + Sometimes it is necessary to select several different files/directories + from the same dialog box. In this case it is possible to derive from the + QtxPathDialog class and use createFileEntry() method to add required + number of file entries. +*/ + +/*! + \brief Constructor. + \param import if \c true, the dialog box is shown for "open" mode, + otherwise, it is shown in the "save" mode + \param parent parent widget + \param modal if \c true, the dialog box should be modal + \param resize if \c true, the dialog box is resizable + \param buttons required buttons (QtxDialog::ButtonFlags) + \param f window flags +*/ +QtxPathDialog::QtxPathDialog( const bool import, QWidget* parent, const bool modal, + const bool resize, const int buttons, Qt::WindowFlags f ) +: QtxDialog( parent, modal, resize, buttons, f ), + myDefault( -1 ), + myEntriesFrame( 0 ), + myOptionsFrame( 0 ) +{ + initialize(); + + setWindowTitle( tr( import ? "Open file" : "Save file" ) ); + + setDefaultEntry( createFileEntry( tr( "File name" ), import ? OpenFile : SaveFile ) ); + QLineEdit* le = fileEntry( defaultEntry() ); + if ( le ) + le->setMinimumWidth( 200 ); + + validate(); + + setFocusProxy( le ); + + updateVisibility(); +} + +/*! + \brief Constructor. + \param parent parent widget + \param modal if \c true, the dialog box should be modal + \param resize if \c true, the dialog box is resizable + \param buttons required buttons (QtxDialog::ButtonFlags) + \param f window flags +*/ +QtxPathDialog::QtxPathDialog( QWidget* parent, const bool modal, + const bool resize, const int buttons, Qt::WindowFlags f ) +: QtxDialog( parent, modal, resize, buttons, f ), + myDefault( -1 ), + myEntriesFrame( 0 ), + myOptionsFrame( 0 ) +{ + initialize(); + + updateVisibility(); +} + +/*! + \brief Destructor. +*/ +QtxPathDialog::~QtxPathDialog() +{ +} + +/*! + \brief Get selected file name. + \return file name +*/ +QString QtxPathDialog::fileName() const +{ + return fileName( defaultEntry() ); +} + +/*! + \brief Set the file name. + \param txt new file name + \param autoExtension if \c true an extension is determined automatically by file +*/ +void QtxPathDialog::setFileName( const QString& txt, const bool autoExtension ) +{ + setFileName( defaultEntry(), txt, autoExtension ); +} + +/*! + \brief Get current file filter. + \return file filter +*/ +QString QtxPathDialog::filter() const +{ + return filter( defaultEntry() ); +} + +/*! + \brief Change file filter. + + Filter is a list of file masks, separated by ';;'. For example, + "*.h;;*.cxx" + + \param fltr new file filter +*/ +void QtxPathDialog::setFilter( const QString& fltr ) +{ + setFilter( defaultEntry(), fltr ); +} + +/*! + \brief Show/hide the path dialog box/ + \param on new visibility state +*/ +void QtxPathDialog::setVisible( bool on ) +{ + if ( on ) + updateVisibility(); + + QtxDialog::setVisible( on ); +} + +/*! + \brief Called when user clicks a "browse" button + to open standard file dialog. +*/ +void QtxPathDialog::onBrowse() +{ + const QObject* obj = sender(); + + int id = -1; + + for ( FileEntryMap::Iterator it = myEntries.begin(); it != myEntries.end() && id == -1; ++it ) + { + if ( it.value().btn == obj ) + id = it.key(); + } + + if ( id == -1 ) + return; + + FileEntry& entry = myEntries[id]; + + bool isDir = entry.mode != OpenFile && entry.mode != SaveFile; + + if ( !entry.dlg ) + { + entry.dlg = new QFileDialog( this, windowTitle(), QDir::current().path() ); + switch ( entry.mode ) + { + case NewDir: + case OpenDir: + case SaveDir: + isDir = true; + entry.dlg->setFileMode( QFileDialog::DirectoryOnly ); + break; + case SaveFile: + entry.dlg->setFileMode( QFileDialog::AnyFile ); + break; + case OpenFile: + default: + entry.dlg->setFileMode( QFileDialog::ExistingFiles ); + break; + } + } + + if ( !isDir ) + { + QStringList fList = prepareFilters( entry.filter ); + if ( !fList.isEmpty() ) + entry.dlg->setFilters( fList ); + } + entry.dlg->selectFile( fileName( id ) ); + + if ( entry.dlg->exec() != Accepted ) + return; + + QStringList fileList = entry.dlg->selectedFiles(); + QString fName = !fileList.isEmpty() ? fileList.first() : QString(); + + if ( fName.isEmpty() ) + return; + + if ( Qtx::extension( fName ).isEmpty() && !isDir ) + fName = autoExtension( fName, entry.dlg->selectedFilter() ); + + fName = QDir::convertSeparators( fName ); + QString prev = QDir::convertSeparators( fileName( id ) ); + if ( isDir ) + { + while ( prev.length() && prev.at( prev.length() - 1 ) == QDir::separator() ) + prev.remove( prev.length() - 1, 1 ); + while ( fName.length() && fName.at( fName.length() - 1 ) == QDir::separator() ) + fName.remove( fName.length() - 1, 1 ); + } + + if ( prev == fName ) + return; + + setFileName( id, fName ); + fileNameChanged( id, fName ); + + if ( id == defaultEntry() ) + emit fileNameChanged( fName ); +} + +/*! + \brief Called when user presses \c Return key being in the line edit. +*/ +void QtxPathDialog::onReturnPressed() +{ + const QObject* obj = sender(); + + int id = -1; + for ( FileEntryMap::Iterator it = myEntries.begin(); it != myEntries.end() && id == -1; ++it ) + { + if ( it.value().edit == obj ) + id = it.key(); + } + + if ( id == -1 ) + return; + + fileNameChanged( id, fileName( id ) ); + + if ( id == defaultEntry() ) + emit fileNameChanged( fileName() ); +} + +/*! + \brief Called when the text in the line edit is changed by the user. + \param txt current text (not used) +*/ +void QtxPathDialog::onTextChanged( const QString& /*txt*/ ) +{ + validate(); +} + +/*! + \brief Check validity of the entered text and enable/disable standard + \c OK, \c Yes buttons. +*/ +void QtxPathDialog::validate() +{ + setButtonEnabled( isValid(), OK | Yes ); +} + +/*! + \brief Check if the entered file/directory name is valid. + \return \c true if selected file name is valid +*/ +bool QtxPathDialog::isValid() +{ + bool ok = true; + for ( FileEntryMap::Iterator it = myEntries.begin(); it != myEntries.end() && ok; ++it ) + { + if ( it.value().edit->isEnabled() ) + ok = !it.value().edit->text().trimmed().isEmpty(); + } + + return ok; +} + +/*! + \brief Check if the entered data is acceptable. + \return \c true if entered data is acceptable +*/ +bool QtxPathDialog::acceptData() const +{ + bool ok = true; + + QWidget* parent = (QWidget*)this; + + FileEntryMap::ConstIterator it; + for ( it = myEntries.begin(); it != myEntries.end() && ok; ++it ) + { + const FileEntry& entry = it.value(); + QFileInfo fileInfo( entry.edit->text() ); + if ( entry.edit->text().isEmpty() ) + { + QMessageBox::critical( parent, windowTitle(), tr( "File name not specified" ), + QMessageBox::Ok, QMessageBox::NoButton ); + ok = false; + } + else switch ( entry.mode ) + { + case OpenFile: + if ( !fileInfo.exists() ) + { + QMessageBox::critical( parent, windowTitle(), tr( "File \"%1\" does not exist" ).arg( fileInfo.filePath() ), + QMessageBox::Ok, QMessageBox::NoButton ); + ok = false; + } + break; + case SaveFile: + if ( fileInfo.exists() ) + ok = QMessageBox::warning( parent, windowTitle(), tr( "File \"%1\" already exist. Do you want to overwrite it?" ).arg( fileInfo.filePath() ), + QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes; + break; + case OpenDir: + if ( !fileInfo.exists() || !fileInfo.isDir() ) + { + QMessageBox::critical( parent, windowTitle(), tr( "Directory \"%1\" does not exist" ).arg( fileInfo.filePath() ), + QMessageBox::Ok, QMessageBox::NoButton ); + ok = false; + } + break; + case SaveDir: + if ( fileInfo.exists() && !fileInfo.isDir() ) + { + QMessageBox::critical( parent, windowTitle(), tr( "Directory \"%1\" can't be created because file with the same name exist" ).arg( fileInfo.filePath() ), + QMessageBox::Ok, QMessageBox::NoButton ); + ok = false; + } + break; + case NewDir: + if ( fileInfo.exists() ) + { + if ( !fileInfo.isDir() ) + { + QMessageBox::critical( parent, windowTitle(), tr( "Directory \"%1\" can't be created because file with the same name exist" ).arg( fileInfo.filePath() ), + QMessageBox::Ok, QMessageBox::NoButton ); + ok = false; + } + else if ( QDir( fileInfo.filePath() ).count() > 2 ) + ok = QMessageBox::warning( parent, windowTitle(), tr( "Directory \"%1\" not empty. Do you want to remove all files in this directory?" ).arg( fileInfo.filePath() ), + QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes; + } + break; + default: + break; + } + + if ( !ok ) + entry.edit->setFocus(); + } + + return ok; +} + +/*! + \brief Perform custom actions when the file name is changed. + + This method can be redefined in the successor classes. + Default implementation does nothing. + + \param id file entry + \param fileName file name +*/ +void QtxPathDialog::fileNameChanged( int /*id*/, QString /*fileName*/ ) +{ +} + +/*! + \fn void QtxPathDialog::fileNameChanged( QString fileName ); + \brief Emitted when the file name is changed. + \param fileName file name +*/ + +/*! + \brief Get options grame widget. + \return options frame widget +*/ +QFrame* QtxPathDialog::optionsFrame() +{ + return myOptionsFrame; +} + +/*! + \brief Get file name from specified entry. + \param id file entry ID + \return file name or null string if \a id is invalid +*/ +QString QtxPathDialog::fileName( const int id ) const +{ + QString res; + if ( myEntries.contains( id ) ) + res = myEntries[id].edit->text(); + return res; +} + +/*! + \brief Change file name by specified file entry. + \param id file entry ID + \param txt new file name + \param autoExt if \c true, assign extension automatically +*/ +void QtxPathDialog::setFileName( const int id, const QString& txt, const bool autoExt ) +{ + int mode; + QLineEdit* le = fileEntry( id, mode ); + + if ( le ) + { + if ( autoExt && ( mode == OpenFile || mode == SaveFile ) ) + le->setText( autoExtension( txt, filter( id ) ) ); + else + le->setText( txt ); + } +} + +/*! + \brief Get file filter from the specified file entry. + \param id file entry ID + \return file filter or null string if \a id is invalid +*/ +QString QtxPathDialog::filter( const int id ) const +{ + QString res; + if ( myEntries.contains( id ) ) + res = myEntries[id].filter; + return res; +} + +/*! + \brief Set file filter to the specified file entry. + \param id file entry ID + \param filter file filter or null string if \a id is invalid +*/ +void QtxPathDialog::setFilter( const int id, const QString& filter ) +{ + if ( myEntries.contains( id ) ) + myEntries[id].filter = filter; +} + +/*! + \brief Get line edit widget for the specified file entry. + \param id file entry ID + \return line edit widget or 0 if \a id is invalid +*/ +QLineEdit* QtxPathDialog::fileEntry( const int id ) const +{ + QLineEdit* le = 0; + if ( myEntries.contains( id ) ) + le = myEntries[id].edit; + + return le; +} + +/*! + \brief Get line edit widget and file mode for the specified file entry. + \param id file entry ID + \param theMode to return file entry mode + \return line edit widget or 0 if \a id is invalid +*/ +QLineEdit* QtxPathDialog::fileEntry( const int theId, int& theMode ) const +{ + QLineEdit* le = 0; + if ( myEntries.contains( theId ) ) + { + le = myEntries[theId].edit; + theMode = myEntries[theId].mode; + } + + return le; +} + +/*! + \brief Create new file entry. + + If required file entry is already in use or if specified \a id is < 0, + new ID is generated and returned. + + \param lab file entry title + \param mode file entry mode + \param id required file entry ID + \return created file entry ID +*/ +int QtxPathDialog::createFileEntry( const QString& lab, const int mode, + const QString& filter, const int id ) +{ + int num = id; + if ( num == -1 ) + { + num--; + while ( myEntries.contains( num ) ) + num--; + } + + FileEntry entry; + entry.dlg = 0; + entry.mode = mode; + entry.filter = filter; + + new QLabel( lab, myEntriesFrame ); + entry.edit = new QLineEdit( myEntriesFrame ); + + entry.btn = new QPushButton( myEntriesFrame ); + entry.btn->setAutoDefault( false ); + entry.btn->setIcon( QPixmap( open_icon ) ); + + Qtx::PathType type = Qtx::PT_OpenFile; + switch ( mode ) + { + case OpenFile: + type = Qtx::PT_OpenFile; + break; + case SaveFile: + type = Qtx::PT_SaveFile; + break; + case OpenDir: + case SaveDir: + case NewDir: + type = Qtx::PT_Directory; + break; + } + entry.edit->setCompleter( Qtx::pathCompleter( type, filter ) ); + + connect( entry.btn, SIGNAL( clicked() ), this, SLOT( onBrowse() ) ); + connect( entry.edit, SIGNAL( returnPressed() ), this, SLOT( onReturnPressed() ) ); + connect( entry.edit, SIGNAL( textChanged( const QString& ) ), this, SLOT( onTextChanged( const QString& ) ) ); + + myEntries.insert( num, entry ); + + return num; +} + +/*! + \brief Get default file entry ID. + \return default entry ID +*/ +int QtxPathDialog::defaultEntry() const +{ + return myDefault; +} + +/*! + \brief Set default entry. + \param id new default entry ID +*/ +void QtxPathDialog::setDefaultEntry( const int id ) +{ + myDefault = id; +} + +/*! + \brief Initialize dialog layout. +*/ +void QtxPathDialog::initialize() +{ + setWindowTitle( tr( "File dialog" ) ); + + QVBoxLayout* main = new QVBoxLayout( mainFrame() ); + main->setMargin( 0 ); + + QtxGroupBox* base = new QtxGroupBox( "", mainFrame() ); + main->addWidget( base ); + + QtxGridBox* mainGroup = new QtxGridBox( 1, Qt::Horizontal, base, 0 ); + base->setWidget( mainGroup ); + + myEntriesFrame = new QtxGridBox( 3, Qt::Horizontal, mainGroup ); + myOptionsFrame = new QFrame( mainGroup ); +} + +/*! + \brief Prepare file filters. + \param list of file masks, separated by ';;', for example, "*.h;;*.cxx" + \return list of processed file filters +*/ +QStringList QtxPathDialog::prepareFilters( const QString& filter ) const +{ + QStringList res; + bool allFilter = false; + if ( !filter.isEmpty() ) + { + res = filter.split( ";;" ); + for ( QStringList::ConstIterator it = res.begin(); it != res.end() && !allFilter; ++it ) + { + QStringList wildCards = filterWildCards( *it ); + allFilter = wildCards.indexOf( "*.*" ) != -1; + } + } + + if ( !allFilter ) + res.append( tr( "All files (*.*)" ) ); + + return res; +} + +/*! + \brief Get wildcards from the specified file filter. + \param theFilter file filter being processed + \return list of filters with filtered wild cards +*/ +QStringList QtxPathDialog::filterWildCards( const QString& theFilter ) const +{ + QStringList res; + + int b = theFilter.lastIndexOf( "(" ); + int e = theFilter.lastIndexOf( ")" ); + if ( b != -1 && e != -1 ) + { + QString content = theFilter.mid( b + 1, e - b - 1 ).trimmed(); + QStringList lst = content.split( " " ); + for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) + { + if ( (*it).indexOf( "." ) != -1 ) + res.append( (*it).trimmed() ); + } + } + return res; +} + +/*! + \brief Get file file name with automatically assigned extension. + \param theFileName file name being processed + \param theFilter list of file filters + \return file name with assigned extension +*/ +QString QtxPathDialog::autoExtension( const QString& theFileName, const QString& theFilter ) const +{ + QString fName = theFileName; + + if ( fName.isEmpty() ) + return fName; + + QString filter; + QStringList filters = prepareFilters( theFilter ); + if ( !filters.isEmpty() ) + filter = filters.first(); + + QStringList wildCards = filterWildCards( filter ); + if ( !wildCards.isEmpty() ) + { + QString ext = wildCards.first(); + if ( ext.indexOf( "." ) != -1 ) + ext = ext.mid( ext.indexOf( "." ) + 1 ); + + if ( !ext.isEmpty() && !ext.contains( "*" ) ) + fName = QDir::convertSeparators( fName ) + QString( "." ) + ext; + } + + return fName; +} + +/*! + \brief Check if there are visible child widgets. + \param wid parent widget being checked + \return \c true if widget \a wid has visible children +*/ +bool QtxPathDialog::hasVisibleChildren( QWidget* wid ) const +{ + bool res = false; + if ( wid ) + { + const QObjectList& aChildren = wid->children(); + for ( QObjectList::const_iterator it = aChildren.begin(); it != aChildren.end() && !res; ++it ) + { + if ( (*it)->isWidgetType() ) + res = ((QWidget*)(*it))->isVisibleTo( wid ); + } + } + return res; +} + +/*! + \brief Upadte dialof box's child widgets visibility state. +*/ +void QtxPathDialog::updateVisibility() +{ + if ( hasVisibleChildren( myEntriesFrame ) ) + myEntriesFrame->show(); + else + myEntriesFrame->hide(); + + if ( hasVisibleChildren( myOptionsFrame ) ) + myOptionsFrame->show(); + else + myOptionsFrame->hide(); +} diff --git a/src/Qtx/QtxPathDialog.h b/src/Qtx/QtxPathDialog.h new file mode 100755 index 000000000..57b887756 --- /dev/null +++ b/src/Qtx/QtxPathDialog.h @@ -0,0 +1,118 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPathDialog.h +// Author: Sergey TELKOV + +#ifndef QTXPATHDIALOG_H +#define QTXPATHDIALOG_H + +#include "QtxDialog.h" + +#include + +class QFrame; +class QLineEdit; +class QPushButton; +class QFileDialog; + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +class QTX_EXPORT QtxPathDialog : public QtxDialog +{ + Q_OBJECT + +protected: + QtxPathDialog( QWidget* = 0, const bool = true, const bool = false, + const int = Standard, Qt::WindowFlags = 0 ); + +public: + QtxPathDialog( const bool, QWidget* = 0, const bool = true, + const bool = false, const int = Standard, Qt::WindowFlags = 0 ); + virtual ~QtxPathDialog(); + + QString fileName() const; + void setFileName( const QString&, const bool = false ); + + QString filter() const; + void setFilter( const QString& ); + +signals: + void fileNameChanged( QString ); + +public slots: + virtual void setVisible( bool ); + +protected slots: + void validate(); + +private slots: + void onBrowse(); + void onReturnPressed(); + void onTextChanged( const QString& ); + +protected: + virtual bool isValid(); + virtual bool acceptData() const; + virtual void fileNameChanged( int, QString ); + + QFrame* optionsFrame(); + QString fileName( const int ) const; + void setFileName( const int, const QString&, const bool = false ); + + QString filter( const int ) const; + void setFilter( const int, const QString& ); + + QLineEdit* fileEntry( const int ) const; + QLineEdit* fileEntry( const int, int& ) const; + int createFileEntry( const QString&, const int, + const QString& = QString(), const int = -1 ); + + int defaultEntry() const; + void setDefaultEntry( const int ); + +private: + void initialize(); + void updateVisibility(); + QStringList prepareFilters( const QString& ) const; + bool hasVisibleChildren( QWidget* ) const; + QStringList filterWildCards( const QString& ) const; + QString autoExtension( const QString&, const QString& = QString::null ) const; + +protected: + enum { OpenFile, SaveFile, OpenDir, SaveDir, NewDir }; + +private: + typedef struct { int mode; QLineEdit* edit; QString filter; + QPushButton* btn; QFileDialog* dlg; } FileEntry; + typedef QMap FileEntryMap; + +private: + FileEntryMap myEntries; + int myDefault; + QWidget* myEntriesFrame; + QFrame* myOptionsFrame; +}; + +#ifdef WIN32 +#pragma warning( default:4251 ) +#endif + +#endif diff --git a/src/Qtx/QtxPathEdit.cxx b/src/Qtx/QtxPathEdit.cxx new file mode 100644 index 000000000..3e0c37fa0 --- /dev/null +++ b/src/Qtx/QtxPathEdit.cxx @@ -0,0 +1,248 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPathEdit.cxx +// Author: Sergey TELKOV + +#include "QtxPathEdit.h" + +#include +#include +#include +#include +#include +#include +#include + +static const char* browse_icon[] = { +"16 16 5 1", +" c none", +". c #ffff00", +"# c #848200", +"a c #ffffff", +"b c #000000", +" ", +" bbb ", +" b b b", +" bb", +" bbb bbb", +" ba.abbbbbbb ", +" b.a.a.a.a.b ", +" ba.a.a.a.ab ", +" b.a.abbbbbbbbbb", +" ba.ab#########b", +" b.ab#########b ", +" bab#########b ", +" bb#########b ", +" bbbbbbbbbbb ", +" ", +" " +}; + +/*! + \class QtxPathEdit + \brief The QtxPathEdit class represents a widget for file or directory + path preference items editing. + + The path preference item is represented as the line edit box for the + direct path editing and small button clicking on which invokes browse + dialog box. The widget can be used in different modes: "Open File", + "Save File", "Select Directory". The mode defines the type of the + standard browse dialog box which is invoked on the button clicking. + + Initial path value can be set with setPath() method. Chosen path + can be retrieved with the path() method. The widget mode can be set + with setPathType() and retrieved with pathType() method. + + In addition, file/direcrory filters (wildcards) can be set with the + setPathFilter() method and retrieved with pathFilter() method. +*/ + +/*! + \brief Constructor + \param type widget mode (Qtx::PathType) + \param parent parent widget + \sa pathType(), setPathType() +*/ +QtxPathEdit::QtxPathEdit( const Qtx::PathType type, QWidget* parent ) +: QFrame( parent ), + myType( type ) +{ + initialize(); +} + +/*! + \brief Constructor + + Qtx::PT_OpenFile mode is used by default. + + \param parent parent widget + \sa pathType(), setPathType() +*/ +QtxPathEdit::QtxPathEdit( QWidget* parent ) +: QFrame( parent ), + myType( Qtx::PT_OpenFile ) +{ + initialize(); +} + +/*! + \brief Destructor +*/ +QtxPathEdit::~QtxPathEdit() +{ +} + +/*! + \brief Get widget mode. + \return currently used widget mode (Qtx::PathType) + \sa setPathType() +*/ +Qtx::PathType QtxPathEdit::pathType() const +{ + return myType; +} + +/*! + \brief Set widget mode. + \param type new widget mode (Qtx::PathType) + \sa pathType() +*/ +void QtxPathEdit::setPathType( const Qtx::PathType type ) +{ + if ( myType == type ) + return; + + myType = type; + updateState(); +} + +/*! + \brief Get currently selected path. + \return file or directory path entered by the user + \sa setPath() +*/ +QString QtxPathEdit::path() const +{ + return myPath->text(); +} + +/*! + \brief Set path. + \param txt file or directory path + \sa path() +*/ +void QtxPathEdit::setPath( const QString& txt ) +{ + myPath->setText( txt ); +} + +/*! + \brief Get currently used path filters. + \return file or directory path filters + \sa setPathFilter() +*/ +QString QtxPathEdit::pathFilter() const +{ + return myFilter; +} + +/*! + \brief Set path filters. + \param f new file or directory path filters + \sa pathFilter() +*/ +void QtxPathEdit::setPathFilter( const QString& f ) +{ + if ( myFilter == f ) + return; + + myFilter = f; + updateState(); +} + +/*! + \brief Called when user clicks "Browse" button. + + Invokes standard browsng dialog box depending on the used widget mode. + + \param on (not used) + \sa mode(), setMode() +*/ +void QtxPathEdit::onBrowse( bool /*on*/ ) +{ + QString path; + QString initial = QFileInfo( myPath->text() ).path(); + switch ( pathType() ) + { + case Qtx::PT_OpenFile: + path = QFileDialog::getOpenFileName( myPath, QString(), initial, pathFilter() ); + break; + case Qtx::PT_SaveFile: + path = QFileDialog::getSaveFileName( myPath, QString(), initial, pathFilter() ); + break; + case Qtx::PT_Directory: + path = QFileDialog::getExistingDirectory( myPath, QString(), initial ); + break; + } + + if ( !path.isEmpty() ) + myPath->setText( QDir::convertSeparators( path ) ); + + myPath->setFocus(); +} + +/*! + \brief Get internal line edit widget. + \return line edit box widget +*/ +QLineEdit* QtxPathEdit::lineEdit() const +{ + return myPath; +} + +/*! + \brief Perform internal widget intialization. +*/ +void QtxPathEdit::initialize() +{ + QHBoxLayout* base = new QHBoxLayout( this ); + base->setMargin( 0 ); + base->setSpacing( 5 ); + + base->addWidget( myPath = new QLineEdit( this ) ); + myPath->setValidator( new QRegExpValidator( QRegExp( "^([\\w/]{2}|[A-Z]:)[^:;\\*\\?]*[\\w\\\\/\\.]$" ), myPath ) ); + + QToolButton* browse = new QToolButton( this ); + browse->setIcon( QPixmap( browse_icon ) ); + base->addWidget( browse ); + + connect( browse, SIGNAL( clicked( bool ) ), this, SLOT( onBrowse( bool ) ) ); + + setFocusProxy( myPath ); + + updateState(); +} + +/*! + \brief Update widget state. +*/ +void QtxPathEdit::updateState() +{ + myPath->setCompleter( Qtx::pathCompleter( pathType(), pathFilter() ) ); +} diff --git a/src/Qtx/QtxPathEdit.h b/src/Qtx/QtxPathEdit.h new file mode 100644 index 000000000..c4fe189c6 --- /dev/null +++ b/src/Qtx/QtxPathEdit.h @@ -0,0 +1,65 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPathEdit.h +// Author: Sergey TELKOV + +#ifndef QTXPATHEDIT_H +#define QTXPATHEDIT_H + +#include "Qtx.h" + +#include + +class QLineEdit; + +class QTX_EXPORT QtxPathEdit : public QFrame +{ + Q_OBJECT + +public: + QtxPathEdit( const Qtx::PathType, QWidget* = 0 ); + QtxPathEdit( QWidget* = 0 ); + virtual ~QtxPathEdit(); + + QString path() const; + void setPath( const QString& ); + + Qtx::PathType pathType() const; + void setPathType( const Qtx::PathType ); + + QString pathFilter() const; + void setPathFilter( const QString& ); + +private slots: + void onBrowse( bool = false ); + +protected: + QLineEdit* lineEdit() const; + +private: + void initialize(); + void updateState(); + +private: + QLineEdit* myPath; + Qtx::PathType myType; + QString myFilter; +}; + +#endif diff --git a/src/Qtx/QtxPathListEdit.cxx b/src/Qtx/QtxPathListEdit.cxx new file mode 100644 index 000000000..dee61a389 --- /dev/null +++ b/src/Qtx/QtxPathListEdit.cxx @@ -0,0 +1,811 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPathListEdit.cxx +// Author: Sergey TELKOV + +#include "QtxPathListEdit.h" + +#include "QtxPathEdit.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char* delete_icon[] = { +"16 16 3 1", +"` c #810000", +" c none", +"# c #ffffff", +" ", +" ", +" ``# ``# ", +" ````# ``# ", +" ````# ``# ", +" ```# `# ", +" `````# ", +" ```# ", +" `````# ", +" ```# ``# ", +" ```# ``# ", +" ```# `# ", +" ```# `# ", +" `# `# ", +" ", +" " +}; + +static const char* insert_icon[] = { +"16 16 5 1", +"` c #000000", +". c #ffff00", +"# c #9d9da1", +" c none", +"b c #ffffff", +" ", +" ", +" # #b #. ", +" # #.#.` ` ` ", +" .#.b#### ` ", +" ### .. ", +" . # .# ` ", +" #` #. ", +" # ` ", +" ` ", +" ` ", +" ` ", +" ` ", +" ` ` ` ` ` ` ", +" ", +" " +}; + +static const char* movedown_icon[] = { +"16 16 2 1", +"` c #000000", +" c none", +" ", +" ", +" ``` ", +" ``` ", +" ``` ", +" ``` ", +" ``` ", +" ``` ", +" ``````````` ", +" ````````` ", +" ``````` ", +" ````` ", +" ``` ", +" ` ", +" ", +" " +}; + +static const char* moveup_icon[] = { +"16 16 2 1", +"` c #000000", +" c none", +" ", +" ", +" ` ", +" ``` ", +" ````` ", +" ``````` ", +" ````````` ", +" ``````````` ", +" ``` ", +" ``` ", +" ``` ", +" ``` ", +" ``` ", +" ``` ", +" ", +" " +}; + + +/*! + \class QtxPathListEdit::Editor + \brief Path editor widget + \internal +*/ + +class QtxPathListEdit::Editor : public QtxPathEdit +{ +public: + /*! + \brief Constructor + \internal + */ + Editor( QWidget* parent = 0 ) : QtxPathEdit( parent ) + { + layout()->setSpacing( 0 ); + lineEdit()->setFrame( false ); + } + + /*! + \brief Destructor + \internal + */ + virtual ~Editor() {} +}; + +/*! + \class QtxPathListEdit::Delegate + \brief Custom item delegate for the paths list widget. + \internal +*/ + +class QtxPathListEdit::Delegate : public QItemDelegate +{ +public: + Delegate( QtxPathListEdit*, QObject* = 0 ); + virtual ~Delegate(); + + virtual QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const; + virtual void setModelData( QWidget*, QAbstractItemModel*, const QModelIndex& ) const; + virtual void setEditorData( QWidget*, const QModelIndex& ) const; + virtual void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const; + +protected: + virtual void drawFocus( QPainter*, const QStyleOptionViewItem&, const QRect& ) const; + +private: + QtxPathListEdit* myPathEdit; +}; + +/*! + \brief Constructor. + \internal + \param pe path list editor + \param parent parent widget +*/ +QtxPathListEdit::Delegate::Delegate( QtxPathListEdit* pe, QObject* parent ) +: QItemDelegate( parent ), + myPathEdit( pe ) +{ +} + +/*! + \brief Destructor. + \internal +*/ +QtxPathListEdit::Delegate::~Delegate() +{ +} + +/*! + \brief Create editor widget. + \internal + \param parent parent widget + \param option style option + \param index data model index +*/ +QWidget* QtxPathListEdit::Delegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, + const QModelIndex& index ) const +{ + return myPathEdit->createEditor( parent ); +} + +/*! + \brief Set modified data back to the data model. + \internal + \param editor editor widget + \param model data model + \param index data model index +*/ +void QtxPathListEdit::Delegate::setModelData( QWidget* editor, QAbstractItemModel* model, + const QModelIndex& index ) const +{ + myPathEdit->setModelData( editor, index ); +} + +/*! + \brief Set data from the data model to the editor. + \internal + \param editor editor widget + \param index data model index +*/ +void QtxPathListEdit::Delegate::setEditorData( QWidget* editor, const QModelIndex& index ) const +{ + myPathEdit->setEditorData( editor, index ); +} + +/*! + \brief Customize paint operation. + \internal + \param painter painter + \param option style option + \param index data model index +*/ +void QtxPathListEdit::Delegate::paint( QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index ) const +{ + QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; + if ( cg == QPalette::Normal && !( option.state & QStyle::State_Active ) ) + cg = QPalette::Inactive; + + if ( option.state & QStyle::State_Selected ) + { + painter->fillRect( option.rect, option.palette.brush( cg, QPalette::Highlight ) ); + painter->setPen( option.palette.color( cg, QPalette::HighlightedText ) ); + } + else + painter->setPen( option.palette.color( cg, QPalette::Text ) ); + + QItemDelegate::paint( painter, option, index ); +} + +/*! + \brief Customize drawing selection focus operation. + \internal + \param painter painter + \param option style option + \param rect selection rectangle +*/ +void QtxPathListEdit::Delegate::drawFocus( QPainter* painter, const QStyleOptionViewItem& option, + const QRect& rect ) const +{ + QItemDelegate::drawFocus( painter, option, option.rect ); +} + +/*! + \class QtxPathListEdit + \brief The QtxPathListEdit class represents a widget for files or + directories paths list preference items editing. + + The path list preference item is represented as the list box widget. + It provides such operations like adding new file/directory path to the + list, removing selected paths and modifying of already entered ones. + + The widget can be used in two modes: list of files or list of directories. + The mode defines the type of the standard browse dialog box which is + invoked on the browse button clicking. + + Initial path list value can be set with setPathList() method. Chosen path + list can be retrieved with the pathList() method. The widget mode can be set + with setPathType() and retrieved with pathType() method. + + In addition, it is possible to add path items to the list with the insert() + method, remove items with the remove() methods, clear all the widget contents + with the clear() method. To get the number of entered paths can be retrieved + with the count() method. To check if any path already exists in the paths list, + use contains() method. +*/ + +/*! + \brief Constructor. + \param type widget mode (Qtx::PathType) + \param parent parent widget + \sa pathType(), setPathType() +*/ +QtxPathListEdit::QtxPathListEdit( const Qtx::PathType type, QWidget* parent ) +: QFrame( parent ), + myCompleter( 0 ), + myType( type ), + myDuplicate( false ) +{ + initialize(); +} + +/*! + \brief Constructor. + + Qtx::PT_OpenFile mode is used by default. + + \param parent parent widget + \sa pathType(), setPathType() +*/ +QtxPathListEdit::QtxPathListEdit( QWidget* parent ) +: QFrame( parent ), + myCompleter( 0 ), + myType( Qtx::PT_OpenFile ), + myDuplicate( false ) +{ + initialize(); +} + +/*! + \brief Destructor. +*/ +QtxPathListEdit::~QtxPathListEdit() +{ +} + +/*! + \brief Get widget mode. + \return currently used widget mode (Qtx::PathType) + \sa setPathType() +*/ +Qtx::PathType QtxPathListEdit::pathType() const +{ + return myType; +} + +/*! + \brief Set widget mode. + \param t new widget mode (Qtx::PathType) + \sa pathType() +*/ +void QtxPathListEdit::setPathType( const Qtx::PathType t ) +{ + if ( myType == t ) + return; + + myType = t; + + delete myCompleter; + myCompleter = 0; +} + +/*! + \brief Get currently selected paths list. + \return files or directories paths list entered by the user + \sa setPathList() +*/ +QStringList QtxPathListEdit::pathList() const +{ + return myModel->stringList(); +} + +/*! + \brief Set paths list. + \param lst files or directories paths list + \sa pathList() +*/ +void QtxPathListEdit::setPathList( const QStringList& lst ) +{ + myModel->setStringList( lst ); +} + +/*! + \brief Check if the duplication of paths is enabled. + \return \c true if the duplication is enabled +*/ +bool QtxPathListEdit::isDuplicateEnabled() const +{ + return myDuplicate; +} + +/*! + \brief Enable/disable paths duplication. + \param on new flag value +*/ +void QtxPathListEdit::setDuplicateEnabled( const bool on ) +{ + myDuplicate = on; +} + +/*! + \brief Get number of currently entered paths. + \return current paths number +*/ +int QtxPathListEdit::count() const +{ + return myModel->rowCount(); +} + +/*! + \brief Check if the specified \a path already exists in + the paths list. + \param path path to be checked + \return \c true if the path is already selected by the user + or \c false otherwise +*/ +bool QtxPathListEdit::contains( const QString& path ) const +{ + return myModel->stringList().contains( path ); +} + +/*! + \brief Clear paths list. +*/ +void QtxPathListEdit::clear() +{ + myModel->removeRows( 0, myModel->rowCount() ); +} + +/*! + \brief Remove path from the paths list. + \param idx path index in the list +*/ +void QtxPathListEdit::remove( const int idx ) +{ + if ( 0 <= idx && idx < myModel->rowCount() ) + myModel->removeRow( idx ); +} + +/*! + \brief Remove path from the paths list. + \param path path to be removed +*/ +void QtxPathListEdit::remove( const QString& path ) +{ + QModelIndexList indexes = myModel->match( myModel->index( 0, 0 ), Qt::DisplayRole, path, + myModel->rowCount(), Qt::MatchExactly | Qt::MatchCaseSensitive ); + while ( !indexes.isEmpty() ) + { + myModel->removeRow( indexes.last().row() ); + indexes.removeLast(); + } +} + +/*! + \brief Add path to the list of paths. + + If the specified index is out of range, the path is added to + the end of the list. + + \param path path to be added + \param idx index in the list to which the path should be inserted. +*/ +void QtxPathListEdit::insert( const QString& path, const int idx ) +{ + int index = idx < 0 ? myModel->rowCount() : qMin( idx, myModel->rowCount() ); + if ( myModel->insertRow( index ) ) + myModel->setData( myModel->index( index, 0 ), path, Qt::EditRole ); +} + +/* +bool QtxPathListEdit::validate( const bool quietMode ) +{ + if ( myEdited ) + { + QString dirPath = QFileInfo( myEdit->text().stripWhiteSpace() ).filePath(); + QDir dir(dirPath); + QListBoxItem* found = 0; + for (unsigned i = 0; i < myList->count()-1; i++) { + QDir aDir(myList->text(i)); + if ( aDir.canonicalPath().isNull() && myList->text(i) == dir.absPath() || + !aDir.canonicalPath().isNull() && aDir.exists() && aDir.canonicalPath() == dir.canonicalPath()) { + found = myList->item(i); + break; + } + } + if (dirPath.isEmpty()) { + if (found) { + // it should be last (empty) item in the list - nothing to do + return true; + } + else { + // delete directory from the list + removeDir(myLastSelected); + return true; + } + } + else { + if (found) { + if (found != myLastSelected) { + // it is forbidden to add directory more then once + if ( !quietMode ) + QMessageBox::critical(this, + tr("Error"), + tr("Directory already specified."), + tr("Ok")); + myEdit->setFocus(); + return false; + } + } + else { + if (!dir.exists()) { + if ( !quietMode && QMessageBox::information(this, + tr("Warning"), + tr("%1\n\nThe directory doesn't exist.\nAdd directory anyway?").arg(dir.absPath()), + tr("Yes"), tr("No"), QString::null, 1, 1) == 1) { + myEdit->setFocus(); + return false; + } + } + // append + appendDir(myLastSelected, dir.absPath()); + } + } + } + return true; +} +*/ + +/*! + \brief Customize child widget events processing. + \param o event receiver object + \param e event + \return \c true if the further event processing should be stopped. +*/ +bool QtxPathListEdit::eventFilter( QObject* o, QEvent* e ) +{ + if ( e->type() == QEvent::KeyPress ) + { + QKeyEvent* ke = (QKeyEvent*)e; + if ( ke->key() == Qt::Key_Delete ) + onDelete(); + else if ( ke->key() == Qt::Key_Insert ) + onInsert(); + else if ( ke->key() == Qt::Key_Up && ke->modifiers() == Qt::CTRL ) + { + onUp(); + return true; + } + else if ( ke->key() == Qt::Key_Down && ke->modifiers() == Qt::CTRL ) + { + onDown(); + return true; + } + } + + return QFrame::eventFilter( o, e ); +} + +/*! + \brief Called when button is clicked. + + Inserts new empty line to the list and sets input focus to it. + + \param on (not used) +*/ +void QtxPathListEdit::onInsert( bool /*on*/ ) +{ + int empty = -1; + QStringList lst = myModel->stringList(); + for ( int r = 0; r < lst.count() && empty == -1; r++ ) + { + if ( lst.at( r ).isEmpty() ) + empty = r; + } + + if ( empty == -1 ) + myModel->insertRows( empty = myModel->rowCount(), 1 ); + + QModelIndex idx = myModel->index( empty, 0 ); + myList->setCurrentIndex( idx ); + myList->edit( idx ); +} + +/*! + \brief Called when button is clicked. + + Removes currently selected path item. + + \param on (not used) +*/ +void QtxPathListEdit::onDelete( bool ) +{ + QModelIndex idx = myList->currentIndex(); + if ( !idx.isValid() ) + return; + + myModel->removeRow( idx.row() ); +} + +/*! + \brief Called when button is clicked. + + Move currently selected path item up to one row in the paths list. + + \param on (not used) +*/ +void QtxPathListEdit::onUp( bool ) +{ + QModelIndex idx = myList->currentIndex(); + if ( !idx.isValid() || idx.row() < 1 ) + return; + + QModelIndex toIdx = myModel->index( idx.row() - 1, 0 ); + + QVariant val = myModel->data( toIdx, Qt::DisplayRole ); + myModel->setData( toIdx, myModel->data( idx, Qt::DisplayRole ), Qt::DisplayRole ); + myModel->setData( idx, val, Qt::DisplayRole ); + + myList->setCurrentIndex( toIdx ); +} + +/*! + \brief Called when button is clicked. + + Move currently selected path item down to one row in the paths list. + + \param on (not used) +*/ +void QtxPathListEdit::onDown( bool ) +{ + QModelIndex idx = myList->currentIndex(); + if ( !idx.isValid() || idx.row() >= myModel->rowCount() - 1 ) + return; + + QModelIndex toIdx = myModel->index( idx.row() + 1, 0 ); + + QVariant val = myModel->data( toIdx, Qt::DisplayRole ); + myModel->setData( toIdx, myModel->data( idx, Qt::DisplayRole ), Qt::DisplayRole ); + myModel->setData( idx, val, Qt::DisplayRole ); + + myList->setCurrentIndex( toIdx ); +} + +/*! + \brief Perform internal widget initialization. +*/ +void QtxPathListEdit::initialize() +{ + QVBoxLayout* base = new QVBoxLayout( this ); + base->setMargin( 0 ); + base->setSpacing( 5 ); + + QWidget* cBox = new QWidget( this ); + base->addWidget( cBox ); + + QHBoxLayout* cLayout = new QHBoxLayout( cBox ); + cLayout->setMargin( 0 ); + cLayout->setSpacing( 0 ); + + cLayout->addStretch( 1 ); + + QToolButton* insertBtn = new QToolButton( cBox ); + insertBtn->setIcon( QPixmap( insert_icon ) ); + cLayout->addWidget( insertBtn ); + + QToolButton* deleteBtn = new QToolButton( cBox ); + deleteBtn->setIcon( QPixmap( delete_icon ) ); + cLayout->addWidget( deleteBtn ); + + QToolButton* upBtn = new QToolButton( cBox ); + upBtn->setIcon( QPixmap( moveup_icon ) ); + cLayout->addWidget( upBtn ); + + QToolButton* downBtn = new QToolButton( cBox ); + downBtn->setIcon( QPixmap( movedown_icon ) ); + cLayout->addWidget( downBtn ); + + + myList = new QListView( this ); + myList->setAlternatingRowColors( true ); + myList->setItemDelegate( new Delegate( this, myList ) ); + myList->setModel( myModel = new QStringListModel( myList ) ); + myList->setSelectionMode( QListView::SingleSelection ); + myList->setSelectionBehavior( QListView::SelectRows ); + myList->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + myList->setEditTriggers( QListView::DoubleClicked ); + myList->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); + myList->installEventFilter( this ); + + base->addWidget( myList ); + + connect( insertBtn, SIGNAL( clicked( bool ) ), this, SLOT( onInsert( bool ) ) ); + connect( deleteBtn, SIGNAL( clicked( bool ) ), this, SLOT( onDelete( bool ) ) ); + connect( upBtn, SIGNAL( clicked( bool ) ), this, SLOT( onUp( bool ) ) ); + connect( downBtn, SIGNAL( clicked( bool ) ), this, SLOT( onDown( bool ) ) ); +} + +/*! + \brief Create editor widget. + \param parent parent widget for the editor + \return created editor widget +*/ +QWidget* QtxPathListEdit::createEditor( QWidget* parent ) +{ + QtxPathEdit* edit = new Editor( parent ); + edit->setPathType( pathType() ); + return edit; +} + +/*! + \brief Set modified data from the editor to the list widget. + \param editor editor widget + \param index data model index +*/ +void QtxPathListEdit::setModelData( QWidget* editor, const QModelIndex& index ) +{ + QtxPathEdit* edit = ::qobject_cast( editor ); + if ( !edit ) + return; + + QString path = edit->path().trimmed(); + + if ( !isDuplicateEnabled() && !checkDuplicate( path, index.row() ) ) + return; + + if ( !checkExistance( path ) ) + return; + + myModel->setData( index, path, Qt::EditRole ); +} + +/*! + \brief Set data to the editor from the list widget when + user starts path edition. + \param editor editor widget + \param index data model index +*/ +void QtxPathListEdit::setEditorData( QWidget* editor, const QModelIndex& index ) +{ + QtxPathEdit* edit = ::qobject_cast( editor ); + if ( !edit ) + return; + + QVariant v = myModel->data( index, Qt::EditRole ); + edit->setPath( v.toString() ); +} + +/*! + \brief Check if path is correct (exists) and optionally + show the question message box. + \param str path to be checked + \param msg if \c true and path does not exist, question message box is shown + \return \c true if the user confirms the path adding +*/ +bool QtxPathListEdit::checkExistance( const QString& str, const bool msg ) +{ + if ( pathType() == Qtx::PT_SaveFile ) + return true; + + bool ok = QFileInfo( str ).exists(); + if ( !ok && msg ) + ok = QMessageBox::question( this, tr( "Warning" ), tr( "Path \"%1\" doesn't exist. Add it to list anyway?" ).arg( str ), + QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes; + + if ( ok && QFileInfo( str ).exists() ) + { + switch ( pathType() ) + { + case Qtx::PT_OpenFile: + ok = QFileInfo( str ).isFile(); + if ( !ok && msg ) + QMessageBox::warning( this, tr( "Error" ), tr( "Location \"%1\" doesn't point to file" ).arg( str ) ); + break; + case Qtx::PT_Directory: + ok = QFileInfo( str ).isDir(); + if ( !ok && msg ) + QMessageBox::warning( this, tr( "Error" ), tr( "Location \"%1\" doesn't point to directory" ).arg( str ) ); + break; + } + } + + return ok; +} + +/*! + \brief Check if path already exists in the list and optionally + show the warning message box. + \param str path to be checked + \param row row corresponding to the path checked + \param msg if \c true and path does not exist, warning message box is shown + \return \c true if the user confirms the path adding +*/ +bool QtxPathListEdit::checkDuplicate( const QString& str, const int row, const bool msg ) +{ + int cur = -1; + QStringList lst = myModel->stringList(); + for ( int r = 0; r < lst.count() && cur == -1; r++ ) + { + if ( r != row && lst.at( r ) == str ) + cur = r; + } + + if ( cur != -1 && msg ) + QMessageBox::warning( this, tr( "Error" ), tr( "Path \"%1\" already exist in the list" ).arg( str ) ); + + return cur == -1; +} diff --git a/src/Qtx/QtxPathListEdit.h b/src/Qtx/QtxPathListEdit.h new file mode 100644 index 000000000..de24b82fa --- /dev/null +++ b/src/Qtx/QtxPathListEdit.h @@ -0,0 +1,97 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPathListEdit.h +// Author: Sergey TELKOV + +#ifndef QTXPATHLISTEDIT_H +#define QTXPATHLISTEDIT_H + +#include "Qtx.h" + +#include +#include + +class QLineEdit; +class QListView; +class QCompleter; +class QModelIndex; +class QToolButton; +class QStringListModel; + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +class QTX_EXPORT QtxPathListEdit : public QFrame +{ + Q_OBJECT + + class Editor; + class Delegate; + +public: + QtxPathListEdit( const Qtx::PathType, QWidget* = 0 ); + QtxPathListEdit( QWidget* = 0 ); + virtual ~QtxPathListEdit(); + + Qtx::PathType pathType() const; + void setPathType( const Qtx::PathType ); + + QStringList pathList() const; + void setPathList( const QStringList& ); + + bool isDuplicateEnabled() const; + void setDuplicateEnabled( const bool ); + + int count() const; + bool contains( const QString& ) const; + + void clear(); + void remove( const int ); + void remove( const QString& ); + void insert( const QString&, const int = -1 ); + + bool eventFilter( QObject*, QEvent* ); + +protected slots: + void onUp( bool = false ); + void onDown( bool = false ); + void onInsert( bool = false ); + void onDelete( bool = false ); + +private: + void initialize(); + QWidget* createEditor( QWidget* ); + void setModelData( QWidget*, const QModelIndex& ); + void setEditorData( QWidget*, const QModelIndex& ); + + bool checkExistance( const QString&, const bool = true ); + bool checkDuplicate( const QString&, const int, const bool = true ); + +private: + QListView* myList; + Qtx::PathType myType; + QStringListModel* myModel; + QCompleter* myCompleter; + bool myDuplicate; + + friend class QtxPathListEdit::Delegate; +}; + +#endif diff --git a/src/Qtx/QtxPopupMgr.cxx b/src/Qtx/QtxPopupMgr.cxx new file mode 100644 index 000000000..3efd99ae1 --- /dev/null +++ b/src/Qtx/QtxPopupMgr.cxx @@ -0,0 +1,742 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPopupMgr.cxx +// Author: Alexander SOLOVYOV, Sergey TELKOV + +#include "QtxPopupMgr.h" +#include "QtxAction.h" +#include "QtxEvalExpr.h" +#include + +/*! + \brief Used for comparing of two QVariant values. + \param v1 first argument for comparison + \param v2 second argument for comparison + \return \c true if \a v1 less than \a v2 +*/ +bool operator<( const QVariant& v1, const QVariant& v2 ) +{ + QVariant::Type t1 = v1.type(), t2 = v2.type(); + if ( t1 == t2 ) + { + switch( t1 ) + { + case QVariant::Int: + return v1.toInt() < v2.toInt(); + break; + case QVariant::Double: + return v1.toDouble() < v2.toDouble(); + break; + case QVariant::String: + return v1.toString() < v2.toString(); + break; + case QVariant::StringList: + case QVariant::List: + { + const QList& aList1 = v1.toList(), aList2 = v2.toList(); + QList::const_iterator anIt1 = aList1.begin(), aLast1 = aList1.end(), + anIt2 = aList2.begin(), aLast2 = aList2.end(); + for ( ; anIt1 != aLast1 && anIt2 != aLast2; anIt1++, anIt2++ ) + { + if ( (*anIt1) != (*anIt2) ) + return (*anIt1)<(*anIt2); + } + return anIt1 == aLast1 && anIt2 != aLast2; + break; + } + default: + return v1.toString() < v2.toString(); + break; + } + } + else + return t1 < t2; +} + +/*! + \class QtxPopupMgr::PopupCreator + \internal + \brief Popup menu actions creator. + + Used by Reader to create actions by reading descriptions from the file + and fill in the action manager with the actions. +*/ + +class QtxPopupMgr::PopupCreator : public QtxActionMgr::Creator +{ +public: + PopupCreator( QtxActionMgr::Reader*, QtxPopupMgr* ); + virtual ~PopupCreator(); + + virtual int append( const QString&, const bool, + const ItemAttributes&, const int ); + + virtual QString rule( const ItemAttributes&, + const QtxPopupMgr::RuleType = VisibleRule ) const; + +private: + QtxPopupMgr* myMgr; +}; + +/*! + \brief Constructor. + \param r menu action reader + \param mgr popup menu manager +*/ +QtxPopupMgr::PopupCreator::PopupCreator( QtxActionMgr::Reader* r, + QtxPopupMgr* mgr ) +: QtxActionMgr::Creator( r ), + myMgr( mgr ) +{ +} + +/*! + \brief Destructor. +*/ +QtxPopupMgr::PopupCreator::~PopupCreator() +{ +} + +/*! + \brief Create and append new action to the action manager. + \param tag item tag name + \param subMenu \c true if this item is submenu + \param attr attributes map + \param pId parent action ID + \return menu action ID +*/ +int QtxPopupMgr::PopupCreator::append( const QString& tag, const bool subMenu, + const ItemAttributes& attr, const int pId ) +{ + if ( !myMgr || !reader() ) + return -1; + + QString label = reader()->option( "label", "label" ), + id = reader()->option( "id", "id" ), + pos = reader()->option( "pos", "pos" ), + group = reader()->option( "group", "group" ), + tooltip = reader()->option( "tooltip", "tooltip" ), + sep = reader()->option( "separator", "separator" ), + accel = reader()->option( "accel", "accel" ), + icon = reader()->option( "icon", "icon" ), + toggle = reader()->option( "toggle", "toggle" ); + + QtxActionMenuMgr* mgr = myMgr; + + int res = -1, actId = intValue( attr, id, -1 );; + if ( subMenu ) + res = mgr->insert( strValue( attr, label ), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) ); + else if ( tag == sep ) + res = mgr->insert( separator(), pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) ); + else + { + QIcon set; + QPixmap pix; + QString name = strValue( attr, icon ); + if( !name.isEmpty() ) + { + if ( loadPixmap( name, pix ) ) + set = QIcon( pix ); + } + + QString actLabel = strValue( attr, label ); + QtxAction* newAct = new QtxAction( strValue( attr, tooltip ), set, actLabel, + QKeySequence( strValue( attr, accel ) ), + myMgr ); + newAct->setToolTip( strValue( attr, tooltip ) ); + QString toggleact = strValue( attr, toggle ); + bool isToggle = !toggleact.isEmpty(); + newAct->setCheckable( isToggle ); + newAct->setChecked( toggleact.toLower() == "true" ); + + connect( newAct ); + int aid = mgr->registerAction( newAct, actId ); + QString arule = rule( attr, QtxPopupMgr::VisibleRule ); + if ( !arule.isEmpty() ) + myMgr->setRule( newAct, arule, QtxPopupMgr::VisibleRule ); + arule = rule( attr, QtxPopupMgr::EnableRule ); + if ( !arule.isEmpty() ) + myMgr->setRule( newAct, arule, QtxPopupMgr::EnableRule ); + arule = rule( attr, QtxPopupMgr::ToggleRule ); + if ( isToggle && !arule.isEmpty() ) + myMgr->setRule( newAct, arule, QtxPopupMgr::ToggleRule ); + res = mgr->insert( aid, pId, intValue( attr, group, 0 ), intValue( attr, pos, -1 ) ); + } + + return res; +} + +/*! + \brief Get the rule for the menu item. + + Default implementation returns empty rule. + + \param attr attributes map + \param ruleType rule type (QtxPopupMgr::RuleType) + \return rule for the menu item corresponding to the rule type +*/ +QString QtxPopupMgr::PopupCreator::rule( const ItemAttributes& /*attr*/, + const QtxPopupMgr::RuleType /*ruleType*/ ) const +{ + return QString(); +} + +/*! + \class QtxPopupMgr + \brief Popup menu manager. + + Menu manager allows using of set of action for automatic generating of + application context popup menu by reuquest and dynamic update of its + contents. + + Use insert() methods to add menu items to the popup menu. + + The visibility, enable and toggle state of the menu item is controlled + by the syntaxic rules, which can be set with setRule() methods. + The rules are parsed automatically with help of QtxEvalParser class. + + QtxPopupSelection class is used as back-end for getting value of each + parameter found in the rule by the expression parser. + Use setSelection() and selection() to set/get the selection instance + for the popup menu manager. + + Popup menu manager automatically optimizes the menu by removing + extra separators, hiding empty popup submenus etc. +*/ + +/*! + \brief Constructor. + \param object parent object +*/ +QtxPopupMgr::QtxPopupMgr( QObject* parent ) +: QtxActionMenuMgr( 0, parent ), + mySelection( 0 ) +{ +} + +/*! + \brief Constructor. + \param popup popup menu + \param object parent object +*/ +QtxPopupMgr::QtxPopupMgr( QMenu* popup, QObject* parent ) +: QtxActionMenuMgr( popup, parent ), + mySelection( 0 ) +{ +} + +/*! + \brief Destructor. +*/ +QtxPopupMgr::~QtxPopupMgr() +{ +} + +/*! + \brief Get popup menu. + \return popup menu +*/ +QMenu* QtxPopupMgr::menu() const +{ + return ::qobject_cast( menuWidget() ); +} + +/*! + \brief Get popup menu. + \param menu popup menu +*/ +void QtxPopupMgr::setMenu( QMenu* menu ) +{ + setMenuWidget( menu ); +} + +/*! + \brief Get selection. + \return current selection object +*/ +QtxPopupSelection* QtxPopupMgr::selection() const +{ + return mySelection; +} + +/*! + \brief Set selection. + \param sel new selection object +*/ +void QtxPopupMgr::setSelection( QtxPopupSelection* sel ) +{ + if ( mySelection == sel ) + return; + + delete mySelection; + + mySelection = sel; + + if ( mySelection ) + mySelection->setParent( this ); + + QtxActionMgr::triggerUpdate(); +} + +/*! + \brief Register an action and return its identifier. + + If \a id is less than 0, the identifier for the action is generated automatically. + If action with given \a id is already registered, it will be re-registered. + If required \a id is already in use, new identifier is generatied; in this case + returning value will different from required one. + + \param act action to be registered + \param id action ID + \param rule syntax rule + \param ruleType rule type (QtxPopupMgr::RuleType) + \return action ID (the same as \a id or generated one) +*/ +int QtxPopupMgr::registerAction( QAction* act, const int id, const QString& rule, const QtxPopupMgr::RuleType ruleType ) +{ + int _id = QtxActionMenuMgr::registerAction( act, id ); + setRule( act, rule, ruleType ); + return _id; +} + +/*! + \brief Unregister action from internal map. + \param id action ID +*/ +void QtxPopupMgr::unRegisterAction( const int id ) +{ + QAction* a = action( id ); + if ( myRules.contains( a ) ) + { + for ( ExprMap::iterator it = myRules[a].begin(); it != myRules[a].end(); ++it ) + delete it.value(); + } + myRules.remove( a ); + + remove( id ); + + QtxActionMenuMgr::unRegisterAction( id ); +} + +/*! + \brief Insert action to the popup menu manager. + \param id action ID + \param pId parent menu action ID + \param rule syntax rule + \param ruleType rule type (QtxPopupMgr::RuleType) + \return action ID +*/ +int QtxPopupMgr::insertAction( const int id, const int pId, const QString& rule, const RuleType ruleType ) +{ + int res = QtxActionMenuMgr::insert( id, pId, -1 ); + setRule( action( id ), rule, ruleType ); + return res; +} + +/*! + \brief Insert action to the popup menu manager. + \param a action + \param pId parent menu action ID + \param rule syntax rule + \param ruleType rule type (QtxPopupMgr::RuleType) + \return action ID +*/ +int QtxPopupMgr::insertAction( QAction* a, const int pId, const QString& rule, const RuleType ruleType ) +{ + int res = QtxActionMenuMgr::insert( a, pId, -1 ); + setRule( a, rule, ruleType ); + return res; +} + +/*! + \brief Get rule of type \a type for the action \a a. + \param a action + \param ruleType rule type (QtxPopupMgr::RuleType) + \return rule of required type +*/ +QString QtxPopupMgr::rule( QAction* a, const RuleType ruleType ) const +{ + QString rule; + QtxEvalExpr* expr = expression( a, ruleType ); + if ( expr ) + rule = expr->expression(); + return rule; +} + +/*! + \brief Get rule of type \a type for the action \a id. + \param id action ID + \param ruleType rule type (QtxPopupMgr::RuleType) + \return rule of required type +*/ +QString QtxPopupMgr::rule( const int id, const RuleType ruleType ) const +{ + return rule( action( id ), ruleType ); +} + +/*! + \brief Set rule of type \a type for the action \a a. + \param a action + \param rule rule + \param ruleType rule type (QtxPopupMgr::RuleType) + \return rule of required type +*/ +void QtxPopupMgr::setRule( QAction* a, const QString& rule, const RuleType ruleType ) +{ + if ( !a ) + return; + + QtxEvalExpr* expr = expression( a, ruleType, true ); + + expr->setExpression( rule ); +} + +/*! + \brief Set rule of type \a type for the action \a id. + \param id action ID + \param rule rule + \param ruleType rule type (QtxPopupMgr::RuleType) + \return rule of required type +*/ +void QtxPopupMgr::setRule( const int id, const QString& rule, const RuleType ruleType ) +{ + setRule( action( id ), rule, ruleType ); +} + +/*! + \brief Calculate an expression. + \param p expression parser + \return \c true if parser has finished work without errors +*/ +bool QtxPopupMgr::result( QtxEvalParser* p ) const +{ + bool res = false; + if ( p ) + { + QVariant vv = p->calculate(); + res = p->error() == QtxEvalExpr::OK && + ( ( vv.type() == QVariant::Int && vv.toInt() != 0 ) || + ( vv.type() == QVariant::Bool && vv.toBool() ) ); + } + return res; +} + +/*! + \brief Fill the parser with parameters of the expression. + + The values of the parameters are given from the selection object + (QtxPopupSelection). + + \param p expression parser + \param returning list of parameters names which are not retrieved from the selection + \sa selection() +*/ +void QtxPopupMgr::setParameters( QtxEvalParser* p, QStringList& specific ) const +{ + if ( !p || !mySelection ) + return; + + QStringList params = p->parameters(); + for ( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + { + QVariant v = parameter( *it ); + if ( v.isValid() ) + p->setParameter( *it, v ); + else + specific.append( *it ); + } +} + +/*! + \brief Check the rule for the action. + \param act action + \param ruleType rule type (QtxPopupMgr::RuleType) + \return \c true if current selection satisfies the action rule +*/ +bool QtxPopupMgr::isSatisfied( QAction* act, const RuleType ruleType ) const +{ + if ( !act ) + return false; + + QtxEvalExpr* exp = expression( act, ruleType ); + if ( !exp ) + return true; + + bool res = false; + + QtxEvalParser* p = exp->parser(); + + QStringList specific; + p->clearParameters(); + setParameters( p, specific ); + + QMap, int> aCorteges; + if ( !specific.isEmpty() ) + { + if ( mySelection ) + { + res = false; + for ( int i = 0; i < mySelection->count() && !res; i++ ) + { + QList c; + for ( QStringList::const_iterator anIt1 = specific.begin(); anIt1 != specific.end(); ++anIt1 ) + c.append( parameter( *anIt1, i ) ); + aCorteges.insert( c, 0 ); + } + for ( QMap, int>::const_iterator anIt = aCorteges.begin(); anIt != aCorteges.end(); ++anIt ) + { + const QList& aCortege = anIt.key(); + QStringList::const_iterator anIt1 = specific.begin(), aLast1 = specific.end(); + QList::const_iterator anIt2 = aCortege.begin(); + for ( ; anIt1 != aLast1; anIt1++, anIt2++ ) + p->setParameter( *anIt1, *anIt2 ); + res = res || result( p ); + } + } + else + res = false; + } + else + res = result( p ); + + return res; +} + +/*! + \brief Check if the menu item is visible. + \param id action ID + \param place some parent action ID + \return \c true if the action is visible +*/ +bool QtxPopupMgr::isVisible( const int id, const int place ) const +{ + return QtxActionMenuMgr::isVisible( id, place ) && isSatisfied( action( id ) ); +} + +/*! + \brief Perform internal update of the popup menu according + to the current selection. +*/ +void QtxPopupMgr::internalUpdate() +{ + myCache.clear(); + + for ( RuleMap::iterator it = myRules.begin(); it != myRules.end(); ++it ) + { + ExprMap& map = it.value(); + if ( it.key()->isCheckable() && map.contains( ToggleRule ) && + !map[ToggleRule]->expression().isEmpty() ) + it.key()->setChecked( isSatisfied( it.key(), ToggleRule ) ); + } + + QtxActionMenuMgr::internalUpdate(); + + myCache.clear(); +} + +/*! + \brief Update popup according to the current selection. +*/ +void QtxPopupMgr::updateMenu() +{ + internalUpdate(); +} + +/*! + \brief Get an syntax expression for the action according to the specified rule type. + \param a action + \param ruleType rule type (QtxPopupMgr::RuleType) + \param create if \c true an expression does not exist, create it + \return syntax expression +*/ +QtxEvalExpr* QtxPopupMgr::expression( QAction* a, const RuleType ruleType, const bool create ) const +{ + QtxEvalExpr* res = 0; + + QtxPopupMgr* that = (QtxPopupMgr*)this; + RuleMap& ruleMap = that->myRules; + if ( !ruleMap.contains( a ) && create ) + ruleMap.insert( a, ExprMap() ); + + if ( ruleMap.contains( a ) ) + { + ExprMap& exprMap = ruleMap[a]; + if ( exprMap.contains( ruleType ) ) + res = exprMap[ruleType]; + else if ( create ) + exprMap.insert( ruleType, res = new QtxEvalExpr() ); + } + + return res; +} + +/*! + \brief Load actions description from the file. + \param fname file name + \param r action reader + \return \c true on success and \c false on error +*/ +bool QtxPopupMgr::load( const QString& fname, QtxActionMgr::Reader& r ) +{ + PopupCreator cr( &r, this ); + return r.read( fname, cr ); +} + +/* + \brief Get the specified parameter value. + \param name parameter name + \param idx additional index used when used parameters with same names + \return parameter value + \sa selection() +*/ +QVariant QtxPopupMgr::parameter( const QString& name, const int idx ) const +{ + QVariant val; + QString cacheName = name + ( idx >= 0 ? QString( "_%1" ).arg( idx ) : QString() ); + if ( myCache.contains( cacheName ) ) + val = myCache[cacheName]; + else + { + if ( selection() ) + val = idx < 0 ? selection()->parameter( name ) : + selection()->parameter( idx, name ); + if ( val.isValid() ) + { + QtxPopupMgr* that = (QtxPopupMgr*)this; + that->myCache.insert( cacheName, val ); + } + } + return val; +} + +/*! + \class QtxPopupSelection + \brief This class is a part of the popup menu management system. + + The QtxPopupSelection class is used as back-end for getting value + of each parameter found in the rule by the expression parser. + + For example, it can be used for the analyzing of the currently + selected objects and defining the values of the parameters used + in the rules syntax expression. Rules, in their turn, define + each action state - visibility, enabled and toggled state. +*/ + +/*! + \brief Constructor. +*/ +QtxPopupSelection::QtxPopupSelection() +: QObject( 0 ) +{ +} + +/*! + \brief Destructor. +*/ +QtxPopupSelection::~QtxPopupSelection() +{ +} + +/*! + \brief Get an option value. + \param optName option name + \return option value or empty string if option is not found +*/ +QString QtxPopupSelection::option( const QString& optName ) const +{ + QString opt; + if ( myOptions.contains( optName ) ) + opt = myOptions[optName]; + return opt; +} + +/*! + \brief Set an option value. + \param optName option name + \param opt option value +*/ +void QtxPopupSelection::setOption( const QString& optName, const QString& opt ) +{ + myOptions.insert( optName, opt ); +} + +/*! + \brief Get the parameter value. + \param str parameter name + \return parameter value +*/ +QVariant QtxPopupSelection::parameter( const QString& str ) const +{ + if ( str == selCountParam() ) + return count(); + else if ( str.startsWith( equalityParam() ) ) + { + QtxEvalSetSets::ValueSet set; + QString par = str.mid( equalityParam().length() ); + for ( int i = 0; i < (int)count(); i++ ) + { + QVariant v = parameter( i, par ); + if ( v.isValid() ) + QtxEvalSetSets::add( set, v ); + else + return QVariant(); + } + return set; + } + else + return QVariant(); +} + +/*! + \brief Get symbol which detects the name of the parameter list. + \return equality symbol (by default, "$") +*/ +QString QtxPopupSelection::equalityParam() const +{ + QString str = option( "equality" ); + if ( str.isEmpty() ) + str = "$"; + return str; +} + +/*! + \brief Get name of the parameter, specifing number of selected objects + \return parameter name (by default, "selcount") +*/ +QString QtxPopupSelection::selCountParam() const +{ + QString str = option( "equality" ); + if ( str.isEmpty() ) + str = "selcount"; + return str; +} + +/*! + \fn int QtxPopupSelection::count() const; + \brief Get number of the selected objects. + \return nb of selected objects +*/ + +/*! + \fn QVariant QtxPopupSelection::parameter( const int idx, const QString& name ) const; + \brief Get number of the selected objects. + \param idx parameter index + \param name parameter name + \return parameter value +*/ diff --git a/src/Qtx/QtxPopupMgr.h b/src/Qtx/QtxPopupMgr.h new file mode 100644 index 000000000..2dbea1280 --- /dev/null +++ b/src/Qtx/QtxPopupMgr.h @@ -0,0 +1,126 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPopupMgr.h +// Author: Alexander SOLOVYOV, Sergey TELKOV + +#ifndef QTXPOPUPMGR_H +#define QTXPOPUPMGR_H + +#include "QtxActionMenuMgr.h" + +#include +#include + +class QtxEvalExpr; +class QtxEvalParser; +class QtxPopupSelection; + +class QTX_EXPORT QtxPopupMgr : public QtxActionMenuMgr +{ + Q_OBJECT + +public: + //! Menu item rule type + typedef enum { + VisibleRule, //!< menu item visibility state + EnableRule, //!< menu item enable state + ToggleRule //!< menu item toggle state + } RuleType; + +private: + class PopupCreator; + +public: + QtxPopupMgr( QObject* = 0 ); + QtxPopupMgr( QMenu*, QObject* = 0 ); + virtual ~QtxPopupMgr(); + + int insertAction( const int, const int, const QString&, const RuleType = VisibleRule ); + int insertAction( QAction*, const int, const QString&, const RuleType = VisibleRule ); + + virtual int registerAction( QAction*, const int, const QString& rule, + const RuleType = VisibleRule ); + virtual void unRegisterAction( const int ); + + virtual bool isVisible( const int actId, const int place ) const; + + QString rule( QAction*, const RuleType = VisibleRule ) const; + QString rule( const int, const RuleType = VisibleRule ) const; + + void setRule( QAction*, const QString&, const RuleType = VisibleRule ); + void setRule( const int, const QString&, const RuleType = VisibleRule ); + + QtxPopupSelection* selection() const; + void setSelection( QtxPopupSelection* ); + + QMenu* menu() const; + void setMenu( QMenu* ); + + void updateMenu(); + + virtual bool load( const QString&, QtxActionMgr::Reader& ); + +protected: + virtual void internalUpdate(); + void setParameters( QtxEvalParser*, QStringList& ) const; + virtual bool isSatisfied( QAction*, const RuleType = VisibleRule ) const; + QtxEvalExpr* expression( QAction*, const RuleType = VisibleRule, const bool = false ) const; + +private: + bool result( QtxEvalParser* p ) const; + QVariant parameter( const QString&, const int = -1 ) const; + +private: + typedef QMap ExprMap; + typedef QMap RuleMap; + typedef QMap CacheMap; + +private: + RuleMap myRules; + CacheMap myCache; + QtxPopupSelection* mySelection; +}; + +class QTX_EXPORT QtxPopupSelection : public QObject +{ + Q_OBJECT + +public: + QtxPopupSelection(); + virtual ~QtxPopupSelection(); + + virtual int count() const = 0; + virtual QVariant parameter( const QString& ) const; + virtual QVariant parameter( const int, const QString& ) const = 0; + + QString option( const QString& ) const; + void setOption( const QString&, const QString& ); + +private: + QString equalityParam() const; + QString selCountParam() const; + +private: + typedef QMap OptionsMap; + +private: + OptionsMap myOptions; +}; + +#endif // QTXPOPUPMGR_H diff --git a/src/Qtx/QtxPreferenceMgr.cxx b/src/Qtx/QtxPreferenceMgr.cxx new file mode 100644 index 000000000..ee4397694 --- /dev/null +++ b/src/Qtx/QtxPreferenceMgr.cxx @@ -0,0 +1,1110 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPreferenceMgr.cxx +// Author: Sergey TELKOV + +#include "QtxPreferenceMgr.h" + +#include "QtxResourceMgr.h" + +#include +#include + +/*! + \class QtxPreferenceItem::Updater + \brief Preference item updater. + \internal +*/ + +class QtxPreferenceItem::Updater : public QObject +{ + Updater(); +public: + ~Updater(); + + static Updater* instance(); + + void updateItem( QtxPreferenceItem* ); + void removeItem( QtxPreferenceItem* ); + +protected: + virtual void customEvent( QEvent* ); + +private: + QList myItems; + static Updater* _Updater; +}; + +QtxPreferenceItem::Updater* QtxPreferenceItem::Updater::_Updater = 0; + +/*! + \brief Constructor. + \internal +*/ +QtxPreferenceItem::Updater::Updater() +{ +} + +/*! + \brief Destructor. + \internal +*/ +QtxPreferenceItem::Updater::~Updater() +{ +} + +/*! + \brief Get the only updater instance. + \internal + \return the only updater instance +*/ +QtxPreferenceItem::Updater* QtxPreferenceItem::Updater::instance() +{ + if ( !_Updater ) + _Updater = new Updater(); + return _Updater; +} + +/*! + \brief Update the preference item. + \internal + \param item preference item to be updated +*/ +void QtxPreferenceItem::Updater::updateItem( QtxPreferenceItem* item ) +{ + if ( !item || myItems.contains( item ) ) + return; + + myItems.append( item ); + QApplication::postEvent( this, new QEvent( QEvent::User ) ); +} + +/*! + \brief Called when preference item is removed. + \internal + \param item preference item being removed +*/ +void QtxPreferenceItem::Updater::removeItem( QtxPreferenceItem* item ) +{ + myItems.removeAll( item ); +} + +/*! + \brief Custom events provessing. Updates all the items. + \internal + \param e custom event (not used) +*/ +void QtxPreferenceItem::Updater::customEvent( QEvent* /*e*/ ) +{ + QList lst = myItems; + for ( QList::const_iterator it = lst.begin(); it != lst.end(); ++it ) + (*it)->updateContents(); +} + +/*! + \class QtxPreferenceItem + \brief Base class for implementing of all the preference items. + + To implement any specific preference item, cubclass from the + QtxPreferenceItem and redefine store() and retrieve() methods. +*/ + +/*! + \brief Constructor. + \param parent parent preference item +*/ +QtxPreferenceItem::QtxPreferenceItem( QtxPreferenceItem* parent ) +: myParent( 0 ) +{ + myId = generateId(); + + if ( parent ) + parent->insertItem( this ); +} + +/*! + \brief Constructor. + \param title item title + \param parent parent preference item +*/ +QtxPreferenceItem::QtxPreferenceItem( const QString& title, QtxPreferenceItem* parent ) +: myParent( 0 ), + myTitle( title ) +{ + myId = generateId(); + + if ( parent ) + parent->insertItem( this ); +} + +/*! + \brief Constructor. + \param title item title + \param sect resource file section to be associated with the item + \param param resource file parameter to be associated with the item + \param parent parent preference item +*/ +QtxPreferenceItem::QtxPreferenceItem( const QString& title, const QString& sect, + const QString& param, QtxPreferenceItem* parent ) +: myParent( 0 ), + myTitle( title ), + mySection( sect ), + myParameter( param ) +{ + myId = generateId(); + + if ( parent ) + parent->insertItem( this ); +} + +/*! + \brief Destructor. +*/ +QtxPreferenceItem::~QtxPreferenceItem() +{ + ItemList list = myChildren; + myChildren.clear(); + qDeleteAll( list ); + + if ( myParent ) + myParent->removeItem( this ); + + Updater::instance()->removeItem( this ); +} + +/*! + \brief Get unique item identifier. + \return item ID +*/ +int QtxPreferenceItem::id() const +{ + return myId; +} + +/*! + \brief Get unique item type identifier. + \return item type ID +*/ +int QtxPreferenceItem::rtti() const +{ + return QtxPreferenceItem::RTTI(); +} + +/*! + \brief Specify unique item class identifier. + \return item class ID +*/ +int QtxPreferenceItem::RTTI() +{ + return 1; +} + +/*! + \brief Get root preference item. + \return root item +*/ +QtxPreferenceItem* QtxPreferenceItem::rootItem() const +{ + QtxPreferenceItem* item = (QtxPreferenceItem*)this; + while ( item->parentItem() ) + item = item->parentItem(); + return item; +} + +/*! + \brief Get parent preference item. + \return parent item +*/ +QtxPreferenceItem* QtxPreferenceItem::parentItem() const +{ + return myParent; +} + +/*! + \brief Append child preference item. + + Removes (if necessary) the item from the previous parent. + + \param item item to be added + \sa removeItem() +*/ +void QtxPreferenceItem::insertItem( QtxPreferenceItem* item ) +{ + if ( !item || myChildren.contains( item ) ) + return; + + if ( item->parentItem() && item->parentItem() != this ) + item->parentItem()->removeItem( item ); + + item->myParent = this; + myChildren.append( item ); + + itemAdded( item ); +} + +/*! + \brief Remove child preference item. + \param item item to be removed + \sa insertItem() +*/ +void QtxPreferenceItem::removeItem( QtxPreferenceItem* item ) +{ + if ( !item || !myChildren.contains( item ) ) + return; + + item->myParent = 0; + myChildren.removeAll( item ); + + itemRemoved( item ); +} + +/*! + \brief Get all child preference items. + \param rec recursion boolean flag + \return list of child items +*/ +QList QtxPreferenceItem::childItems( const bool rec ) const +{ + QList lst = myChildren; + if ( rec ) + { + for ( ItemList::const_iterator it = myChildren.begin(); it != myChildren.end(); ++it ) + lst += (*it)->childItems( rec ); + } + + return lst; +} + +/*! + \brief Get preference item depth. + \return item depth +*/ +int QtxPreferenceItem::depth() const +{ + return parentItem() ? parentItem()->depth() + 1 : 0; +} + +/*! + \brief Get child preference items number. + \return number of child items + \sa isEmpty() +*/ +int QtxPreferenceItem::count() const +{ + return myChildren.count(); +} + +/*! + \brief Check if the item has children. + \return \c true if item does not have children + \sa count() +*/ +bool QtxPreferenceItem::isEmpty() const +{ + return myChildren.isEmpty(); +} + +/*! + \brief Get preference item icon. + \return item icon + \sa setIcon() +*/ +QIcon QtxPreferenceItem::icon() const +{ + return myIcon; +} + +/*! + \brief Get preference item title. + \return item title + \sa setTitle() +*/ +QString QtxPreferenceItem::title() const +{ + return myTitle; +} + +/*! + \brief Get resource file settings associated to the preference item. + \param sec used to return resource file section name + \param param used to return resource file parameter name + \sa setResource() +*/ +void QtxPreferenceItem::resource( QString& sec, QString& param ) const +{ + sec = mySection; + param = myParameter; +} + +/*! + \brief Set prefence item icon. + \param ico new item icon + \sa icon() +*/ +void QtxPreferenceItem::setIcon( const QIcon& ico ) +{ + if ( myIcon.serialNumber() == ico.serialNumber() ) + return; + + myIcon = ico; + sendItemChanges(); +} + +/*! + \brief Set preference item title . + \param title new item title + \sa title() +*/ +void QtxPreferenceItem::setTitle( const QString& title ) +{ + if ( myTitle == title ) + return; + + myTitle = title; + sendItemChanges(); +} + +/*! + \brief Assign resource file settings to the preference item. + \param sec resource file section name + \param param resource file parameter name + \sa resource() +*/ +void QtxPreferenceItem::setResource( const QString& sec, const QString& param ) +{ + mySection = sec; + myParameter = param; +} + +/*! + \brief Update preference item. +*/ +void QtxPreferenceItem::updateContents() +{ + Updater::instance()->removeItem( this ); +} + +/*! + \brief Get preference item option value. + \param name option name + \return property value or null QVariant if option is not set + \sa setOption() +*/ +QVariant QtxPreferenceItem::option( const QString& name ) const +{ + return optionValue( name.toLower() ); +} + +/*! + \brief Set preference item option value. + \param name option name + \param val new property value + \sa option() +*/ +void QtxPreferenceItem::setOption( const QString& name, const QVariant& val ) +{ + QVariant old = optionValue( name.toLower() ); + setOptionValue( name.toLower(), val ); + if ( old != optionValue( name.toLower() ) ) + sendItemChanges(); +} + +/*! + \fn void QtxPreferenceItem::store(); + \brief Save preference item (for example, to the resource file). + + This method should be implemented in the subclasses. + + \sa retrieve() +*/ + +/*! + \fn virtual void QtxPreferenceItem::retrieve(); + \brief Restore preference item (for example, from the resource file). + + This method should be implemented in the subclasses. + + \sa store() +*/ + +/*! + \brief Get the value of the associated resource file setting. + \return associated resource file setting value + \sa setResourceValue() +*/ +QString QtxPreferenceItem::resourceValue() const +{ + return getString(); +} + +/*! + \brief Get the value of the associated resource file setting. + \param val new associated resource file setting value + \sa resourceValue() +*/ +void QtxPreferenceItem::setResourceValue( const QString& val ) +{ + setString( val ); +} + +/*! + \brief Get the resources manager. + \return resource manager pointer or 0 if it is not defined +*/ +QtxResourceMgr* QtxPreferenceItem::resourceMgr() const +{ + QtxPreferenceMgr* mgr = preferenceMgr(); + return mgr ? mgr->resourceMgr() : 0; +} + +/*! + \brief Get the parent preferences manager. + \return preferences manager or 0 if it is not defined +*/ +QtxPreferenceMgr* QtxPreferenceItem::preferenceMgr() const +{ + return parentItem() ? parentItem()->preferenceMgr() : 0; +} + +/*! + \brief Find the item by the specified identifier. + \param id child item ID + \param rec if \c true recursive search is done + \return child item or 0 if it is not found +*/ +QtxPreferenceItem* QtxPreferenceItem::findItem( const int id, const bool rec ) const +{ + QtxPreferenceItem* item = 0; + for ( ItemList::const_iterator it = myChildren.begin(); it != myChildren.end() && !item; ++it ) + { + QtxPreferenceItem* i = *it; + if ( i->id() == id ) + item = i; + else if ( rec ) + item = i->findItem( id, rec ); + } + return item; +} + +/*! + \brief Find the item by the specified title. + \param title child item title + \param rec if \c true recursive search is done + \return child item or 0 if it is not found +*/ +QtxPreferenceItem* QtxPreferenceItem::findItem( const QString& title, const bool rec ) const +{ + QtxPreferenceItem* item = 0; + for ( ItemList::const_iterator it = myChildren.begin(); it != myChildren.end() && !item; ++it ) + { + QtxPreferenceItem* i = *it; + if ( i->title() == title ) + item = i; + else if ( rec ) + item = i->findItem( title, rec ); + } + return item; +} + +/*! + \brief Find the item by the specified title and identifier. + \param title child item title + \param id child item ID + \param rec if \c true recursive search is done + \return child item or 0 if it is not found +*/ +QtxPreferenceItem* QtxPreferenceItem::findItem( const QString& title, const int id, const bool rec ) const +{ + QtxPreferenceItem* item = 0; + for ( ItemList::const_iterator it = myChildren.begin(); it != myChildren.end() && !item; ++it ) + { + QtxPreferenceItem* i = *it; + if ( i->title() == title && i->id() == id ) + item = i; + else if ( rec ) + item = i->findItem( title, id, rec ); + } + return item; +} + + +/*! + \brief Get integer resources value corresponding to the item. + \param val default value (returned if there is no such resource) + \return integer value of the associated resource + \sa setInteger() +*/ +int QtxPreferenceItem::getInteger( const int val ) const +{ + QtxResourceMgr* resMgr = resourceMgr(); + return resMgr ? resMgr->integerValue( mySection, myParameter, val ) : val; +} + +/*! + \brief Get double resources value corresponding to the item. + \param val default value (returned if there is no such resource) + \return double value of the associated resource + \sa setDouble() +*/ +double QtxPreferenceItem::getDouble( const double val ) const +{ + QtxResourceMgr* resMgr = resourceMgr(); + return resMgr ? resMgr->doubleValue( mySection, myParameter, val ) : val; +} + +/*! + \brief Get boolean resources value corresponding to the item. + \param val default value (returned if there is no such resource) + \return boolean value of the associated resource + \sa setBoolean() +*/ +bool QtxPreferenceItem::getBoolean( const bool val ) const +{ + QtxResourceMgr* resMgr = resourceMgr(); + return resMgr ? resMgr->booleanValue( mySection, myParameter, val ) : val; +} + +/*! + \brief Get string resources value corresponding to the item. + \param val default value (returned if there is no such resource) + \return string value of the associated resource + \sa setString() +*/ +QString QtxPreferenceItem::getString( const QString& val ) const +{ + QtxResourceMgr* resMgr = resourceMgr(); + return resMgr ? resMgr->stringValue( mySection, myParameter, val ) : val; +} + +/*! + \brief Get color resources value corresponding to the item. + \param val default value (returned if there is no such resource) + \return color value of the associated resource + \sa setColor() +*/ +QColor QtxPreferenceItem::getColor( const QColor& val ) const +{ + QtxResourceMgr* resMgr = resourceMgr(); + return resMgr ? resMgr->colorValue( mySection, myParameter, val ) : val; +} + +/*! + \brief Get font resources value corresponding to the item. + \param val default value (returned if there is no such resource) + \return font value of the associated resource + \sa setFont() +*/ +QFont QtxPreferenceItem::getFont( const QFont& val ) const +{ + QtxResourceMgr* resMgr = resourceMgr(); + return resMgr ? resMgr->fontValue( mySection, myParameter, val ) : val; +} + +/*! + \brief Set integer resources value corresponding to the item. + \param val new value + \sa getInteger() +*/ +void QtxPreferenceItem::setInteger( const int val ) +{ + QtxResourceMgr* resMgr = resourceMgr(); + if ( resMgr ) + resMgr->setValue( mySection, myParameter, val ); +} + +/*! + \brief Set double resources value corresponding to the item. + \param val new value + \sa getDouble() +*/ +void QtxPreferenceItem::setDouble( const double val ) +{ + QtxResourceMgr* resMgr = resourceMgr(); + if ( resMgr ) + resMgr->setValue( mySection, myParameter, val ); +} + +/*! + \brief Set boolean resources value corresponding to the item. + \param val new value + \sa getBoolean() +*/ +void QtxPreferenceItem::setBoolean( const bool val ) +{ + QtxResourceMgr* resMgr = resourceMgr(); + if ( resMgr ) + resMgr->setValue( mySection, myParameter, val ); +} + +/*! + \brief Set string resources value corresponding to the item. + \param val new value + \sa getString() +*/ +void QtxPreferenceItem::setString( const QString& val ) +{ + QtxResourceMgr* resMgr = resourceMgr(); + if ( resMgr ) + resMgr->setValue( mySection, myParameter, val ); +} + +/*! + \brief Set color resources value corresponding to the item. + \param val new value + \sa getColor() +*/ +void QtxPreferenceItem::setColor( const QColor& val ) +{ + QtxResourceMgr* resMgr = resourceMgr(); + if ( resMgr ) + resMgr->setValue( mySection, myParameter, val ); +} + +/*! + \brief Set font resources value corresponding to the item. + \param val new value + \sa getFont() +*/ +void QtxPreferenceItem::setFont( const QFont& val ) +{ + QtxResourceMgr* resMgr = resourceMgr(); + if ( resMgr ) + resMgr->setValue( mySection, myParameter, val ); +} + +/*! + \brief Callback function which is called when the child + preference item is added. + + This function can be reimplemented in the subclasses to customize + child item addition operation. Base implementation does nothing. + + \param item child item being added + \sa itemRemoved(), itemChanged() +*/ +void QtxPreferenceItem::itemAdded( QtxPreferenceItem* /*item*/ ) +{ +} + +/*! + \brief Callback function which is called when the child + preference item is removed. + + This function can be reimplemented in the subclasses to customize + child item removal operation. Base implementation does nothing. + + \param item child item being removed + \sa itemAdded(), itemChanged() +*/ +void QtxPreferenceItem::itemRemoved( QtxPreferenceItem* /*item*/ ) +{ +} + +/*! + \brief Callback function which is called when the child + preference item is modified. + + This function can be reimplemented in the subclasses to customize + child item modifying operation. Base implementation does nothing. + + \param item child item being modified + \sa itemAdded(), itemRemoved() +*/ +void QtxPreferenceItem::itemChanged( QtxPreferenceItem* /*item*/ ) +{ +} + +/*! + \brief Initiate item updating. +*/ +void QtxPreferenceItem::triggerUpdate() +{ + Updater::instance()->updateItem( this ); +} + +/*! + \brief Get preference item option value. + + This function can be reimplemented in the subclasses. + Base implementation does nothing. + + \param name option name + \return property value or null QVariant if option is not set + \sa setOptionValue() +*/ +QVariant QtxPreferenceItem::optionValue( const QString& /*name*/ ) const +{ + return QVariant(); +} + +/*! + \brief Set preference item option value. + + This function can be reimplemented in the subclasses. + Base implementation does nothing. + + \param name option name + \param val new property value + \sa optionValue() +*/ +void QtxPreferenceItem::setOptionValue( const QString& /*name*/, const QVariant& /*val*/ ) +{ +} + +/*! + \brief Initiate item changing call back operation. +*/ +void QtxPreferenceItem::sendItemChanges() +{ + if ( parentItem() ) + parentItem()->itemChanged( this ); +} + +/*! + \brief Generate unique preference item identifier. + \return unique item ID +*/ +int QtxPreferenceItem::generateId() +{ + static int _id = 0; + return _id++; +} + +/*! + \class QtxPreferenceMgr + \brief Class for managing preferences items. +*/ + +/*! + \brief Constructor. + \param mgr resources manager +*/ +QtxPreferenceMgr::QtxPreferenceMgr( QtxResourceMgr* mgr ) +: QtxPreferenceItem( 0 ), + myResMgr( mgr ) +{ +} + +/*! + \brief Destructor. +*/ +QtxPreferenceMgr::~QtxPreferenceMgr() +{ +} + +/*! + \brief Get the resources manager. + \return resource manager pointer or 0 if it is not defined +*/ +QtxResourceMgr* QtxPreferenceMgr::resourceMgr() const +{ + return myResMgr; +} + +/*! + \brief Get the parent preferences manager. + \return pointer to itself +*/ +QtxPreferenceMgr* QtxPreferenceMgr::preferenceMgr() const +{ + return (QtxPreferenceMgr*)this; +} + +/* + \brief Add new preference item. + \param label label of widget to edit preference item + \param pId parent preference item id + \param type preference item type + \param section resource file section associated to the preference item + \param param resource file parameter associated to the preference item +*/ +/* +int QtxPreferenceMgr::addItem( const QString& label, const int pId, const int type, + const QString& section, const QString& param ) +{ + Item* i = createItem( label, type, pId ); + if ( !i ) + return -1; + + if ( !myItems.contains( i->id() ) ) + { + myItems.insert( i->id(), i ); + + i->setTitle( label ); + i->setResource( section, param ); + + if ( !i->parentItem() && !myChildren.contains( i ) ) + myChildren.append( i ); + + itemAdded( i ); + } + + return i->id(); +} +*/ + +/*! + \brief Get preference item option value. + \param id preference item ID + \param propName option name + \return property value or null QVariant if option is not set + \sa setOption() +*/ +QVariant QtxPreferenceMgr::option( const int id, const QString& propName ) const +{ + QVariant propValue; + QtxPreferenceItem* i = findItem( id, true ); + if ( i ) + propValue = i->option( propName ); + return propValue; +} + +/*! + \brief Set preference item option value. + \param id preference item ID + \param propName option name + \param propValue new property value + \sa option() +*/ +void QtxPreferenceMgr::setOption( const int id, const QString& propName, const QVariant& propValue ) +{ + QtxPreferenceItem* i = findItem( id, true ); + if ( i ) + i->setOption( propName, propValue ); +} + +/*! + \brief Store all preferences item to the resource manager. + \sa retrieve() +*/ +void QtxPreferenceMgr::store() +{ + ResourceMap before; + resourceValues( before ); + + QList items = childItems( true ); + for ( QList::iterator it = items.begin(); it != items.end(); ++it ) + (*it)->store(); + + ResourceMap after; + resourceValues( after ); + + ResourceMap changed; + differentValues( before, after, changed ); + + changedResources( changed ); +} + +/*! + \brief Retrieve all preference items from the resource manager. + \sa store() +*/ +void QtxPreferenceMgr::retrieve() +{ + QList items = childItems( true ); + for ( QList::iterator it = items.begin(); it != items.end(); ++it ) + (*it)->retrieve(); +} + +/*! + \brief Dumps all values to the backup container. + \sa fromBackup() +*/ +void QtxPreferenceMgr::toBackup() +{ + myBackup.clear(); + resourceValues( myBackup ); +} + +/*! + \brief Restore all values from the backup container. + \sa toBackup() +*/ +void QtxPreferenceMgr::fromBackup() +{ + ResourceMap before; + resourceValues( before ); + + setResourceValues( myBackup ); + + ResourceMap after; + resourceValues( after ); + + ResourceMap changed; + differentValues( before, after, changed ); + + changedResources( changed ); +} + +/*! + \brief Update preferences manager. + + Base implementation does nothing. +*/ +void QtxPreferenceMgr::update() +{ +} + +/* + \brief Create preference item. + \param label preference item title + \param type preference item type + \param pId parent preference item ID + \return new item +*/ +/* +QtxPreferenceItem* QtxPreferenceMgr::createItem( const QString& label, const int type, const int pId ) +{ + Item* i = 0; + if ( pId < 0 ) + i = createItem( label, type ); + else + { + Item* pItem = item( pId ); + if ( pItem ) + { + i = pItem->createItem( label, type ); + pItem->insertChild( i ); + } + } + + return i; +} +*/ + +/*! + \brief Get all resources items values. + \param map used as container filled with the resources values (:) + \sa setResourceValues() +*/ +void QtxPreferenceMgr::resourceValues( QMap& map ) const +{ + QString sect, name; + QtxResourceMgr* resMgr = resourceMgr(); + QList items = childItems( true ); + for ( QList::const_iterator it = items.begin(); it != items.end(); ++it ) + { + QtxPreferenceItem* item = *it; + item->resource( sect, name ); + if ( resMgr->hasValue( sect, name ) ) + map.insert( item->id(), item->resourceValue() ); + } +} + +/*! + \brief Get all resources items values. + \param map used as container filled with the resources values + (:) + \sa setResourceValues() +*/ +void QtxPreferenceMgr::resourceValues( ResourceMap& map ) const +{ + QString sect, name; + QtxResourceMgr* resMgr = resourceMgr(); + QList items = childItems( true ); + for ( QList::const_iterator it = items.begin(); it != items.end(); ++it ) + { + QtxPreferenceItem* item = *it; + item->resource( sect, name ); + if ( resMgr->hasValue( sect, name ) ) + map.insert( item, item->resourceValue() ); + } +} + +/*! + \brief Set all resources items values. + \param map map with resources values (:) + \sa resourceValues() +*/ +void QtxPreferenceMgr::setResourceValues( QMap& map ) const +{ + for ( QMap::const_iterator it = map.begin(); it != map.end(); ++it ) + { + QtxPreferenceItem* i = findItem( it.key(), true ); + if ( i ) + i->setResourceValue( it.value() ); + } +} + +/*! + \brief Set all resources items values. + \param map map with resources values (:) + \sa resourceValues() +*/ +void QtxPreferenceMgr::setResourceValues( ResourceMap& map ) const +{ + for ( ResourceMap::const_iterator it = map.begin(); it != map.end(); ++it ) + it.key()->setResourceValue( it.value() ); +} + +/*! + \brief Compare two maps of resources values to find differences. + \param map1 first map + \param map2 second map + \param resMap map to be filled with different values + \param fromFirst if \c true, then \a resMap will be filled with the values + from \a map1, otherwise - from \a map2 +*/ +void QtxPreferenceMgr::differentValues( const QMap& map1, const QMap& map2, + QMap& resMap, const bool fromFirst ) const +{ + resMap.clear(); + const QMap& later = fromFirst ? map1 : map2; + const QMap& early = fromFirst ? map2 : map1; + + for ( QMap::const_iterator it = later.begin(); it != later.end(); ++it ) + { + if ( !early.contains( it.key() ) || early[it.key()] != it.value() ) + resMap.insert( it.key(), it.value() ); + } +} + +/*! + \brief Compare two maps of resources values to find differences. + \param map1 first map + \param map2 second map + \param resMap map to be filled with different values + \param fromFirst if \c true, then \a resMap will be filled with the values + from \a map1, otherwise - from \a map2 +*/ +void QtxPreferenceMgr::differentValues( const ResourceMap& map1, const ResourceMap& map2, + ResourceMap& resMap, const bool fromFirst ) const +{ + resMap.clear(); + const ResourceMap& later = fromFirst ? map1 : map2; + const ResourceMap& early = fromFirst ? map2 : map1; + + for ( ResourceMap::const_iterator it = later.begin(); it != later.end(); ++it ) + { + if ( !early.contains( it.key() ) || early[it.key()] != it.value() ) + resMap.insert( it.key(), it.value() ); + } +} + +/*! + \brief Perform custom activity on resource changing. + + This method is called from store() and fromBackup() methods. + Base implementation does nothing. + + \sa store(), fromBackup() +*/ +void QtxPreferenceMgr::changedResources( const ResourceMap& ) +{ +} diff --git a/src/Qtx/QtxPreferenceMgr.h b/src/Qtx/QtxPreferenceMgr.h new file mode 100644 index 000000000..50fc32416 --- /dev/null +++ b/src/Qtx/QtxPreferenceMgr.h @@ -0,0 +1,179 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxPreferenceMgr.h +// Author: Sergey TELKOV + +#ifndef QTXPREFERENCEMGR_H +#define QTXPREFERENCEMGR_H + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +#include "Qtx.h" + +#include +#include +#include +#include + +class QtxResourceMgr; +class QtxPreferenceMgr; + +class QTX_EXPORT QtxPreferenceItem +{ + class Updater; + +public: + QtxPreferenceItem( QtxPreferenceItem* = 0 ); + QtxPreferenceItem( const QString&, QtxPreferenceItem* ); + QtxPreferenceItem( const QString&, const QString&, const QString&, QtxPreferenceItem* ); + virtual ~QtxPreferenceItem(); + + int id() const; + virtual int rtti() const; + + QtxPreferenceItem* rootItem() const; + QtxPreferenceItem* parentItem() const; + QList childItems( const bool = false ) const; + + int depth() const; + int count() const; + virtual bool isEmpty() const; + + void insertItem( QtxPreferenceItem* ); + void removeItem( QtxPreferenceItem* ); + + QIcon icon() const; + QString title() const; + void resource( QString&, QString& ) const; + + virtual void setIcon( const QIcon& ); + virtual void setTitle( const QString& ); + virtual void setResource( const QString&, const QString& ); + + virtual void updateContents(); + + QVariant option( const QString& ) const; + void setOption( const QString&, const QVariant& ); + + virtual void store() = 0; + virtual void retrieve() = 0; + + QString resourceValue() const; + void setResourceValue( const QString& ); + + QtxPreferenceItem* findItem( const int, const bool = false ) const; + QtxPreferenceItem* findItem( const QString&, const bool = false ) const; + QtxPreferenceItem* findItem( const QString&, const int, const bool = false ) const; + + virtual QtxResourceMgr* resourceMgr() const; + virtual QtxPreferenceMgr* preferenceMgr() const; + + static int RTTI(); + +protected: + int getInteger( const int = 0 ) const; + double getDouble( const double = 0.0 ) const; + bool getBoolean( const bool = false ) const; + QColor getColor( const QColor& = QColor() ) const; + QFont getFont( const QFont& = QFont() ) const; + QString getString( const QString& = QString::null ) const; + + void setInteger( const int ); + void setDouble( const double ); + void setBoolean( const bool ); + void setColor( const QColor& ); + void setFont( const QFont& ); + void setString( const QString& ); + + virtual void itemAdded( QtxPreferenceItem* ); + virtual void itemRemoved( QtxPreferenceItem* ); + virtual void itemChanged( QtxPreferenceItem* ); + + void sendItemChanges(); + + virtual void triggerUpdate(); + + virtual QVariant optionValue( const QString& ) const; + virtual void setOptionValue( const QString&, const QVariant& ); + +protected: + typedef QList ItemList; + +private: + static int generateId(); + +private: + int myId; + QtxPreferenceItem* myParent; + ItemList myChildren; + + QIcon myIcon; + QString myTitle; + QString mySection; + QString myParameter; +}; + +class QTX_EXPORT QtxPreferenceMgr : public QtxPreferenceItem +{ +public: + QtxPreferenceMgr( QtxResourceMgr* ); + virtual ~QtxPreferenceMgr(); + + virtual QtxResourceMgr* resourceMgr() const; + virtual QtxPreferenceMgr* preferenceMgr() const; + + QVariant option( const int, const QString& ) const; + void setOption( const int, const QString&, const QVariant& ); + + virtual void store(); + virtual void retrieve(); + + virtual void update(); + + virtual void toBackup(); + virtual void fromBackup(); + +protected: + typedef QMap ResourceMap; + + void resourceValues( QMap& ) const; + void resourceValues( ResourceMap& ) const; + + void setResourceValues( QMap& ) const; + void setResourceValues( ResourceMap& ) const; + + void differentValues( const QMap&, const QMap&, + QMap&, const bool fromFirst = false ) const; + void differentValues( const ResourceMap&, const ResourceMap&, + ResourceMap&, const bool fromFirst = false ) const; + + virtual void changedResources( const ResourceMap& ); + +private: + QtxResourceMgr* myResMgr; + ResourceMap myBackup; +}; + +#ifdef WIN32 +#pragma warning( default:4251 ) +#endif + +#endif diff --git a/src/Qtx/QtxResourceMgr.cxx b/src/Qtx/QtxResourceMgr.cxx index 5f6edf1c4..2741e8352 100644 --- a/src/Qtx/QtxResourceMgr.cxx +++ b/src/Qtx/QtxResourceMgr.cxx @@ -16,19 +16,21 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#include "QtxResourceMgr.h" - -#include -#include -#include -#include -#include +// File: QtxResourceMgr.cxx +// Author: Alexander SOLOVYOV, Sergey TELKOV -#include -#include +#include "QtxResourceMgr.h" +#include +#include +#include +#include +#include +#include #ifndef QT_NO_DOM -#include +#include +#include +#include #endif #define EMULATE_GLOBAL_CONTEXT @@ -36,8 +38,9 @@ #include /*! - Class: QtxResourceMgr::Resources - Level: Internal + \class QtxResourceMgr::Resources + \internal + \brief Represents container for settings read from the resource file. */ class QtxResourceMgr::Resources @@ -84,14 +87,19 @@ private: typedef QMap SectionMap; private: - QtxResourceMgr* myMgr; - SectionMap mySections; - QString myFileName; - QMap myPixmapCache; + QtxResourceMgr* myMgr; //!< resources manager + SectionMap mySections; //!< sections map + QString myFileName; //!< resources file name + QMap myPixmapCache; //!< pixmaps cache friend class QtxResourceMgr::Format; }; +/*! + \brief Constructor. + \param mgr parent resources manager + \param fileName resources file name +*/ QtxResourceMgr::Resources::Resources( QtxResourceMgr* mgr, const QString& fileName ) : myMgr( mgr ), myFileName( fileName ) @@ -99,15 +107,19 @@ QtxResourceMgr::Resources::Resources( QtxResourceMgr* mgr, const QString& fileNa } /*! - Destructor + \brief Destructor. */ QtxResourceMgr::Resources::~Resources() { } /*! - Returns name of resource file - This file is used to load/save operations + \brief Get resources file name. + + This file is used to load/save operations. + + \return file name + \sa setFile() */ QString QtxResourceMgr::Resources::file() const { @@ -115,8 +127,9 @@ QString QtxResourceMgr::Resources::file() const } /*! - Sets name of resource file - \param fn - name of file + \brief Set resources file name. + \param fn file name + \sa file() */ void QtxResourceMgr::Resources::setFile( const QString& fn ) { @@ -124,14 +137,12 @@ void QtxResourceMgr::Resources::setFile( const QString& fn ) } /*! - Returns string representation of parameter value - Returns QString::null if there is no such parameter - - \param sect - name of section - \param name - name of parameter - \param subst - if it is true, then the substitution of variables - will be done with help of makeSubstitution method - \sa makeSubstitution() + \brief Get string representation of parameter value. + \param sect section name + \param name parameter name + \param subst if \c true, perform variables substitution + \return parameter value or null QString if there is no such parameter + \sa setValue(), makeSubstitution() */ QString QtxResourceMgr::Resources::value( const QString& sect, const QString& name, const bool subst ) const { @@ -147,11 +158,11 @@ QString QtxResourceMgr::Resources::value( const QString& sect, const QString& na } /*! - Sets value by it's string representation - - \param sect - name of section - \param name - name of parameter - \param val - string value + \brief Set parameter value. + \param sect section name + \param name parameter name + \param val parameter value + \sa value(), makeSubstitution() */ void QtxResourceMgr::Resources::setValue( const QString& sect, const QString& name, const QString& val ) { @@ -162,8 +173,9 @@ void QtxResourceMgr::Resources::setValue( const QString& sect, const QString& na } /*! - \return true if section exists - \param sect - name of section + \brief Check section existence. + \param sect section name + \return \c true if section exists */ bool QtxResourceMgr::Resources::hasSection( const QString& sect ) const { @@ -171,9 +183,10 @@ bool QtxResourceMgr::Resources::hasSection( const QString& sect ) const } /*! - \return true if parameter exists in section - \param sect - name of section - \param name - name of parameter + \brief Check parameter existence. + \param sect section name + \param name parameter name + \return \c true if parameter exists in specified section */ bool QtxResourceMgr::Resources::hasValue( const QString& sect, const QString& name ) const { @@ -181,8 +194,8 @@ bool QtxResourceMgr::Resources::hasValue( const QString& sect, const QString& na } /*! - Removes section from resources - \param sect - name of section + \brief Remove resourcs section. + \param sect secton name */ void QtxResourceMgr::Resources::removeSection( const QString& sect ) { @@ -190,9 +203,9 @@ void QtxResourceMgr::Resources::removeSection( const QString& sect ) } /*! - Removes parameter from section - \param sect - name of section - \param name - name of parameter + \brief Remove parameter from the section. + \param sect section name + \param name parameter name */ void QtxResourceMgr::Resources::removeValue( const QString& sect, const QString& name ) { @@ -206,7 +219,7 @@ void QtxResourceMgr::Resources::removeValue( const QString& sect, const QString& } /*! - Removes all sections + \brief Remove all sections. */ void QtxResourceMgr::Resources::clear() { @@ -214,6 +227,7 @@ void QtxResourceMgr::Resources::clear() } /*! + \brief Get all sections names. \return list of section names */ QStringList QtxResourceMgr::Resources::sections() const @@ -222,8 +236,9 @@ QStringList QtxResourceMgr::Resources::sections() const } /*! - \return list of parameter names from section - \param sec - name of section + \brief Get all parameters name in specified section. + \param sec section name + \return list of settings names */ QStringList QtxResourceMgr::Resources::parameters( const QString& sec ) const { @@ -234,11 +249,19 @@ QStringList QtxResourceMgr::Resources::parameters( const QString& sec ) const } /*! - \return path of file from directory built by parameter - \return QString::null if built path doesn't exist - \param sec - name of section - \param prefix - name of parameter containing some path - \param name - name of file + \brief Get absolute path to the file which name is defined by the parameter. + + The file name is defined by \a name argument, while directory name is retrieved + from resources parameter \a prefix of section \a sec. Both directory and file name + can be relative. If the directory is relative, it is calculated from the initial + resources file name (see file()). Directory parameter can contain environment + variables, which are substituted automatically. + + \param sec section name + \param prefix parameter containing directory name + \param name file name + \return absolute file path or null QString if file does not exist + \sa fileName(), file(), makeSubstitution() */ QString QtxResourceMgr::Resources::path( const QString& sec, const QString& prefix, const QString& name ) const { @@ -252,7 +275,8 @@ QString QtxResourceMgr::Resources::path( const QString& sec, const QString& pref } /*! - \return corresponding resource manager + \brief Get resource manager + \return resource manager pointer */ QtxResourceMgr* QtxResourceMgr::Resources::resMgr() const { @@ -260,7 +284,12 @@ QtxResourceMgr* QtxResourceMgr::Resources::resMgr() const } /*! - \return instance of section by it's name. Section will be created if it doesn't exist + \brief Get resources section by specified name. + + If section does not exist it is created (empty). + + \param sn section name + \return resources section */ QtxResourceMgr::Section QtxResourceMgr::Resources::section( const QString& sn ) { @@ -271,7 +300,9 @@ QtxResourceMgr::Section QtxResourceMgr::Resources::section( const QString& sn ) } /*! - \return instance of section by it's name. Section will be created if it doesn't exist + \brief Get resources section by specified name. + \param sn section name + \return resources section */ const QtxResourceMgr::Section QtxResourceMgr::Resources::section( const QString& sn ) const { @@ -279,10 +310,21 @@ const QtxResourceMgr::Section QtxResourceMgr::Resources::section( const QString& } /*! - \return full path of file - \param sect - name of section - \param prefix - name of parameter containing some path - \param name - name of file + \brief Get file path. + + The file name is defined by \a name argument, while directory name is retrieved + from resources parameter \a prefix of section \a sec. Both directory and file name + can be relative. If the directory is relative, it is calculated from the initial + resources file name (see file()). Directory parameter can contain environment + variables, which are substituted automatically. + File existence is not checked. + + \param sec section name + \param prefix parameter containing directory name + \param name file name + \return absolute file path or null QString if \a prefix parameter + does not exist in section \sec + \sa path(), file(), makeSubstitution() */ QString QtxResourceMgr::Resources::fileName( const QString& sect, const QString& prefix, const QString& name ) const { @@ -309,10 +351,16 @@ QString QtxResourceMgr::Resources::fileName( const QString& sect, const QString& } /*! - \return QPixmap loaded from file - \param sect - name of section - \param prefix - name of parameter containing some path - \param name - name of picture file + \brief Load and return pixmap from external file. + + If QtxResourceMgr::isPixmapCached() is \c true then cached pixmap is returned + (if it is already loaded), otherwise it is loaded from file. + If the file name is invalid, null pixmap is returned. + + \param sect section name + \param prefix parameter containing resources directory name + \param name pixmap file name + \return pixmap loaded from file */ QPixmap QtxResourceMgr::Resources::loadPixmap( const QString& sect, const QString& prefix, const QString& name ) const { @@ -331,10 +379,11 @@ QPixmap QtxResourceMgr::Resources::loadPixmap( const QString& sect, const QStrin } /*! - \return just created and loaded translator - \param sect - name of section - \param prefix - name of parameter containing some path - \param name - name of file + \brief Load translator. + \param sect section name + \param prefix parameter containing resources directory + \param name translation file name + \return just created and loaded translator or 0 in case of error */ QTranslator* QtxResourceMgr::Resources::loadTranslator( const QString& sect, const QString& prefix, const QString& name ) const { @@ -387,11 +436,18 @@ QTranslator* QtxResourceMgr::Resources::loadTranslator( const QString& sect, con } /*! - Finds in string variables by patterns: ${name} or $(name) or %name% - \return first found name or QString::null if there is no ones - \param str - string where the search is processed - \param start - integer value for returning start position of variable - \param len - integer value for returning length of variable + \brief Parse given string to retrieve environment variable. + + Looks through the string for the patterns: ${name} or $(name) or %name%. + 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. + + \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 QtxResourceMgr::Resources::environmentVariable( const QString& str, int& start, int& len ) const { @@ -428,13 +484,15 @@ QString QtxResourceMgr::Resources::environmentVariable( const QString& str, int& } /*! - Substitutes variables by its' values. If variable is from enviroment, - it will be replaced by environment value. If it isn't, method tries to - find it's value among resources - \return new variant of string 'str' - \param str - string to process substitution - \param sect - section, in which the variables will be finding - \param name - name of variable which must be ignored during substitution + \brief Substitute variables by their values. + + Environment variable is substituted by its value. For other variables resource + manager tries to find value among defined resources parameters. + + \param str string to be processed + \param sect section, where variables are searched + \param name name of variable which must be ignored during substitution + \return processed string (with all substitutions made) */ QString QtxResourceMgr::Resources::makeSubstitution( const QString& str, const QString& sect, const QString& name ) const { @@ -476,9 +534,11 @@ QString QtxResourceMgr::Resources::makeSubstitution( const QString& str, const Q } /*! - Class: QtxResourceMgr::IniFormat - Level: Internal + \class QtxResourceMgr::IniFormat + \internal + \brief Reader/writer for .ini resources files. */ + class QtxResourceMgr::IniFormat : public Format { public: @@ -491,7 +551,7 @@ protected: }; /*! - Default constructor + \brief Constructor. */ QtxResourceMgr::IniFormat::IniFormat() : Format( "ini" ) @@ -499,16 +559,17 @@ QtxResourceMgr::IniFormat::IniFormat() } /*! - Destructor + \brief Destructor. */ QtxResourceMgr::IniFormat::~IniFormat() { } /*! - Loads resources from ini-file to map of sections - \param fname - name of resource file - \param secMap - map of sections + \brief Load resources from ini-file. + \param fname resources file name + \param secMap resources map to be filled in + \return \c true on success and \c false on error */ bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap& secMap ) { @@ -576,9 +637,10 @@ bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap& secMap ) { @@ -606,8 +668,9 @@ bool QtxResourceMgr::IniFormat::save( const QString& fname, const QMap& secMap ) { @@ -744,9 +808,10 @@ bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap& secMap ) { @@ -789,7 +854,8 @@ bool QtxResourceMgr::XmlFormat::save( const QString& fname, const QMap& secMap ) + \brief Load resources from the specified resources file. + + Should be implemented in the successors. + + \param fname resources file name + \param secMap resources map to be filled in + \return \c true on success and \c false on error */ /*! - \brief Constructs the resource manager object for application. - \param appName - name of the application which resources will be used. - \param resVarTemplate - template for the resource environment variable name which - should point to the resource directory list. - Default value is "%1Resources". Its mean that for application - with name "MyApp" environment variable "MyAppResources" will - be used. Template may not have the parameter '%1' substituted - by application name. In this case this string will be used as - is without substitution. - Resource environment variable should contains one or several resource directories - separated by symbol ';'. Resource directories list transfered into the setDirList(). - These directories and the user home directory used for the loading application resources. - Each of the resource directories can contains resource file. The name of this file defined - by the function globalFileName(). Resource file name in the user home defined by the - function userFileName(). Any resource looking firstly in the user home resources then - resource directories used in the specified order. All setted resources always stored into - the resource file at the user home. Only user home resource file is saved. - If you want to ignore of loading of Local User Preferences, you needs setup setIngoreUserValues() - as true. + \fn virtual bool QtxResourceMgr::Format::save( const QString& fname, + const QMap& secMap ) + + \brief Save resources to the specified resources file. + + Should be implemented in the successors. + + \param fname resources file name + \param secMap resources map + \return \c true on success and \c false on error +*/ + +/*! + \class QtxResourceMgr + \brief Application resources manager. + + This class can be used to define settings, save/load settings and + application preferences to the resource file(s), load translation files + (internationalization mechanism), load pixmaps and other resources from + external files, etc. + + Currently it supports .ini and .xml resources file formats. To implement + own resources file format, inherit from the Format class and implement virtual + Format::load() and Format::save() methods. + + Resources manager is initialized by the (symbolic) name of the application. + The parameter \a resVarTemplate specifies the template for the environment + variable which should point to the resource directory or list of directories. + Environment variable name is calculated by substitution of "%1" substring in + the \a resVarTemplate parameter (if it contains such substring) by the + application name (\a appName). + By default, \a resVarTemplate is set to "%1Resources". For example, if the application name + is "MyApp", the environment variable "MyAppResources" will be inspected in this case. + + Resource manager can handle several global application configuration files and + one user configuration file. Location of global configuration files is defined + by the environment variable (see above) and these files are always read-only. + The name of the global configuration files is retrieved by calling virtual method + globalFileName() which can be redefined in the QtxResourceMgr class successors. + User configuration file always situated in the user's home directory. It's name + is defined by calling virtual method userFileName() which can be also redefined + in the QtxResourceMgr class successors. This is the only file which the preferences + changed by the user during the application session are written to (usually + when the application closes). + + Resources environment variable should contain one or several resource directories + (separated by ";" symbol on Windows and ":" or ";" on Linux). Each resource directory + can contain application global configuration file. The user configuration file has + the highest priority, for the global configuration files the priority is decreasing from + left to right, i.e. the first directory in the directoris list, defined by the + resources environment variable has higher priority. Priority has the meaning when + searching requested resources (application preference, pixmap file name, translation + file, etc). + Loading of the user configuration file can be omitted by calling setIgnoreUserValues() + with \c true parameter. + + Resources manager operates with such terms like options, sections and parameters. + Parametets are named application resources, for example, application preferences like + integer, double, boolean or string values, pictures, font and color definitions, etc. + Parameters are organized inside the resources files into the named groups - sections. + Options are special kind of resoures which allow customizing resource files interpreting. + For example, by default language settings are defined in the resource file in the + section "language". It is possible to change this section name by setting "language" + option to another value (see setOption()). + + Retrieving preferences values can be done by using one of value() methods, each returns + \c true if the corresponding preference is found. Another way is to use integerValue(), + doubleValue(), etc methods, which allow specifying default value which is used if the + specified preference is not found. Removing of preferences or sections can be done using + remove(const QString& sect) or remove(const QString& sect, const QString& name) methods. + To add the preference or to change exiting preference value use setValue() methods family. + Methods hasSection() and hasValue() can be used to check existence of section or + preference (in the specified section). List of all sections can be retrieved with the + sections() method, and list of all settings names in some specified section can be + obtained with parameters() method. + + Pixmaps can be loaded with the loadPixmap() methods. If the specified pixmap is not found, + the default one is returned. Default pixmap can be set by setDefaultPixmap(). + + One of the key feature of the resources manager is support of application + internationalization mechanism. Translation files for the specified language can be loaded + with loadLanguage() method. +*/ + +/*! + \brief Constructs the resource manager. + \param appName application name + \param resVarTemplate resource environment variable pattern */ QtxResourceMgr::QtxResourceMgr( const QString& appName, const QString& resVarTemplate ) : myAppName( appName ), myCheckExist( true ), + myDefaultPix( 0 ), myIsPixmapCached( true ), myIsIgnoreUserValues( false ) { @@ -991,7 +1145,9 @@ QtxResourceMgr::QtxResourceMgr( const QString& appName, const QString& resVarTem } /*! - \brief Destructs the resource manager object and free allocated memory. + \brief Destructor. + + Destroy the resource manager and free allocated memory. */ QtxResourceMgr::~QtxResourceMgr() { @@ -1003,10 +1159,13 @@ QtxResourceMgr::~QtxResourceMgr() myResources.clear(); for ( FormatList::iterator formIt = myFormats.begin(); formIt != myFormats.end(); ++formIt ) delete *formIt; + + delete myDefaultPix; } /*! - \brief Returns the application name. + \brief Get the application name. + \return application name */ QString QtxResourceMgr::appName() const { @@ -1014,9 +1173,12 @@ QString QtxResourceMgr::appName() const } /*! - \brief Returns the checking of the existance flag. If its 'true' then resource - will be setted into the manager only if it doesn't exist or has different - value that existing value. + \brief Get the "check existance" flag + + If this flag is \c true then preference can be set (with setValue() method) + only if it doesn't exist or if the value is changed. + + \return \c true if "check existance" flag is set */ bool QtxResourceMgr::checkExisting() const { @@ -1024,8 +1186,8 @@ bool QtxResourceMgr::checkExisting() const } /*! - \brief Sets the checking of the existance flag. - \param on - boolean value of the flag. + \brief Set the "check existance" flag. + \param on new flag value */ void QtxResourceMgr::setCheckExisting( const bool on ) { @@ -1033,7 +1195,13 @@ void QtxResourceMgr::setCheckExisting( const bool on ) } /*! - \brief Returns the resource directories list except user home directory. + \brief Get the resource directories list. + + Home user directory (where the user application configuration file is situated) + is not included. This is that directories list defined by the application + resources environment variable. + + \return list of directories names */ QStringList QtxResourceMgr::dirList() const { @@ -1041,8 +1209,11 @@ QStringList QtxResourceMgr::dirList() const } /*! - \brief Initialise the manager. Prepare the resource containers and load resources. - \param autoLoad - if 'true' then all resources will be loaded. + \brief Initialise resources manager. + + Prepare the resources containers and load resources (if \a autoLoad is \c true). + + \param autoLoad if \c true then all resources are loaded */ void QtxResourceMgr::initialize( const bool autoLoad ) const { @@ -1065,7 +1236,15 @@ void QtxResourceMgr::initialize( const bool autoLoad ) const } /*! - \brief Return true if all loaded pixmaps are stored in internal map; by default: true + \brief Get "cached pixmaps" option value. + + Resources manager allows possibility to cache loaded pixmaps that allow to + improve application performance. This feature is turned on by default - all + loaded pixmaps are stored in the internal map. Switching of this feature on/off + can be done by setIsPixmapCached() method. + + \return \c true if pixmap cache is turned on + \sa setIsPixmapCached() */ bool QtxResourceMgr::isPixmapCached() const { @@ -1073,8 +1252,9 @@ bool QtxResourceMgr::isPixmapCached() const } /*! - \brief Set true, if it is necessary to store all loaded pixmap in internal map - (it accelerates following calls of loadPixmap) + \brief Switch "cached pixmaps" option on/off. + \param on enable pixmap cache if \c true and disable it if \c false + \sa isPixmapCached() */ void QtxResourceMgr::setIsPixmapCached( const bool on ) { @@ -1082,7 +1262,7 @@ void QtxResourceMgr::setIsPixmapCached( const bool on ) } /*! - \brief Removes all resources from the manager. + \brief Remove all resources from the resources manager. */ void QtxResourceMgr::clear() { @@ -1091,8 +1271,12 @@ void QtxResourceMgr::clear() } /*! - Set state 'ignore user values'. - If it is true, then all resources loaded from user home directory is ignored + \brief Set "ignore user values" option value. + + If this option is \c true, then all resources loaded from user home directory are ignored. + + \param val new option value + \sa ignoreUserValues() */ void QtxResourceMgr::setIgnoreUserValues( const bool val ) { @@ -1100,7 +1284,10 @@ void QtxResourceMgr::setIgnoreUserValues( const bool val ) } /*! - \return state 'ignore user values' + \brief Get "ignore user values" option value. + + \return "ignore user values" option value + \sa setIgnoreUserValues() */ bool QtxResourceMgr::ignoreUserValues() const { @@ -1108,11 +1295,12 @@ bool QtxResourceMgr::ignoreUserValues() const } /*! - \brief Get the resource value as integer. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param iVal - Reference on the variable which should contains the resource output. + \brief Get interger parameter value. + \param sect section name + \param name parameter name + \param iVal parameter to return resulting integer value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a iVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, int& iVal ) const { @@ -1127,11 +1315,12 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, int& iVal } /*! - \brief Get the resource value as double. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param dVal - Reference on the variable which should contains the resource output. + \brief Get double parameter value. + \param sect section name + \param name parameter name + \param dVal parameter to return resulting double value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a dVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, double& dVal ) const { @@ -1146,11 +1335,12 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, double& dV } /*! - \brief Get the resource value as boolean. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param bVal - Reference on the variable which should contains the resource output. + \brief Get boolean parameter value. + \param sect section name + \param name parameter name + \param bVal parameter to return resulting boolean value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a bVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, bool& bVal ) const { @@ -1180,11 +1370,12 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, bool& bVal } /*! - \brief Get the resource value as color. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param cVal - Reference on the variable which should contains the resource output. + \brief Get color parameter value. + \param sect section name + \param name parameter name + \param cVal parameter to return resulting color value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a cVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, QColor& cVal ) const { @@ -1228,11 +1419,12 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, QColor& cV } /*! - \brief Get the resource value as font. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param fVal - Reference on the variable which should contains the resource output. + \brief Get font parameter value. + \param sect section name + \param name parameter name + \param fVal parameter to return resulting font value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a fVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, QFont& fVal ) const { @@ -1273,11 +1465,12 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, QFont& fVa } /*! - \brief Get the resource value as byte array. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param baVal - Reference on the variable which should contains the resource output. + \brief Get byte array parameter value. + \param sect section name + \param name parameter name + \param baVal parameter to return resulting byte array value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a baVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, QByteArray& baVal ) const { @@ -1307,14 +1500,13 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, QByteArray } /*! - \brief Get the resource value as string (native format). Returns 'true' if it - successfull otherwise returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param val - Reference on the variable which should contains the resource output. - \param subst - If 'true' then manager substitute reference on environment variables - and other resources by thier values. Default value of this parameter - is 'true' + \brief Get string parameter value (native format). + \param sect section name + \param name parameter name + \param val parameter to return resulting byte array value + \param subst if \c true perform environment variables substitution + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a val value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, QString& val, const bool subst ) const { @@ -1337,11 +1529,15 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, QString& v } /*! - \brief Returns the integer resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get interger parameter value. + + If the specified parameter is not found or can not be converted to the integer value, + the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ int QtxResourceMgr::integerValue( const QString& sect, const QString& name, const int def ) const { @@ -1352,11 +1548,15 @@ int QtxResourceMgr::integerValue( const QString& sect, const QString& name, cons } /*! - \brief Returns the double resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get double parameter value. + + If the specified parameter is not found or can not be converted to the double value, + the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ double QtxResourceMgr::doubleValue( const QString& sect, const QString& name, const double def ) const { @@ -1367,11 +1567,15 @@ double QtxResourceMgr::doubleValue( const QString& sect, const QString& name, co } /*! - \brief Returns the boolean resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get boolean parameter value. + + If the specified parameter is not found or can not be converted to the boolean value, + the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ bool QtxResourceMgr::booleanValue( const QString& sect, const QString& name, const bool def ) const { @@ -1382,11 +1586,15 @@ bool QtxResourceMgr::booleanValue( const QString& sect, const QString& name, con } /*! - \brief Returns the font resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get font parameter value. + + If the specified parameter is not found or can not be converted to the font value, + the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ QFont QtxResourceMgr::fontValue( const QString& sect, const QString& name, const QFont& def ) const { @@ -1397,11 +1605,15 @@ QFont QtxResourceMgr::fontValue( const QString& sect, const QString& name, const } /*! - \brief Returns the color resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get color parameter value. + + If the specified parameter is not found or can not be converted to the color value, + the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ QColor QtxResourceMgr::colorValue( const QString& sect, const QString& name, const QColor& def ) const { @@ -1412,11 +1624,14 @@ QColor QtxResourceMgr::colorValue( const QString& sect, const QString& name, con } /*! - \brief Returns the string resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get string parameter value. + + If the specified parameter is not found, the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ QString QtxResourceMgr::stringValue( const QString& sect, const QString& name, const QString& def ) const { @@ -1427,11 +1642,14 @@ QString QtxResourceMgr::stringValue( const QString& sect, const QString& name, c } /*! - \brief Returns the byte array resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get byte array parameter value. + + If the specified parameter is not found, the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ QByteArray QtxResourceMgr::byteArrayValue( const QString& sect, const QString& name, const QByteArray& def ) const { @@ -1442,9 +1660,10 @@ QByteArray QtxResourceMgr::byteArrayValue( const QString& sect, const QString& n } /*! - \brief Checks existance of the specified resource. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. + \brief Check parameter existence. + \param sect section name + \param name parameter name + \return \c true if parameter exists in specified section */ bool QtxResourceMgr::hasValue( const QString& sect, const QString& name ) const { @@ -1458,8 +1677,9 @@ bool QtxResourceMgr::hasValue( const QString& sect, const QString& name ) const } /*! - \brief Checks existance of the specified resource section. - \param sect - Resource section name which contains resource. + \brief Check section existence. + \param sect section name + \return \c true if section exists */ bool QtxResourceMgr::hasSection( const QString& sect ) const { @@ -1473,10 +1693,10 @@ bool QtxResourceMgr::hasSection( const QString& sect ) const } /*! - \brief Sets the integer resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set integer parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, int val ) { @@ -1488,10 +1708,10 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, int val } /*! - \brief Sets the double resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set double parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, double val ) { @@ -1503,10 +1723,10 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, double } /*! - \brief Sets the boolean resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set boolean parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, bool val ) { @@ -1518,10 +1738,10 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, bool va } /*! - \brief Sets the color resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set color parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QColor& val ) { @@ -1533,10 +1753,10 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const Q } /*! - \brief Sets the font resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set font parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QFont& val ) { @@ -1558,10 +1778,10 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const Q } /*! - \brief Sets the string resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set string parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QString& val ) { @@ -1573,10 +1793,10 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const Q } /*! - \brief Sets the string resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set byte array parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QByteArray& val ) { @@ -1588,16 +1808,15 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const Q QStringList lst; for ( int i = 0; i < val.size(); i++ ) { - ::sprintf( buf, "#%02X", val.at( i ) ); + ::sprintf( buf, "#%02X", (unsigned char)val.at( i ) ); lst.append( QString( buf ) ); } - setResource( sect, name, lst.join( " " ) ); } /*! - \brief Remove the all specified resource section. - \param sect - Resource section name. + \brief Remove resources section. + \param sect section name */ void QtxResourceMgr::remove( const QString& sect ) { @@ -1608,9 +1827,9 @@ void QtxResourceMgr::remove( const QString& sect ) } /*! - \brief Remove the specified resource. - \param sect - Resource section name. - \param name - Name of the resource. + \brief Remove the specified parameter. + \param sect section name + \param name parameter name */ void QtxResourceMgr::remove( const QString& sect, const QString& name ) { @@ -1621,7 +1840,8 @@ void QtxResourceMgr::remove( const QString& sect, const QString& name ) } /*! - \brief Returns the current format which operates with resource files. + \brief Get current configuration files format. + \return configuration files format name */ QString QtxResourceMgr::currentFormat() const { @@ -1632,8 +1852,8 @@ QString QtxResourceMgr::currentFormat() const } /*! - \brief Sets the current format which operates with resource files. - \param fmt - Resource format name. + \brief Set current configuration files format. + \param fmt configuration files format name */ void QtxResourceMgr::setCurrentFormat( const QString& fmt ) { @@ -1659,8 +1879,9 @@ void QtxResourceMgr::setCurrentFormat( const QString& fmt ) } /*! - \brief Returns the resource format object by it name. - \param fmt - Resource format name. + \brief Get configuration files format by specified format name. + \param fmt configuration files format name + \return format object or 0 if format is not defined */ QtxResourceMgr::Format* QtxResourceMgr::format( const QString& fmt ) const { @@ -1675,8 +1896,11 @@ QtxResourceMgr::Format* QtxResourceMgr::format( const QString& fmt ) const } /*! - \brief Add the resource format to the manager. Newly added become current. - \param form - Resource format object. + \brief Install configuration files format. + + Added format becomes current. + + \param form format object to be installed */ void QtxResourceMgr::installFormat( QtxResourceMgr::Format* form ) { @@ -1685,8 +1909,8 @@ void QtxResourceMgr::installFormat( QtxResourceMgr::Format* form ) } /*! - \brief Remove the resource format from the manager. - \param form - Resource format object. + \brief Remove configuration files format. + \param form format object to be uninstalled */ void QtxResourceMgr::removeFormat( QtxResourceMgr::Format* form ) { @@ -1694,7 +1918,8 @@ void QtxResourceMgr::removeFormat( QtxResourceMgr::Format* form ) } /*! - \brief Returns the string list of the resource format options names. + \brief Get resource format options names. + \return list of options names */ QStringList QtxResourceMgr::options() const { @@ -1702,9 +1927,13 @@ QStringList QtxResourceMgr::options() const } /*! - \brief Returns the string value for the specified option. If option doesn't exist - then empty string will be returned. - \param opt - Option name. + \brief Get the string value of the specified resources format option. + + If option does not exist, null QString is returned. + + \param opt option name + \return option value + \sa setOption(), options() */ QString QtxResourceMgr::option( const QString& opt ) const { @@ -1715,9 +1944,10 @@ QString QtxResourceMgr::option( const QString& opt ) const } /*! - \brief Sets the string value for the specified option. - \param opt - Option name. - \param val - Option value. + \brief Set the string value of the specified resources format option. + \param opt option name + \param val option value + \sa option(), options() */ void QtxResourceMgr::setOption( const QString& opt, const QString& val ) { @@ -1725,7 +1955,9 @@ void QtxResourceMgr::setOption( const QString& opt, const QString& val ) } /*! - \brief Load the all resources from the resource files. + \brief Load all resources from all resource files (global and user). + \return \c true on success and \c false on error + \sa save() */ bool QtxResourceMgr::load() { @@ -1743,7 +1975,9 @@ bool QtxResourceMgr::load() } /*! - \brief Import some file with resources + \brief Import resources from specified resource file. + \param fname resources file name + \return \c true on success and \c false on error */ bool QtxResourceMgr::import( const QString& fname ) { @@ -1763,7 +1997,8 @@ bool QtxResourceMgr::import( const QString& fname ) } /*! - \brief Save the changed resources in to the user resource file. + \brief Save all resources to the user resource files. + \return \c true on success and \c false on error */ bool QtxResourceMgr::save() { @@ -1780,7 +2015,8 @@ bool QtxResourceMgr::save() } /*! - \brief Returns the string list of the existing section names.. + \brief Get all sections names. + \return list of section names */ QStringList QtxResourceMgr::sections() const { @@ -1802,8 +2038,9 @@ QStringList QtxResourceMgr::sections() const } /*! - \brief Returns the string list of the existing resource names in the specified section. - \param sec - Resource section name. + \brief Get all parameters name in specified section. + \param sec section name + \return list of settings names */ QStringList QtxResourceMgr::parameters( const QString& sec ) const { @@ -1834,11 +2071,18 @@ QStringList QtxResourceMgr::parameters( const QString& sec ) const } /*! - \return path of file from directory built by parameter - \return QString::null if built path doesn't exist - \param sec - name of section - \param prefix - name of parameter containing some path - \param name - name of file + \brief Get absolute path to the file which name is defined by the parameter. + + The file name is defined by \a name argument, while directory name is retrieved + from resources parameter \a prefix of section \a sec. Both directory and file name + can be relative. If the directory is relative, it is calculated from the initial + resources file name. Directory parameter can contain environment + variables, which are substituted automatically. + + \param sec section name + \param prefix parameter containing directory name + \param name file name + \return absolute file path or null QString if file does not exist */ QString QtxResourceMgr::path( const QString& sect, const QString& prefix, const QString& name ) const { @@ -1849,7 +2093,13 @@ QString QtxResourceMgr::path( const QString& sect, const QString& prefix, const } /*! - \return section corresponding to resources paths + \brief Get application resources section name. + + By default, application resources section name is "resources" but + it can be changed by setting the corresponding resources manager option. + + \return section corresponding to the resources directories + \sa option(), setOption() */ QString QtxResourceMgr::resSection() const { @@ -1860,7 +2110,13 @@ QString QtxResourceMgr::resSection() const } /*! - \return section corresponding to language settings + \brief Get application language section name. + + By default, application language section name is "language" but + it can be changed by setting the corresponding resources manager option. + + \return section corresponding to the application language settings + \sa option(), setOption() */ QString QtxResourceMgr::langSection() const { @@ -1871,26 +2127,44 @@ QString QtxResourceMgr::langSection() const } /*! - \return default image used when during loading the image file doesn't exist + \brief Get default pixmap. + + Default pixmap is used when requested pixmap resource is not found. + + \return default pixmap + \sa setDefaultPixmap(), loadPixmap() */ QPixmap QtxResourceMgr::defaultPixmap() const { - return myDefaultPix; + QPixmap res; + if ( myDefaultPix && !myDefaultPix->isNull() ) + res = *myDefaultPix; + return res; } /*! - Set image as default image used when during loading the image file doesn't exist - \param pix - image + \brief Set default pixmap. + + Default pixmap is used when requested pixmap resource is not found. + + \param pix default pixmap + \sa defaultPixmap(), loadPixmap() */ void QtxResourceMgr::setDefaultPixmap( const QPixmap& pix ) { - myDefaultPix = pix; + delete myDefaultPix; + if ( pix.isNull() ) + myDefaultPix = 0; + else + myDefaultPix = new QPixmap( pix ); } /*! - \return image loaded from file - \param prefix - name of parameter containing some path - \param name - name of file + \brief Load pixmap resource. + \param prefix parameter which refers to the resources directory (directories) + \param name pixmap file name + \return pixmap loaded from the file + \sa defaultPixmap(), setDefaultPixmap() */ QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name ) const { @@ -1898,12 +2172,14 @@ QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name ) } /*! - \return image loaded from file - \param prefix - name of parameter containing some path - \param name - name of file - \param useDef - indicates if it is possible to use default image returning by defaultPixmap() method. - If it is false, the empty pixmap will be used as default - \sa defaultPixmap() + \brief Load pixmap resource. + \overload + \param prefix parameter which refers to the resources directory (directories) + \param name pixmap file name + \param useDef if \c false, default pixmap is not returned if resource is not found, + in this case null pixmap is returned instead + \return pixmap loaded from the file + \sa defaultPixmap(), setDefaultPixmap() */ QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name, const bool useDef ) const { @@ -1911,13 +2187,13 @@ QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name, } /*! - Finds in all sections an existing path corresponding to 'prefix' parameter - and load image with name 'name' from this folder - - \return image loaded from file - \param prefix - name of parameter containing some path - \param name - name of file - \param defPix - default image used when file doesn't exist + \brief Load pixmap resource. + \overload + \param prefix parameter which refers to the resources directory (directories) + \param name pixmap file name + \param defPix default which should be used if the resource file doesn't exist + \return pixmap loaded from the file + \sa defaultPixmap(), setDefaultPixmap() */ QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name, const QPixmap& defPix ) const { @@ -1932,20 +2208,25 @@ QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name, } /*! - Loads translator for language - Name of translator file is constructed by list returning by option "translators" or, - if it is empty, by predefined pattern "%P_msg_%L.qm". It is recommended to used in translators - name the strings %A, %P, %L whose will be replaced by application name, prefix and language name correspondingly + \brief Load translation files according to the specified language. + + Names of the translation files are calculated according to the pattern specified + by the "translators" option (this option is read from the section "language" of resources files). + By default, "%P_msg_%L.qm" pattern is used. + Keywords \%A, \%P, \%L in the pattern are substituted by the application name, prefix and language name + correspondingly. + For example, for prefix "SUIT" an language "en", all translation files "SUIT_msg_en.qm" are searched and + loaded. - \param pref - name of parameter containing path to translator's file. - If it is empty, the list of parameters from resource section ( resSection() ) - is used. + If prefix is empty or null string, all translation files specified in the "resources" section of resources + files are loaded (actually, the section is retrieved from resSection() method). + If language is not specified, it is retrieved from the langSection() method, and if the latest is also empty, + by default "en" (English) language is used. - \param l - name of language. If it is empty, then value of parameter "language" - from language section ( langSection() ) is used. If it is also empty, then - predefined name "en" is used + \param pref parameter which defines translation context (for example, package name) + \param l language name - \sa resSection(), langSection() + \sa resSection(), langSection(), loadTranslators() */ void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l ) { @@ -2006,10 +2287,10 @@ void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l ) } /*! - Loads translators by path and list of files - - \param prefix - value of this parameter must contain path - \param translators - list of translators' files + \brief Load translation files for the specified translation context. + \param prefix parameter which defines translation context (for example, package name) + \param translators list of translation files + \sa loadLanguage() */ void QtxResourceMgr::loadTranslators( const QString& prefix, const QStringList& translators ) { @@ -2037,10 +2318,10 @@ void QtxResourceMgr::loadTranslators( const QString& prefix, const QStringList& } /*! - Loads translator by path and file name - - \param prefix - value of this parameter must contain path - \param name - name of translator file + \brief Load translation file. + \param prefix parameter which defines translation context (for example, package name) + \param name translator file name + \sa loadLanguage(), loadTranslators() */ void QtxResourceMgr::loadTranslator( const QString& prefix, const QString& name ) { @@ -2061,9 +2342,8 @@ void QtxResourceMgr::loadTranslator( const QString& prefix, const QString& name } /*! - Remove all translators corresponding to prefix - - \param prefix - parameter containing path + \brief Remove all translators corresponding to the specified translation context. + \param prefix parameter which defines translation context (for example, package name) */ void QtxResourceMgr::removeTranslators( const QString& prefix ) { @@ -2080,9 +2360,9 @@ void QtxResourceMgr::removeTranslators( const QString& prefix ) } /*! - Moves translators corresponding to prefix to the top of translator stack - - \param prefix - parameter containing path + \brief Move all translators corresponding to the specified translation context + to the top of translators stack (increase their priority). + \param prefix parameter which defines translation context (for example, package name) */ void QtxResourceMgr::raiseTranslators( const QString& prefix ) { @@ -2097,7 +2377,8 @@ void QtxResourceMgr::raiseTranslators( const QString& prefix ) } /*! - Copies all resources to user resources, so that they will be saved in user home folder + \brief Copy all parameters to the user resources in order to + saved them lately in the user home folder. */ void QtxResourceMgr::refresh() { @@ -2111,7 +2392,11 @@ void QtxResourceMgr::refresh() } /*! - \brief Sets the resource directories list except user home directory and clear resources + \brief Set the resource directories (where global confguration files are searched). + + This function also clears all currently set resources. + + \param dl directories list */ void QtxResourceMgr::setDirList( const QStringList& dl ) { @@ -2123,10 +2408,10 @@ void QtxResourceMgr::setDirList( const QStringList& dl ) } /*! - Sets resource value - \param sect - name of section - \param name - name of parameter - \param val - string representation of value + \brief Set parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setResource( const QString& sect, const QString& name, const QString& val ) { @@ -2137,10 +2422,22 @@ void QtxResourceMgr::setResource( const QString& sect, const QString& name, cons } /*! - \return name of resource file, which is being found in user home directory - \param appName - name of application - \param for_load - flag indicating that file will be used for loading (true) or for saving(false) - It makes possible to use different resource files for loading and saving + \brief Get user configuration file name. + + This method can be redefined in the successor class to customize the user configuration file name. + User configuration file is always situated in the user's home directory. By default .rc + file is used on Linux (e.g. .MyApprc) and . under Windows (e.g. MyApp.xml). + + Parameter \a for_load (not used in default implementation) specifies the usage mode, i.e. if + user configuration file is opened for reading or writing. This allows customizing a way of application + resources initializing (for example, if the user configuraion file includes version number and there is + no file corresponding to this version in the user's home directory, it could be good idea to try + the configuration file from the previous versions of the application). + + \param appName application name + \param for_load boolean flag indicating that file is opened for loading or saving (not used) + \return user configuration file name + \sa globalFileName() */ QString QtxResourceMgr::userFileName( const QString& appName, const bool /*for_load*/ ) const { @@ -2160,7 +2457,16 @@ QString QtxResourceMgr::userFileName( const QString& appName, const bool /*for_l } /*! - \return name of resource file, which is being found in all resource directories, except user home + \brief Get global configuration file name. + + This method can be redefined in the successor class to customize the global configuration file name. + Global configuration files are searched in the directories specified by the application resources + environment variable (e.g. MyAppResources). By default . file name is used + (e.g. MyApp.xml). + + \param appName application name + \return global configuration file name + \sa userFileName() */ QString QtxResourceMgr::globalFileName( const QString& appName ) const { @@ -2168,10 +2474,13 @@ QString QtxResourceMgr::globalFileName( const QString& appName ) const } /*! - Replaced substrings by pattern %A, %B, etc by values from map + \brief Perform substitution of the patterns like \%A, \%B, etc by values from the map. + + Used by loadLanguage(). - \param src - string to be processed - \param substMap - map of values for replacing + \param src sring to be processed + \param substMap map of values for replacing + \return processed string */ QString QtxResourceMgr::substMacro( const QString& src, const QMap& substMap ) const { diff --git a/src/Qtx/QtxResourceMgr.h b/src/Qtx/QtxResourceMgr.h index 13f116fcd..b70caa2c5 100644 --- a/src/Qtx/QtxResourceMgr.h +++ b/src/Qtx/QtxResourceMgr.h @@ -16,31 +16,32 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#ifndef QTX_RESOURCEMGR_H -#define QTX_RESOURCEMGR_H +// File: QtxResourceMgr.h +// Author: Alexander SOLOVYOV, Sergey TELKOV + +#ifndef QTXRESOURCEMGR_H +#define QTXRESOURCEMGR_H #include "Qtx.h" -#include -#include -#include -#include -#include +#ifndef QTX_NO_INDEXED_MAP +#include "QtxMap.h" +#endif -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include -class QPixmap; +class QTranslator; #ifdef WIN32 #pragma warning( disable:4251 ) #endif -/*! - Class: QtxResourceMgr -*/ - class QTX_EXPORT QtxResourceMgr { class IniFormat; @@ -50,14 +51,10 @@ class QTX_EXPORT QtxResourceMgr public: class Format; - template class IMap; - template class IMapIterator; - template class IMapConstIterator; - #ifdef QTX_NO_INDEXED_MAP - typedef QMap Section; + typedef QMap Section; //!< resource section #else - typedef IMap Section; + typedef IMap Section; //!< resource section #endif public: @@ -165,25 +162,21 @@ private: typedef QMap TransListMap; private: - QString myAppName; - QStringList myDirList; - FormatList myFormats; - OptionsMap myOptions; - ResList myResources; - bool myCheckExist; - TransListMap myTranslator; - QPixmap myDefaultPix; - bool myIsPixmapCached; - - bool myIsIgnoreUserValues; + QString myAppName; //!< application name + QStringList myDirList; //!< list of resources directories + FormatList myFormats; //!< list of formats + OptionsMap myOptions; //!< options map + ResList myResources; //!< resources list + bool myCheckExist; //!< "check existance" flag + TransListMap myTranslator; //!< map of loaded translators + QPixmap* myDefaultPix; //!< default icon + bool myIsPixmapCached; //!< "cached pixmaps" flag + + bool myIsIgnoreUserValues; //!< "ignore user values" flag friend class QtxResourceMgr::Format; }; -/*! - Class: QtxResourceMgr::Format -*/ - class QTX_EXPORT QtxResourceMgr::Format { public: @@ -204,192 +197,8 @@ protected: virtual bool save( const QString&, const QMap& ) = 0; private: - QString myFmt; - QMap myOpt; -}; - -/*! - Class: QtxResourceMgr::IMapIterator -*/ - -template class QtxResourceMgr::IMapIterator -{ -public: - IMapIterator() : myMap( 0 ), myIndex( 0 ) { init(); } - IMapIterator( const IMap* m ) : myMap( const_cast< IMap* >( m ) ), myIndex( 0 ) { init(); } - IMapIterator( const IMapIterator& i ) : myMap( i.myMap ), myIndex( i.myIndex ) { init(); } - - bool operator==( const IMapIterator& i ) { return !operator!=( i ); } - bool operator!=( const IMapIterator& i ) { return !myMap || myMap != i.myMap || myIndex != i.myIndex; } - - operator bool() const { return myIndex >= 0; } - - const Key& key() const { return myMap->key( myIndex ); } - Value& value() { return myMap->value( myIndex ); } - const Value& value() const { return myMap->value( myIndex ); } - - Value& operator*() { return value(); } - - IMapIterator& operator++() { myIndex++; init(); return *this; } - IMapIterator operator++( int ) { IMapIterator i = *this; myIndex++; init(); return i; } - IMapIterator& operator--() { myIndex--; init(); return *this; } - IMapIterator operator--( int ) { IMapIterator i = *this; myIndex--; init(); return i; } - -private: - IMapIterator( const IMap* m, const int index ) : myMap( const_cast< IMap* >( m ) ), myIndex( index ) { init(); } - void init() { if ( !myMap || myIndex >= myMap->count() ) myIndex = -1; } - -private: - IMap* myMap; - int myIndex; - - friend class IMap; - friend class IMapConstIterator; + QString myFmt; //!< format name + QMap myOpt; //!< options map }; -/*! - Class: QtxResourceMgr::IMapConstIterator -*/ - -template class QtxResourceMgr::IMapConstIterator -{ -public: - IMapConstIterator() : myMap( 0 ), myIndex( 0 ) { init(); } - IMapConstIterator( const IMap* m ) : myMap( const_cast< IMap* >( m ) ), myIndex( 0 ) { init(); } - IMapConstIterator( const IMapConstIterator& i ) : myMap( i.myMap ), myIndex( i.myIndex ) { init(); } - IMapConstIterator( const IMapIterator& i ) : myMap( i.myMap ), myIndex( i.myIndex ) { init(); } - - bool operator==( const IMapConstIterator& i ) { return !operator!=( i ); } - bool operator!=( const IMapConstIterator& i ) { return !myMap || myMap != i.myMap || myIndex != i.myIndex; } - - operator bool() const { return myIndex >= 0; } - - const Key& key() const { return myMap->key( myIndex ); } - const Value value() const { return myMap->value( myIndex ); } - - const Value operator*() const { return value(); } - - IMapConstIterator& operator++() { myIndex++; init(); return *this; } - IMapConstIterator operator++( int ) { IMapConstIterator i = *this; myIndex++; init(); return i; } - IMapConstIterator& operator--() { myIndex--; init(); return *this; } - IMapConstIterator operator--( int ) { IMapConstIterator i = *this; myIndex--; init(); return i; } - -private: - IMapConstIterator( const IMap* m, const int index ): myMap( const_cast< IMap* >( m ) ), myIndex( index ) { init(); } - void init() { if ( !myMap || myIndex >= myMap->count() ) myIndex = -1; } - -private: - IMap* myMap; - int myIndex; - - friend class IMap; -}; - -/*! - Class: QtxResourceMgr::IMap -*/ - -template class QtxResourceMgr::IMap -{ -public: - typedef IMapIterator Iterator; - typedef IMapConstIterator ConstIterator; - -public: - IMap() {} - IMap( const IMap& m ) : myKeys( m.myKeys ), myData( m.myData ) {} - IMap& operator=( const IMap& m ) { myKeys = m.myKeys; myData = m.myData; return *this; } - - int count() const { return myData.count(); } - int size() const { return myData.count(); } - bool empty() const { return myData.empty(); } - bool isEmpty() const { return myData.empty(); } - - void clear() { myKeys.clear(); myData.clear(); } - - QList keys() const { return myKeys; } - QList values() const { QList l; for ( int i = 0; i < count(); i++ ) l.append( value( i ) ); return l; } - bool contains ( const Key& key ) const { return myData.contains( key ); } - - Iterator begin() { return Iterator( this ); } - Iterator end() { return Iterator( this, count() ); } - ConstIterator begin() const { return ConstIterator( this ); } - ConstIterator end() const { return ConstIterator( this, count() ); } - - Iterator insert( const Key& key, const Value& value, bool overwrite = true ) - { - if ( myData.find( key ) == myData.end() || overwrite ) - { - if ( myData.find( key ) != myData.end() && overwrite ) - myKeys.removeAt( myKeys.indexOf( key ) ); - myKeys.append( key ); - myData[key] = value; - } - return Iterator( this, index( key ) ); - } - - Iterator replace( const Key& key, const Value& value ) - { - if ( myData.find( key ) == myData.end() ) - myKeys.append( key ); - myData[ key ] = value; - return Iterator( this, index( key ) ); - } - - int index( const Key& key ) const { return myKeys.indexOf( key ); } - Iterator at( const int index ) { return Iterator( this, index ); } - ConstIterator at( const int index ) const { return ConstIterator( this, index ); } - - Key& key( const int index ) - { - if ( index < 0 || index >= (int)myKeys.count() ) - return dummyKey; - return myKeys[index]; - } - - Value value( const int index ) - { - if ( index < 0 || index >= (int)myKeys.count() ) - return dummyValue; - return myData[ myKeys[index] ]; - } - - Value operator[]( const Key& key ) - { - if ( myData.find( key ) == myData.end() ) - insert( key, Value() ); - return myData[ key ]; - } - - const Value operator[]( const Key& key ) const - { - if ( myData.find( key ) == myData.end() ) - return dummyValue; - return myData[key]; - } - - void erase( Iterator it ) { remove( it ); } - void erase( const Key& key ) { remove( key ); } - void erase( const int index ) { remove( index ); } - void remove( Iterator it ) { if ( it.myMap != this ) return; remove( it.myIndex ); } - void remove( const Key& key ) { remove( index( key ) ); } - void remove( const int index ) - { - if ( index >= 0 && index < (int)myKeys.count() ) - { - myData.remove( myKeys[index] ); - myKeys.removeAt( index ); - } - } - -private: - QList myKeys; - QMap myData; - Key dummyKey; - Value dummyValue; - - friend class IMapIterator; - friend class IMapConstIterator; -}; - -#endif +#endif // QTXRESOURCEMGR_H diff --git a/src/Qtx/QtxSplash.cxx b/src/Qtx/QtxSplash.cxx new file mode 100644 index 000000000..f99e36b2a --- /dev/null +++ b/src/Qtx/QtxSplash.cxx @@ -0,0 +1,922 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxSplash.cxx +// Author: Vadim SANDLER + +#include "QtxSplash.h" + +#include +#include +#include +#include + +/*! + \class ProgressEvent + \internal + \brief Progress change custom event. +*/ + +class ProgressEvent: public QEvent +{ +public: + /*! + \brief Constructor. + \param msg progress message + \param progress current progress (for example, in %) + */ + ProgressEvent( const QString& msg, const int progress = 0 ) + : QEvent( (QEvent::Type)id() ), + myMessage( msg ), + myProgress( progress ) + {} + /*! + \brief Get progress message. + \return message + */ + QString message() const { return myMessage; } + /*! + \brief Get current progress. + \return current progress + */ + int progress() const { return myProgress; } + /*! + \brief Get message identifier. + \return custom message ID + */ + static int id() { return QEvent::User + 10; } + +private: + QString myMessage; + int myProgress; +}; + +/*! + \class QtxSplash + \brief The QtxSplash widget provides a splash screen that can be shown during application startup.. + + A splash screen is a widget that is usually displayed when an application is being started. + Splash screens are often used for applications that have long start up times to provide + the user with feedback that the application is loading. + + Only one instance of the QtxSplash widget can be created. To access to the splash screen widget, + use static method QtxSplash::splash(), which creates and instance of the QtxSplash widget if + necessary and returns pointer to it. You should not destroy yhis instance - it is done automatically + after application main window is shown. Just use methods finish() to make splash screen wait untill + main window is shown. + + The splash screen appears in the center of the screen. The most common usage is to show a splash + screen before the main widget is displayed on the screen. + For example, + \code + int main(int argc, char *argv[]) + { + QApplication app(argc, argv); + QPixmap pixmap(":/splash.png"); + QtxSplash* splash = QtxsSplash::splash(pixmap); + splash->show(); + app.processEvents(); + ... // do application loading and initialization + MainWindow window; + window.show(); + splash->finish(&window); + return app.exec(); + } + \endcode + + The user can hide the splash screen by clicking on it with the mouse. Since the splash screen is + typically displayed before the event loop has started running, it is necessary to periodically call + QApplication::processEvents() to receive the mouse clicks. + This feature can be switched off by using method setHideOnClick() with \c false parameter. + + It is sometimes useful to update the splash screen with messages and/or progress information, + for example, announcing connections established or modules loaded as the application starts up. + QtxSplash class provides the functionality to show status messages and(or) progress bar. + + \code + QPixmap pixmap(":/splash.png"); + QtxSplash* splash = QtxSplash::splash(pixmap); + splash->setProgress(0, 5); + splash->show(); + app.processEvents(); + // doing first step + splash->message("Step 1"); + splash->ress(1); + qApp->processEvents(); + // ... perform some actions + // doing second step + splash->message("Step 2"); + splash->setProgress(2); + qApp->processEvents(); + // ... perform some actions + ... et cetera + \endcode + + There is a static function QtxSplash::setStatus() which allows to put next status message + and progress with one call. It can substitue two calls: message() and setProgress(). + + QtxSplash class provides alos a lot of functions to set-up its behavior. Set progress + bar width with setProgressWidth() method, its position and direction with setProgressFlags(). + It can be single-colored or gradient-colored. Use setProgressColors() method for this. + You can even set your own gradient scale with QLinearGradient and use it for the progress + bar coloring: setProgressGradient(). + + To change the progress bar and status message transparency, use setOpacity() function. + The methods setTextAlignment(), setTextColor() and setTextColors() can be used to change + the attributes of the status message. +*/ + +//! The only one instance of splash screen +QtxSplash* QtxSplash::mySplash = 0; + +/*! + \brief Constructor. + \brief Construct a splash screen that will display the \a pixmap. + \param pixmap splash screen pixmap +*/ +QtxSplash::QtxSplash( const QPixmap& pixmap ) +: QWidget( 0, Qt::SplashScreen | Qt::WindowStaysOnTopHint ), + myAlignment( Qt::AlignBottom | Qt::AlignRight ), + myColor( Qt::white ), + myHideOnClick( false ), + myProgress( 0 ), + myTotal( 0 ), + myStartColor( Qt::red ), + myGradientType( Vertical ), + myProgressWidth( 10 ), + myProgressFlags( BottomSide | LeftToRight ), + myMargin( 5 ), + myOpacity( 1.0 ), + myError( 0 ), + myGradientUsed( false ) +{ + setAttribute( Qt::WA_DeleteOnClose, true ); + setPixmap( pixmap ); +} + +/*! + \brief Destructor. +*/ +QtxSplash::~QtxSplash() +{ + mySplash = 0; +} + +/*! + \brief Get the only instance of the splash screen widget. + + If the splash screen widget does not exist yet, it is created with specified + pixmap. Otherwise, pixmap \a px is set to existing widget. + + \param px splash screen pixmap + \return splash screen widget +*/ +QtxSplash* QtxSplash::splash( const QPixmap& px ) +{ + if ( !mySplash ) + mySplash = new QtxSplash( px ); + else if ( !px.isNull() ) + mySplash->setPixmap( px ); + return mySplash; +} + +/*! + \brief Send the status message and (optionally) current progress + to the splash screen. + + This function can be used, for example, from an external thread + which checks the application loading progress. + + \param msg progress status message + \param progress current progress + \sa message(), setProgress() +*/ +void QtxSplash::setStatus( const QString& msg, const int progress ) +{ + if ( mySplash ) { + QApplication::postEvent( mySplash, new ProgressEvent( msg, progress ) ); + QApplication::instance()->processEvents(); + } +} + +/*! + \brief Set error status and show error message box to the user. + \param error error message + \param title message box title + \param code error code +*/ +void QtxSplash::error( const QString& error, const QString& title, const int code ) +{ + if ( mySplash ) { + mySplash->setError( code ); + QMessageBox::critical( mySplash, + title.isEmpty() ? tr( "Error" ) : title, + error, + tr( "&OK" ) ); + } + else { + printf( "QtxSplash::error: %s\n",error.toLatin1().constData() ); + } +} + +/*! + \brief Set the pixmap that will be used as the splash screen's image. + \param pixmap spash screen image pixmap + \sa pixmap() +*/ +void QtxSplash::setPixmap( const QPixmap& pixmap ) +{ + if ( pixmap.hasAlpha() ) { + QPixmap opaque( pixmap.size() ); + QPainter p( &opaque ); + p.fillRect( 0, 0, pixmap.width(), pixmap.height(), palette().background() ); + p.drawPixmap( 0, 0, pixmap ); + p.end(); + myPixmap = opaque; + } + else { + myPixmap = pixmap; + } + QRect r( 0, 0, myPixmap.size().width(), myPixmap.size().height() ); + resize( myPixmap.size() ); + move( QApplication::desktop()->screenGeometry().center() - r.center() ); + if ( !isVisible() ) + drawContents(); + else + repaint(); +} + +/*! + \brief Get the pixmap that is used as the splash screen's image. + \return spash screen image pixmap + \sa setPixmap() +*/ +QPixmap QtxSplash::pixmap() const +{ + return myPixmap; +} + +/*! + \brief Set/clear the 'hide on mouse click' flag. + + When this flag is set, user can hide the splash screen window + by clicking on it with mouse. + But for this to work it is necessary to call periodically + QApplication::processEvents() in order to allow event loop to process + events because usually main application loop is not yet started + at that moment. + + By default this flag is set to \c false. + + \param on new flag state + \sa hideOnClick() +*/ +void QtxSplash::setHideOnClick( const bool on ) +{ + myHideOnClick = on; +} + +/*! + \brief Get the 'hide on mouse click' flag. + \return 'hide on mouse click' flag + \sa setHideOnClick() +*/ +bool QtxSplash::hideOnClick() const +{ + return myHideOnClick; +} + +/*! + \brief Set total progress steps to \a total. + \param total total number of progress steps + \sa totalSteps(), setProgress(), progress() +*/ +void QtxSplash::setTotalSteps( const int total ) +{ + myTotal = total; + repaint(); +} + +/*! + \brief Get total progress steps number. + \return total number of progress steps + \sa setTotalSteps(), setProgress(), progress() +*/ +int QtxSplash::totalSteps() const +{ + return myTotal; +} + +/*! + \brief Set current progress. + \param progress current progress + \sa progress(), setTotalSteps(), setTotalSteps(), +*/ +void QtxSplash::setProgress( const int progress ) +{ + myProgress = progress > 0 ? progress : 0; + repaint(); +} + +/*! + \brief Get current progress. + \return current progress + \sa setProgress(), setTotalSteps(), setTotalSteps(), +*/ +int QtxSplash::progress() const +{ + return myProgress; +} + +/*! + \brief Set current progress to \a progress and total number of + progress steps to \a total. + \param progress current progress + \param total total number of progress steps +*/ +void QtxSplash::setProgress( const int progress, const int total ) +{ + myTotal = total; + myProgress = progress > 0 ? progress : 0; + repaint(); +} + +/*! + \brief Set margin (a border width). + \param margin new margin width + \sa margin() +*/ +void QtxSplash::setMargin( const int margin ) +{ + myMargin = margin > 0 ? margin : 0; + repaint(); +} + +/*! + \brief Get margin (a border width). + \return current margin width + \sa setMargin() +*/ +int QtxSplash::margin() const +{ + return myMargin; +} + +/*! + \brief Set progress bar width. + \param width new progress bar width + \sa progressWidth() +*/ +void QtxSplash::setProgressWidth( const int width ) +{ + myProgressWidth = width > 0 ? width : 0; + repaint(); +} + +/*! + \brief Get progress bar width. + \return current progress bar width + \sa setProgressWidth() +*/ +int QtxSplash::progressWidth() const +{ + return myProgressWidth; +} + +/*! + \brief Set progress bar position and direction. + + By default, progress bar is displayed at the bottom side and + shows progress from left to right. + + \param flags ORed progress bar flags (QtxSplash::ProgressBarFlags) + \sa progressFlags() +*/ +void QtxSplash::setProgressFlags( const int flags ) +{ + myProgressFlags = flags; + if ( !( myProgressFlags & ( LeftSide | RightSide | TopSide | BottomSide ) ) ) + myProgressFlags |= BottomSide; + if ( !( myProgressFlags & ( LeftToRight | RightToLeft ) ) ) + myProgressFlags |= LeftToRight ; + repaint(); +} + +/*! + \brief Get progress bar flags: position and direction. + \return ORed progress bar flags (QtxSplash::ProgressBarFlags) + \sa setProgressFlags() +*/ +int QtxSplash::progressFlags() const +{ + return myProgressFlags; +} + +/*! + \brief Set progress bar colors. + + If the colors differ the gradient color bar is drawn. + + If the \a endColor is not valid, \a startColor is used instead + (no gradient coloring). + + The parameter \a gradientType defines the type of gradient + to be drawn - horizontal or vertical. Default is vertical. + + Note, that methods setProgressGradient() and setProgressColors() are + alternative. Only the latest used is taken into account. + + \param startColor start gradient color (or mono-color) + \param endColor end gradient color + \param gradientType gradient type (QtxSplash::GradientType) + \sa progressColors(), setProgressGradient() +*/ +void QtxSplash::setProgressColors( const QColor& startColor, + const QColor& endColor, + const GradientType gradientType ) +{ + if ( startColor.isValid() ) + myStartColor = startColor; + myEndColor = endColor; + myGradientType = gradientType; + myGradientUsed = false; + repaint(); +} + +/*! + \brief Get progress colors and gradient type. + \param startColor start gradient color (or mono-color) + \param endColor end gradient color + \return gradient type (QtxSplash::GradientType) + \sa setProgressColors() +*/ +QtxSplash::GradientType QtxSplash::progressColors( QColor& startColor, + QColor& endColor ) const +{ + startColor = myStartColor; + endColor = myEndColor; + return myGradientType; +} + +/*! + \brief Set custom progress bar colors. + + The gradient start and final stops are scaled to the actual progress + bar size. For example: + \code + QLinearGradient lg(0.5, 0, 1, 1); + lg.setColorAt(0.2, Qt::blue); + lg.setColorAt(0.6, Qt::red); + lg.setSpread(QGradient::RepeatSpread); + splash->setProgressGradient(lg); + \endcode + The above code creates linear gradient, which sets start stop to the + center of the progress bar; the final stop is always in the end of + the progress bar. The color scale (blue to red) is changed by the + progress bar diagonal. + + Note, that methods setProgressGradient() and setProgressColors() are + alternative. Only the latest used is taken into account. + + \param gradient color gradient to be used for progress bar coloring + \sa progressGradient(), setProgressColors() +*/ +void QtxSplash::setProgressGradient( const QLinearGradient& gradient ) +{ + myGradient = gradient; + myGradientUsed = true; + repaint(); +} + +/*! + \brief Get custom progress bar colors. + \return color gradient used for progress bar coloring + \sa setProgressGradient() +*/ +QLinearGradient QtxSplash::progressGradient() const +{ + return myGradient; +} + +/*! + \brief Set progress bar and status text message opacity. + + The value should be in the range 0.0 to 1.0, where 0.0 is fully + transparent and 1.0 is fully opaque. + + \param opacity new opacity value + \sa opacity() +*/ +void QtxSplash::setOpacity( const double opacity ) +{ + myOpacity = opacity < 0.0 ? 0.0 : ( opacity > 1.0 ? 1.0 : opacity ); + repaint(); +} + +/*! + \brief Get progress bar and status text message opacity. + \return current opacity value + \sa setOpacity() +*/ +double QtxSplash::opacity() const +{ + return myOpacity; +} + +/*! + \brief Set message text alignment flags. + + Default flags are Qt::AlignBottom | Qt::AlignRight. + + \param alignment alignment flags (Qt::Alignment) + \sa textAlignment() +*/ +void QtxSplash::setTextAlignment( const int alignment ) +{ + myAlignment = alignment; + repaint(); +} + +/*! + \brief Get message text alignment flags. + \return alignment flags (Qt::Alignment) + \sa setTextAlignment() +*/ +int QtxSplash::textAlignment() const +{ + return myAlignment; +} + +/*! + \brief Set message text color. + + Default message color is white. + + \param color message text color + \sa setTextColors() +*/ +void QtxSplash::setTextColor( const QColor& color ) +{ + if ( myColor.isValid() ) + myColor = color; + myShadowColor = QColor(); + repaint(); +} + +/*! + \brief Get message text color. + \return color message text color + \sa setTextColor() +*/ +QColor QtxSplash::textColor() const +{ + return myColor; +} + +/*! + \brief Set message text color and text shadow color. + \param color message text color + \param shadow message text shadow color + \sa textColors(), textColor(), setTextColor() +*/ +void QtxSplash::setTextColors( const QColor& color, const QColor& shadow ) +{ + if ( myColor.isValid() ) + myColor = color; + myShadowColor = shadow; + repaint(); +} + +/*! + \brief Get message text color and text shadow color. + \param color message text color + \param shadow message text shadow color + \sa setTextColors(), textColor(), setTextColor() +*/ +void QtxSplash::textColors( QColor& color, QColor& shadow ) const +{ + color = myColor; + shadow = myShadowColor; +} + +/*! + \brief Get current status message. + \return status message +*/ +QString QtxSplash::message() const +{ + return myMessage; +} + +/*! + \brief Get error code. + + This function returns error code, set previoiusly with + error(const QString&, const QString&, const int) method. + If no error code has been set, 0 is returned. + + \return last error code +*/ +int QtxSplash::error() const +{ + return myError; +} + +/*! + \brief Wait until widget \a mainWin is displayed. + + Makes the splash screen wait until the widget \a mainWin is displayed + and then hide and close splash window. + + \param mainWin application main window +*/ +void QtxSplash::finish( QWidget* mainWin ) +{ + if ( mainWin ) { +#if defined(Q_WS_X11) + extern void qt_x11_wait_for_window_manager(QWidget *mainWin); + qt_x11_wait_for_window_manager(mainWin); +#endif + } + close(); +} + +/*! + \brief Repaint the splash screen. +*/ +void QtxSplash::repaint() +{ + drawContents(); + QWidget::repaint(); + QApplication::flush(); +} + +/*! + \brief Set status message for the splash screen and define its color + and aligment flags. + \param msg status message + \param alignment message text alignment flags (Qt::Alignment) + \param color message text color +*/ +void QtxSplash::message( const QString& msg, + int alignment, + const QColor& color ) +{ + myMessage = msg; + myAlignment = alignment; + if ( color.isValid() ) + myColor = color; + repaint(); +} + +/*! + \overload + \brief Set status message for the splash screen. + \param msg status message +*/ +void QtxSplash::message( const QString& msg ) +{ + myMessage = msg; + repaint(); +} + +/*! + \brief Remove the message being displayed on the splash screen. + \sa message() +*/ +void QtxSplash::clear() +{ + myMessage = QString::null; + repaint(); +} + +/*! + \brief Draw the contents of the splash screen. + \param painter painter +*/ +void QtxSplash::drawContents( QPainter* p ) +{ + // draw progress bar + if ( myTotal > 0 ) { + p->save(); + drawProgressBar( p ); + p->restore(); + } + + // draw status message + if ( !myMessage.isEmpty() ) { + p->save(); + drawMessage( p ); + p->restore(); + } +} + +/*! + \brief Process mouse button pressing event. + + Hides splash screen if the 'hide on mouse click' flag is set. + + \param me mouse event (not used) + \sa hideOnClick(), setHideOnClick() +*/ +void QtxSplash::mousePressEvent( QMouseEvent* /*me*/ ) +{ + if ( myHideOnClick ) + hide(); +} + +/*! + \brief Customize paint event. + + This function is implemented to work-around the Qt bug + on some Linux distribututions when the drawing on the + splash screen widget is not allowed. + + \param pe paint event (not used) +*/ +void QtxSplash::paintEvent( QPaintEvent* /*pe*/ ) +{ + QPainter p( this ); + QPixmap pix = palette().brush( backgroundRole() ).texture(); + p.drawPixmap( 0, 0, pix ); +} + +/*! + \brief Process custom event sent by setStatus() method. + \param ce custom event + \sa setStatus(). +*/ +void QtxSplash::customEvent( QEvent* ce ) +{ + if ( ce->type() == ProgressEvent::id() ) { + ProgressEvent* pe = (ProgressEvent*)ce; + pe->message().isEmpty() ? clear() : message( pe->message() ); + setProgress( pe->progress() ); + QApplication::instance()->processEvents(); + } +} + +/*! + \brief Draw progress bar. + \param p painter +*/ +void QtxSplash::drawProgressBar( QPainter* p ) +{ + // get rect, margin, progress bar width + QRect r = rect(); + int m = margin(); + int pw = progressWidth(); + + // calculate drawing rect + // ... first set default position (if none or wrong position is set) + if ( myProgressFlags & BottomSide ) + r = QRect( r.x() + m, r.height() - (m + pw), r.width() - 2 * m, pw ); + else if ( myProgressFlags & TopSide ) + r = QRect( r.x() + m, r.y() + m, r.width() - 2 * m, pw ); + else if ( myProgressFlags & LeftSide ) + r = QRect( r.x() + m, r.y() + m, pw, r.height() - 2 * m ); + else if ( myProgressFlags & RightSide ) + r = QRect( r.width() - (m + pw), r.y() + m, pw, r.height() - 2 * m ); + + QRect cr = r; + if ( myProgressFlags & TopSide || myProgressFlags & BottomSide ) { + cr.setWidth( (int)( r.width() * ( myProgress > 0 ? myProgress : 0 ) / myTotal ) ); + if ( myProgressFlags & RightToLeft ) + cr.translate( r.width() - cr.width(), 0 ); + } + else if ( myProgressFlags & LeftSide || myProgressFlags & RightSide ) { + cr.setHeight( (int)( r.height() * ( myProgress > 0 ? myProgress : 0 ) / myTotal ) ); + if ( myProgressFlags & RightToLeft) + cr.translate( 0, r.height() - cr.height() ); + } + int x1, x2, y1, y2; + if ( myGradientType == Horizontal ) { + x1 = r.left(); x2 = r.right(); y1 = y2 = 0; + } + else { + x1 = x2 = 0; y1 = r.top(); y2 = r.bottom(); + } + QLinearGradient lg; + if ( myGradientUsed ) { + QPointF start = myGradient.start(); + QPointF final = myGradient.finalStop(); + qreal xd = final.x() - start.x(); + qreal yd = final.y() - start.y(); + lg.setStart( xd != 0 ? r.left() + r.width() * start.x() / xd : 0, + yd != 0 ? r.top() + r.height() * start.y() / yd : 0 ); + lg.setFinalStop( xd != 0 ? r.right() : 0, yd != 0 ? r.bottom() : 0 ); + lg.setStops( myGradient.stops() ); + lg.setSpread( myGradient.spread() ); + } + else { + lg.setStart( x1, y1 ); + lg.setFinalStop( x2, y2 ); + lg.setColorAt( 0, myStartColor ); + lg.setColorAt( 1, myEndColor.isValid() ? myEndColor : myStartColor ); + } + p->setOpacity( myOpacity ); + p->setClipRect( cr ); + p->fillRect( r, lg ); + p->setClipping( false ); + + // draw progress bar outline rectangle + p->setPen( palette().color( QPalette::Dark ) ); + p->drawLine( r.left(), r.top(), r.right(), r.top() ); + p->drawLine( r.left(), r.top(), r.left(), r.bottom() ); + p->setPen( palette().color( QPalette::Light ) ); + p->drawLine( r.left(), r.bottom(), r.right(), r.bottom() ); + p->drawLine( r.right(), r.top(), r.right(), r.bottom() ); +} + +/*! + \brief Draw status message. + \param p painter +*/ +void QtxSplash::drawMessage( QPainter* p ) +{ + // get rect, margin, progress bar width + QRect r = rect(); + int m = margin(); + int pw = progressWidth(); + + // calculate drawing rect + QFontMetrics f( font() ); + int spacing = f.lineSpacing(); + // ... base rect + QRect r1( r.x() + m, r.y() + m, r.width() - 2 * m, r.height() - 2 * m ); + r1.setY( r1.y() - f.leading() ); + // ... take into account progress bar + if ( 1 ) { // if ( myTotal > 0 ) : vsr changed: otherwise text is jumping + if ( myProgressFlags & BottomSide ) + r1.setHeight( r1.height() - pw ); + else if ( myProgressFlags & TopSide ) + r1.setY( r1.y() + pw ); + else if ( myProgressFlags & LeftSide ) + r1.setX( r1.x() + pw ); + else if ( myProgressFlags & RightSide ) + r1.setWidth( r1.width() - pw ); + } + + // ... take into account trailing '\n' symbols + int shift = 0; + int i = myMessage.length() - 1; + while( i >= 0 && myMessage[ i-- ] == '\n' ) + shift += spacing; + r1.setHeight( r1.height() - shift ); + + p->setOpacity( myOpacity ); + + // draw shadow status text + if ( myShadowColor.isValid() ) { + QRect r2 = r1; + if ( myAlignment & Qt::AlignLeft ) r2.setLeft ( r2.left() + 1 ); + if ( myAlignment & Qt::AlignTop ) r2.setTop ( r2.top() + 1 ); + if ( myAlignment & Qt::AlignRight ) r2.setRight ( r2.right() + 1 ); + if ( myAlignment & Qt::AlignBottom ) r2.setBottom( r2.bottom() + 1 ); + p->setPen( myShadowColor ); + p->drawText( r2, myAlignment, myMessage ); + } + + // draw foreground status text + p->setPen( myColor ); + p->drawText( r1, myAlignment, myMessage ); +} + +/*! + \brief Draw the splash screen window contents. +*/ +void QtxSplash::drawContents() +{ + QPixmap textPix = myPixmap; + QPainter painter( &textPix ); + painter.initFrom( this ); + drawContents( &painter ); + QPalette pal = palette(); + pal.setBrush( backgroundRole(), QBrush( textPix ) ); + setPalette( pal ); +} + +/*! + \brief Sets error code. + \param code error code +*/ +void QtxSplash::setError( const int code ) +{ + myError = code; +} + diff --git a/src/Qtx/QtxSplash.h b/src/Qtx/QtxSplash.h new file mode 100644 index 000000000..bd952119b --- /dev/null +++ b/src/Qtx/QtxSplash.h @@ -0,0 +1,158 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxSplash.h +// Author: Vadim SANDLER + +#ifndef QTXSPLASH_H +#define QTXSPLASH_H + +#include "Qtx.h" + +#include +#include +#include + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +class QTX_EXPORT QtxSplash : public QWidget +{ + Q_OBJECT + +private: + QtxSplash( const QPixmap& ); + +public: + //! Gradient type + typedef enum { + Horizontal, //!< horizontal + Vertical //!< vertical + } GradientType; + + //! Progress bar position and direction + typedef enum { + LeftSide = 0x0001, //!< progress bar is displayed at the left side + RightSide = 0x0002, //!< progress bar is displayed at the right side + TopSide = 0x0004, //!< progress bar is displayed at the top side + BottomSide = 0x0008, //!< progress bar is displayed at the bottom side + LeftToRight = 0x0010, //!< show progress from left to right (from top to bottom) + RightToLeft = 0x0020 //!< show progress from right to left (from bottom to top) + } ProgressBarFlags; + + virtual ~QtxSplash(); + + static QtxSplash* splash( const QPixmap& = QPixmap() ); + + static void setStatus( const QString&, const int = 0 ); + static void error( const QString&, const QString& = QString::null, const int = -1 ); + + void setPixmap( const QPixmap& ); + QPixmap pixmap() const; + + void setHideOnClick( const bool ); + bool hideOnClick() const; + + void setTotalSteps( const int ); + int totalSteps() const; + + void setProgress( const int ); + void setProgress( const int, const int ); + int progress() const; + + void setMargin( const int ); + int margin() const; + + void setProgressWidth( const int ); + int progressWidth() const; + + void setProgressFlags( const int ); + int progressFlags() const; + + void setProgressColors( const QColor&, + const QColor& = QColor(), + const GradientType = Vertical ); + GradientType progressColors( QColor&, QColor& ) const; + + void setProgressGradient( const QLinearGradient& ); + QLinearGradient progressGradient() const; + + void setOpacity( const double ); + double opacity() const; + + void setTextAlignment( const int ); + int textAlignment() const; + + void setTextColor( const QColor& ); + QColor textColor() const; + void setTextColors( const QColor&, const QColor& = QColor() ); + void textColors( QColor&, QColor& ) const; + + QString message() const; + + int error() const; + + void finish( QWidget* ); + void repaint(); + +public slots: + void message( const QString&, + const int, + const QColor& = QColor() ); + void message( const QString& ); + void clear(); + +protected: + virtual void mousePressEvent( QMouseEvent* ); + virtual void customEvent( QEvent* ); + virtual void paintEvent( QPaintEvent* ); + + virtual void drawContents( QPainter* ); + + virtual void drawProgressBar( QPainter* ); + virtual void drawMessage( QPainter* ); + +private: + void drawContents(); + void setError( const int ); + +private: + static QtxSplash* mySplash; + + QPixmap myPixmap; //!< splash pixmap + QString myMessage; //!< current status message + int myAlignment; //!< text alignment flags (Qt::Alignment) + QColor myColor; //!< text color + QColor myShadowColor; //!< text shadow color + bool myHideOnClick; //!< 'hide on click' flag + int myProgress; //!< current progress + int myTotal; //!< total progress steps + QColor myStartColor; //!< progress bar gradient starting color + QColor myEndColor; //!< progress bar gradient ending color + GradientType myGradientType; //!< progress bar gradient direction + QLinearGradient myGradient; //!< progress bar custom gradient + int myProgressWidth; //!< progress bar width + int myProgressFlags; //!< progress bar flags (QtxSplash::ProgressBarFlags) + int myMargin; //!< margin (for progress bar and status message) + double myOpacity; //!< progress bar / status message opacity + int myError; //!< error code + bool myGradientUsed; //!< 'use custom gradient color scale' flag +}; + +#endif diff --git a/src/Qtx/QtxToolBar.cxx b/src/Qtx/QtxToolBar.cxx index f436f68a7..50972d29a 100644 --- a/src/Qtx/QtxToolBar.cxx +++ b/src/Qtx/QtxToolBar.cxx @@ -21,15 +21,14 @@ #include "QtxToolBar.h" -#include -#include -#include -#include -#include +#include +#include +#include /*! - Class: QtxToolBar::Watcher [Internal] - Descr: Internal object with event filter. + \class QtxToolBar::Watcher + \internal + \brief Internal class which goal is to watch parent toolbar state changing. */ class QtxToolBar::Watcher : public QObject @@ -38,7 +37,7 @@ public: Watcher( QtxToolBar* ); void shown( QtxToolBar* ); - void hided( QtxToolBar* ); + void hidden( QtxToolBar* ); virtual bool eventFilter( QObject*, QEvent* ); @@ -64,18 +63,15 @@ private: }; /*! - Constructor + \brief Constructor. + \param cont toolbar to be watched */ QtxToolBar::Watcher::Watcher( QtxToolBar* cont ) : QObject( cont ), -myCont( cont ), -myState( true ), -myEmpty( false ) + myCont( cont ), + myState( true ), + myEmpty( false ) { -/* - if ( myCont->mainWindow() ) - myState = myCont->mainWindow()->appropriate( myCont ); -*/ myCont->installEventFilter( this ); myVisible = myCont->isVisibleTo( myCont->parentWidget() ); @@ -83,7 +79,10 @@ myEmpty( false ) } /*! - Custom event filter + \brief Custom event filter. + \param o event receiver object + \param e event sent to object + \return \c true if further event processing should be stopped */ bool QtxToolBar::Watcher::eventFilter( QObject* o, QEvent* e ) { @@ -107,7 +106,8 @@ bool QtxToolBar::Watcher::eventFilter( QObject* o, QEvent* e ) } /*! - Sets internal visibility state to true + \brief Set internal status to "shown" + \param tb toolbar */ void QtxToolBar::Watcher::shown( QtxToolBar* tb ) { @@ -118,9 +118,10 @@ void QtxToolBar::Watcher::shown( QtxToolBar* tb ) } /*! - Sets internal visibility state to false + \brief Set internal status to "hidden" + \param tb toolbar */ -void QtxToolBar::Watcher::hided( QtxToolBar* tb ) +void QtxToolBar::Watcher::hidden( QtxToolBar* tb ) { if ( tb != myCont ) return; @@ -129,7 +130,7 @@ void QtxToolBar::Watcher::hided( QtxToolBar* tb ) } /*! - Shows corresponding QtxToolBar + \brief Show the toolbar being watched */ void QtxToolBar::Watcher::showContainer() { @@ -143,7 +144,7 @@ void QtxToolBar::Watcher::showContainer() } /*! - Hides corresponding QtxToolBar + \brief Hide the toolbar being watched */ void QtxToolBar::Watcher::hideContainer() { @@ -157,7 +158,8 @@ void QtxToolBar::Watcher::hideContainer() } /*! - Event handler of custom events + \brief Proces custom events. + \param e custom event */ void QtxToolBar::Watcher::customEvent( QEvent* e ) { @@ -165,13 +167,18 @@ void QtxToolBar::Watcher::customEvent( QEvent* e ) { case Install: installFilters(); + break; case Update: updateVisibility(); + break; + default: + break; } } /*! - Installs event filters + \brief Install this object as event dilter to all children widgets + of the toolbar being watched. */ void QtxToolBar::Watcher::installFilters() { @@ -187,7 +194,8 @@ void QtxToolBar::Watcher::installFilters() } /*! - Update visibility state + \brief Update visibility state of all children widgets of the toolbar + being watched. */ void QtxToolBar::Watcher::updateVisibility() { @@ -196,18 +204,14 @@ void QtxToolBar::Watcher::updateVisibility() bool vis = false; - const QObjectList& objList = myCont->children(); - for ( QObjectList::const_iterator it = objList.begin(); it != objList.end() && !vis; ++it ) - { - QObject* obj = *it; - if ( !obj->isWidgetType() || !qstrcmp( "qt_dockwidget_internal", obj->objectName().toLatin1() ) ) - continue; + QList actList = myCont->actions(); - if ( obj->inherits( "QToolBarHandle" ) || obj->inherits( "QToolBarExtension" ) ) + for ( QList::const_iterator it = actList.begin(); it != actList.end() && !vis; ++it ) + { + if ( (*it)->isSeparator() ) continue; - QWidget* wid = (QWidget*)*it; - vis = wid->isVisibleTo( wid->parentWidget() ); + vis = (*it)->isVisible(); } QMainWindow* mw = myCont->mainWindow(); @@ -229,94 +233,84 @@ void QtxToolBar::Watcher::updateVisibility() } /*! - Constructor + \class QtxToolBar + \brief Enhanced toolbar class. +*/ + +/*! + \brief Constructor. + \param watch if \c true the event filter is installed to watch toolbar state changes + to update it properly + \param label toolbar title + \param parent parent widget */ QtxToolBar::QtxToolBar( const bool watch, const QString& label, QWidget* parent ) : QToolBar( label, parent ), -myWatcher( 0 ), -myStretch( false ) + myWatcher( 0 ), + myStretch( false ) { if ( watch ) myWatcher = new Watcher( this ); + + if ( QMainWindow* mw = ::qobject_cast( parent ) ) + mw->addToolBar( this ); } /*! - Constructor + \brief Constructor. + \param label toolbar title + \param parent parent widget */ QtxToolBar::QtxToolBar( const QString& label, QWidget* parent ) : QToolBar( label, parent ), -myWatcher( 0 ), -myStretch( false ) + myWatcher( 0 ), + myStretch( false ) { + if ( QMainWindow* mw = ::qobject_cast( parent ) ) + mw->addToolBar( this ); } /*! - Constructor + \brief Constructor. + \param watch if \c true the event filter is installed to watch toolbar state changes + to update it properly + \param parent parent widget */ QtxToolBar::QtxToolBar( const bool watch, QWidget* parent ) : QToolBar( parent ), -myWatcher( 0 ), -myStretch( false ) + myWatcher( 0 ), + myStretch( false ) { if ( watch ) myWatcher = new Watcher( this ); + + if ( QMainWindow* mw = ::qobject_cast( parent ) ) + mw->addToolBar( this ); } /*! - Constructor + \brief Constructor. + \param parent parent widget */ QtxToolBar::QtxToolBar( QWidget* parent ) : QToolBar( parent ), -myWatcher( 0 ), -myStretch( false ) + myWatcher( 0 ), + myStretch( false ) { + if ( QMainWindow* mw = ::qobject_cast( parent ) ) + mw->addToolBar( this ); } /*! - Destructor + \brief Destructor. */ QtxToolBar::~QtxToolBar() { } /*! - \return the recommended size for the widget -*/ -QSize QtxToolBar::sizeHint() const -{ - QSize sz = QToolBar::sizeHint(); -/* - if ( place() == InDock && isStretchable() && area() ) - { - if ( orientation() == Horizontal ) - sz.setWidth( area()->width() ); - else - sz.setHeight( area()->height() ); - } -*/ - return sz; -} - -/*! - \return the recommended minimum size for the widget -*/ -QSize QtxToolBar::minimumSizeHint() const -{ - QSize sz = QToolBar::minimumSizeHint(); -/* - if ( place() == InDock && isStretchable() && area() ) - { - if ( orientation() == Horizontal ) - sz.setWidth( area()->width() ); - else - sz.setHeight( area()->height() ); - } -*/ - return sz; -} - -/*! - Shows toolbar + \brief Show/hide the toolbar. + \param on new visibility state */ void QtxToolBar::setVisible( bool visible ) { @@ -325,14 +319,15 @@ void QtxToolBar::setVisible( bool visible ) if ( visible ) myWatcher->shown( this ); else - myWatcher->hided( this ); + myWatcher->hidden( this ); } QToolBar::setVisible( visible ); } /*! - Returns the main window + \brief Get parent main window. + \return main window pointer */ QMainWindow* QtxToolBar::mainWindow() const { @@ -345,3 +340,11 @@ QMainWindow* QtxToolBar::mainWindow() const } return mw; } + +bool QtxToolBar::event( QEvent* e ) +{ + if ( e->type() == QEvent::WindowTitleChange && objectName().isEmpty() ) + setObjectName( windowTitle() ); + + return QToolBar::event( e ); +} diff --git a/src/Qtx/QtxToolBar.h b/src/Qtx/QtxToolBar.h index e1757edf3..56207f26b 100644 --- a/src/Qtx/QtxToolBar.h +++ b/src/Qtx/QtxToolBar.h @@ -19,9 +19,12 @@ // File: QtxToolBar.h // Author: Sergey TELKOV +#ifndef QTXTOOLBAR_H +#define QTXTOOLBAR_H + #include "Qtx.h" -#include +#include class QTX_EXPORT QtxToolBar : public QToolBar { @@ -36,15 +39,17 @@ public: QtxToolBar( QWidget* = 0 ); virtual ~QtxToolBar(); - virtual QSize sizeHint() const; - virtual QSize minimumSizeHint() const; - QMainWindow* mainWindow() const; public slots: virtual void setVisible( bool ); +protected: + virtual bool event( QEvent* ); + private: - Watcher* myWatcher; - bool myStretch; + Watcher* myWatcher; //!< watcher object + bool myStretch; //!< stretching toolbar flag (not used) }; + +#endif // QTXTOOLBAR_H diff --git a/src/Qtx/QtxToolTip.cxx b/src/Qtx/QtxToolTip.cxx new file mode 100755 index 000000000..e7888a4da --- /dev/null +++ b/src/Qtx/QtxToolTip.cxx @@ -0,0 +1,272 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxToolTip.cxx +// Author: Sergey TELKOV + +#include "QtxToolTip.h" + +#include +#include +#include +#include +#include +#include +#include + +#define TOOLTIP_SHOW_DELAY 0500 +#define TOOLTIP_HIDE_DELAY 7000 + +/*! + Constructor +*/ +QtxToolTip::QtxToolTip( QWidget* parent ) +: QLabel( parent, Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::Tool | Qt::WindowStaysOnTopHint | Qt::Window ) +{ + setObjectName( "" ); + setIndent( 3 ); + setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); + QPalette palette; + palette.setColor( backgroundRole(), QColor( 255, 255, 231 ) ); + setPalette( palette ); + + myWidgetRegion = QRect( -1, -1, -1, -1 ); + + setFrameShape( QFrame::Panel ); + setFrameShadow( QFrame::Plain ); + + parent->setMouseTracking( true ); + parent->installEventFilter( this ); + installEventFilter( this ); + + mySleepTimer = new QTimer( this ); + mySleepTimer->setSingleShot( true ); + myWakeUpTimer = new QTimer( this ); + myWakeUpTimer->setSingleShot( true ); + connect( mySleepTimer, SIGNAL( timeout() ), this, SLOT( onSleepTimeOut() ) ); + connect( myWakeUpTimer, SIGNAL( timeout() ), this, SLOT( onWakeUpTimeOut() ) ); + + myWakeUpDelayTime = 700; + myShowDelayTime = 5000; +} + +/*! + Destructor +*/ +QtxToolTip::~QtxToolTip() +{ +} + +/*! + Custom event filter +*/ +bool QtxToolTip::eventFilter( QObject* o, QEvent* e ) +{ + if ( ( e->type() == QEvent::Destroy ) || ( e->type() == QEvent::Close ) || ( e->type() == QEvent::Hide ) ) + { + hideTip(); + } + if ( e->type() == QEvent::Leave ) + { + if ( isVisible() && ( o == this ) ) + hideTip(); + myWakeUpTimer->stop(); + } + if ( e->type() == QEvent::MouseMove ) + { + QMouseEvent* me = (QMouseEvent*)e; + QPoint thePos = parentWidget()->mapFromGlobal( me->globalPos() ); + if ( myWakeUpTimer->isActive() ) + { + myWakeUpTimer->stop(); + myWakeUpTimer->start( myWakeUpDelayTime ); + } + if ( isVisible() ) + { + if ( !myWidgetRegion.contains( thePos ) ) + { + hideTip(); + myWidgetRegion = QRect( -1, -1, -1, -1 ); + } + } + else + { + if ( !myWidgetRegion.isValid() || myWidgetRegion.contains( thePos ) ) + myWakeUpTimer->start( myWakeUpDelayTime ); + } + } + if ( e->type() == QEvent::KeyPress ) + { + hideTip(); + } + if ( o == parent() && ( e->type() == QEvent::MouseButtonPress || + e->type() == QEvent::MouseButtonRelease ) ) + { + hideTip(); + } + return false; +} + +/*! + Shows tool tip + \param aPos - position + \param text - tooltip text + \param aWidgetRegion - rectangle +*/ +void QtxToolTip::showTip( const QPoint& aPos, const QString& text, const QRect& aWidgetRegion ) +{ + QFontMetrics theFM = fontMetrics(); + int theHeight = theFM.height(); + int theWidth = theFM.width( text ) + 2; + showTip( QRect( QPoint( aPos.x(), aPos.y() + 10 ), QSize( theWidth, theHeight ) ), text, aWidgetRegion ); +} + +/*! + Shows tool tip + \param aRegion - tooltip region + \param text - tooltip text + \param aWidgetRegion - widget rectangle +*/ +void QtxToolTip::showTip( const QRect& aRegion, const QString& text, const QRect& aWidgetRegion ) +{ + setText( text ); + myWidgetRegion = aWidgetRegion; + setGeometry( aRegion ); + if ( myShowDelayTime != 0 ) + mySleepTimer->start( myShowDelayTime ); + show(); +} + +/*! + Hides tooltip +*/ +void QtxToolTip::hideTip() +{ + hide(); + myWidgetRegion = QRect( -1, -1, -1, -1 ); + mySleepTimer->stop(); +} + +/*! + It is called when there is a possibility that a tool tip should be shown and + must decide whether there is a tool tip for the point p in the widget that this QToolTip object relates to + \param pos - position +*/ +void QtxToolTip::maybeTip( const QPoint& pos ) +{ + QString text; + QRect textRegion, theRegion( -1, -1, -1, -1 ); + QFont theFnt = font(); + + emit maybeTip( pos, text, theFnt, textRegion, theRegion ); + + if ( theRegion.isValid() ) + { + setFont( theFnt ); + int margin = lineWidth() + indent(); + QRect dspRegion( QPoint( textRegion.x() - margin, textRegion.y() ), + QSize( textRegion.width() + 2 * margin, textRegion.height() ) ); + QRect tipRegion( parentWidget()->mapToGlobal( dspRegion.topLeft() ), dspRegion.size() ); + if ( tipRegion.left() < 0 ) + tipRegion.translate( -1 * tipRegion.left(), 0 ); + showTip( tipRegion, text, theRegion ); + } +} + +/*! + SLOT: called when sleep time is out +*/ +void QtxToolTip::onSleepTimeOut() +{ + mySleepTimer->stop(); + hideTip(); +} + +/*! + SLOT: called when wake time is out +*/ +void QtxToolTip::onWakeUpTimeOut() +{ + myWakeUpTimer->stop(); + QPoint pos = QCursor::pos(); + if ( parentWidget() ) + pos = parentWidget()->mapFromGlobal( pos ); + maybeTip( pos ); +} + +/*! + Custom mouse press event handler +*/ +void QtxToolTip::mousePressEvent( QMouseEvent* e ) +{ + hideTip(); + QWidget* reciever = parentWidget(); + QMouseEvent* me = new QMouseEvent( QEvent::MouseButtonPress, + reciever->mapFromGlobal( e->globalPos() ), + e->button(), e->buttons(), Qt::KeypadModifier ); + QApplication::sendEvent( reciever, me ); +} + +/*! + Custom mouse double click event handler +*/ +void QtxToolTip::mouseDoubleClickEvent( QMouseEvent* e ) +{ + hideTip(); + QWidget* reciever = parentWidget(); + QMouseEvent* me = new QMouseEvent( QEvent::MouseButtonDblClick, + reciever->mapFromGlobal( e->globalPos() ), + e->button(), e->buttons(), Qt::KeypadModifier ); + QApplication::sendEvent( reciever, me ); +} + +/*! + Sets wake delay time + \param theTime +*/ +void QtxToolTip::setWakeUpDelayTime( int theTime ) +{ + if( !(theTime < 0) ) + myWakeUpDelayTime = theTime; +} + +/*! + Sets show delay time + \param theTime +*/ +void QtxToolTip::setShowDelayTime( int theTime ) +{ + if( !(theTime < 0) ) + myShowDelayTime = theTime; +} + +/*! + \return timer measuring time of sleeping +*/ +QTimer* QtxToolTip::sleepTimer() const +{ + return mySleepTimer; +} + +/*! + \return timer measuring time of waking up +*/ +QTimer* QtxToolTip::wakeUpTimer() const +{ + return myWakeUpTimer; +} diff --git a/src/Qtx/QtxToolTip.h b/src/Qtx/QtxToolTip.h new file mode 100755 index 000000000..d558f9c06 --- /dev/null +++ b/src/Qtx/QtxToolTip.h @@ -0,0 +1,78 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxToolTip.h +// Author: Sergey TELKOV + +#ifndef QTXTOOLTIP_H +#define QTXTOOLTIP_H + +#include "Qtx.h" + +#include + +class QTimer; + +class QTX_EXPORT QtxToolTip : public QLabel +{ + Q_OBJECT + +public: + QtxToolTip( QWidget* = 0 ); + virtual ~QtxToolTip(); + + void hideTip(); + + virtual void showTip( const QPoint& aPos, + const QString& text, const QRect& aWidgetRegion ); + virtual void showTip( const QRect& aRegion, + const QString& text, const QRect& aWidgetRegion ); + + virtual bool eventFilter( QObject* o, QEvent* e ); + + void setWakeUpDelayTime( int ); + void setShowDelayTime( int ); + + int wakeUpDelayTime() const { return myWakeUpDelayTime; } + int showDelayTime() const { return myShowDelayTime; } + +signals: + void maybeTip( QPoint, QString&, QFont&, QRect&, QRect& ); + +protected slots: + void onSleepTimeOut(); + void onWakeUpTimeOut(); + +protected: + virtual void maybeTip( const QPoint& ); + virtual void mousePressEvent( QMouseEvent* ); + virtual void mouseDoubleClickEvent( QMouseEvent* ); + + QTimer* sleepTimer() const; + QTimer* wakeUpTimer() const; + +private: + QTimer* myWakeUpTimer; + QTimer* mySleepTimer; + QRect myWidgetRegion; + + int myShowDelayTime; + int myWakeUpDelayTime; +}; + +#endif diff --git a/src/Qtx/QtxValidator.cxx b/src/Qtx/QtxValidator.cxx new file mode 100644 index 000000000..690986559 --- /dev/null +++ b/src/Qtx/QtxValidator.cxx @@ -0,0 +1,136 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxValidator.cxx +// Author: Alexandre SOLOVYOV + +#include "QtxValidator.h" + +/*! + \class QtxIntValidator + \brief Validator for integer numbers with possibility to fix up the invalid value. +*/ + +/*! + \brief Constructor. + \param parent parent object +*/ +QtxIntValidator::QtxIntValidator( QObject* parent ) +: QIntValidator( parent ) +{ +} + +/*! + \brief Constructor. + \param bot minimum possible value + \param top maximum possible value + \param parent parent object +*/ +QtxIntValidator::QtxIntValidator( const int bot, const int top, QObject* parent ) +: QIntValidator( bot, top, parent ) +{ +} + +/*! + \brief Destructor. +*/ +QtxIntValidator::~QtxIntValidator() +{ +} + +/*! + \brief Validate the input and fixup it if necessary. + + If the string represents integer value less then minimum value, it becomes equal to the minimum. + if the string represents integer value more then mazimum value, it becomes equal to the maximum. + If the string is not evaluated as integer it becomes equal to \c 0. + + \param str the string to be validated +*/ +void QtxIntValidator::fixup( QString& str ) const +{ + bool ok = false; + int i = str.toInt( &ok ); + if ( ok ) + { + if ( i < bottom() ) + str = QString::number( bottom() ); + else if( i > top() ) + str = QString::number( top() ); + } + else + str = QString ( "0" ); +} + +/*! + \class QtxDoubleValidator + \brief Validator for double numbers with possibility to fix up the invalid value. +*/ + +/*! + \brief Constructor + \param parent parent object +*/ +QtxDoubleValidator::QtxDoubleValidator( QObject* parent ) +: QDoubleValidator( parent ) +{ +} + +/*! + \brief Constructor. + \param bot minimum possible value + \param top maximum possible value + \param dec precision (number of digits after dot) + \param parent parent object +*/ +QtxDoubleValidator::QtxDoubleValidator( const double bot, const double top, + const int dec, QObject* parent ) +: QDoubleValidator( bot, top, dec, parent ) +{ +} + +/*! + \brief Destructor. +*/ +QtxDoubleValidator::~QtxDoubleValidator() +{ +} + +/*! + \brief Validate the input and fixup it if necessary. + + If the string represents double value less then minimum value, it becomes equal to the minimum. + if the string represents double value more then mazimum value, it becomes equal to the maximum. + If the string is not evaluated as double it becomes equal to \c 0. + + \param str the string to be validated +*/ +void QtxDoubleValidator::fixup( QString& str ) const +{ + bool ok = false; + double d = str.toDouble( &ok ); + if ( ok ) + { + if ( d < bottom() ) + str = QString::number( bottom() ); + else if ( d > top() ) + str = QString::number( top() ); + } + else + str = QString( "0" ); +} diff --git a/src/Qtx/QtxValidator.h b/src/Qtx/QtxValidator.h new file mode 100644 index 000000000..b6a6103a0 --- /dev/null +++ b/src/Qtx/QtxValidator.h @@ -0,0 +1,53 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxValidator.h +// Author: Alexandre SOLOVYOV + +#ifndef QTXVALIDATOR_H +#define QTXVALIDATOR_H + +#include "Qtx.h" + +#include + +class QTX_EXPORT QtxIntValidator : public QIntValidator +{ + Q_OBJECT + +public: + QtxIntValidator( QObject* ); + QtxIntValidator( const int, const int, QObject* ); + virtual ~QtxIntValidator(); + + virtual void fixup( QString& ) const; +}; + +class QTX_EXPORT QtxDoubleValidator : public QDoubleValidator +{ + Q_OBJECT + +public: + QtxDoubleValidator( QObject* ); + QtxDoubleValidator( const double, const double, const int, QObject* ); + virtual ~QtxDoubleValidator(); + + virtual void fixup( QString& ) const; +}; + +#endif // QTXVALIDATOR_H diff --git a/src/Qtx/QtxWorkspace.cxx b/src/Qtx/QtxWorkspace.cxx new file mode 100644 index 000000000..dd303ed6c --- /dev/null +++ b/src/Qtx/QtxWorkspace.cxx @@ -0,0 +1,137 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxWorkspace.cxx +// Author: Sergey TELKOV + +#include "QtxWorkspace.h" + +#include + +/*! + \class QtxWorkspace + \brief A workspace widget which can be used in the MDI application + as top-level widget in the application main window. + + Provides methods to tile child windows in horizontal or vertical + direction. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +QtxWorkspace::QtxWorkspace( QWidget* parent ) +: QWorkspace( parent ) +{ +} + +/*! + \brief Destructor. +*/ +QtxWorkspace::~QtxWorkspace() +{ +} + +/*! + \brief Tiles child windows vertically. +*/ +void QtxWorkspace::tileVertical() +{ + QWidgetList winList = windowList(); + if ( winList.isEmpty() ) + return; + + int count = 0; + for ( QWidgetList::const_iterator itr = winList.begin(); itr != winList.end(); ++itr ) + if ( !( (*itr)->windowState() & Qt::WindowMinimized ) ) + count++; + + if ( !count ) + return; + + if ( activeWindow() && ( activeWindow()->windowState() & Qt::WindowMaximized ) ) + activeWindow()->showNormal(); + + int y = 0; + int heightForEach = height() / count; + for ( QWidgetList::iterator it = winList.begin(); it != winList.end(); ++it ) + { + QWidget* win = *it; + if ( win->windowState() & Qt::WindowMinimized ) + continue; + + if ( win->windowState() & Qt::WindowMaximized ) + { + win->hide(); + win->showNormal(); + } + +// QApplication::sendPostedEvents( 0, QEvent::ShowNormal ); + + int prefH = win->minimumHeight() + win->parentWidget()->baseSize().height(); + int actualH = qMax( heightForEach, prefH ); + + win->parentWidget()->setGeometry( 0, y, width(), actualH ); + y += actualH; + } +} + +/*! + \brief Tiles child windows horizontally. +*/ +void QtxWorkspace::tileHorizontal() +{ + QWidgetList winList = windowList(); + if ( winList.isEmpty() ) + return; + + int count = 0; + for ( QWidgetList::const_iterator itr = winList.begin(); itr != winList.end(); ++itr ) + if ( !( (*itr)->windowState() & Qt::WindowMinimized ) ) + count++; + + if ( !count ) + return; + + if ( activeWindow() && activeWindow()->windowState() & Qt::WindowMaximized ) + activeWindow()->showNormal(); + + int x = 0; + int widthForEach = width() / count; + for ( QWidgetList::iterator it = winList.begin(); it != winList.end(); ++it ) + { + QWidget* win = *it; + if ( win->windowState() & Qt::WindowMinimized ) + continue; + + if ( win->windowState() & Qt::WindowMaximized ) + { + win->hide(); + win->showNormal(); + } + +// QApplication::sendPostedEvents( 0, QEvent::ShowNormal ); + + int prefW = win->minimumWidth(); + int actualW = qMax( widthForEach, prefW ); + + win->parentWidget()->setGeometry( x, 0, actualW, height() ); + x += actualW; + } +} diff --git a/src/Qtx/QtxWorkspace.h b/src/Qtx/QtxWorkspace.h new file mode 100644 index 000000000..224d729c1 --- /dev/null +++ b/src/Qtx/QtxWorkspace.h @@ -0,0 +1,50 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxWorkspace.h +// Author: Sergey TELKOV + +#ifndef QTXWORKSPACE_H +#define QTXWORKSPACE_H + +#include "Qtx.h" + +#include + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +class QTX_EXPORT QtxWorkspace : public QWorkspace +{ + Q_OBJECT + +public: + QtxWorkspace( QWidget* = 0 ); + virtual ~QtxWorkspace(); + +public slots: + void tileVertical(); + void tileHorizontal(); +}; + +#ifdef WIN32 +#pragma warning( default:4251 ) +#endif + +#endif diff --git a/src/Qtx/QtxWorkspaceAction.cxx b/src/Qtx/QtxWorkspaceAction.cxx new file mode 100644 index 000000000..938b43801 --- /dev/null +++ b/src/Qtx/QtxWorkspaceAction.cxx @@ -0,0 +1,413 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxWorkspaceAction.cxx +// Author: Sergey TELKOV + +#include "QtxWorkspaceAction.h" + +#include "QtxWorkspace.h" + +#include +#include + +/*! + \class QtxWorkspaceAction + \brief Implements actions group for menu Windows with standard operations, like + "Cascade", "Tile", "Tile Horizontally", etc. +*/ + +/*! + \brief Constructor. + \param ws parent workspace + \param parent parent object (owner of the action) +*/ +QtxWorkspaceAction::QtxWorkspaceAction( QtxWorkspace* ws, QObject* parent ) +: QtxActionSet( parent ), + myWorkspace( ws ), + myWindowsFlag( true ) +{ + insertAction( new QtxAction( tr( "Arranges the windows as overlapping tiles" ), + tr( "Cascade" ), 0, this ), Cascade ); + insertAction( new QtxAction( tr( "Arranges the windows as nonoverlapping tiles" ), + tr( "Tile" ), 0, this ), Tile ); + insertAction( new QtxAction( tr( "Arranges the windows as nonoverlapping horizontal tiles" ), + tr( "Tile horizontally" ), 0, this ), HTile ); + insertAction( new QtxAction( tr( "Arranges the windows as nonoverlapping vertical tiles" ), + tr( "Tile vertically" ), 0, this ), VTile ); + + connect( this, SIGNAL( triggered( int ) ), this, SLOT( onTriggered( int ) ) ); + + setMenuActions( Standard ); +} + +/*! + \brief Destructor. +*/ +QtxWorkspaceAction::~QtxWorkspaceAction() +{ +} + +/*! + \brief Get workspace. + \return parent workspace +*/ +QtxWorkspace* QtxWorkspaceAction::workspace() const +{ + return myWorkspace; +} + +/*! + \brief Set actions to be visible in the menu. + + Actions, which IDs are set in \a flags parameter, will be shown in the + menu bar. Other actions will not be shown. + + \param flags ORed together actions flags +*/ +void QtxWorkspaceAction::setMenuActions( const int flags ) +{ + action( Cascade )->setVisible( flags & Cascade ); + action( Tile )->setVisible( flags & Tile ); + action( VTile )->setVisible( flags & VTile ); + action( HTile )->setVisible( flags & HTile ); + myWindowsFlag = flags & Windows; +} + +/*! + \brief Get menu actions which are currently visible in the menu bar. + \return ORed together actions flags + \sa setMenuActions() +*/ +int QtxWorkspaceAction::menuActions() const +{ + int ret = 0; + ret = ret | ( action( Cascade )->isVisible() ? Cascade : 0 ); + ret = ret | ( action( Tile )->isVisible() ? Tile : 0 ); + ret = ret | ( action( VTile )->isVisible() ? VTile : 0 ); + ret = ret | ( action( HTile )->isVisible() ? HTile : 0 ); + ret = ret | ( myWindowsFlag ? Windows : 0 ); + return ret; +} + +/*! + \brief Get keyboard accelerator for the specified action. + \param id menu action ID + \return keyboard accelerator of menu item or 0 if there is no such action +*/ +int QtxWorkspaceAction::accel( const int id ) const +{ + int a = 0; + if ( action( id ) ) + a = action( id )->shortcut(); + return a; +} + +/*! + \brief Get icon for the specified action. + + If \a id is invalid, null icon is returned. + + \param id menu action ID + \return menu item icon +*/ +QIcon QtxWorkspaceAction::icon( const int id ) const +{ + QIcon ico; + if ( action( id ) ) + ico = action( id )->icon(); + return ico; +} + +/*! + \brief Get menu item text for the specified action. + \param id menu action ID + \return menu item text or null QString if there is no such action +*/ +QString QtxWorkspaceAction::text( const int id ) const +{ + QString txt; + if ( action( id ) ) + txt = action( id )->text(); + return txt; +} + +/*! + \brief Get status bar tip for the specified action. + \param id menu action ID + \return status bar tip menu item or null QString if there is no such action +*/ +QString QtxWorkspaceAction::statusTip( const int id ) const +{ + QString txt; + if ( action( id ) ) + txt = action( id )->statusTip(); + return txt; +} + +/*! + \brief Set keyboard accelerator for the specified action. + \param id menu action ID + \param a new keyboard accelerator +*/ +void QtxWorkspaceAction::setAccel( const int id, const int a ) +{ + if ( action( id ) ) + action( id )->setShortcut( a ); +} + +/*! + \brief Set menu item icon for the specified action. + \param id menu action ID + \param ico new menu item icon +*/ +void QtxWorkspaceAction::setIcon( const int id, const QIcon& icon ) +{ + if ( action( id ) ) + action( id )->setIcon( icon ); +} + +/*! + \brief Set menu item text for the specified action. + \param id menu action ID + \param txt new menu item text +*/ +void QtxWorkspaceAction::setText( const int id, const QString& txt ) +{ + if ( action( id ) ) + action( id )->setText( txt ); +} + +/*! + \brief Set menu item status bar tip for the specified action. + \param id menu action ID + \param txt new menu item status bar tip +*/ +void QtxWorkspaceAction::setStatusTip( const int id, const QString& txt ) +{ + if ( action( id ) ) + action( id )->setStatusTip( txt ); +} + +/*! + \brief Process action activated by the user. + \param type action ID +*/ +void QtxWorkspaceAction::perform( const int type ) +{ + switch ( type ) + { + case Cascade: + cascade(); + break; + case Tile: + tile(); + break; + case VTile: + tileVertical(); + break; + case HTile: + tileHorizontal(); + break; + } +} + +/*! + \brief Tile child windows in the workspace. +*/ +void QtxWorkspaceAction::tile() +{ + QtxWorkspace* ws = workspace(); + if ( ws ) + ws->tile(); +} + +/*! + \brief Cascade child windows in the workspace. +*/ +void QtxWorkspaceAction::cascade() +{ + QtxWorkspace* ws = workspace(); + if ( !ws ) + return; + + ws->cascade(); + + int w = ws->width(); + int h = ws->height(); + + QWidgetList winList = ws->windowList(); + for ( QWidgetList::iterator it = winList.begin(); it != winList.end(); ++it ) + (*it)->resize( int( w * 0.8 ), int( h * 0.8 ) ); +} + +/*! + \brief Tile child windows in the workspace in the vertical direction. +*/ +void QtxWorkspaceAction::tileVertical() +{ + QtxWorkspace* ws = workspace(); + if ( ws ) + ws->tileVertical(); +} + +/*! + \brief Tile child windows in the workspace in the horizontal direction. +*/ +void QtxWorkspaceAction::tileHorizontal() +{ + QtxWorkspace* ws = workspace(); + if ( ws ) + ws->tileHorizontal(); +} + +/*! + \brief Called when action is added to the menu bar. + \param w menu bar widget this action is being added to +*/ +void QtxWorkspaceAction::addedTo( QWidget* w ) +{ + QtxActionSet::addedTo( w ); + + QMenu* pm = ::qobject_cast( w ); + if ( pm ) + connect( pm, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) ); +} + +/*! + \brief Called when action is removed from the menu bar. + \param w menu bar widget this action is being removed from +*/ +void QtxWorkspaceAction::removedFrom( QWidget* w ) +{ + QtxActionSet::removedFrom( w ); + + QMenu* pm = ::qobject_cast( w ); + if ( pm ) + disconnect( pm, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) ); +} + +/*! + \brief Update all menu action state. +*/ +void QtxWorkspaceAction::updateContent() +{ + bool count = workspace() ? workspace()->windowList().count() : 0; + action( Cascade )->setEnabled( count ); + action( Tile )->setEnabled( count ); + action( HTile )->setEnabled( count ); + action( VTile )->setEnabled( count ); + + updateWindows(); +} + +/*! + \brief Update actions which refer to the opened child windows. +*/ +void QtxWorkspaceAction::updateWindows() +{ + QtxWorkspace* ws = workspace(); + if ( !ws ) + return; + + QList lst = actions(); + for ( QList::iterator it = lst.begin(); it != lst.end(); ++it ) + { + int id = actionId( *it ); + if ( id >= Windows ) + removeAction( *it ); + } + + bool base = action( Cascade )->isVisible() || action( Tile )->isVisible() || + action( HTile )->isVisible() || action( VTile )->isVisible(); + + QList items; + QMap map; + if ( menuActions() & Windows ) + { + int index = 1; + QWidgetList wList = ws->windowList(); + for ( QWidgetList::iterator it = wList.begin(); it != wList.end(); ++it, index++ ) + { + QWidget* wid = *it; + QAction* a = new QtxAction( wid->windowTitle(), wid->windowTitle(), 0, this, true ); + a->setChecked( wid == ws->activeWindow() ); + items.append( a ); + map.insert( a, Windows + index ); + } + + if ( base && !items.isEmpty() ) + { + QAction* sep = new QtxAction( this ); + sep->setSeparator( true ); + items.prepend( sep ); + map.insert( sep, Windows ); + } + } + + if ( !items.isEmpty() ) + insertActions( items ); + + for ( QMap::const_iterator itr = map.begin(); itr != map.end(); ++itr ) + setActionId( itr.key(), itr.value() ); +} + +/*! + \brief Called when parent menu is about to show. + + Updates all menu items. +*/ +void QtxWorkspaceAction::onAboutToShow() +{ + QMenu* pm = ::qobject_cast( sender() ); + if ( pm ) + updateContent(); +} + +/*! + \brief Called when menu item corresponding to some child window is activated. + + Activates correposponding child window. + + \param idx menu item index +*/ +void QtxWorkspaceAction::activateItem( const int idx ) +{ + QtxWorkspace* ws = workspace(); + if ( !ws ) + return; + + QWidgetList wList = ws->windowList(); + if ( idx >= 0 && idx < (int)wList.count() ) + wList.at( idx )->setFocus(); +} + +/*! + \brief Called when menu item is activated by the user. + + Perform the corresponding action. + + \param id menu item identifier +*/ +void QtxWorkspaceAction::onTriggered( int id ) +{ + if ( id < Windows ) + perform( id ); + else + activateItem( id - Windows - 1 ); +} diff --git a/src/Qtx/QtxWorkspaceAction.h b/src/Qtx/QtxWorkspaceAction.h new file mode 100644 index 000000000..a4ade9c06 --- /dev/null +++ b/src/Qtx/QtxWorkspaceAction.h @@ -0,0 +1,97 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxWorkspaceAction.h +// Author: Sergey TELKOV + +#ifndef QTXWORKSPACEACTION_H +#define QTXWORKSPACEACTION_H + +#include "QtxActionSet.h" + +class QtxWorkspace; + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +class QTX_EXPORT QtxWorkspaceAction : public QtxActionSet +{ + Q_OBJECT + +public: + //! Actions (menu items) ID + enum { Cascade = 0x0001, //!< "Cascade child windows" operation + Tile = 0x0002, //!< "Tile child windows" operation + VTile = 0x0004, //!< "Tile child windows vertically" operation + HTile = 0x0008, //!< "Tile child windows horizontally" operation + Windows = 0x0010, //!< A list of child windows menu items + Standard = Cascade | Tile | Windows, + Operations = Cascade | Tile | VTile | HTile, + All = Standard | HTile | VTile }; + +public: + QtxWorkspaceAction( QtxWorkspace*, QObject* = 0 ); + virtual ~QtxWorkspaceAction(); + + QtxWorkspace* workspace() const; + + int menuActions() const; + void setMenuActions( const int ); + + QIcon icon( const int ) const; + QString text( const int ) const; + int accel( const int ) const; + QString statusTip( const int ) const; + + void setAccel( const int, const int ); + void setIcon( const int, const QIcon& ); + void setText( const int, const QString& ); + void setStatusTip( const int, const QString& ); + + void perform( const int ); + +public slots: + void tile(); + void cascade(); + void tileVertical(); + void tileHorizontal(); + +private slots: + void onAboutToShow(); + void onTriggered( int ); + +protected: + virtual void addedTo( QWidget* ); + virtual void removedFrom( QWidget* ); + +private: + void updateContent(); + void updateWindows(); + void activateItem( const int ); + +private: + QtxWorkspace* myWorkspace; //!< parent workspace + bool myWindowsFlag; //!< "show child windows items" flag +}; + +#ifdef WIN32 +#pragma warning( default:4251 ) +#endif + +#endif diff --git a/src/Qtx/QtxWorkstack.cxx b/src/Qtx/QtxWorkstack.cxx index e98cd5123..0d72eb2ec 100644 --- a/src/Qtx/QtxWorkstack.cxx +++ b/src/Qtx/QtxWorkstack.cxx @@ -1,17 +1,17 @@ // Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D -// +// // 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 +// License as published by the Free Software Foundation; either // version 2.1 of the License. -// -// 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 +// +// 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 +// 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 @@ -23,2623 +23,2926 @@ #include "QtxAction.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 #define DARK_COLOR_LIGHT 250 /*! - Constructor + \class QtxWorkstackArea::WidgetEvent + \internal + \brief Internal class used to forward child widgets events to the workarea */ -QtxWorkstack::QtxWorkstack( QWidget* parent ) -: QWidget( parent ), -myWin( 0 ), -myArea( 0 ), -myWorkWin( 0 ), -myWorkArea( 0 ) + +class QtxWorkstackArea::WidgetEvent : public QEvent { - myActionsMap.insert( SplitVertical, new QtxAction( QString(), tr( "Split vertically" ), 0, this ) ); - myActionsMap.insert( SplitHorizontal, new QtxAction( QString(), tr( "Split horizontally" ), 0, this ) ); - myActionsMap.insert( Close, new QtxAction( QString(), tr( "Close" ), 0, this ) ); - myActionsMap.insert( Rename, new QtxAction( QString(), tr( "Rename" ), 0, this ) ); +public: + WidgetEvent( Type t, QWidget* w = 0 ) : QEvent( t ), myWidget( w ) {}; - connect( myActionsMap[SplitVertical], SIGNAL( triggered( bool ) ), this, SLOT( splitVertical() ) ); - connect( myActionsMap[SplitHorizontal], SIGNAL( triggered( bool ) ), this, SLOT( splitHorizontal() ) ); - connect( myActionsMap[Close], SIGNAL( triggered( bool ) ), this, SLOT( onCloseWindow() ) ); - connect( myActionsMap[Rename], SIGNAL( triggered( bool ) ), this, SLOT( onRename() ) ); + QWidget* widget() const { return myWidget; } - QVBoxLayout* base = new QVBoxLayout( this ); - base->setMargin( 0 ); +private: + QWidget* myWidget; // event receiver widget +}; - mySplit = new QSplitter( this ); - mySplit->setChildrenCollapsible( false ); - base->addWidget( mySplit ); -} +/*! + \class QtxWorkstackDrag + \internal + \brief Workstack drag object +*/ /*! - Destructor + \brief Constructor. + \param ws parent workstack + \param child child widget container */ -QtxWorkstack::~QtxWorkstack() +QtxWorkstackDrag::QtxWorkstackDrag( QtxWorkstack* ws, QtxWorkstackChild* child ) +: QObject( 0 ), + myWS( ws ), + myChild( child ), + myTab( -1 ), + myArea( 0 ), + myTabRect( 0 ), + myAreaRect( 0 ) { + QApplication::instance()->installEventFilter( this ); } /*! - \return list of all widgets in all areas + \brief Destructor. */ -QWidgetList QtxWorkstack::windowList() const +QtxWorkstackDrag::~QtxWorkstackDrag() { - QList lst; - areas( mySplit, lst, true ); - - QWidgetList widList; - for ( QList::iterator it = lst.begin(); it != lst.end(); ++it ) - { - QWidgetList wids = (*it)->widgetList(); - for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr ) - widList.append( *itr ); - } + QApplication::instance()->removeEventFilter( this ); - return widList; + endDrawRect(); } /*! - \return list of all widgets in active area + \brief Custom event filter. + \param o event receiver widget + \param e event + \return \c true if event should be filtered (stop further processing) */ -QWidgetList QtxWorkstack::splitWindowList() const +bool QtxWorkstackDrag::eventFilter( QObject*, QEvent* e ) { - return myArea ? myArea->widgetList() : QWidgetList(); + switch ( e->type() ) + { + case QEvent::MouseMove: + updateTarget( ((QMouseEvent*)e)->globalPos() ); + break; + case QEvent::MouseButtonRelease: + drawRect(); + endDrawRect(); + dropWidget(); + deleteLater(); + break; + default: + return false; + } + return true; } /*! - \return active widget + \brief Detect and set dropping target widget. + \param p current dragging position */ -QWidget* QtxWorkstack::activeWindow() const +void QtxWorkstackDrag::updateTarget( const QPoint& p ) { - return myWin; + int tab = -1; + QtxWorkstackArea* area = detectTarget( p, tab ); + setTarget( area, tab ); } /*! - Splits widgets - \param o - orientation (Qt::Orientation) + \brief Detect dropping target. + \param p current dragging position + \param tab resulting target tab page index + \return target workarea or 0 if there is no correct drop target */ -void QtxWorkstack::split( const int o ) +QtxWorkstackArea* QtxWorkstackDrag::detectTarget( const QPoint& p, int& tab ) const { - QtxWorkstackArea* area = myWorkArea; - if ( !area ) - area = activeArea(); - if ( !area ) - return; - - if ( area->widgetList().count() < 2 ) - return; - - QWidget* curWid = area->activeWidget(); - if ( !curWid ) - return; - - QSplitter* s = splitter( area ); - QList areaList; - areas( s, areaList ); - - QList splitList; - splitters( s, splitList ); - - QSplitter* trg = 0; - if ( areaList.count() + splitList.count() < 2 || s->orientation() == o ) - trg = s; + if ( p.isNull() ) + return 0; - if ( !trg ) - trg = wrapSplitter( area ); + QtxWorkstackArea* area = myWS->areaAt( p ); + if ( area ) + tab = area->tabAt( p ); + return area; +} - if ( !trg ) +/*! + \brief Set dropping target. + \param area new target workarea + \param tab target workarea's tab page index +*/ +void QtxWorkstackDrag::setTarget( QtxWorkstackArea* area, const int tab ) +{ + if ( !area || ( myArea == area && tab == myTab ) ) return; - trg->setOrientation( (Qt::Orientation)o ); + startDrawRect(); - QtxWorkstackArea* newArea = createArea( 0 ); - trg->insertWidget( trg->indexOf( area ) + 1, newArea ); + if ( myArea ) + drawRect(); - area->removeWidget( curWid ); - newArea->insertWidget( curWid ); + myTab = tab; + myArea = area; - distributeSpace( trg ); + if ( myArea ) + drawRect(); +} - curWid->show(); - curWid->setFocus(); +/*! + \brief Called when drop operation is finished. + + Inserts dropped widget to the target workarea. +*/ +void QtxWorkstackDrag::dropWidget() +{ + if ( myArea ) + myArea->insertWidget( myChild->widget(), myTab ); } /*! - \brief Split workarea of the given widget on two parts. - \param wid - widget, belonging to this workstack - \param o - orientation of splitting (Qt::Horizontal or Qt::Vertical) - \param type - type of splitting, see SplitType enumeration + \brief Draw floating rectangle. */ -void QtxWorkstack::Split( QWidget* wid, const Qt::Orientation o, const SplitType type ) +void QtxWorkstackDrag::drawRect() { - if (!wid) return; + if ( !myArea ) + return; - // find area of the given widget - QtxWorkstackArea* area = NULL; - QList allAreas; - areas(mySplit, allAreas, true); + QRect r = myArea->floatRect(); + int m = 2; - - for ( QList::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it ) + r.setTop( r.top() + m + 2 ); + r.setLeft( r.left() + m + 2 ); + r.setRight( r.right() - m - 2 ); + r.setBottom( r.bottom() - m - 2 ); + + if ( myAreaRect ) { - if ( (*it)->contains( wid ) ) - area = *it; + myAreaRect->setGeometry( r ); + myAreaRect->setVisible( r.isValid() ); } - if ( !area ) - return; - - QWidgetList wids = area->widgetList(); - if ( wids.count() < 2 ) - return; + QRect tr = myArea->floatTab( myTab ); - QSplitter* s = splitter( area ); - QList areaList; - areas( s, areaList ); + tr.setTop( tr.top() + m ); + tr.setLeft( tr.left() + m ); + tr.setRight( tr.right() - m ); + tr.setBottom( tr.bottom() - m ); - QList splitList; - splitters(s, splitList); + if ( myTabRect ) + { + myTabRect->setGeometry( tr ); + myTabRect->setVisible( tr.isValid() ); + } +} - QSplitter* trg = 0; - if (areaList.count() + splitList.count() < 2 || s->orientation() == o) - trg = s; +/*! + \brief Delete rubber band on the end on the dragging operation. +*/ +void QtxWorkstackDrag::endDrawRect() +{ + delete myAreaRect; + myAreaRect = 0; - if (!trg) trg = wrapSplitter(area); - if (!trg) return; + delete myTabRect; + myTabRect = 0; +} - trg->setOrientation(o); +/*! + \brief Create rubber band to be drawn on the dragging operation. +*/ +void QtxWorkstackDrag::startDrawRect() +{ + if ( !myTabRect ) + myTabRect = new QRubberBand( QRubberBand::Rectangle ); - QtxWorkstackArea* newArea = createArea(0); - insertWidget(newArea, trg, area); + myTabRect->hide(); - switch ( type ) - { - case SPLIT_STAY: - for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr ) - { - QWidget* wid_i = *itr; - if ( wid_i != wid ) - { - area->removeWidget( wid_i ); - newArea->insertWidget( wid_i ); - } - } - break; - case SPLIT_AT: - { - QWidgetList::iterator itr = wids.begin(); - for ( ; itr != wids.end() && *itr != wid; ++itr ) - { - } - for ( ; itr != wids.end(); ++itr ) - { - area->removeWidget( *itr ); - newArea->insertWidget( *itr ); - } - } - break; - case SPLIT_MOVE: - area->removeWidget( wid ); - newArea->insertWidget( wid ); - break; - } + if ( !myAreaRect ) + myAreaRect = new QRubberBand( QRubberBand::Rectangle ); - distributeSpace( trg ); + myAreaRect->hide(); } /*! - \brief Move widget(s) from source workarea into target workarea - or just reorder widgets inside one workarea. - \param wid1 - widget from target workarea - \param wid2 - widget from source workarea - \param all - if this parameter is TRUE, all widgets from source workarea will - be moved into the target one, else only the \a wid2 will be moved + \class QtxWorkstackArea + \internal + \brief Workstack widget workarea. +*/ - Move \a wid2 in target workarea. Put it right after \a wid1. - If value of boolean argument is TRUE, all widgets from source workarea - will be moved together with \a wid2, source workarea will be deleted. - If \a wid1 and \a wid2 belongs to one workarea, simple reordering will take place. +/*! + \brief Constructor. + \param parent parent widget */ -void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all ) +QtxWorkstackArea::QtxWorkstackArea( QWidget* parent ) +: QFrame( parent ) { - if ( !wid1 || !wid2 ) - return; + setFrameStyle( QFrame::Panel | QFrame::Sunken ); - // find area of the widgets - QtxWorkstackArea *area1 = 0, *area2 = 0; - QList allAreas; - areas( mySplit, allAreas, true ); - for ( QList::iterator it = allAreas.begin(); it != allAreas.end() && !( area1 && area2 ); ++it ) - { - if ( (*it)->contains( wid1 ) ) - area1 = *it; + QVBoxLayout* base = new QVBoxLayout( this ); + base->setMargin( frameWidth() ); - if ( (*it)->contains( wid2 ) ) - area2 = *it; - } + QWidget* top = new QWidget( this ); + base->addWidget( top ); - if ( !area1 || !area2 ) - return; + QHBoxLayout* tl = new QHBoxLayout( top ); + tl->setMargin( 0 ); - QWidget* curWid = area1->activeWidget(); - if ( !curWid ) - return; + myBar = new QtxWorkstackTabBar( top ); + tl->addWidget( myBar, 1 ); - if ( area1 == area2 ) - { - if ( all ) - { - // Set wid1 at first position, wid2 at second - area1->insertWidget( wid1 ); - area1->insertWidget( wid2, 1 ); - } - else - { - // Set wid2 right after wid1 - area1->removeWidget( wid2 ); - int wid1_ind = 0; - QWidgetList wids1 = area1->widgetList(); - for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind ); - area1->insertWidget( wid2, wid1_ind + 1 ); - } - } - else - { - int wid1_ind = 0; - QWidgetList wids1 = area1->widgetList(); - for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind ); - if ( all ) - { - // Set wid2 right after wid1, other widgets from area2 right after wid2 - QWidgetList wids2 = area2->widgetList(); - QWidgetList::iterator itr2 = wids2.begin(); - for ( int ind = wid1_ind + 1; itr2 != wids2.end(); ++itr2, ++ind ) - { - area2->removeWidget( *itr2 ); - if ( *itr2 == wid2 ) - area1->insertWidget( *itr2, wid1_ind + 1 ); - else - area1->insertWidget( *itr2, ind ); - } - } - else - { - // Set wid2 right after wid1 - area2->removeWidget( wid2 ); - area1->insertWidget( wid2, wid1_ind + 1 ); - } - } + QPushButton* close = new QPushButton( top ); + close->setIcon( style()->standardIcon( QStyle::SP_TitleBarCloseButton ) ); + close->setAutoDefault( true ); + close->setFlat( true ); + myClose = close; + tl->addWidget( myClose ); - area1->setActiveWidget( curWid ); + myStack = new QStackedWidget( this ); + + base->addWidget( myStack, 1 ); + + connect( myClose, SIGNAL( clicked() ), this, SLOT( onClose() ) ); + connect( myBar, SIGNAL( currentChanged( int ) ), this, SLOT( onCurrentChanged( int ) ) ); + connect( myBar, SIGNAL( dragActiveTab() ), this, SLOT( onDragActiveTab() ) ); + connect( myBar, SIGNAL( contextMenuRequested( QPoint ) ), this, SLOT( onContextMenuRequested( QPoint ) ) ); + + updateState(); + + updateActiveState(); + + QApplication::instance()->installEventFilter( this ); } -static void setSizes (QIntList& szList, const int item_ind, - const int new_near, const int new_this, const int new_farr) +/*! + \brief Destructor. +*/ +QtxWorkstackArea::~QtxWorkstackArea() { - // set size to all items before an item # - int cur_pos = 0; - QIntList::iterator its = szList.begin(); - for (; its != szList.end() && cur_pos < item_ind; ++its, ++cur_pos) { - *its = new_near; - } - if (its == szList.end()) return; - // set size to item # - *its = new_this; - ++its; - // set size to all items after an item # - for (; its != szList.end(); ++its) { - *its = new_farr; - } + QApplication::instance()->removeEventFilter( this ); } /*! -* \brief Set position of the widget relatively its splitter. -* \param wid - widget to set position of -* \param pos - position relatively splitter. Value in range [0..1]. -* -* Orientation of positioning will correspond to the splitter orientation. + \brief Check if workarea contains visible widgets. + \return \c true if area is empty (all child widgets are removed or now shown) */ -void QtxWorkstack::SetRelativePositionInSplitter( QWidget* wid, const double position ) +bool QtxWorkstackArea::isEmpty() const { - if ( position < 0.0 || 1.0 < position) - return; + bool res = false; + for ( WidgetInfoMap::ConstIterator it = myInfo.begin(); it != myInfo.end() && !res; ++it ) + res = it.value().vis; + return !res; +} +/*! + \brief Add widget to the workarea. + \param wid widget to be added + \param idx position in the area widget to be added to + \param f widget flags + \return child widget container object (or 0 if index is invalid) +*/ +QWidget* QtxWorkstackArea::insertWidget( QWidget* wid, const int idx, Qt::WindowFlags f ) +{ if ( !wid ) - return; + return 0; - // find area of the given widget - QtxWorkstackArea* area = NULL; - QList allAreas; - areas( mySplit, allAreas, true ); - for ( QList::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it ) + int pos = myList.indexOf( wid ); + if ( pos != -1 && ( pos == idx || ( idx < 0 && pos == (int)myList.count() - 1 ) ) ) + return 0; + + myList.removeAll( wid ); + pos = idx < 0 ? myList.count() : idx; + myList.insert( qMin( pos, (int)myList.count() ), wid ); + if ( !myInfo.contains( wid ) ) { - if ( (*it)->contains( wid ) ) - area = *it; + QtxWorkstackChild* child = new QtxWorkstackChild( wid, myStack, f ); + myChild.insert( wid, child ); + myInfo.insert( wid, WidgetInfo() ); + myInfo[wid].id = generateId(); + myInfo[wid].vis = wid->isVisibleTo( wid->parentWidget() ); + + connect( child, SIGNAL( destroyed( QObject* ) ), this, SLOT( onChildDestroyed( QObject* ) ) ); + connect( wid, SIGNAL( destroyed() ), this, SLOT( onWidgetDestroyed() ) ); + connect( child, SIGNAL( shown( QtxWorkstackChild* ) ), this, SLOT( onChildShown( QtxWorkstackChild* ) ) ); + connect( child, SIGNAL( hidden( QtxWorkstackChild* ) ), this, SLOT( onChildHidden( QtxWorkstackChild* ) ) ); + connect( child, SIGNAL( activated( QtxWorkstackChild* ) ), this, SLOT( onChildActivated( QtxWorkstackChild* ) ) ); + connect( child, SIGNAL( captionChanged( QtxWorkstackChild* ) ), this, SLOT( onChildCaptionChanged( QtxWorkstackChild* ) ) ); } - if ( !area ) - return; + updateState(); - QSplitter* split = splitter( area ); - if ( !split ) - return; + setWidgetActive( wid ); + wid->setFocus(); - // find index of the area in its splitter - int item_ind = -1; - bool isFound = false; - const QObjectList& was = split->children(); - for ( QObjectList::const_iterator ito = was.begin(); ito != was.end() && !isFound; ++ito, ++item_ind ) - { - if ( *ito == area ) - isFound = true; - } + return myChild[wid]; +} - if ( !isFound || item_ind == 0 ) +/*! + \brief Create and show popup menu for the area. + \param p mouse pointer position at which popup menu should be shown +*/ +void QtxWorkstackArea::onContextMenuRequested( QPoint p ) +{ + const QtxWorkstackTabBar* bar = ::qobject_cast( sender() ); + if ( !bar ) return; - QIntList szList = split->sizes(); - int splitter_size = ( split->orientation() == Qt::Horizontal ? split->width() : split->height()); - int nb = szList.count(); + QWidget* wid = 0; + int idx = tabAt( p ); + if ( idx != -1 ) + wid = widget( myBar->tabId( idx ) ); - int new_prev = int( splitter_size * position / item_ind ); - int new_next = int( splitter_size * ( 1.0 - position ) / ( nb - item_ind ) ); - setSizes( szList, item_ind, new_prev, new_next, new_next ); - split->setSizes( szList ); + emit contextMenuRequested( wid, p ); } /*! -* \brief Set position of the widget relatively the entire workstack. -* \param wid - widget to set position of -* \param o - orientation of positioning (Qt::Horizontal or Qt::Vertical). -* If o = Qt::Horizontal, horizontal position of \a wid will be changed. -* If o = Qt::Vertical, vertical position of \a wid will be changed. -* \param pos - position relatively workstack. Value in range [0..1]. + \brief Called when area's child widget is destroyed. + + Removes child widget from the area. */ -void QtxWorkstack::SetRelativePosition( QWidget* wid, const Qt::Orientation o, - const double position ) +void QtxWorkstackArea::onWidgetDestroyed() { - if ( position < 0.0 || 1.0 < position ) - return; + if ( sender() ) + removeWidget( (QWidget*)sender(), false ); +} - if ( !wid ) +/*! + \brief Remove widget from workarea. + \param wid widget to be removed + \param del if \c true the widget should be also deleted +*/ +void QtxWorkstackArea::removeWidget( QWidget* wid, const bool del ) +{ + if ( !myList.contains( wid ) ) return; - int splitter_size = o == Qt::Horizontal ? mySplit->width() : mySplit->height(); - int need_pos = int( position * splitter_size ); - int splitter_pos = 0; + if ( myBar->indexOf( widgetId( wid ) ) != -1 ) + myBar->removeTab( myBar->indexOf( widgetId( wid ) ) ); - if ( setPosition( wid, mySplit, o, need_pos, splitter_pos ) != 0 ) + myStack->removeWidget( child( wid ) ); + + myList.removeAll( wid ); + myInfo.remove( wid ); + myChild.remove( wid ); + + if ( del ) { - // impossible to set required position + delete child( wid ); + if ( myList.isEmpty() ) + delete this; + else + updateState(); } + else + updateState(); } /*! -* \brief Sets the action's accelerator key to accel. -* \param id - the key of the action in the actions map. -* \param accel - action's accelerator key. + \brief Get all visible child widgets. + \return list of visible child widgets */ -void QtxWorkstack::setAccel( const int id, const int accel ) +QWidgetList QtxWorkstackArea::widgetList() const { - if ( !myActionsMap.contains( id ) ) - return; - - myActionsMap[id]->setShortcut( accel ); + QWidgetList lst; + for ( QWidgetList::const_iterator it = myList.begin(); it != myList.end(); ++it ) + { + if ( widgetVisibility( *it ) ) + lst.append( *it ); + } + return lst; } /*! -* \brief Returns the action's accelerator key. -* \param id - the key of the action in the actions map. -* \retval int - action's accelerator key. + \brief Get active child widget. + \return active widget */ -int QtxWorkstack::accel( const int id ) const +QWidget* QtxWorkstackArea::activeWidget() const { - int res = 0; - if ( myActionsMap.contains( id ) ) - res = myActionsMap[id]->shortcut(); - return res; + return widget( myBar->tabId( myBar->currentIndex() ) ); } -bool QtxWorkstack::isActionEnabled( const int id ) const +/*! + \brief Set active widget. + \param wid widget to be made active +*/ +void QtxWorkstackArea::setActiveWidget( QWidget* wid ) { - bool res = false; - if ( myActionsMap.contains( id ) ) - res = myActionsMap[id]->isEnabled(); - return res; + myBar->setCurrentIndex( myBar->indexOf( widgetId( wid ) ) ); } -void QtxWorkstack::setActionEnabled( const int id, const bool on ) +/*! + \brief Check if area owns the specified widget. + \param wid widget to be checked + \return \c true if area contains widget +*/ +bool QtxWorkstackArea::contains( QWidget* wid ) const { - if ( myActionsMap.contains( id ) ) - myActionsMap[id]->setEnabled( on ); + return myList.contains( wid ); } -static int positionSimple (QIntList& szList, const int nb, const int splitter_size, - const int item_ind, const int item_rel_pos, - const int need_pos, const int splitter_pos) +/*! + \brief Show/hide workarea. + \param on new visibility state +*/ +void QtxWorkstackArea::setVisible( bool on ) { - if (item_ind == 0) { // cannot move in this splitter - return (need_pos - splitter_pos); - } - - int delta = 0; - int new_prev = 0; - int new_this = szList[item_ind]; - int new_next = 0; + QMap map; + for ( QWidgetList::iterator it = myList.begin(); it != myList.end(); ++it ) + { + map.insert( *it, isBlocked( *it ) ); + setBlocked( *it, true ); + } - bool isToCheck = false; + QFrame::setVisible( on ); - if (need_pos < splitter_pos) { - // Set size of all previous workareas to zero <-- - if (item_ind == nb - 1) { - // item iz last in the splitter, it will occupy all the splitter - new_this = splitter_size; - } else { - // recompute size of next items in splitter - new_next = (splitter_size - new_this) / (nb - item_ind - 1); - } - delta = need_pos - splitter_pos; + for ( QWidgetList::iterator itr = myList.begin(); itr != myList.end(); ++itr ) + setBlocked( *itr, map.contains( *itr ) ? map[*itr] : false ); +} - } else if (need_pos > (splitter_pos + splitter_size)) { - // Set size of all next workareas to zero --> - // recompute size of previous items in splitter - new_this = 0; - new_prev = (splitter_size - new_this) / item_ind; - delta = need_pos - (splitter_pos + splitter_size - new_this); +/*! + \brief Check if workarea is active. + \return \c true if area is active +*/ +bool QtxWorkstackArea::isActive() const +{ + QtxWorkstack* ws = workstack(); + if ( !ws ) + return false; - } else { // required position lays inside this splitter - // Move workarea inside splitter into required position <-> - int new_item_rel_pos = need_pos - splitter_pos; - new_prev = new_item_rel_pos / item_ind; - if (need_pos < (splitter_pos + item_rel_pos)) { - // Make previous workareas smaller, next - bigger - // No problem to keep old size of the widget - } else { - // Make previous workareas bigger, next - smaller - if (new_this > splitter_size - new_item_rel_pos) { - new_this = splitter_size - new_item_rel_pos; - } - // jfa to do: in this case fixed size of next widgets could prevent right resizing - isToCheck = true; - } - if (item_ind == nb - 1) { - new_this = splitter_size - new_item_rel_pos; - } else { - new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1); - } - delta = 0; - } + return ws->activeArea() == this; +} - setSizes (szList, item_ind, new_prev, new_this, new_next); - return delta; +/*! + \brief Update active tab bar state (active/inactive). +*/ +void QtxWorkstackArea::updateActiveState() +{ + myBar->setActive( isActive() ); } /*! -* \brief Set position of given widget. -* \param wid - widget to be moved -* \param split - currently processed splitter (goes from more common -* to more particular splitter in recursion calls) -* \param o - orientation of positioning -* \param need_pos - required position of the given widget in pixels -* (from top/left side of workstack area) -* \param splitter_pos - position of the splitter \a split -* (from top/left side of workstack area) -* \retval int - returns difference between a required and a distinguished position. -* -* Internal method. Recursively calls itself. -* Is called from SetRelativePosition public method. + \brief Get parent workstack + \return workstack owning this workarea */ -int QtxWorkstack::setPosition( QWidget* wid, QSplitter* split, const Qt::Orientation o, - const int need_pos, const int splitter_pos ) +QtxWorkstack* QtxWorkstackArea::workstack() const { - if ( !wid || !split ) - return need_pos - splitter_pos; + QtxWorkstack* ws = 0; + QWidget* wid = parentWidget(); + while ( wid && !ws ) + { + if ( wid->inherits( "QtxWorkstack" ) ) + ws = (QtxWorkstack*)wid; + wid = wid->parentWidget(); + } + return ws; +} - // Find corresponding sub-splitter. - // Find also index of appropriate item in current splitter. - int cur_ind = 0, item_ind = 0; - bool isBottom = false, isFound = false; - QSplitter* sub_split = NULL; - const QObjectList& objs = split->children(); - for ( QObjectList::const_iterator it = objs.begin(); it != objs.end() && !isFound; ++it ) +/*! + \brief Custom event filter. + + Process events from child widgets. + + \param o event receiver widget + \param e event + \return \c true if event should be filtered (stop further processing) +*/ +bool QtxWorkstackArea::eventFilter( QObject* o, QEvent* e ) +{ + if ( o->isWidgetType() ) { - QtxWorkstackArea* area = ::qobject_cast( *it ); - if ( area ) + QWidget* wid = (QWidget*)o; + if ( e->type() == QEvent::FocusIn || e->type() == QEvent::MouseButtonPress ) { - if ( area->contains( wid ) ) + bool ok = false; + while ( !ok && wid && wid != myClose ) { - item_ind = cur_ind; - isBottom = true; - isFound = true; + ok = wid == this; + wid = wid->parentWidget(); } - cur_ind++; + if ( ok ) + QApplication::postEvent( this, new WidgetEvent( (QEvent::Type)( e->type() == QEvent::FocusIn ? ActivateWidget : FocusWidget ) ) ); } - else if ( (*it)->inherits( "QSplitter" ) ) + } + return false; +} + +/*! + \brief Get rectangle to be drawn when highlighting drop area. + \return area drop rectangle +*/ +QRect QtxWorkstackArea::floatRect() const +{ + QRect r = myStack->geometry(); + return QRect( mapToGlobal( r.topLeft() ), mapToGlobal( r.bottomRight() ) ); +} + +/*! + \brief Get rectangle to be drawn when highlighting drop area on tab bar. + \param idx tab index + \return tab bar drop rectrangle +*/ +QRect QtxWorkstackArea::floatTab( const int idx ) const +{ + QRect r = myBar->tabRect( idx ); + return QRect( myBar->mapToGlobal( r.topLeft() ), r.size() ); +} + +/*! + \brief Get tab index by point. + \param p point + \return tab covering point or -1 if there is no tab covering point +*/ +int QtxWorkstackArea::tabAt( const QPoint& pnt ) const +{ + int idx = -1; + QPoint p = myBar->mapFromGlobal( pnt ); + for ( int i = 0; i < myBar->count() && idx == -1; i++ ) + { + QRect r = myBar->tabRect( i ); + if ( r.isValid() && r.contains( p ) ) + idx = i; + } + return idx; +} + +/*! + \brief Event handler for custom events. + \param e custom event +*/ +void QtxWorkstackArea::customEvent( QEvent* e ) +{ + WidgetEvent* we = (WidgetEvent*)e; + + switch ( we->type() ) + { + case ActivateWidget: + emit activated( activeWidget() ); + break; + case FocusWidget: + if ( activeWidget() ) { - QList areaList; - areas( (QSplitter*)(*it), areaList, true ); - for ( QList::iterator ita = areaList.begin(); ita != areaList.end() && !isFound; ++ita ) + if ( !activeWidget()->focusWidget() ) + activeWidget()->setFocus(); + else { - if ( (*ita)->contains( wid ) ) + if ( activeWidget()->focusWidget()->hasFocus() ) { - item_ind = cur_ind; - isFound = true; - sub_split = (QSplitter*)*it; - } + QFocusEvent in( QEvent::FocusIn ); + QApplication::sendEvent( this, &in ); + } + else + activeWidget()->focusWidget()->setFocus(); } - cur_ind++; } + break; + case RemoveWidget: + removeWidget( we->widget() ); + break; + default: + break; } +} - if ( !isFound ) - return ( need_pos - splitter_pos ); +/*! + \brief Customize focus in event handler. + \param e focus in event +*/ +void QtxWorkstackArea::focusInEvent( QFocusEvent* e ) +{ + QFrame::focusInEvent( e ); - if ( split->orientation() == o ) - { - // Find coordinates of near and far sides of the appropriate item relatively current splitter - int splitter_size = ( o == Qt::Horizontal ? split->width() : split->height() ); - QIntList szList = split->sizes(); - int nb = szList.count(); - int item_rel_pos = 0; // position of near side of item relatively this splitter - for (int i = 0; i < item_ind; i++) { - item_rel_pos += szList[i]; - } - int item_size = szList[item_ind]; // size of item - int item_pos = splitter_pos + item_rel_pos; + emit activated( activeWidget() ); +} - // Resize splitter items to complete the conditions - if (isBottom) { - // I. Bottom of splitters stack reached +/*! + \brief Customize mouse press event handler. + \param e mouse press event +*/ +void QtxWorkstackArea::mousePressEvent( QMouseEvent* e ) +{ + QFrame::mousePressEvent( e ); - int delta = positionSimple(szList, nb, splitter_size, item_ind, item_rel_pos, need_pos, splitter_pos); - split->setSizes(szList); - // Recompute delta, as some windows can reject given size - int new_item_rel_pos = 0; - QIntList szList1 = split->sizes(); - for (int i = 0; i < item_ind; i++) { - new_item_rel_pos += szList1[i]; - } - delta = need_pos - (splitter_pos + new_item_rel_pos); - return delta; + emit activated( activeWidget() ); +} - } else { - // II. Bottom of splitters stack is not yet reached +/*! + \brief Called when user presses "Close" button. +*/ +void QtxWorkstackArea::onClose() +{ + QWidget* wid = activeWidget(); + if ( wid ) + wid->close(); +} - if (item_ind == 0) { // cannot move in this splitter - // Process in sub-splitter - return setPosition(wid, sub_split, o, need_pos, splitter_pos); - } +/*! + \brief Called when user selects any tab page. + \param idx tab page index (not used) +*/ +void QtxWorkstackArea::onCurrentChanged( int /*idx*/ ) +{ + updateCurrent(); - int new_prev = 0; - int new_this = szList[item_ind]; - int new_next = 0; + emit activated( activeWidget() ); +} - if (need_pos < splitter_pos) { - // Set size of all previous workareas to zero <-- - if (item_ind == nb - 1) { - new_this = splitter_size; - } else { - new_next = (splitter_size - new_this) / (nb - item_ind - 1); - } - setSizes (szList, item_ind, new_prev, new_this, new_next); - split->setSizes(szList); - // Recompute splitter_pos, as some windows can reject given size - int new_item_rel_pos = 0; - QIntList szList1 = split->sizes(); - for (int i = 0; i < item_ind; i++) { - new_item_rel_pos += szList1[i]; - } - // Process in sub-splitter - return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos); - } else if (need_pos > (splitter_pos + splitter_size)) { - // Set size of all next workareas to zero --> - new_prev = (splitter_size - new_this) / item_ind; - setSizes (szList, item_ind, new_prev, new_this, new_next); - split->setSizes(szList); - // Recompute splitter_pos, as some windows can reject given size - int new_item_rel_pos = 0; - QIntList szList1 = split->sizes(); - for (int i = 0; i < item_ind; i++) { - new_item_rel_pos += szList1[i]; - } - // Process in sub-splitter - return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos); - } else { - // Set appropriate size of all previous/next items <-> - int new_item_rel_pos = item_rel_pos; - if (need_pos < item_pos || (item_pos + item_size) < need_pos) { - // Move item inside splitter into required position <-> - int new_this = szList[item_ind]; - int new_next = 0; - new_item_rel_pos = need_pos - splitter_pos; - if ((item_pos + item_size) < need_pos) { - //new_item_rel_pos = need_pos - (item_pos + item_size); - new_item_rel_pos = item_rel_pos + (need_pos - (item_pos + item_size)); - } - int new_prev = new_item_rel_pos / item_ind; - if (need_pos < (splitter_pos + item_rel_pos)) { - // Make previous workareas smaller, next - bigger - // No problem to keep old size of the widget - } else { - // Make previous workareas bigger, next - smaller - if (new_this > splitter_size - new_item_rel_pos) { - new_this = splitter_size - new_item_rel_pos; - } - } - if (item_ind == nb - 1) { - new_this = splitter_size - new_item_rel_pos; - } else { - new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1); - } - setSizes (szList, item_ind, new_prev, new_this, new_next); - split->setSizes(szList); - // Recompute new_item_rel_pos, as some windows can reject given size - new_item_rel_pos = 0; - QIntList szList1 = split->sizes(); - for (int i = 0; i < item_ind; i++) { - new_item_rel_pos += szList1[i]; - } - } else { - // Do nothing - } - // Process in sub-splitter - int add_pos = setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos); - if (add_pos == 0) - return 0; +/*! + \brief Called when user starts tab page dragging. +*/ +void QtxWorkstackArea::onDragActiveTab() +{ + QtxWorkstackChild* c = child( activeWidget() ); + if ( !c ) + return; - // this can be if corresponding workarea is first in sub-splitter - // or sub-splitter has another orientation + new QtxWorkstackDrag( workstack(), c ); +} - // Resize ones again to reach precize position <-> - int need_pos_1 = splitter_pos + new_item_rel_pos + add_pos; +/*! + \brief Called when area's child widget container is destroyed. + \param obj widget container being destroyed +*/ +void QtxWorkstackArea::onChildDestroyed( QObject* obj ) +{ + QtxWorkstackChild* child = (QtxWorkstackChild*)obj; + myStack->removeWidget( child ); - // Move workarea inside splitter into required position <-> - int delta_1 = positionSimple(szList, nb, splitter_size, item_ind, - new_item_rel_pos, need_pos_1, splitter_pos); - split->setSizes(szList); - // Recompute new_item_rel_pos, as some windows can reject given size - new_item_rel_pos = 0; - QIntList szList1 = split->sizes(); - for (int i = 0; i < item_ind; i++) { - new_item_rel_pos += szList1[i]; - } - delta_1 = need_pos_1 - (splitter_pos + new_item_rel_pos); - return delta_1; - } - } - } else { - return setPosition(wid, sub_split, o, need_pos, splitter_pos); + QWidget* wid = 0; + for ( ChildMap::ConstIterator it = myChild.begin(); it != myChild.end() && !wid; ++it ) + { + if ( it.value() == child ) + wid = it.key(); } - return 0; + myChild.remove( wid ); + + QApplication::postEvent( this, new WidgetEvent( (QEvent::Type)RemoveWidget, wid ) ); } /*! - Redistributes space among widgets equally + \brief Called when child widget container is shown. + \param c child widget container being shown */ -void QtxWorkstack::distributeSpace( QSplitter* split ) const +void QtxWorkstackArea::onChildShown( QtxWorkstackChild* c ) { - if ( !split ) + setWidgetShown( c->widget(), true ); +} + +/*! + \brief Called when child widget container is hidden. + \param c child widget container being hidden +*/ +void QtxWorkstackArea::onChildHidden( QtxWorkstackChild* c ) +{ + setWidgetShown( c->widget(), false ); +} + +/*! + \brief Called when child widget container is activated. + \param c child widget container being activated +*/ +void QtxWorkstackArea::onChildActivated( QtxWorkstackChild* c ) +{ + setWidgetActive( c->widget() ); +} + +/*! + \brief Called when child widget container's title is changed. + \param c child widget container which title is changed +*/ +void QtxWorkstackArea::onChildCaptionChanged( QtxWorkstackChild* c ) +{ + updateTab( c->widget() ); +} + +/*! + \brief Update current child widget container. + + Raises widget when active tab page is changed. +*/ +void QtxWorkstackArea::updateCurrent() +{ + QMap map; + for ( QWidgetList::iterator it = myList.begin(); it != myList.end(); ++it ) + { + map.insert( *it, isBlocked( *it ) ); + setBlocked( *it, true ); + } + + QWidget* cur = child( widget( myBar->tabId( myBar->currentIndex() ) ) ); + if ( cur ) + myStack->setCurrentWidget( cur ); + + for ( QWidgetList::iterator itr = myList.begin(); itr != myList.end(); ++itr ) + setBlocked( *itr, map.contains( *itr ) ? map[*itr] : false ); +} + +/*! + \brief Update tab bar. + \param wid tab page widget +*/ +void QtxWorkstackArea::updateTab( QWidget* wid ) +{ + int idx = myBar->indexOf( widgetId( wid ) ); + if ( idx < 0 ) return; - QIntList szList = split->sizes(); - int size = ( split->orientation() == Qt::Horizontal ? - split->width() : split->height() ) / szList.count(); - for ( QIntList::iterator it = szList.begin(); it != szList.end(); ++it ) - *it = size; - split->setSizes( szList ); + myBar->setTabIcon( idx, wid->windowIcon() ); + myBar->setTabText( idx, wid->windowTitle() ); } /*! - Splits widgets vertically + \brief Get child widget by specified identifier. + \param id widget ID + \return widget or 0, if identifier in invalid */ -void QtxWorkstack::splitVertical() +QWidget* QtxWorkstackArea::widget( const int id ) const { - split( Qt::Horizontal ); + QWidget* wid = 0; + for ( WidgetInfoMap::ConstIterator it = myInfo.begin(); it != myInfo.end() && !wid; ++it ) + { + if ( it.value().id == id ) + wid = it.key(); + } + return wid; } /*! - Splits widgets horizontally + \brief Get child widget identifier. + \param wid widget + \return widget ID or -1 if widget is not found */ -void QtxWorkstack::splitHorizontal() +int QtxWorkstackArea::widgetId( QWidget* wid ) const { - split( Qt::Vertical ); + int id = -1; + if ( myInfo.contains( wid ) ) + id = myInfo[wid].id; + return id; } /*! - SLOT: called if action "Rename" is activated, changes caption of widget + \brief Get child widget's visibility. + \param wid widget + \return \c true if widget is visible */ -void QtxWorkstack::onRename() +bool QtxWorkstackArea::widgetVisibility( QWidget* wid ) const { - if ( !myWorkWin ) + bool res = false; + if ( myInfo.contains( wid ) ) + res = myInfo[wid].vis; + return res; +} + +/*! + \brief Set active child widget. + \param wid widget to be set active +*/ +void QtxWorkstackArea::setWidgetActive( QWidget* wid ) +{ + int id = widgetId( wid ); + if ( id < 0 ) return; - bool ok = false; - QString newName = QInputDialog::getText( topLevelWidget(), tr( "Rename" ), tr( "Enter new name:" ), - QLineEdit::Normal, myWorkWin->windowTitle(), &ok ); - if ( ok && !newName.isEmpty() ) - myWorkWin->setWindowTitle( newName ); + myBar->setCurrentIndex( myBar->indexOf( id ) ); +} + +/*! + \brief Show/hide child widget. + \param wid widget + \param on new visibility state +*/ +void QtxWorkstackArea::setWidgetShown( QWidget* wid, const bool on ) +{ + if ( isBlocked( wid ) || !myInfo.contains( wid ) || myInfo[wid].vis == on ) + return; + + myInfo[wid].vis = on; + updateState(); +} + +/*! + \brief Update internal state. +*/ +void QtxWorkstackArea::updateState() +{ + bool updBar = myBar->updatesEnabled(); + bool updStk = myStack->updatesEnabled(); + myBar->setUpdatesEnabled( false ); + myStack->setUpdatesEnabled( false ); + + bool block = myBar->signalsBlocked(); + myBar->blockSignals( true ); + + QWidget* prev = activeWidget(); + + int idx = 0; + for ( QWidgetList::iterator it = myList.begin(); it != myList.end(); ++it ) + { + QWidget* wid = *it; + int id = widgetId( wid ); + + if ( id < 0 ) + continue; + + bool vis = widgetVisibility( wid ); + + int cIdx = myBar->indexOf( id ); + if ( cIdx != -1 && ( !vis || myBar->indexOf( id ) != idx ) ) + myBar->removeTab( cIdx ); + + if ( myBar->indexOf( id ) == -1 && vis ) + myBar->setTabId( myBar->insertTab( idx, wid->windowTitle() ), id ); + + updateTab( wid ); + + bool block = isBlocked( wid ); + setBlocked( wid, true ); + + QtxWorkstackChild* cont = child( wid ); + + if ( !vis ) + myStack->removeWidget( cont ); + else if ( myStack->indexOf( cont ) < 0 ) + myStack->addWidget( cont ); + + if ( vis ) + idx++; + + setBlocked( wid, block ); + } + + int curId = widgetId( prev ); + if ( myBar->indexOf( curId ) < 0 ) + { + QWidget* wid = 0; + int pos = myList.indexOf( prev ); + for ( int i = pos - 1; i >= 0 && !wid; i-- ) + { + if ( widgetVisibility( myList.at( i ) ) ) + wid = myList.at( i ); + } + + for ( int j = pos + 1; j < (int)myList.count() && !wid; j++ ) + { + if ( widgetVisibility( myList.at( j ) ) ) + wid = myList.at( j ); + } + + if ( wid ) + curId = widgetId( wid ); + } + + myBar->setCurrentIndex( myBar->indexOf( curId ) ); + + myBar->blockSignals( block ); + + updateCurrent(); + + myBar->updateActiveState(); + + myBar->setUpdatesEnabled( updBar ); + myStack->setUpdatesEnabled( updStk ); + if ( updBar ) + myBar->update(); + if ( updStk ) + myStack->update(); + + QResizeEvent re( myBar->size(), myBar->size() ); + QApplication::sendEvent( myBar, &re ); + + if ( isEmpty() ) + { + hide(); + emit deactivated( this ); + } + else + { + show(); + if ( prev != activeWidget() ) + emit activated( activeWidget() ); + } } /*! - Wraps area into new splitter - \return new splitter + \brief Generate unique widget identifier. + \return first non shared widget ID */ -QSplitter* QtxWorkstack::wrapSplitter( QtxWorkstackArea* area ) +int QtxWorkstackArea::generateId() const { - if ( !area ) - return 0; - - QSplitter* pSplit = splitter( area ); - if ( !pSplit ) - return 0; - - bool upd = pSplit->updatesEnabled(); - pSplit->setUpdatesEnabled( false ); - - QIntList szList = pSplit->sizes(); - - QSplitter* wrap = new QSplitter( 0 ); -#if defined QT_VERSION && QT_VERSION >= 0x30200 - wrap->setChildrenCollapsible( false ); -#endif - pSplit->insertWidget( pSplit->indexOf( area ) + 1, wrap ); - wrap->setVisible( true ); - wrap->addWidget( area ); + QMap map; - pSplit->setSizes( szList ); + for ( WidgetInfoMap::const_iterator it = myInfo.begin(); it != myInfo.end(); ++it ) + map.insert( it.value().id, 0 ); - pSplit->setUpdatesEnabled( upd ); + int id = 0; + while ( map.contains( id ) ) + id++; - return wrap; + return id; } /*! - Reparenst and adds widget - \param wid - widget - \param pWid - parent widget - \param after - after widget + \brief Check if the child wiget is blocked. + \param wid widget + \return \c true if the widget is blocked */ -void QtxWorkstack::insertWidget( QWidget* wid, QWidget* pWid, QWidget* after ) +bool QtxWorkstackArea::isBlocked( QWidget* wid ) const { - if ( !wid || !pWid ) - return; - - QWidgetList moveList; - const QObjectList& lst = pWid->children(); - bool found = false; - for ( QObjectList::const_iterator it = lst.begin(); it != lst.end(); ++it ) - { - if ( found && ( (*it)->inherits( "QSplitter" ) || - (*it)->inherits( "QtxWorkstackArea" ) ) ) - moveList.append( (QWidget*)(*it) ); - if ( *it == after ) - found = true; - } - - QMap map; - for ( QWidgetList::iterator it = moveList.begin(); it != moveList.end(); ++it ) - { - map.insert( *it, (*it)->isVisibleTo( (*it)->parentWidget() ) ); - (*it)->setParent( 0 ); - (*it)->hide(); - } - - wid->setParent( pWid ); - - for ( QWidgetList::iterator itr = moveList.begin(); itr != moveList.end(); ++itr ) - { - (*itr)->setParent( pWid ); - (*itr)->setShown( map.contains( *itr ) ? map[*itr] : false ); - } + return myBlock.contains( wid ); } /*! -* \brief Closes the active window. + \brief Block widget. + \param wid widget + \param on new blocked state */ -void QtxWorkstack::onCloseWindow() +void QtxWorkstackArea::setBlocked( QWidget* wid, const bool on ) { - if ( myWorkWin ) - myWorkWin->close(); - else if( activeWindow() ) - activeWindow()->close(); + if ( on ) + myBlock.insert( wid, 0 ); + else + myBlock.remove( wid ); } /*! - SLOT: called on area is destroyed - Sets focus to neighbour area + \brief Get child widget container. + \param wid child widget + \return child widget container corresponding to the \a wid */ -void QtxWorkstack::onDestroyed( QObject* obj ) +QtxWorkstackChild* QtxWorkstackArea::child( QWidget* wid ) const { - QtxWorkstackArea* area = (QtxWorkstackArea*)obj; + QtxWorkstackChild* res = 0; + if ( myChild.contains( wid ) ) + res = myChild[wid]; + return res; +} - if ( area == myArea ) - myArea = 0; +/*! + \fn void QtxWorkstackArea::activated( QWidget* w ) + \brief Emitted when child widget is activated. + \param w child widget being activated +*/ - if ( !myArea ) - { - QtxWorkstackArea* cur = neighbourArea( area ); - if ( cur ) - cur->setFocus(); - } +/*! + \fn void QtxWorkstackArea::contextMenuRequested( QWidget* w, QPoint p ) + \brief Emitted when context popup menu is requested. + \param w child widget popup menu requested for + \param p point popup menu to be shown at +*/ - QApplication::postEvent( this, new QEvent( QEvent::User ) ); -} +/*! + \fn void QtxWorkstackArea::deactivated( QtxWorkstackArea* wa ) + \brief Emitted when workarea is deactivated. + \param wa workarea being deactivated +*/ + +/*! + \class QtxWorkstackChild + \internal + \brief Workarea child widget container. +*/ /*! - SLOT: called on window activating + \brief Constructor. + \param wid child widget + \param parent parent widget + \param f widget flags */ -void QtxWorkstack::onWindowActivated( QWidget* ) +QtxWorkstackChild::QtxWorkstackChild( QWidget* wid, QWidget* parent, Qt::WindowFlags f ) +: QWidget( parent ), + myWidget( wid ) { - const QObject* obj = sender(); - if ( !obj->inherits( "QtxWorkstackArea" ) ) - return; + myWidget->setParent( this, f ); + myWidget->installEventFilter( this ); + QVBoxLayout* base = new QVBoxLayout( this ); + base->addWidget( myWidget ); - setActiveArea( (QtxWorkstackArea*)obj ); + connect( myWidget, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); } /*! - SLOT: called on window deactivating + \brief Destructor. */ -void QtxWorkstack::onDeactivated( QtxWorkstackArea* area ) +QtxWorkstackChild::~QtxWorkstackChild() { - if ( myArea != area ) - return; - - QList lst; - areas( mySplit, lst, true ); + QApplication::instance()->removeEventFilter( this ); - int idx = lst.indexOf( area ); - if ( idx == -1 ) + if ( !widget() ) return; - myWin = 0; - myArea = 0; + disconnect( widget(), SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); - QtxWorkstackArea* newArea = neighbourArea( area ); - if ( newArea && newArea->activeWidget() ) - newArea->activeWidget()->setFocus(); + widget()->hide(); + widget()->removeEventFilter( this ); - QApplication::postEvent( this, new QEvent( QEvent::User ) ); + widget()->setParent( 0 ); } /*! - Creates and shows popup menu for area - \param w - area - \param p - popup position + \brief Get child widget. + \return child widget */ -void QtxWorkstack::onContextMenuRequested( QWidget* w, QPoint p ) +QWidget* QtxWorkstackChild::widget() const { - QtxWorkstackArea* anArea = ::qobject_cast( (QObject*)sender() ); - if ( !anArea ) - anArea = activeArea(); - - if ( !anArea ) - return; - - QWidgetList lst = anArea->widgetList(); - if ( lst.isEmpty() ) - return; + return myWidget; +} - myWorkWin = w; - myWorkArea = anArea; +/*! + \brief Custom event filter. - QMenu* pm = new QMenu(); - - if ( lst.count() > 1 ) - { - if ( myActionsMap[SplitVertical]->isEnabled() ) - pm->addAction( myActionsMap[SplitVertical] ); - if ( myActionsMap[SplitHorizontal]->isEnabled() ) - pm->addAction( myActionsMap[SplitHorizontal] ); - pm->addSeparator(); - } + Process events from child widgets. - if ( w ) + \param o event receiver widget + \param e event + \return \c true if event should be filtered (stop further processing) +*/ +bool QtxWorkstackChild::eventFilter( QObject* o, QEvent* e ) +{ + if ( o->isWidgetType() ) { - if ( myActionsMap[Close]->isEnabled() ) - pm->addAction( myActionsMap[Close] ); - if ( myActionsMap[Rename]->isEnabled() ) - pm->addAction( myActionsMap[Rename] ); - } - - Qtx::simplifySeparators( pm ); + if ( e->type() == QEvent::WindowTitleChange || e->type() == QEvent::WindowIconChange ) + emit captionChanged( this ); - if ( !pm->actions().isEmpty() ) - pm->exec( p ); + if ( !e->spontaneous() && ( e->type() == QEvent::Show || e->type() == QEvent::ShowToParent ) ) + emit shown( this ); - delete pm; + if ( !e->spontaneous() && ( e->type() == QEvent::Hide || e->type() == QEvent::HideToParent ) ) + emit hidden( this ); - myWorkWin = 0; - myWorkArea = 0; + if ( e->type() == QEvent::FocusIn ) + emit activated( this ); + } + return QWidget::eventFilter( o, e ); } -QWidget* QtxWorkstack::addWindow( QWidget* w, Qt::WindowFlags f ) +/*! + \brief Called when child widget is destroyed. + \param obj child widget being destroyed +*/ +void QtxWorkstackChild::onDestroyed( QObject* obj ) { - if ( !w ) - return 0; + if ( obj != widget() ) + return; - return targetArea()->insertWidget( w, -1, f ); + myWidget = 0; + deleteLater(); } /*! - Handler of custom events + \brief Customize child event handler. + \param e child event */ -void QtxWorkstack::customEvent( QEvent* ) +void QtxWorkstackChild::childEvent( QChildEvent* e ) { - updateState(); + if ( e->removed() && e->child() == widget() ) + { + myWidget = 0; + deleteLater(); + } + QWidget::childEvent( e ); } /*! - \return splitter corresponding to area - \param area + \fn void QtxWorkstackChild::shown( QtxWorkstackChild* w ) + \brief Emitted when child widget is shown. + \param w child widget container */ -QSplitter* QtxWorkstack::splitter( QtxWorkstackArea* area ) const -{ - if ( !area ) - return 0; - QSplitter* split = 0; +/*! + \fn void QtxWorkstackChild::hidden( QtxWorkstackChild* w ) + \brief Emitted when child widget is hidden. + \param w child widget container +*/ - QWidget* wid = area->parentWidget(); - if ( wid && wid->inherits( "QSplitter" ) ) - split = (QSplitter*)wid; +/*! + \fn void QtxWorkstackChild::activated( QtxWorkstackChild* w ) + \brief Emitted when child widget is activated. + \param w child widget container +*/ - return split; -} +/*! + \fn void QtxWorkstackChild::captionChanged( QtxWorkstackChild* w ) + \brief Emitted when child widget's title is changed. + \param w child widget container +*/ /*! - Fills list with children splitters - \param split - parent splitter - \param splitList - list to be filled with - \param rec - recursive search of children + \class QtxWorkstackTabBar + \internal + \brief Workstack tab bar widget */ -void QtxWorkstack::splitters( QSplitter* split, QList& splitList, const bool rec ) const + +/*! + \brief Constructor. + \param parent parent widget +*/ +QtxWorkstackTabBar::QtxWorkstackTabBar( QWidget* parent ) +: QTabBar( parent ), + myId( -1 ) { - if ( !split ) - return; + setDrawBase( true ); + setElideMode( Qt::ElideNone ); - const QObjectList& objs = split->children(); - for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it ) - { - if ( rec ) - splitters( (QSplitter*)*it, splitList, rec ); - if ( (*it)->inherits( "QSplitter" ) ) - splitList.append( (QSplitter*)*it ); - } + connect( this, SIGNAL( currentChanged( int ) ), this, SLOT( onCurrentChanged( int ) ) ); } /*! - Fills list with children areas - \param split - parent splitter - \param areaList - list to be filled with - \param rec - recursive search of children + \brief Destructor. */ -void QtxWorkstack::areas( QSplitter* split, QList& areaList, const bool rec ) const +QtxWorkstackTabBar::~QtxWorkstackTabBar() { - if ( !split ) - return; +} - const QObjectList& objs = split->children(); - for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it ) - { - if ( (*it)->inherits( "QtxWorkstackArea" ) ) - areaList.append( (QtxWorkstackArea*)*it ); - else if ( rec && (*it)->inherits( "QSplitter" ) ) - areas( (QSplitter*)*it, areaList, rec ); - } +/*! + \brief Get tab page identifier. + \param index tab page index + \return tab page ID or -1 if \a index is out of range +*/ +int QtxWorkstackTabBar::tabId( const int index ) const +{ + QVariant v = tabData( index ); + if ( !v.canConvert( QVariant::Int ) ) + return -1; + return v.toInt(); } /*! - \return active area + \brief Set tab page identifier. + \param index tab page index + \param id tab page ID */ -QtxWorkstackArea* QtxWorkstack::activeArea() const +void QtxWorkstackTabBar::setTabId( const int index, const int id ) { - return myArea; + setTabData( index, id ); } /*! - \return active area or current area or create new area of there is no one + \brief Get tab page index by specified identifier. + \param id tab page ID + \return tab page index or -1 if not found */ -QtxWorkstackArea* QtxWorkstack::targetArea() +int QtxWorkstackTabBar::indexOf( const int id ) const { - QtxWorkstackArea* area = activeArea(); - if ( !area ) - area = currentArea(); - if ( !area ) + int index = -1; + for ( int i = 0; i < (int)count() && index < 0; i++ ) { - QList lst; - areas( mySplit, lst ); - if ( !lst.isEmpty() ) - area = lst.first(); + if ( tabId( i ) == id ) + index = i; } - - if ( !area ) - area = createArea( mySplit ); - - return area; + return index; } /*! - \return current area (that has focus) + \brief Check if the tab bar is active. + \return \c true if tab bar is active */ -QtxWorkstackArea* QtxWorkstack::currentArea() const +bool QtxWorkstackTabBar::isActive() const { - QtxWorkstackArea* area = 0; - QWidget* wid = focusWidget(); - while ( wid && !area ) - { - if ( wid->inherits( "QtxWorkstackArea" ) ) - area = (QtxWorkstackArea*)wid; - wid = wid->parentWidget(); - } - - return area; + return myActive; } /*! - Creates new area + \brief Set tab bar active/inactive. + \param on new active state */ -QtxWorkstackArea* QtxWorkstack::createArea( QWidget* parent ) const +void QtxWorkstackTabBar::setActive( const bool on ) { - QtxWorkstackArea* area = new QtxWorkstackArea( parent ); - - connect( area, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); - connect( area, SIGNAL( activated( QWidget* ) ), this, SLOT( onWindowActivated( QWidget* ) ) ); - connect( area, SIGNAL( contextMenuRequested( QWidget*, QPoint ) ), - this, SLOT( onContextMenuRequested( QWidget*, QPoint ) ) ); - connect( area, SIGNAL( deactivated( QtxWorkstackArea* ) ), this, SLOT( onDeactivated( QtxWorkstackArea* ) ) ); + if ( myActive == on ) + return; - return area; + myActive = on; + updateActiveState(); } /*! - Sets area as active - \param area + \brief Update tab bar according to the 'active' state. */ -void QtxWorkstack::setActiveArea( QtxWorkstackArea* area ) +void QtxWorkstackTabBar::updateActiveState() { - QWidget* oldCur = myWin; - - QtxWorkstackArea* oldArea = myArea; - - myArea = area; - - if ( myArea != oldArea ) - { - if ( oldArea ) - oldArea->updateActiveState(); - if ( myArea ) - myArea->updateActiveState(); - } - - if ( myArea ) - myWin = myArea->activeWidget(); - - if ( myWin && oldCur != myWin ) - emit windowActivated( myWin ); + QColor bc = palette().color( QPalette::Text ); + QColor ac = isActive() ? palette().color( QPalette::Highlight ) : bc; + for ( int i = 0; i < (int)count(); i++ ) + setTabTextColor( i, currentIndex() == i ? ac : bc ); } /*! - \return neighbour area - \param area - area to search neighbour + \brief Called when current tab page is changed. + \param idx tab page index (not used) */ -QtxWorkstackArea* QtxWorkstack::neighbourArea( QtxWorkstackArea* area ) const +void QtxWorkstackTabBar::onCurrentChanged( int /*index*/ ) { - QList lst; - areas( mySplit, lst, true ); - int pos = lst.indexOf( area ); - if ( pos < 0 ) - return 0; - - QtxWorkstackArea* na = 0; - for ( int i = pos - 1; i >= 0 && !na; i-- ) - { - if ( !lst.at( i )->isEmpty() ) - na = lst.at( i ); - } - - for ( int j = pos + 1; j < (int)lst.count() && !na; j++ ) - { - if ( !lst.at( j )->isEmpty() ) - na = lst.at( j ); - } - return na; + updateActiveState(); } /*! - \return area covering point - \param p - point + \brief Customize mouse move event handler. + \param e mouse event */ -QtxWorkstackArea* QtxWorkstack::areaAt( const QPoint& p ) const +void QtxWorkstackTabBar::mouseMoveEvent( QMouseEvent* e ) { - QtxWorkstackArea* area = 0; - QList lst; - areas( mySplit, lst, true ); - for ( QList::iterator it = lst.begin(); it != lst.end() && !area; ++it ) + if ( myId != -1 && !tabRect( indexOf( myId ) ).contains( e->pos() ) ) { - QtxWorkstackArea* cur = *it; - QRect r = cur->geometry(); - if ( cur->parentWidget() ) - r = QRect( cur->parentWidget()->mapToGlobal( r.topLeft() ), r.size() ); - if ( r.contains( p ) ) - area = cur; + myId = -1; + emit dragActiveTab(); } - return area; + + QTabBar::mouseMoveEvent( e ); } /*! - Update + \brief Customize mouse press event handler. + \param e mouse event */ -void QtxWorkstack::updateState() +void QtxWorkstackTabBar::mousePressEvent( QMouseEvent* e ) { - updateState( mySplit ); + QTabBar::mousePressEvent( e ); + + if ( e->button() == Qt::LeftButton ) + myId = tabId( currentIndex() ); } /*! - Update splitters + \brief Customize mouse release event handler. + \param e mouse event */ -void QtxWorkstack::updateState( QSplitter* split ) +void QtxWorkstackTabBar::mouseReleaseEvent( QMouseEvent* e ) { - QList recList; - splitters( split, recList, false ); - for ( QList::iterator itr = recList.begin(); itr != recList.end(); ++itr ) - updateState( *itr ); - - QList splitList; - splitters( split, splitList, false ); - - QList areaList; - areas( split, areaList, false ); - - bool vis = false; - for ( QList::iterator it = areaList.begin(); it != areaList.end(); ++it ) - { - if ( (*it)->isEmpty() ) - (*it)->hide(); - else - { - (*it)->show(); - vis = true; - } - } - - if ( split == mySplit ) - return; + QTabBar::mouseReleaseEvent( e ); - for ( QList::iterator iter = splitList.begin(); iter != splitList.end() && !vis; ++iter ) - vis = (*iter)->isVisibleTo( (*iter)->parentWidget() ); + myId = -1; - if ( areaList.isEmpty() && splitList.isEmpty() ) - delete split; - else if ( vis ) - split->show(); - else - split->hide(); + if ( e->button() == Qt::RightButton ) + emit contextMenuRequested( e->globalPos() ); } /*! - Gets splitter info for debug - \param split - splitter - \param info - string to be filled with info + \brief Customize context menu event handler. + \param e context menu event */ -void QtxWorkstack::splitterInfo( QSplitter* split, QString& info ) const +void QtxWorkstackTabBar::contextMenuEvent( QContextMenuEvent* e ) { - if ( !split ) - return; - - const QObjectList& objs = split->children(); + if ( e->reason() != QContextMenuEvent::Mouse ) + emit contextMenuRequested( e->globalPos() ); +} - QString sizesStr; - QList sizes = split->sizes(); - for ( QList::iterator sIt = sizes.begin(); sIt != sizes.end(); ++sIt ) +/* +void QtxWorkstackTabBar::paintLabel( QPainter* p, const QRect& br, QTab* t, bool has_focus ) const +{ + if ( currentTab() != t->identifier() ) { - if ( *sIt > 1 ) // size 1 pixel usually means empty Workstack area, which will NOT be re-created, - sizesStr += QString( ":%1" ).arg( *sIt ); // so we don't need to store its size + QFont fnt = p->font(); + fnt.setUnderline( false ); + p->setFont( fnt ); } + QTabBar::paintLabel( p, br, t, has_focus ); +} +*/ - if ( !sizesStr.isEmpty() ) // cut the first ':' - sizesStr = sizesStr.right( sizesStr.length() - 1 ); +/*! + \fn void QtxWorkstackTabBar::dragActiveTab() + \brief Emitted when dragging operation is started. +*/ - info += QString( "(splitter orientation=%1 sizes=%3 " ).arg( split->orientation() ).arg( sizesStr ); - - for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it ) - { - if ( (*it)->inherits( "QSplitter" ) ) - splitterInfo( (QSplitter*)*it, info ); - else if ( (*it)->inherits( "QtxWorkstackArea" ) ) - { - QtxWorkstackArea* area = (QtxWorkstackArea*)*it; - if ( area->isEmpty() ) - continue; - info += QString( "(views active='%1'" ).arg( area->activeWidget()->objectName() ); - QWidgetList views = area->widgetList(); - for ( QWidgetList::iterator wIt = views.begin(); wIt != views.end(); ++wIt ) - info += QString( " '%1'" ).arg( (*wIt)->objectName() ); - info += ')'; - } - } +/*! + \fn void QtxWorkstackTabBar::contextMenuRequested( QPoint p ) + \brief Emitted when context popup menu is requested. + \param p point popup menu to be shown at +*/ - info += ')'; - printf( (const char*)QString( info + '\n' ).toLatin1() ); -} +/*! + \class QtxWorkstack + \brief Workstack widget. + Organizes the child widgets in the tabbed space. + Allows splitting the working area to arrange the child widgets in + arbitrary way. Any widgets can be moved to another working area with + drag-n-drop operation. -//Cuts starting '(' symbol and ending '(' symbol -void cutBrackets( QString& parameters ) -{ - QChar c1 = parameters[0]; - QChar c2 = parameters[int(parameters.length()-1)]; - if ( !parameters.isEmpty() && c1 == '(' && c2 == ')' ) - parameters = parameters.mid( 1, parameters.length()-2 ); -} + This widget can be used as workspace of the application main window, + for example, as kind of implementation of multi-document interface. +*/ -/* - for strings like "(splitter orientation=0 children=2 sizes=332:478" returns values of - parameters. For example, getValue( example, "children" ) returns "2" - getValue( example, "sizes" ) returns "332:478" +/*! + \brief Constructor. + \param parent parent widget */ -QString getValue( const QString& str, const QString& valName ) +QtxWorkstack::QtxWorkstack( QWidget* parent ) +: QWidget( parent ), + myWin( 0 ), + myArea( 0 ), + myWorkWin( 0 ), + myWorkArea( 0 ) { - int i = str.indexOf( valName ); - if ( i != -1 ) - { - int equal_i = str.indexOf( '=', i ); - if ( equal_i != -1 ) - { - int space_i = str.indexOf( ' ', ++equal_i ); - if ( space_i != -1 ) - return str.mid( equal_i, space_i - equal_i ); - } - } - return QString(); + myActionsMap.insert( SplitVertical, new QtxAction( QString(), tr( "Split vertically" ), 0, this ) ); + myActionsMap.insert( SplitHorizontal, new QtxAction( QString(), tr( "Split horizontally" ), 0, this ) ); + myActionsMap.insert( Close, new QtxAction( QString(), tr( "Close" ), 0, this ) ); + myActionsMap.insert( Rename, new QtxAction( QString(), tr( "Rename" ), 0, this ) ); + + connect( myActionsMap[SplitVertical], SIGNAL( triggered( bool ) ), this, SLOT( splitVertical() ) ); + connect( myActionsMap[SplitHorizontal], SIGNAL( triggered( bool ) ), this, SLOT( splitHorizontal() ) ); + connect( myActionsMap[Close], SIGNAL( triggered( bool ) ), this, SLOT( onCloseWindow() ) ); + connect( myActionsMap[Rename], SIGNAL( triggered( bool ) ), this, SLOT( onRename() ) ); + + QVBoxLayout* base = new QVBoxLayout( this ); + base->setMargin( 0 ); + + mySplit = new QSplitter( this ); + mySplit->setChildrenCollapsible( false ); + base->addWidget( mySplit ); } -/* - checks format of splitter parameters string +/*! + \brief Destructor. */ -bool checkFormat( const QString& parameters ) +QtxWorkstack::~QtxWorkstack() { - QString params( parameters ); - // 1. begins and ends with brackets - QChar c1 = params[0]; - QChar c2 = params[int(params.length()-1)]; - bool ok = ( c1 == '(' && c2 == ')' ); - if ( !ok ) return ok; - ::cutBrackets( params ); - // 2. has splitter word - ok = ( params.left( 8 ) == "splitter" ); - if ( !ok ) return ok; - // 3. has children? = '(' is found - int i = params.indexOf( '(' ); - ok = i != -1; - if ( !ok ) return ok; - params = params.left( i ); // cut all children, they will be checked later - // 4. has orientation word and correct value - ::getValue( params, "orientation" ).toInt( &ok ); - if ( !ok ) return ok; - // 5. has sizes word and values - ok = ! ::getValue( params, "sizes" ).isEmpty(); - if ( !ok ) return ok; - // 6. check children -> number of '(' == number of ')' in original string - ok = ( parameters.contains( '(' ) == parameters.contains( ')' ) ); - return ok; } -/* - Returns children of splitter in a list. Children are separated by '(' and ')' symbols +/*! + \brief Get all child widgets in all workareas. + \return list of widgets in all workareas */ -QStringList getChildren( const QString& str ) +QWidgetList QtxWorkstack::windowList() const { - QStringList lst; - if ( !str.startsWith( "(" ) ) - return lst; - - int i = 1, - nOpen = 1, // count brackets: '(' increments nOpen, ')' decrements - start = 0; - while ( i < (int)str.length() ) + QList lst; + areas( mySplit, lst, true ); + + QWidgetList widList; + for ( QList::iterator it = lst.begin(); it != lst.end(); ++it ) { - if ( str[i] == '(' ) - { - nOpen++; - if ( nOpen == 1 ) - start = i; - } - else if ( str[i] == ')' ) - { - nOpen--; - if ( nOpen == 0 ) - lst.append( str.mid( start, i-start+1 ) ); - } - i++; + QWidgetList wids = (*it)->widgetList(); + for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr ) + widList.append( *itr ); } - return lst; + return widList; } -// for a string like "views active='AnotherView' 'GLView' 'AnotherView'" -// getViewName( example, 0 ) returns "GLView", -// getViewName( example, 1 ) -> "AnotherView", etc. -QString getViewName( const QString& str, int i ) +/*! + \brief Get all child widgets in the active workarea. + \return list of widgets in active workarea +*/ +QWidgetList QtxWorkstack::splitWindowList() const { - QRegExp exp( "\\s'\\w+'" ); - int start = 0; // start index of view name in the string - int num = 0 ; // index of found match - while ( ( start = exp.indexIn( str, start ) ) != -1 && num < i ) - { - start += exp.matchedLength(); - num ++; - } - if ( start != -1 ) // +2 and -3 avoid starting space and starting and ending ' symbols - return str.mid( start + 2, exp.matchedLength() - 3 ); - - return QString(); + return myArea ? myArea->widgetList() : QWidgetList(); } -// returns widget with given name -QWidget* getView( const QWidget* parent, const QString& aName ) +/*! + \brief Get active widget. + \return active widget +*/ +QWidget* QtxWorkstack::activeWindow() const { - QWidget* view = 0; - QList l = qFindChildren( parent->topLevelWidget(), aName ); - if ( !l.isEmpty() ) - view = ::qobject_cast( l.first() ); - return view; + return myWin; } /*! - Installs a splitter described by given parameters string + \brief Split workstack. + + Splitting is possible only if there are two or more widgets in the workarea. + This function splits current workarea to two new ones. + + \param o splitting orientation (Qt::Orientation) */ -void QtxWorkstack::setSplitter( QSplitter* splitter, const QString& parameters, QMap >& sMap ) +void QtxWorkstack::split( const int o ) { - printf( QString( parameters + '\n' ).toLatin1() ); - if ( !::checkFormat( parameters ) ) { - printf( "\nInvalid format of workstack parameters. Positions of viewers can not be restored.\n" ); + QtxWorkstackArea* area = myWorkArea; + if ( !area ) + area = activeArea(); + if ( !area ) return; - } - QString params( parameters ); - ::cutBrackets( params ); + if ( area->widgetList().count() < 2 ) + return; - // get splitter sizes and store it in the map for future setting - QList sizes; - QStringList sizesLst = ::getValue( params, "sizes" ).split( ':', QString::SkipEmptyParts ); - QStringList::Iterator it; - for ( it = sizesLst.begin(); it != sizesLst.end(); ++it ) - sizes.append( (*it).toInt() ); - sMap[ splitter ] = sizes; + QWidget* curWid = area->activeWidget(); + if ( !curWid ) + return; - // set orientation of splitter - int orient = ::getValue( params, "orientation" ).toInt(); - splitter->setOrientation( (Qt::Orientation)orient ); + QSplitter* s = splitter( area ); + QList areaList; + areas( s, areaList ); - // get children - QString options = params.left( params.indexOf( '(' ) ); - QString childrenStr = params.right( params.length()-options.length() ); - QStringList children = ::getChildren( childrenStr ); + QList splitList; + splitters( s, splitList ); - // debug output.. - // printf (" splitter orient=%d, sizes_count=%d, children=%d\n", orient, sizes.count(), children.count() ); - // for ( QStringList::Iterator tit = children.begin(); tit != children.end(); ++tit ) - // printf (" |-> child = [%s]\n", (*tit).latin1() ); + QSplitter* trg = 0; + if ( areaList.count() + splitList.count() < 2 || s->orientation() == o ) + trg = s; - for ( it = children.begin(); it != children.end(); ++it ) - { - if ( (*it).startsWith( "(splitter" ) ) - { - QSplitter* newSplitter = new QSplitter( splitter ); - setSplitter( newSplitter, *it, sMap ); - } - else if ( (*it).startsWith( "(views" ) ) - { - QtxWorkstackArea* newArea = createArea( splitter ); - QString activeViewName = ::getValue( *it, "active" ); - QWidget* activeView = 0; - activeViewName = activeViewName.mid( 1, activeViewName.length()-2 ); // chop off ' symbols - int i = 0; - QString viewName = ::getViewName( *it, i ); - while ( !viewName.isEmpty() ) - { - if ( QWidget* view = ::getView( splitter, viewName ) ) - { - newArea->insertWidget( view ); - if ( activeViewName == view->objectName() ) - activeView = view; - } - viewName = ::getViewName( *it, ++i ); - } - if ( activeView ) - newArea->setActiveWidget( activeView ); - } - } + if ( !trg ) + trg = wrapSplitter( area ); + + if ( !trg ) + return; + + trg->setOrientation( (Qt::Orientation)o ); + + QtxWorkstackArea* newArea = createArea( 0 ); + trg->insertWidget( trg->indexOf( area ) + 1, newArea ); + + area->removeWidget( curWid ); + newArea->insertWidget( curWid ); + + distributeSpace( trg ); + + curWid->show(); + curWid->setFocus(); } /*! - Restore workstack's configuration stored in 'parameters' string + \brief Split workarea of the given widget on two parts. + + Splitting is possible only if there are two or more widgets in the workarea. + This function splits current workarea to two new ones. + + \param wid widget belonging to the workstack + \param o splitting orientation type (Qt::Orientation) + \param type splitting type (QtxWorkstack::SplitType) */ -QtxWorkstack& QtxWorkstack::operator<<( const QString& parameters ) +void QtxWorkstack::Split( QWidget* wid, const Qt::Orientation o, const SplitType type ) { - // clear the main splitter - remove all child splitters and empty areas from it - QList splitList; - QList areaList; - splitters( mySplit, splitList, false ); - areas( mySplit, areaList, false ); - for ( QList::iterator iter = splitList.begin(); iter != splitList.end(); ++iter ) - delete *iter; + if (!wid) return; - for ( QList::iterator it = areaList.begin(); it != areaList.end(); ++it ) + // find area of the given widget + QtxWorkstackArea* area = NULL; + QList allAreas; + areas(mySplit, allAreas, true); + + + for ( QList::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it ) { - if ( (*it)->isEmpty() ) - delete *it; + if ( (*it)->contains( wid ) ) + area = *it; } - // restore splitter recursively - QMap< QSplitter*, QList > sMap; - setSplitter( mySplit, parameters, sMap ); + if ( !area ) + return; - // now mySplit may contains empty area (where all views were located before restoring) - // in order setSize to work correctly we have to exclude this area - areaList.clear(); - areas( mySplit, areaList, false ); - for ( QList::iterator delIt = areaList.begin(); delIt != areaList.end(); ++delIt ) + QWidgetList wids = area->widgetList(); + if ( wids.count() < 2 ) + return; + + QSplitter* s = splitter( area ); + QList areaList; + areas( s, areaList ); + + QList splitList; + splitters(s, splitList); + + QSplitter* trg = 0; + if (areaList.count() + splitList.count() < 2 || s->orientation() == o) + trg = s; + + if (!trg) trg = wrapSplitter(area); + if (!trg) return; + + trg->setOrientation(o); + + QtxWorkstackArea* newArea = createArea(0); + insertWidget(newArea, trg, area); + + switch ( type ) { - if ( (*delIt)->isEmpty() ) - delete *delIt; + case SplitStay: + for ( QWidgetList::iterator itr = wids.begin(); itr != wids.end(); ++itr ) + { + QWidget* wid_i = *itr; + if ( wid_i != wid ) + { + area->removeWidget( wid_i ); + newArea->insertWidget( wid_i ); + } + } + break; + case SplitAt: + { + QWidgetList::iterator itr = wids.begin(); + for ( ; itr != wids.end() && *itr != wid; ++itr ) + { + } + for ( ; itr != wids.end(); ++itr ) + { + area->removeWidget( *itr ); + newArea->insertWidget( *itr ); + } + } + break; + case SplitMove: + area->removeWidget( wid ); + newArea->insertWidget( wid ); + break; } - QApplication::instance()->processEvents(); - - // restore splitters' sizes (map of sizes is filled in setSplitters) - for ( QMap< QSplitter*, QList >::iterator itm = sMap.begin(); itm != sMap.end(); ++itm ) - itm.key()->setSizes( itm.value() ); - - return (*this); + distributeSpace( trg ); } /*! - Example of string produced by operator>> : - "(splitter orientation=0 sizes=186:624 (views active='OCCViewer_0_0' 'OCCViewer_0_0') -/ (views active='VTKViewer_0_0' 'VTKViewer_0_0'))" -*/ -QtxWorkstack& QtxWorkstack::operator>>( QString& outParameters ) -{ - splitterInfo( mySplit, outParameters ); - return (*this); -} - - -class QtxWorkstackArea::WidgetEvent : public QEvent -{ -public: - WidgetEvent( Type t, QWidget* w = 0 ) : QEvent( t ), myWidget( w ) {}; + \brief Move widget(s) from the source workarea into the target workarea + or reorder widgets inside one workarea. - QWidget* widget() const { return myWidget; } + Move \a wid2 in target workarea. Put it right after \a wid1. + If \a all parameter is \c true, all widgets from source workarea + will be moved including \a wid2 and source workarea will be deleted then. -private: - QWidget* myWidget; -}; + If \a wid1 and \a wid2 belongs to one workarea, widgets will be just reordered + in that workarea. -/*! - Constructor + \param wid1 widget from target workarea + \param wid2 widget from source workarea + \param all if \c true, all widgets from source workarea will + be moved into the target one, else only the \a wid2 will be moved */ -QtxWorkstackArea::QtxWorkstackArea( QWidget* parent ) -: QFrame( parent ) +void QtxWorkstack::Attract( QWidget* wid1, QWidget* wid2, const bool all ) { - setFrameStyle( QFrame::Panel | QFrame::Sunken ); - - QVBoxLayout* base = new QVBoxLayout( this ); - base->setMargin( frameWidth() ); - - QWidget* top = new QWidget( this ); - base->addWidget( top ); - - QHBoxLayout* tl = new QHBoxLayout( top ); - tl->setMargin( 0 ); - - myBar = new QtxWorkstackTabBar( top ); - tl->addWidget( myBar, 1 ); - - QPushButton* close = new QPushButton( top ); - close->setIcon( style()->standardIcon( QStyle::SP_TitleBarCloseButton ) ); - close->setAutoDefault( true ); - close->setFlat( true ); - myClose = close; - tl->addWidget( myClose ); + if ( !wid1 || !wid2 ) + return; - myStack = new QStackedWidget( this ); + // find area of the widgets + QtxWorkstackArea *area1 = 0, *area2 = 0; + QList allAreas; + areas( mySplit, allAreas, true ); + for ( QList::iterator it = allAreas.begin(); it != allAreas.end() && !( area1 && area2 ); ++it ) + { + if ( (*it)->contains( wid1 ) ) + area1 = *it; - base->addWidget( myStack, 1 ); + if ( (*it)->contains( wid2 ) ) + area2 = *it; + } - connect( myClose, SIGNAL( clicked() ), this, SLOT( onClose() ) ); - connect( myBar, SIGNAL( currentChanged( int ) ), this, SLOT( onCurrentChanged( int ) ) ); - connect( myBar, SIGNAL( dragActiveTab() ), this, SLOT( onDragActiveTab() ) ); - connect( myBar, SIGNAL( contextMenuRequested( QPoint ) ), this, SLOT( onContextMenuRequested( QPoint ) ) ); + if ( !area1 || !area2 ) + return; - updateState(); + QWidget* curWid = area1->activeWidget(); + if ( !curWid ) + return; - updateActiveState(); + if ( area1 == area2 ) + { + if ( all ) + { + // Set wid1 at first position, wid2 at second + area1->insertWidget( wid1 ); + area1->insertWidget( wid2, 1 ); + } + else + { + // Set wid2 right after wid1 + area1->removeWidget( wid2 ); + int wid1_ind = 0; + QWidgetList wids1 = area1->widgetList(); + for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind ); + area1->insertWidget( wid2, wid1_ind + 1 ); + } + } + else + { + int wid1_ind = 0; + QWidgetList wids1 = area1->widgetList(); + for ( QWidgetList::iterator itr1 = wids1.begin(); itr1 != wids1.end() && *itr1 != wid1; ++itr1, ++wid1_ind ); + if ( all ) + { + // Set wid2 right after wid1, other widgets from area2 right after wid2 + QWidgetList wids2 = area2->widgetList(); + QWidgetList::iterator itr2 = wids2.begin(); + for ( int ind = wid1_ind + 1; itr2 != wids2.end(); ++itr2, ++ind ) + { + area2->removeWidget( *itr2 ); + if ( *itr2 == wid2 ) + area1->insertWidget( *itr2, wid1_ind + 1 ); + else + area1->insertWidget( *itr2, ind ); + } + } + else + { + // Set wid2 right after wid1 + area2->removeWidget( wid2 ); + area1->insertWidget( wid2, wid1_ind + 1 ); + } + } - QApplication::instance()->installEventFilter( this ); + area1->setActiveWidget( curWid ); } /*! - Destructor + \brief Calculate sizes of the splitter widget for the workarea. + \internal */ -QtxWorkstackArea::~QtxWorkstackArea() +static void setSizes (QIntList& szList, const int item_ind, + const int new_near, const int new_this, const int new_farr) { - QApplication::instance()->removeEventFilter( this ); + // set size to all items before an item # + int cur_pos = 0; + QIntList::iterator its = szList.begin(); + for (; its != szList.end() && cur_pos < item_ind; ++its, ++cur_pos) { + *its = new_near; + } + if (its == szList.end()) return; + // set size to item # + *its = new_this; + ++its; + // set size to all items after an item # + for (; its != szList.end(); ++its) { + *its = new_farr; + } } /*! - \return true if area is empty -*/ -bool QtxWorkstackArea::isEmpty() const -{ - bool res = false; - for ( WidgetInfoMap::ConstIterator it = myInfo.begin(); it != myInfo.end() && !res; ++it ) - res = it.value().vis; - return !res; -} + \brief Set position of the widget relatively to its parent splitter. -/*! - Adds widget to area - \param wid - widget - \param idx - index + Orientation of positioning will correspond to the splitter orientation. + + \param wid widget + \param pos position relatively to the splitter; value in the range [0..1] */ -QWidget* QtxWorkstackArea::insertWidget( QWidget* wid, const int idx, Qt::WindowFlags f ) +void QtxWorkstack::SetRelativePositionInSplitter( QWidget* wid, const double position ) { - if ( !wid ) - return 0; + if ( position < 0.0 || 1.0 < position) + return; - int pos = myList.indexOf( wid ); - if ( pos != -1 && ( pos == idx || ( idx < 0 && pos == (int)myList.count() - 1 ) ) ) - return 0; + if ( !wid ) + return; - myList.removeAll( wid ); - pos = idx < 0 ? myList.count() : idx; - myList.insert( qMin( pos, (int)myList.count() ), wid ); - if ( !myInfo.contains( wid ) ) + // find area of the given widget + QtxWorkstackArea* area = NULL; + QList allAreas; + areas( mySplit, allAreas, true ); + for ( QList::iterator it = allAreas.begin(); it != allAreas.end() && !area; ++it ) { - QtxWorkstackChild* child = new QtxWorkstackChild( wid, myStack, f ); - myChild.insert( wid, child ); - myInfo.insert( wid, WidgetInfo() ); - myInfo[wid].id = generateId(); - myInfo[wid].vis = wid->isVisibleTo( wid->parentWidget() ); - - connect( child, SIGNAL( destroyed( QObject* ) ), this, SLOT( onChildDestroyed( QObject* ) ) ); - connect( wid, SIGNAL( destroyed() ), this, SLOT( onWidgetDestroyed() ) ); - connect( child, SIGNAL( shown( QtxWorkstackChild* ) ), this, SLOT( onChildShown( QtxWorkstackChild* ) ) ); - connect( child, SIGNAL( hided( QtxWorkstackChild* ) ), this, SLOT( onChildHided( QtxWorkstackChild* ) ) ); - connect( child, SIGNAL( activated( QtxWorkstackChild* ) ), this, SLOT( onChildActivated( QtxWorkstackChild* ) ) ); - connect( child, SIGNAL( captionChanged( QtxWorkstackChild* ) ), this, SLOT( onChildCaptionChanged( QtxWorkstackChild* ) ) ); + if ( (*it)->contains( wid ) ) + area = *it; } - updateState(); + if ( !area ) + return; - setWidgetActive( wid ); - wid->setFocus(); + QSplitter* split = splitter( area ); + if ( !split ) + return; - return myChild[wid]; -} + // find index of the area in its splitter + int item_ind = -1; + bool isFound = false; + const QObjectList& was = split->children(); + for ( QObjectList::const_iterator ito = was.begin(); ito != was.end() && !isFound; ++ito, ++item_ind ) + { + if ( *ito == area ) + isFound = true; + } -/*! - Creates and shows popup menu for area - \param p - popup position -*/ -void QtxWorkstackArea::onContextMenuRequested( QPoint p ) -{ - const QtxWorkstackTabBar* bar = ::qobject_cast( sender() ); - if ( !bar ) + if ( !isFound || item_ind == 0 ) return; - QWidget* wid = 0; - int idx = tabAt( p ); - if ( idx != -1 ) - wid = widget( myBar->tabId( idx ) ); + QIntList szList = split->sizes(); + int splitter_size = ( split->orientation() == Qt::Horizontal ? split->width() : split->height()); + int nb = szList.count(); - emit contextMenuRequested( wid, p ); + int new_prev = int( splitter_size * position / item_ind ); + int new_next = int( splitter_size * ( 1.0 - position ) / ( nb - item_ind ) ); + setSizes( szList, item_ind, new_prev, new_next, new_next ); + split->setSizes( szList ); } /*! - SLOT: called when widget added to area is destroyed, removes widget from area -*/ -void QtxWorkstackArea::onWidgetDestroyed() -{ - if ( sender() ) - removeWidget( (QWidget*)sender(), false ); -} + \brief Set position of the widget relatively to the entire workstack. -/*! - Removes widget from area - \param wid - widget - \param del - auto deleting + If \a o is \c Qt::Horizontal, the horizontal position of \a wid will be changed. + If \a o is \c Qt::Vertical, the vertical position of \a wid will be changed. + + \param wid widget + \param o orientation of positioning (\c Qt::Horizontal or \c Qt::Vertical) + \param pos position relatively to the workstack; value in range [0..1] */ -void QtxWorkstackArea::removeWidget( QWidget* wid, const bool del ) +void QtxWorkstack::SetRelativePosition( QWidget* wid, const Qt::Orientation o, + const double position ) { - if ( !myList.contains( wid ) ) + if ( position < 0.0 || 1.0 < position ) return; - if ( myBar->indexOf( widgetId( wid ) ) != -1 ) - myBar->removeTab( myBar->indexOf( widgetId( wid ) ) ); - - myStack->removeWidget( child( wid ) ); - - myList.removeAll( wid ); - myInfo.remove( wid ); - myChild.remove( wid ); + if ( !wid ) + return; - if ( del ) - { - delete child( wid ); - if ( myList.isEmpty() ) - delete this; - else - updateState(); + int splitter_size = o == Qt::Horizontal ? mySplit->width() : mySplit->height(); + int need_pos = int( position * splitter_size ); + int splitter_pos = 0; + + if ( setPosition( wid, mySplit, o, need_pos, splitter_pos ) != 0 ) + { + // impossible to set required position } - else - updateState(); } /*! - \return list of visible widgets + \brief Set accelerator key-combination for the action with specified \a id. + \param id action ID + \param accel action accelerator */ -QWidgetList QtxWorkstackArea::widgetList() const +void QtxWorkstack::setAccel( const int id, const int accel ) { - QWidgetList lst; - for ( QWidgetList::const_iterator it = myList.begin(); it != myList.end(); ++it ) - { - if ( widgetVisibility( *it ) ) - lst.append( *it ); - } - return lst; + if ( !myActionsMap.contains( id ) ) + return; + + myActionsMap[id]->setShortcut( accel ); } /*! - \return active widget + \brief Get the action's accelerator key-combination. + \param id action ID + \return action accelerator */ -QWidget* QtxWorkstackArea::activeWidget() const +int QtxWorkstack::accel( const int id ) const { - return widget( myBar->tabId( myBar->currentIndex() ) ); + int res = 0; + if ( myActionsMap.contains( id ) ) + res = myActionsMap[id]->shortcut(); + return res; } /*! - Sets widget as active - \param wid - widget + \brief Set actions to be visible in the context popup menu. + + Actions, which IDs are set in \a flags parameter, will be shown in the + context popup menu. Other actions will not be shown. + + \param flags ORed together actions flags */ -void QtxWorkstackArea::setActiveWidget( QWidget* wid ) +void QtxWorkstack::setMenuActions( const int flags ) { - myBar->setCurrentIndex( myBar->indexOf( widgetId( wid ) ) ); + myActionsMap[SplitVertical]->setVisible( flags & SplitVertical ); + myActionsMap[SplitHorizontal]->setVisible( flags & SplitHorizontal ); + myActionsMap[Close]->setVisible( flags & Close ); + myActionsMap[Rename]->setVisible( flags & Rename ); } /*! - \return true if area contains widget - \param wid - widget + \brief Set actions to be visible in the context popup menu. + + Actions, which IDs are set in \a flags parameter, will be shown in the + context popup menu. Other actions will not be shown. + + \param flags ORed together actions flags */ -bool QtxWorkstackArea::contains( QWidget* wid ) const +int QtxWorkstack::menuActions() const { - return myList.contains( wid ); + int ret = 0; + ret = ret | ( myActionsMap[SplitVertical]->isVisible() ? SplitVertical : 0 ); + ret = ret | ( myActionsMap[SplitHorizontal]->isVisible() ? SplitHorizontal : 0 ); + ret = ret | ( myActionsMap[Close]->isVisible() ? Close : 0 ); + ret = ret | ( myActionsMap[Rename]->isVisible() ? Rename : 0 ); + return ret; } /*! - Shows area + \brief Calculate sizes of the splitter widget for the workarea. + \internal */ -void QtxWorkstackArea::setVisible( bool on ) +static int positionSimple (QIntList& szList, const int nb, const int splitter_size, + const int item_ind, const int item_rel_pos, + const int need_pos, const int splitter_pos) { - QMap map; - for ( QWidgetList::iterator it = myList.begin(); it != myList.end(); ++it ) - { - map.insert( *it, isBlocked( *it ) ); - setBlocked( *it, true ); + if (item_ind == 0) { // cannot move in this splitter + return (need_pos - splitter_pos); } - QFrame::setVisible( on ); - - for ( QWidgetList::iterator itr = myList.begin(); itr != myList.end(); ++itr ) - setBlocked( *itr, map.contains( *itr ) ? map[*itr] : false ); -} + int delta = 0; + int new_prev = 0; + int new_this = szList[item_ind]; + int new_next = 0; -/*! - \return true if area is active -*/ -bool QtxWorkstackArea::isActive() const -{ - QtxWorkstack* ws = workstack(); - if ( !ws ) - return false; + bool isToCheck = false; - return ws->activeArea() == this; -} + if (need_pos < splitter_pos) { + // Set size of all previous workareas to zero <-- + if (item_ind == nb - 1) { + // item iz last in the splitter, it will occupy all the splitter + new_this = splitter_size; + } else { + // recompute size of next items in splitter + new_next = (splitter_size - new_this) / (nb - item_ind - 1); + } + delta = need_pos - splitter_pos; -/*! - Update active state of tab bar -*/ -void QtxWorkstackArea::updateActiveState() -{ - myBar->setActive( isActive() ); -} + } else if (need_pos > (splitter_pos + splitter_size)) { + // Set size of all next workareas to zero --> + // recompute size of previous items in splitter + new_this = 0; + new_prev = (splitter_size - new_this) / item_ind; + delta = need_pos - (splitter_pos + splitter_size - new_this); -/*! - \return corresponding workstack -*/ -QtxWorkstack* QtxWorkstackArea::workstack() const -{ - QtxWorkstack* ws = 0; - QWidget* wid = parentWidget(); - while ( wid && !ws ) - { - if ( wid->inherits( "QtxWorkstack" ) ) - ws = (QtxWorkstack*)wid; - wid = wid->parentWidget(); + } else { // required position lays inside this splitter + // Move workarea inside splitter into required position <-> + int new_item_rel_pos = need_pos - splitter_pos; + new_prev = new_item_rel_pos / item_ind; + if (need_pos < (splitter_pos + item_rel_pos)) { + // Make previous workareas smaller, next - bigger + // No problem to keep old size of the widget + } else { + // Make previous workareas bigger, next - smaller + if (new_this > splitter_size - new_item_rel_pos) { + new_this = splitter_size - new_item_rel_pos; + } + // jfa to do: in this case fixed size of next widgets could prevent right resizing + isToCheck = true; + } + if (item_ind == nb - 1) { + new_this = splitter_size - new_item_rel_pos; + } else { + new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1); + } + delta = 0; } - return ws; + + setSizes (szList, item_ind, new_prev, new_this, new_next); + return delta; } /*! - Custom event filter + \brief Set position of the widget. + + Called from SetRelativePosition() public method. + + \param wid widget to be moved + \param split currently processed splitter (goes from more common + to more particular splitter in recursion calls) + \param o orientation of positioning + \param need_pos required position of the given widget in pixels + (from top/left side of workstack area) + \param splitter_pos position of the splitter \a split + (from top/left side of workstack area) + \return difference between a required and a distinguished position */ -bool QtxWorkstackArea::eventFilter( QObject* o, QEvent* e ) +int QtxWorkstack::setPosition( QWidget* wid, QSplitter* split, const Qt::Orientation o, + const int need_pos, const int splitter_pos ) { - if ( o->isWidgetType() ) + if ( !wid || !split ) + return need_pos - splitter_pos; + + // Find corresponding sub-splitter. + // Find also index of appropriate item in current splitter. + int cur_ind = 0, item_ind = 0; + bool isBottom = false, isFound = false; + QSplitter* sub_split = NULL; + const QObjectList& objs = split->children(); + for ( QObjectList::const_iterator it = objs.begin(); it != objs.end() && !isFound; ++it ) { - QWidget* wid = (QWidget*)o; - if ( e->type() == QEvent::FocusIn || e->type() == QEvent::MouseButtonPress ) + QtxWorkstackArea* area = ::qobject_cast( *it ); + if ( area ) { - bool ok = false; - while ( !ok && wid && wid != myClose ) + if ( area->contains( wid ) ) { - ok = wid == this; - wid = wid->parentWidget(); + item_ind = cur_ind; + isBottom = true; + isFound = true; } - if ( ok ) - QApplication::postEvent( this, new WidgetEvent( (QEvent::Type)( e->type() == QEvent::FocusIn ? ActivateWidget : FocusWidget ) ) ); + cur_ind++; + } + else if ( (*it)->inherits( "QSplitter" ) ) + { + QList areaList; + areas( (QSplitter*)(*it), areaList, true ); + for ( QList::iterator ita = areaList.begin(); ita != areaList.end() && !isFound; ++ita ) + { + if ( (*ita)->contains( wid ) ) + { + item_ind = cur_ind; + isFound = true; + sub_split = (QSplitter*)*it; + } + } + cur_ind++; } } - return false; -} -/*! - \return rectangle of area in order to draw drop rectangle on area -*/ -QRect QtxWorkstackArea::floatRect() const -{ - QRect r = myStack->geometry(); - return QRect( mapToGlobal( r.topLeft() ), mapToGlobal( r.bottomRight() ) ); -} + if ( !isFound ) + return ( need_pos - splitter_pos ); -/*! - \return rectangle of tab in order to draw drop rectangle on tab - \param idx - tab index -*/ -QRect QtxWorkstackArea::floatTab( const int idx ) const -{ - QRect r = myBar->tabRect( idx ); - return QRect( myBar->mapToGlobal( r.topLeft() ), r.size() ); -} + if ( split->orientation() == o ) + { + // Find coordinates of near and far sides of the appropriate item relatively current splitter + int splitter_size = ( o == Qt::Horizontal ? split->width() : split->height() ); + QIntList szList = split->sizes(); + int nb = szList.count(); + int item_rel_pos = 0; // position of near side of item relatively this splitter + for (int i = 0; i < item_ind; i++) { + item_rel_pos += szList[i]; + } + int item_size = szList[item_ind]; // size of item + int item_pos = splitter_pos + item_rel_pos; + + // Resize splitter items to complete the conditions + if (isBottom) { + // I. Bottom of splitters stack reached + + int delta = positionSimple(szList, nb, splitter_size, item_ind, item_rel_pos, need_pos, splitter_pos); + split->setSizes(szList); + // Recompute delta, as some windows can reject given size + int new_item_rel_pos = 0; + QIntList szList1 = split->sizes(); + for (int i = 0; i < item_ind; i++) { + new_item_rel_pos += szList1[i]; + } + delta = need_pos - (splitter_pos + new_item_rel_pos); + return delta; + + } else { + // II. Bottom of splitters stack is not yet reached + + if (item_ind == 0) { // cannot move in this splitter + // Process in sub-splitter + return setPosition(wid, sub_split, o, need_pos, splitter_pos); + } + + int new_prev = 0; + int new_this = szList[item_ind]; + int new_next = 0; + + if (need_pos < splitter_pos) { + // Set size of all previous workareas to zero <-- + if (item_ind == nb - 1) { + new_this = splitter_size; + } else { + new_next = (splitter_size - new_this) / (nb - item_ind - 1); + } + setSizes (szList, item_ind, new_prev, new_this, new_next); + split->setSizes(szList); + // Recompute splitter_pos, as some windows can reject given size + int new_item_rel_pos = 0; + QIntList szList1 = split->sizes(); + for (int i = 0; i < item_ind; i++) { + new_item_rel_pos += szList1[i]; + } + // Process in sub-splitter + return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos); + } else if (need_pos > (splitter_pos + splitter_size)) { + // Set size of all next workareas to zero --> + new_prev = (splitter_size - new_this) / item_ind; + setSizes (szList, item_ind, new_prev, new_this, new_next); + split->setSizes(szList); + // Recompute splitter_pos, as some windows can reject given size + int new_item_rel_pos = 0; + QIntList szList1 = split->sizes(); + for (int i = 0; i < item_ind; i++) { + new_item_rel_pos += szList1[i]; + } + // Process in sub-splitter + return setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos); + } else { + // Set appropriate size of all previous/next items <-> + int new_item_rel_pos = item_rel_pos; + if (need_pos < item_pos || (item_pos + item_size) < need_pos) { + // Move item inside splitter into required position <-> + int new_this = szList[item_ind]; + int new_next = 0; + new_item_rel_pos = need_pos - splitter_pos; + if ((item_pos + item_size) < need_pos) { + //new_item_rel_pos = need_pos - (item_pos + item_size); + new_item_rel_pos = item_rel_pos + (need_pos - (item_pos + item_size)); + } + int new_prev = new_item_rel_pos / item_ind; + if (need_pos < (splitter_pos + item_rel_pos)) { + // Make previous workareas smaller, next - bigger + // No problem to keep old size of the widget + } else { + // Make previous workareas bigger, next - smaller + if (new_this > splitter_size - new_item_rel_pos) { + new_this = splitter_size - new_item_rel_pos; + } + } + if (item_ind == nb - 1) { + new_this = splitter_size - new_item_rel_pos; + } else { + new_next = (splitter_size - new_item_rel_pos - new_this) / (nb - item_ind - 1); + } + setSizes (szList, item_ind, new_prev, new_this, new_next); + split->setSizes(szList); + // Recompute new_item_rel_pos, as some windows can reject given size + new_item_rel_pos = 0; + QIntList szList1 = split->sizes(); + for (int i = 0; i < item_ind; i++) { + new_item_rel_pos += szList1[i]; + } + } else { + // Do nothing + } + // Process in sub-splitter + int add_pos = setPosition(wid, sub_split, o, need_pos, splitter_pos + new_item_rel_pos); + if (add_pos == 0) + return 0; -/*! - \return tab covering point - \param p - point -*/ -int QtxWorkstackArea::tabAt( const QPoint& pnt ) const -{ - int idx = -1; - QPoint p = myBar->mapFromGlobal( pnt ); - for ( int i = 0; i < myBar->count() && idx == -1; i++ ) - { - QRect r = myBar->tabRect( i ); - if ( r.isValid() && r.contains( p ) ) - idx = i; - } - return idx; -} + // this can be if corresponding workarea is first in sub-splitter + // or sub-splitter has another orientation -/*! - Event handler for custom events -*/ -void QtxWorkstackArea::customEvent( QEvent* e ) -{ - WidgetEvent* we = (WidgetEvent*)e; + // Resize ones again to reach precize position <-> + int need_pos_1 = splitter_pos + new_item_rel_pos + add_pos; - switch ( we->type() ) - { - case ActivateWidget: - emit activated( activeWidget() ); - break; - case FocusWidget: - if ( activeWidget() ) - { - if ( !activeWidget()->focusWidget() ) - activeWidget()->setFocus(); - else - { - if ( activeWidget()->focusWidget()->hasFocus() ) - { - QFocusEvent in( QEvent::FocusIn ); - QApplication::sendEvent( this, &in ); - } - else - activeWidget()->focusWidget()->setFocus(); + // Move workarea inside splitter into required position <-> + int delta_1 = positionSimple(szList, nb, splitter_size, item_ind, + new_item_rel_pos, need_pos_1, splitter_pos); + split->setSizes(szList); + // Recompute new_item_rel_pos, as some windows can reject given size + new_item_rel_pos = 0; + QIntList szList1 = split->sizes(); + for (int i = 0; i < item_ind; i++) { + new_item_rel_pos += szList1[i]; + } + delta_1 = need_pos_1 - (splitter_pos + new_item_rel_pos); + return delta_1; } } - break; - case RemoveWidget: - removeWidget( we->widget() ); - break; - default: - break; + } else { + return setPosition(wid, sub_split, o, need_pos, splitter_pos); } -} - -/*! - Custom focus in event handler -*/ -void QtxWorkstackArea::focusInEvent( QFocusEvent* e ) -{ - QFrame::focusInEvent( e ); - emit activated( activeWidget() ); + return 0; } /*! - Custom mouse press event handler + \brief Redistribute space among widgets equally. + \param split splitter */ -void QtxWorkstackArea::mousePressEvent( QMouseEvent* e ) +void QtxWorkstack::distributeSpace( QSplitter* split ) const { - QFrame::mousePressEvent( e ); + if ( !split ) + return; - emit activated( activeWidget() ); + QIntList szList = split->sizes(); + int size = ( split->orientation() == Qt::Horizontal ? + split->width() : split->height() ) / szList.count(); + for ( QIntList::iterator it = szList.begin(); it != szList.end(); ++it ) + *it = size; + split->setSizes( szList ); } /*! - SLOT: called if button close is pressed + \brief Split widgets vertically. */ -void QtxWorkstackArea::onClose() +void QtxWorkstack::splitVertical() { - QWidget* wid = activeWidget(); - if ( wid ) - wid->close(); + split( Qt::Horizontal ); } /*! - SLOT: called if tab page is selected + \brief Split widgets horizontally. */ -void QtxWorkstackArea::onCurrentChanged( int ) +void QtxWorkstack::splitHorizontal() { - updateCurrent(); - - emit activated( activeWidget() ); + split( Qt::Vertical ); } /*! - SLOT: called if active tab page is dragged + \brief Called when user activates "Rename" menu item. + + Changes widget title. */ -void QtxWorkstackArea::onDragActiveTab() +void QtxWorkstack::onRename() { - QtxWorkstackChild* c = child( activeWidget() ); - if ( !c ) + if ( !myWorkWin ) return; - new QtxWorkstackDrag( workstack(), c ); + bool ok = false; + QString newName = QInputDialog::getText( topLevelWidget(), tr( "Rename" ), tr( "Enter new name:" ), + QLineEdit::Normal, myWorkWin->windowTitle(), &ok ); + if ( ok && !newName.isEmpty() ) + myWorkWin->setWindowTitle( newName ); } /*! - SLOT: called on child is destroyed, removes from area + \brief Wrap area into the new splitter. + \param workarea + \return new splitter */ -void QtxWorkstackArea::onChildDestroyed( QObject* obj ) +QSplitter* QtxWorkstack::wrapSplitter( QtxWorkstackArea* area ) { - QtxWorkstackChild* child = (QtxWorkstackChild*)obj; - myStack->removeWidget( child ); + if ( !area ) + return 0; - QWidget* wid = 0; - for ( ChildMap::ConstIterator it = myChild.begin(); it != myChild.end() && !wid; ++it ) - { - if ( it.value() == child ) - wid = it.key(); - } + QSplitter* pSplit = splitter( area ); + if ( !pSplit ) + return 0; - myChild.remove( wid ); + bool upd = pSplit->updatesEnabled(); + pSplit->setUpdatesEnabled( false ); - QApplication::postEvent( this, new WidgetEvent( (QEvent::Type)RemoveWidget, wid ) ); -} + QIntList szList = pSplit->sizes(); -/*! - SLOT: called on child is shown -*/ -void QtxWorkstackArea::onChildShown( QtxWorkstackChild* c ) -{ - setWidgetShown( c->widget(), true ); -} + QSplitter* wrap = new QSplitter( 0 ); + wrap->setChildrenCollapsible( false ); + pSplit->insertWidget( pSplit->indexOf( area ) + 1, wrap ); + wrap->setVisible( true ); + wrap->addWidget( area ); -/*! - SLOT: called on child is hidden -*/ -void QtxWorkstackArea::onChildHided( QtxWorkstackChild* c ) -{ - setWidgetShown( c->widget(), false ); -} + pSplit->setSizes( szList ); -/*! - SLOT: called on child is activated -*/ -void QtxWorkstackArea::onChildActivated( QtxWorkstackChild* c ) -{ - setWidgetActive( c->widget() ); -} + pSplit->setUpdatesEnabled( upd ); -/*! - SLOT: called on child caption is changed -*/ -void QtxWorkstackArea::onChildCaptionChanged( QtxWorkstackChild* c ) -{ - updateTab( c->widget() ); + return wrap; } /*! - Raises widget when active tab is changed + \brief Reparent and add widget. + \param wid widget + \param pWid parent widget + \param after widget after which \a wid should be added */ -void QtxWorkstackArea::updateCurrent() +void QtxWorkstack::insertWidget( QWidget* wid, QWidget* pWid, QWidget* after ) { - QMap map; - for ( QWidgetList::iterator it = myList.begin(); it != myList.end(); ++it ) + if ( !wid || !pWid ) + return; + + QWidgetList moveList; + const QObjectList& lst = pWid->children(); + bool found = false; + for ( QObjectList::const_iterator it = lst.begin(); it != lst.end(); ++it ) { - map.insert( *it, isBlocked( *it ) ); - setBlocked( *it, true ); + if ( found && ( (*it)->inherits( "QSplitter" ) || + (*it)->inherits( "QtxWorkstackArea" ) ) ) + moveList.append( (QWidget*)(*it) ); + if ( *it == after ) + found = true; } - QWidget* cur = child( widget( myBar->tabId( myBar->currentIndex() ) ) ); - if ( cur ) - myStack->setCurrentWidget( cur ); - - for ( QWidgetList::iterator itr = myList.begin(); itr != myList.end(); ++itr ) - setBlocked( *itr, map.contains( *itr ) ? map[*itr] : false ); -} - -/*! - Updates tab - \param wid - tab widget -*/ -void QtxWorkstackArea::updateTab( QWidget* wid ) -{ - int idx = myBar->indexOf( widgetId( wid ) ); - if ( idx < 0 ) - return; + QMap map; + for ( QWidgetList::iterator it = moveList.begin(); it != moveList.end(); ++it ) + { + map.insert( *it, (*it)->isVisibleTo( (*it)->parentWidget() ) ); + (*it)->setParent( 0 ); + (*it)->hide(); + } - myBar->setTabIcon( idx, wid->windowIcon() ); - myBar->setTabText( idx, wid->windowTitle() ); -} + wid->setParent( pWid ); -/*! - \return widget - \param id - widget id -*/ -QWidget* QtxWorkstackArea::widget( const int id ) const -{ - QWidget* wid = 0; - for ( WidgetInfoMap::ConstIterator it = myInfo.begin(); it != myInfo.end() && !wid; ++it ) - { - if ( it.value().id == id ) - wid = it.key(); + for ( QWidgetList::iterator itr = moveList.begin(); itr != moveList.end(); ++itr ) + { + (*itr)->setParent( pWid ); + (*itr)->setShown( map.contains( *itr ) ? map[*itr] : false ); } - return wid; } /*! - \return widget id - \param wid - widget + \brief Close active window. */ -int QtxWorkstackArea::widgetId( QWidget* wid ) const +void QtxWorkstack::onCloseWindow() { - int id = -1; - if ( myInfo.contains( wid ) ) - id = myInfo[wid].id; - return id; + if ( myWorkWin ) + myWorkWin->close(); + else if( activeWindow() ) + activeWindow()->close(); } /*! - \return true if widget is visible - \param wid - widget -*/ -bool QtxWorkstackArea::widgetVisibility( QWidget* wid ) const -{ - bool res = false; - if ( myInfo.contains( wid ) ) - res = myInfo[wid].vis; - return res; -} + \brief Called when workarea is destroyed. -/*! - Sets widget as active - \param wid - widget + Set input focus to the neighbour area. + + \param obj workarea being destroyed */ -void QtxWorkstackArea::setWidgetActive( QWidget* wid ) +void QtxWorkstack::onDestroyed( QObject* obj ) { - int id = widgetId( wid ); - if ( id < 0 ) - return; + QtxWorkstackArea* area = (QtxWorkstackArea*)obj; - myBar->setCurrentIndex( myBar->indexOf( id ) ); + if ( area == myArea ) + myArea = 0; + + if ( !myArea ) + { + QtxWorkstackArea* cur = neighbourArea( area ); + if ( cur ) + cur->setFocus(); + } + + QApplication::postEvent( this, new QEvent( QEvent::User ) ); } /*! - Shows/hides widget - \param wid - widget - \param on - new shown state + \brief Called on window activating. + \param area workarea being activated (not used) */ -void QtxWorkstackArea::setWidgetShown( QWidget* wid, const bool on ) +void QtxWorkstack::onWindowActivated( QWidget* /*area*/ ) { - if ( isBlocked( wid ) || !myInfo.contains( wid ) || myInfo[wid].vis == on ) + const QObject* obj = sender(); + if ( !obj->inherits( "QtxWorkstackArea" ) ) return; - myInfo[wid].vis = on; - updateState(); + setActiveArea( (QtxWorkstackArea*)obj ); } /*! - Update + \brief Called on window deactivating. + \param area workarea being deactivated */ -void QtxWorkstackArea::updateState() +void QtxWorkstack::onDeactivated( QtxWorkstackArea* area ) { - bool updBar = myBar->updatesEnabled(); - bool updStk = myStack->updatesEnabled(); - myBar->setUpdatesEnabled( false ); - myStack->setUpdatesEnabled( false ); - - bool block = myBar->signalsBlocked(); - myBar->blockSignals( true ); - - QWidget* prev = activeWidget(); + if ( myArea != area ) + return; - int idx = 0; - for ( QWidgetList::iterator it = myList.begin(); it != myList.end(); ++it ) - { - QWidget* wid = *it; - int id = widgetId( wid ); + QList lst; + areas( mySplit, lst, true ); - if ( id < 0 ) - continue; + int idx = lst.indexOf( area ); + if ( idx == -1 ) + return; - bool vis = widgetVisibility( wid ); + myWin = 0; + myArea = 0; - int cIdx = myBar->indexOf( id ); - if ( cIdx != -1 && ( !vis || myBar->indexOf( id ) != idx ) ) - myBar->removeTab( cIdx ); + QtxWorkstackArea* newArea = neighbourArea( area ); + if ( newArea && newArea->activeWidget() ) + newArea->activeWidget()->setFocus(); - if ( myBar->indexOf( id ) == -1 && vis ) - myBar->setTabId( myBar->insertTab( idx, wid->windowTitle() ), id ); + QApplication::postEvent( this, new QEvent( QEvent::User ) ); +} - updateTab( wid ); +/*! + \brief Create and show popup menu for workarea. + \param w workarea + \param p popup position +*/ +void QtxWorkstack::onContextMenuRequested( QWidget* w, QPoint p ) +{ + QtxWorkstackArea* anArea = ::qobject_cast( (QObject*)sender() ); + if ( !anArea ) + anArea = activeArea(); - bool block = isBlocked( wid ); - setBlocked( wid, true ); + if ( !anArea ) + return; - QtxWorkstackChild* cont = child( wid ); + QWidgetList lst = anArea->widgetList(); + if ( lst.isEmpty() ) + return; - if ( !vis ) - myStack->removeWidget( cont ); - else if ( myStack->indexOf( cont ) < 0 ) - myStack->addWidget( cont ); + myWorkWin = w; + myWorkArea = anArea; - if ( vis ) - idx++; + QMenu* pm = new QMenu(); - setBlocked( wid, block ); + if ( lst.count() > 1 ) + { + if ( myActionsMap[SplitVertical]->isEnabled() ) + pm->addAction( myActionsMap[SplitVertical] ); + if ( myActionsMap[SplitHorizontal]->isEnabled() ) + pm->addAction( myActionsMap[SplitHorizontal] ); + pm->addSeparator(); } - int curId = widgetId( prev ); - if ( myBar->indexOf( curId ) < 0 ) + if ( w ) { - QWidget* wid = 0; - int pos = myList.indexOf( prev ); - for ( int i = pos - 1; i >= 0 && !wid; i-- ) - { - if ( widgetVisibility( myList.at( i ) ) ) - wid = myList.at( i ); - } - - for ( int j = pos + 1; j < (int)myList.count() && !wid; j++ ) - { - if ( widgetVisibility( myList.at( j ) ) ) - wid = myList.at( j ); - } - - if ( wid ) - curId = widgetId( wid ); + if ( myActionsMap[Close]->isEnabled() ) + pm->addAction( myActionsMap[Close] ); + if ( myActionsMap[Rename]->isEnabled() ) + pm->addAction( myActionsMap[Rename] ); } - myBar->setCurrentIndex( myBar->indexOf( curId ) ); + Qtx::simplifySeparators( pm ); - myBar->blockSignals( block ); + if ( !pm->actions().isEmpty() ) + pm->exec( p ); - updateCurrent(); + delete pm; - myBar->updateActiveState(); + myWorkWin = 0; + myWorkArea = 0; +} - myBar->setUpdatesEnabled( updBar ); - myStack->setUpdatesEnabled( updStk ); - if ( updBar ) - myBar->update(); - if ( updStk ) - myStack->update(); +/*! + \brief Add child widget. + \param w widget + \param f widget flags + \return child widget container +*/ +QWidget* QtxWorkstack::addWindow( QWidget* w, Qt::WindowFlags f ) +{ + if ( !w ) + return 0; - QResizeEvent re( myBar->size(), myBar->size() ); - QApplication::sendEvent( myBar, &re ); + return targetArea()->insertWidget( w, -1, f ); +} - if ( isEmpty() ) - { - hide(); - emit deactivated( this ); - } - else - { - show(); - if ( prev != activeWidget() ) - emit activated( activeWidget() ); - } +/*! + \brief Handle custom events. + \param e custom event (not used) +*/ +void QtxWorkstack::customEvent( QEvent* /*e*/ ) +{ + updateState(); } /*! - \return first unshared widget id + \brief Get splitter corresponding to the workarea. + \param workarea + \return splitter corresponding to the workarea */ -int QtxWorkstackArea::generateId() const +QSplitter* QtxWorkstack::splitter( QtxWorkstackArea* area ) const { - QMap map; + if ( !area ) + return 0; - for ( WidgetInfoMap::const_iterator it = myInfo.begin(); it != myInfo.end(); ++it ) - map.insert( it.value().id, 0 ); + QSplitter* split = 0; - int id = 0; - while ( map.contains( id ) ) - id++; + QWidget* wid = area->parentWidget(); + if ( wid && wid->inherits( "QSplitter" ) ) + split = (QSplitter*)wid; - return id; + return split; } /*! - \return true if widget is blocked - \param wid - widget + \brief Get list of child splitters. + \param split parent splitter + \param splitList list to be filled with child splitters + \param rec if \c true, perform recursive search of children */ -bool QtxWorkstackArea::isBlocked( QWidget* wid ) const +void QtxWorkstack::splitters( QSplitter* split, QList& splitList, const bool rec ) const { - return myBlock.contains( wid ); + if ( !split ) + return; + + const QObjectList& objs = split->children(); + for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it ) + { + if ( rec ) + splitters( (QSplitter*)*it, splitList, rec ); + if ( (*it)->inherits( "QSplitter" ) ) + splitList.append( (QSplitter*)*it ); + } } /*! - Blocks widget - \param wid - widget - \param on - new blocked state + \brief Get list of child workareas. + \param split parent splitter + \param areaList list to be filled with child workareas + \param rec if \c true, perform recursive search of children */ -void QtxWorkstackArea::setBlocked( QWidget* wid, const bool on ) +void QtxWorkstack::areas( QSplitter* split, QList& areaList, const bool rec ) const { - if ( on ) - myBlock.insert( wid, 0 ); - else - myBlock.remove( wid ); + if ( !split ) + return; + + const QObjectList& objs = split->children(); + for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it ) + { + if ( (*it)->inherits( "QtxWorkstackArea" ) ) + areaList.append( (QtxWorkstackArea*)*it ); + else if ( rec && (*it)->inherits( "QSplitter" ) ) + areas( (QSplitter*)*it, areaList, rec ); + } } /*! - \return child corresponding to widget - \param wid - widget + \brief Get active workarea. + \return active workarea */ -QtxWorkstackChild* QtxWorkstackArea::child( QWidget* wid ) const +QtxWorkstackArea* QtxWorkstack::activeArea() const { - QtxWorkstackChild* res = 0; - if ( myChild.contains( wid ) ) - res = myChild[wid]; - return res; + return myArea; } /*! - Constructor + \brief Get target area (for which the current operation should be done). + + Returns active workarea or current area (if there is no active workarea). + If there are no workareas, create new workarea and return it. + + \return workarea */ -QtxWorkstackChild::QtxWorkstackChild( QWidget* wid, QWidget* parent, Qt::WindowFlags f ) -: QWidget( parent ), -myWidget( wid ) +QtxWorkstackArea* QtxWorkstack::targetArea() { - myWidget->setParent( this, f ); - myWidget->installEventFilter( this ); - QVBoxLayout* base = new QVBoxLayout( this ); - base->addWidget( myWidget ); + QtxWorkstackArea* area = activeArea(); + if ( !area ) + area = currentArea(); + if ( !area ) + { + QList lst; + areas( mySplit, lst ); + if ( !lst.isEmpty() ) + area = lst.first(); + } - connect( myWidget, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); + if ( !area ) + area = createArea( mySplit ); + + return area; } /*! - Destructor -*/ -QtxWorkstackChild::~QtxWorkstackChild() -{ - QApplication::instance()->removeEventFilter( this ); - - if ( !widget() ) - return; + \brief Get current workarea. - disconnect( widget(), SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); + Current workarea is that one which has input focus. - widget()->hide(); - widget()->removeEventFilter( this ); + \return current area +*/ +QtxWorkstackArea* QtxWorkstack::currentArea() const +{ + QtxWorkstackArea* area = 0; + QWidget* wid = focusWidget(); + while ( wid && !area ) + { + if ( wid->inherits( "QtxWorkstackArea" ) ) + area = (QtxWorkstackArea*)wid; + wid = wid->parentWidget(); + } - widget()->setParent( 0 ); + return area; } /*! - \return corresponding widget + \brief Create new workarea. + \param parent parent widget + \return created workarea */ -QWidget* QtxWorkstackChild::widget() const +QtxWorkstackArea* QtxWorkstack::createArea( QWidget* parent ) const { - return myWidget; + QtxWorkstackArea* area = new QtxWorkstackArea( parent ); + + connect( area, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) ); + connect( area, SIGNAL( activated( QWidget* ) ), this, SLOT( onWindowActivated( QWidget* ) ) ); + connect( area, SIGNAL( contextMenuRequested( QWidget*, QPoint ) ), + this, SLOT( onContextMenuRequested( QWidget*, QPoint ) ) ); + connect( area, SIGNAL( deactivated( QtxWorkstackArea* ) ), this, SLOT( onDeactivated( QtxWorkstackArea* ) ) ); + + return area; } /*! - Custom event filter + \brief Set active workarea. + \param workarea */ -bool QtxWorkstackChild::eventFilter( QObject* o, QEvent* e ) +void QtxWorkstack::setActiveArea( QtxWorkstackArea* area ) { - if ( o->isWidgetType() ) - { - if ( e->type() == QEvent::WindowTitleChange || e->type() == QEvent::WindowIconChange ) - emit captionChanged( this ); + QWidget* oldCur = myWin; - if ( !e->spontaneous() && ( e->type() == QEvent::Show || e->type() == QEvent::ShowToParent ) ) - emit shown( this ); + QtxWorkstackArea* oldArea = myArea; - if ( !e->spontaneous() && ( e->type() == QEvent::Hide || e->type() == QEvent::HideToParent ) ) - emit hided( this ); + myArea = area; - if ( e->type() == QEvent::FocusIn ) - emit activated( this ); + if ( myArea != oldArea ) + { + if ( oldArea ) + oldArea->updateActiveState(); + if ( myArea ) + myArea->updateActiveState(); } - return QWidget::eventFilter( o, e ); + + if ( myArea ) + myWin = myArea->activeWidget(); + + if ( myWin && oldCur != myWin ) + emit windowActivated( myWin ); } /*! - SLOT: called on object is destroyed + \brief Get workarea which is nearest to \a area. + \param area area for which neighbour is searched + \return neighbour area (or 0 if not found) */ -void QtxWorkstackChild::onDestroyed( QObject* obj ) +QtxWorkstackArea* QtxWorkstack::neighbourArea( QtxWorkstackArea* area ) const { - if ( obj != widget() ) - return; + QList lst; + areas( mySplit, lst, true ); + int pos = lst.indexOf( area ); + if ( pos < 0 ) + return 0; - myWidget = 0; - deleteLater(); + QtxWorkstackArea* na = 0; + for ( int i = pos - 1; i >= 0 && !na; i-- ) + { + if ( !lst.at( i )->isEmpty() ) + na = lst.at( i ); + } + + for ( int j = pos + 1; j < (int)lst.count() && !na; j++ ) + { + if ( !lst.at( j )->isEmpty() ) + na = lst.at( j ); + } + return na; } /*! - Custom child event handler + \brief Get workarea covering point. + \return workarea + \param p point */ -void QtxWorkstackChild::childEvent( QChildEvent* e ) +QtxWorkstackArea* QtxWorkstack::areaAt( const QPoint& p ) const { - if ( e->removed() && e->child() == widget() ) + QtxWorkstackArea* area = 0; + QList lst; + areas( mySplit, lst, true ); + for ( QList::iterator it = lst.begin(); it != lst.end() && !area; ++it ) { - myWidget = 0; - deleteLater(); + QtxWorkstackArea* cur = *it; + QRect r = cur->geometry(); + if ( cur->parentWidget() ) + r = QRect( cur->parentWidget()->mapToGlobal( r.topLeft() ), r.size() ); + if ( r.contains( p ) ) + area = cur; } - QWidget::childEvent( e ); + return area; } /*! - Constructor + \brief Update internal state. */ -QtxWorkstackTabBar::QtxWorkstackTabBar( QWidget* parent ) -: QTabBar( parent ), -myId( -1 ) +void QtxWorkstack::updateState() { - setDrawBase( true ); - setElideMode( Qt::ElideNone ); - - connect( this, SIGNAL( currentChanged( int ) ), this, SLOT( onCurrentChanged( int ) ) ); + updateState( mySplit ); } /*! - Destructor + \brief Update splitter state. + \param split splitter to be updated */ -QtxWorkstackTabBar::~QtxWorkstackTabBar() +void QtxWorkstack::updateState( QSplitter* split ) { -} + QList recList; + splitters( split, recList, false ); + for ( QList::iterator itr = recList.begin(); itr != recList.end(); ++itr ) + updateState( *itr ); -int QtxWorkstackTabBar::tabId( const int index ) const -{ - QVariant v = tabData( index ); - if ( !v.canConvert( QVariant::Int ) ) - return -1; - return v.toInt(); -} + QList splitList; + splitters( split, splitList, false ); -void QtxWorkstackTabBar::setTabId( const int index, const int id ) -{ - setTabData( index, id ); -} + QList areaList; + areas( split, areaList, false ); -int QtxWorkstackTabBar::indexOf( const int id ) const -{ - int index = -1; - for ( int i = 0; i < (int)count() && index < 0; i++ ) + bool vis = false; + for ( QList::iterator it = areaList.begin(); it != areaList.end(); ++it ) { - if ( tabId( i ) == id ) - index = i; + if ( (*it)->isEmpty() ) + (*it)->hide(); + else + { + (*it)->show(); + vis = true; + } } - return index; -} -/*! - Returns 'true' if the tab bar is active -*/ -bool QtxWorkstackTabBar::isActive() const -{ - return myActive; + if ( split == mySplit ) + return; + + for ( QList::iterator iter = splitList.begin(); iter != splitList.end() && !vis; ++iter ) + vis = (*iter)->isVisibleTo( (*iter)->parentWidget() ); + + if ( areaList.isEmpty() && splitList.isEmpty() ) + delete split; + else if ( vis ) + split->show(); + else + split->hide(); } /*! - Sets tab bar as active or inactive - \param on - new active state + \brief Get splitter info (for debug purposes) + \param split splitter + \param info string to be filled with splitter data. */ -void QtxWorkstackTabBar::setActive( const bool on ) +void QtxWorkstack::splitterInfo( QSplitter* split, QString& info ) const { - if ( myActive == on ) + if ( !split ) return; - myActive = on; - updateActiveState(); -} + const QObjectList& objs = split->children(); -void QtxWorkstackTabBar::updateActiveState() -{ - QColor bc = palette().color( QPalette::Text ); - QColor ac = isActive() ? palette().color( QPalette::Highlight ) : bc; - for ( int i = 0; i < (int)count(); i++ ) - setTabTextColor( i, currentIndex() == i ? ac : bc ); -} + QString sizesStr; + QList sizes = split->sizes(); + for ( QList::iterator sIt = sizes.begin(); sIt != sizes.end(); ++sIt ) + { + if ( *sIt > 1 ) // size 1 pixel usually means empty Workstack area, which will NOT be re-created, + sizesStr += QString( ":%1" ).arg( *sIt ); // so we don't need to store its size + } -void QtxWorkstackTabBar::onCurrentChanged( int ) -{ - updateActiveState(); -} + if ( !sizesStr.isEmpty() ) // cut the first ':' + sizesStr = sizesStr.right( sizesStr.length() - 1 ); -/*! - Custom mouse move event handler -*/ -void QtxWorkstackTabBar::mouseMoveEvent( QMouseEvent* e ) -{ - if ( myId != -1 && !tabRect( indexOf( myId ) ).contains( e->pos() ) ) + info += QString( "(splitter orientation=%1 sizes=%3 " ).arg( split->orientation() ).arg( sizesStr ); + + for ( QObjectList::const_iterator it = objs.begin(); it != objs.end(); ++it ) { - myId = -1; - emit dragActiveTab(); + if ( (*it)->inherits( "QSplitter" ) ) + splitterInfo( (QSplitter*)*it, info ); + else if ( (*it)->inherits( "QtxWorkstackArea" ) ) + { + QtxWorkstackArea* area = (QtxWorkstackArea*)*it; + if ( area->isEmpty() ) + continue; + info += QString( "(views active='%1'" ).arg( area->activeWidget()->objectName() ); + QWidgetList views = area->widgetList(); + for ( QWidgetList::iterator wIt = views.begin(); wIt != views.end(); ++wIt ) + info += QString( " '%1'" ).arg( (*wIt)->objectName() ); + info += ')'; + } } - QTabBar::mouseMoveEvent( e ); + info += ')'; + printf( (const char*)QString( info + '\n' ).toLatin1() ); } /*! - Custom mouse press event handler + \brief Remove round brackets symbols from the string. + \internal + \param parameters string to be processed */ -void QtxWorkstackTabBar::mousePressEvent( QMouseEvent* e ) +static void cutBrackets( QString& parameters ) { - QTabBar::mousePressEvent( e ); - - if ( e->button() == Qt::LeftButton ) - myId = tabId( currentIndex() ); + QChar c1 = parameters[0]; + QChar c2 = parameters[int(parameters.length()-1)]; + if ( !parameters.isEmpty() && c1 == '(' && c2 == ')' ) + parameters = parameters.mid( 1, parameters.length()-2 ); } /*! - Custom mouse release event handler -*/ -void QtxWorkstackTabBar::mouseReleaseEvent( QMouseEvent* e ) -{ - QTabBar::mouseReleaseEvent( e ); + \brief Parse string to get some parameter value. + \internal - myId = -1; + String \a str can contain the parameters description of kind "= ...". + For example: + \code + QString s = "splitter orientation=0 children=2 sizes=332:478"; + QString orient_val = getValue( s, "children" ); // orient_val contains "2" + QString size_val = getValue( s, "sizes" ); // val contains "332:478" + \endcode - if ( e->button() == Qt::RightButton ) - emit contextMenuRequested( e->globalPos() ); + \param str string to be processed + \param valName parameter name + \return parameter value (or null QStrinhg if parameter is not found) +*/ +static QString getValue( const QString& str, const QString& valName ) +{ + int i = str.indexOf( valName ); + if ( i != -1 ) + { + int equal_i = str.indexOf( '=', i ); + if ( equal_i != -1 ) + { + int space_i = str.indexOf( ' ', ++equal_i ); + if ( space_i != -1 ) + return str.mid( equal_i, space_i - equal_i ); + } + } + return QString(); } /*! - Custom context menu event handler + \brief Check format of splitter parameters string. + \internal + \param parameters splitter parameters description + \return \c true on success and \c false on error */ -void QtxWorkstackTabBar::contextMenuEvent( QContextMenuEvent* e ) +static bool checkFormat( const QString& parameters ) { - if ( e->reason() != QContextMenuEvent::Mouse ) - emit contextMenuRequested( e->globalPos() ); + QString params( parameters ); + // 1. begins and ends with brackets + QChar c1 = params[0]; + QChar c2 = params[int(params.length()-1)]; + bool ok = ( c1 == '(' && c2 == ')' ); + if ( !ok ) return ok; + ::cutBrackets( params ); + // 2. has splitter word + ok = ( params.left( 8 ) == "splitter" ); + if ( !ok ) return ok; + // 3. has children? = '(' is found + int i = params.indexOf( '(' ); + ok = i != -1; + if ( !ok ) return ok; + params = params.left( i ); // cut all children, they will be checked later + // 4. has orientation word and correct value + ::getValue( params, "orientation" ).toInt( &ok ); + if ( !ok ) return ok; + // 5. has sizes word and values + ok = ! ::getValue( params, "sizes" ).isEmpty(); + if ( !ok ) return ok; + // 6. check children -> number of '(' == number of ')' in original string + ok = ( parameters.contains( '(' ) == parameters.contains( ')' ) ); + return ok; } /*! - Draws label of tab bar + \brief Get splitter's children descriptions from the string. + \internal + + Child widgets descriptions are separated by '(' and ')' symbols. + + \param str string to be processed + \return child widgets descriptions */ -/* -void QtxWorkstackTabBar::paintLabel( QPainter* p, const QRect& br, QTab* t, bool has_focus ) const +static QStringList getChildren( const QString& str ) { - if ( currentTab() != t->identifier() ) + QStringList lst; + if ( !str.startsWith( "(" ) ) + return lst; + + int i = 1, + nOpen = 1, // count brackets: '(' increments nOpen, ')' decrements + start = 0; + while ( i < (int)str.length() ) { - QFont fnt = p->font(); - fnt.setUnderline( false ); - p->setFont( fnt ); + if ( str[i] == '(' ) + { + nOpen++; + if ( nOpen == 1 ) + start = i; + } + else if ( str[i] == ')' ) + { + nOpen--; + if ( nOpen == 0 ) + lst.append( str.mid( start, i-start+1 ) ); + } + i++; } - QTabBar::paintLabel( p, br, t, has_focus ); -} -*/ -/*! - Constructor -*/ -QtxWorkstackDrag::QtxWorkstackDrag( QtxWorkstack* ws, QtxWorkstackChild* child ) -: QObject( 0 ), -myWS( ws ), -myChild( child ), -myTab( -1 ), -myArea( 0 ), -myTabRect( 0 ), -myAreaRect( 0 ) -{ - QApplication::instance()->installEventFilter( this ); + return lst; } /*! - Destructor -*/ -QtxWorkstackDrag::~QtxWorkstackDrag() -{ - QApplication::instance()->removeEventFilter( this ); + \brief Get view name by index. + \internal - endDrawRect(); -} + Example: + \code + QString s = "views active='AnotherView' 'GLView' 'AnotherView'"; + QString a0 = getViewName( s, 0 ); // --> a0 contains "GLView" + QString a1 = getViewName( s, 1 ); // --> a1 contains "AnotherView" + \endcode -/*! - Custom event filter + \param str string to be processed + \param i index + \return view name */ -bool QtxWorkstackDrag::eventFilter( QObject*, QEvent* e ) +static QString getViewName( const QString& str, int i ) { - switch ( e->type() ) + QRegExp exp( "\\s'\\w+'" ); + int start = 0; // start index of view name in the string + int num = 0 ; // index of found match + while ( ( start = exp.indexIn( str, start ) ) != -1 && num < i ) { - case QEvent::MouseMove: - updateTarget( ((QMouseEvent*)e)->globalPos() ); - break; - case QEvent::MouseButtonRelease: - drawRect(); - endDrawRect(); - dropWidget(); - deleteLater(); - break; - default: - return false; + start += exp.matchedLength(); + num ++; } - return true; -} + if ( start != -1 ) // +2 and -3 avoid starting space and starting and ending ' symbols + return str.mid( start + 2, exp.matchedLength() - 3 ); -/*! - Updates internal field with widget-target for dropping - \param p - current point of dragging -*/ -void QtxWorkstackDrag::updateTarget( const QPoint& p ) -{ - int tab = -1; - QtxWorkstackArea* area = detectTarget( p, tab ); - setTarget( area, tab ); + return QString(); } /*! - \return target area for dropping by point - \param p - current point of dragging - \param tab - index of tab to dropping + \brief Get child widget with specified name. + \internal + \param parent parent widget + \param aName child widget name + \return child widget or 0 if not found */ -QtxWorkstackArea* QtxWorkstackDrag::detectTarget( const QPoint& p, int& tab ) const +static QWidget* getView( const QWidget* parent, const QString& aName ) { - if ( p.isNull() ) - return 0; - - QtxWorkstackArea* area = myWS->areaAt( p ); - if ( area ) - tab = area->tabAt( p ); - return area; + QWidget* view = 0; + QList l = qFindChildren( parent->topLevelWidget(), aName ); + if ( !l.isEmpty() ) + view = ::qobject_cast( l.first() ); + return view; } /*! - Changes target area for dropping - \param area - new target area - \param tab - tab index + \brief Setup splitter according to the specified parameters string. + \param splitter splitter to be set up + \param parameters splitter parameters description + \param sMap map containing resulting child splitters sizes */ -void QtxWorkstackDrag::setTarget( QtxWorkstackArea* area, const int tab ) +void QtxWorkstack::setSplitter( QSplitter* splitter, const QString& parameters, QMap >& sMap ) { - if ( !area || ( myArea == area && tab == myTab ) ) + printf( QString( parameters + '\n' ).toLatin1() ); + if ( !::checkFormat( parameters ) ) { + printf( "\nInvalid format of workstack parameters. Positions of viewers can not be restored.\n" ); return; + } - startDrawRect(); + QString params( parameters ); + ::cutBrackets( params ); - if ( myArea ) - drawRect(); + // get splitter sizes and store it in the map for future setting + QList sizes; + QStringList sizesLst = ::getValue( params, "sizes" ).split( ':', QString::SkipEmptyParts ); + QStringList::Iterator it; + for ( it = sizesLst.begin(); it != sizesLst.end(); ++it ) + sizes.append( (*it).toInt() ); + sMap[ splitter ] = sizes; - myTab = tab; - myArea = area; + // set orientation of splitter + int orient = ::getValue( params, "orientation" ).toInt(); + splitter->setOrientation( (Qt::Orientation)orient ); - if ( myArea ) - drawRect(); -} + // get children + QString options = params.left( params.indexOf( '(' ) ); + QString childrenStr = params.right( params.length()-options.length() ); + QStringList children = ::getChildren( childrenStr ); -/*! - Called on widget drop, inserts dropped widget to area -*/ -void QtxWorkstackDrag::dropWidget() -{ - if ( myArea ) - myArea->insertWidget( myChild->widget(), myTab ); + // debug output.. + // printf (" splitter orient=%d, sizes_count=%d, children=%d\n", orient, sizes.count(), children.count() ); + // for ( QStringList::Iterator tit = children.begin(); tit != children.end(); ++tit ) + // printf (" |-> child = [%s]\n", (*tit).latin1() ); + + for ( it = children.begin(); it != children.end(); ++it ) + { + if ( (*it).startsWith( "(splitter" ) ) + { + QSplitter* newSplitter = new QSplitter( splitter ); + setSplitter( newSplitter, *it, sMap ); + } + else if ( (*it).startsWith( "(views" ) ) + { + QtxWorkstackArea* newArea = createArea( splitter ); + QString activeViewName = ::getValue( *it, "active" ); + QWidget* activeView = 0; + activeViewName = activeViewName.mid( 1, activeViewName.length()-2 ); // chop off ' symbols + int i = 0; + QString viewName = ::getViewName( *it, i ); + while ( !viewName.isEmpty() ) + { + if ( QWidget* view = ::getView( splitter, viewName ) ) + { + newArea->insertWidget( view ); + if ( activeViewName == view->objectName() ) + activeView = view; + } + viewName = ::getViewName( *it, ++i ); + } + if ( activeView ) + newArea->setActiveWidget( activeView ); + } + } } /*! - Draws float rect + \brief Restore workstack configuration from the state description string. + \param parameters workstack state description + \return reference to this workstack */ -void QtxWorkstackDrag::drawRect() +QtxWorkstack& QtxWorkstack::operator<<( const QString& parameters ) { - if ( !myArea ) - return; + // clear the main splitter - remove all child splitters and empty areas from it + QList splitList; + QList areaList; + splitters( mySplit, splitList, false ); + areas( mySplit, areaList, false ); + for ( QList::iterator iter = splitList.begin(); iter != splitList.end(); ++iter ) + delete *iter; - QRect r = myArea->floatRect(); - int m = 2; + for ( QList::iterator it = areaList.begin(); it != areaList.end(); ++it ) + { + if ( (*it)->isEmpty() ) + delete *it; + } - r.setTop( r.top() + m + 2 ); - r.setLeft( r.left() + m + 2 ); - r.setRight( r.right() - m - 2 ); - r.setBottom( r.bottom() - m - 2 ); + // restore splitter recursively + QMap< QSplitter*, QList > sMap; + setSplitter( mySplit, parameters, sMap ); - if ( myAreaRect ) + // now mySplit may contains empty area (where all views were located before restoring) + // in order setSize to work correctly we have to exclude this area + areaList.clear(); + areas( mySplit, areaList, false ); + for ( QList::iterator delIt = areaList.begin(); delIt != areaList.end(); ++delIt ) { - myAreaRect->setGeometry( r ); - myAreaRect->setVisible( r.isValid() ); + if ( (*delIt)->isEmpty() ) + delete *delIt; } - QRect tr = myArea->floatTab( myTab ); + QApplication::instance()->processEvents(); - tr.setTop( tr.top() + m ); - tr.setLeft( tr.left() + m ); - tr.setRight( tr.right() - m ); - tr.setBottom( tr.bottom() - m ); + // restore splitters' sizes (map of sizes is filled in setSplitters) + for ( QMap< QSplitter*, QList >::iterator itm = sMap.begin(); itm != sMap.end(); ++itm ) + itm.key()->setSizes( itm.value() ); - if ( myTabRect ) - { - myTabRect->setGeometry( tr ); - myTabRect->setVisible( tr.isValid() ); - } + return (*this); } /*! - Deletes internal painter + \brief Dump workstack configuration to the state description string. + \param parameters resulting workstack state description + \return reference to this workstack */ -void QtxWorkstackDrag::endDrawRect() +QtxWorkstack& QtxWorkstack::operator>>( QString& outParameters ) { - delete myAreaRect; - myAreaRect = 0; - - delete myTabRect; - myTabRect = 0; + splitterInfo( mySplit, outParameters ); + return (*this); } /*! - Initialize internal painter + \fn void QtxWorkstack::windowActivated( QWidget* w ) + \brief Emitted when the workstack's child widget \w is activated. + \param w widget being activated */ -void QtxWorkstackDrag::startDrawRect() -{ - if ( !myTabRect ) - myTabRect = new QRubberBand( QRubberBand::Rectangle ); - - myTabRect->hide(); - - if ( !myAreaRect ) - myAreaRect = new QRubberBand( QRubberBand::Rectangle ); - - myAreaRect->hide(); -} diff --git a/src/Qtx/QtxWorkstack.h b/src/Qtx/QtxWorkstack.h index 767127530..17adf9428 100644 --- a/src/Qtx/QtxWorkstack.h +++ b/src/Qtx/QtxWorkstack.h @@ -24,18 +24,17 @@ #include "Qtx.h" -#include -#include -#include -#include +#include +#include +#include +#include +#include class QAction; -class QTabBar; -class QPainter; class QSplitter; class QPushButton; -class QRubberBand; class QStackedWidget; +class QRubberBand; class QtxWorkstackArea; class QtxWorkstackDrag; @@ -51,13 +50,21 @@ class QTX_EXPORT QtxWorkstack : public QWidget Q_OBJECT public: - enum { SplitVertical, SplitHorizontal, Close, Rename }; + //! Workstack actions (context menu items) + enum { SplitVertical = 0x01, //!< "Split vertically" menu item + SplitHorizontal = 0x02, //!< "Split horizontally" menu item + Close = 0x04, //!< "Close" menu item + Rename = 0x08, //!< "Rename" menu item + All = SplitVertical | SplitHorizontal | + Close | Rename //!< all menu items + }; + //! Workstack splitting type enum SplitType { - SPLIT_STAY, //!< given widget stays in its workarea, others are moved into a new one - SPLIT_AT, //!< widgets before a given widget stays in they workarea, others are moved into a new one - SPLIT_MOVE //!< given widget is moved into a new workarea, others stay in an old one + SplitStay, //!< selected widget stays in current workarea, others widgets are moved into a new workarea + SplitAt, //!< all widgets before selected widget stay in current workarea, other widgess are moved into a new workarea + SplitMove //!< selected widget is moved into a new workarea, all other widgets stay in an old workarea }; public: @@ -72,8 +79,8 @@ public: int accel( const int ) const; void setAccel( const int, const int ); - bool isActionEnabled( const int ) const; - void setActionEnabled( const int, const bool ); + void setMenuActions( const int ); + int menuActions() const; void split( const int ); @@ -88,14 +95,14 @@ public: QtxWorkstack& operator<<( const QString& ); QtxWorkstack& operator>>( QString& ); -Q_SIGNALS: +signals: void windowActivated( QWidget* ); -public Q_SLOTS: +public slots: void splitVertical(); void splitHorizontal(); -private Q_SLOTS: +private slots: void onRename(); void onCloseWindow(); void onDestroyed( QObject* ); @@ -136,13 +143,13 @@ private: void setSplitter( QSplitter*, const QString&, QMap< QSplitter*, QList >& ); private: - QWidget* myWin; - QtxWorkstackArea* myArea; - QSplitter* mySplit; - QWidget* myWorkWin; - QtxWorkstackArea* myWorkArea; + QWidget* myWin; //!< active widget + QtxWorkstackArea* myArea; //!< active workarea + QSplitter* mySplit; //!< tol-level splitter + QWidget* myWorkWin; //!< widget where popup menu is invoked (used internally) + QtxWorkstackArea* myWorkArea; //!< workarea where popup menu is invoked (used internally) - QMap myActionsMap; //!< The map of the actions. Allows to get the QAction object by the key. + QMap myActionsMap; //!< actions map friend class QtxWorkstackArea; friend class QtxWorkstackDrag; @@ -182,15 +189,15 @@ public: int tabAt( const QPoint& ) const; -Q_SIGNALS: +signals: void activated( QWidget* ); void contextMenuRequested( QWidget*, QPoint ); void deactivated( QtxWorkstackArea* ); -public Q_SLOTS: +public slots: virtual void setVisible( bool ); -private Q_SLOTS: +private slots: void onClose(); void onCurrentChanged( int ); @@ -198,7 +205,7 @@ private Q_SLOTS: void onChildDestroyed( QObject* ); void onChildShown( QtxWorkstackChild* ); - void onChildHided( QtxWorkstackChild* ); + void onChildHidden( QtxWorkstackChild* ); void onChildActivated( QtxWorkstackChild* ); void onChildCaptionChanged( QtxWorkstackChild* ); @@ -211,7 +218,11 @@ protected: virtual void mousePressEvent( QMouseEvent* ); private: - enum { ActivateWidget = QEvent::User, FocusWidget, RemoveWidget }; + //! Custom events + enum { ActivateWidget = QEvent::User, //!< activate widget event + FocusWidget, //!< focus receiving widget event + RemoveWidget //!< widget removing event + }; private: void updateState(); @@ -244,14 +255,14 @@ private: typedef QMap WidgetInfoMap; private: - QtxWorkstackTabBar* myBar; - QPushButton* myClose; - QStackedWidget* myStack; - - QWidgetList myList; - WidgetInfoMap myInfo; - ChildMap myChild; - BlockMap myBlock; + QtxWorkstackTabBar* myBar; //!< workarea tab bar header + QPushButton* myClose; //!< close button + QStackedWidget* myStack; //!< widget stack + + QWidgetList myList; //!< child widgets list + WidgetInfoMap myInfo; //!< widgets states mp + ChildMap myChild; //!< child widget containers map + BlockMap myBlock; //!< blocked widgets }; class QtxWorkstackChild : public QWidget @@ -266,20 +277,20 @@ public: virtual bool eventFilter( QObject*, QEvent* ); -Q_SIGNALS: +signals: void shown( QtxWorkstackChild* ); - void hided( QtxWorkstackChild* ); + void hidden( QtxWorkstackChild* ); void activated( QtxWorkstackChild* ); void captionChanged( QtxWorkstackChild* ); -private Q_SLOTS: +private slots: void onDestroyed( QObject* ); protected: virtual void childEvent( QChildEvent* ); private: - QWidget* myWidget; + QWidget* myWidget; //!< child widget }; class QtxWorkstackTabBar : public QTabBar @@ -299,11 +310,11 @@ public: void updateActiveState(); -Q_SIGNALS: +signals: void dragActiveTab(); void contextMenuRequested( QPoint ); -private Q_SLOTS: +private slots: void onCurrentChanged( int ); protected: @@ -315,8 +326,8 @@ protected: // virtual void paintLabel( QPainter*, const QRect&, QTab*, bool ) const; private: - int myId; - bool myActive; + int myId; //!< current tab page index + bool myActive; //!< "active" status }; class QtxWorkstackDrag : public QObject @@ -341,17 +352,17 @@ private: void startDrawRect(); private: - QtxWorkstack* myWS; - QtxWorkstackChild* myChild; + QtxWorkstack* myWS; //!< parent workstack + QtxWorkstackChild* myChild; //!< workstack child widget container - int myTab; - QtxWorkstackArea* myArea; - QRubberBand* myTabRect; - QRubberBand* myAreaRect; + int myTab; //!< workarea tab page index + QtxWorkstackArea* myArea; //!< workarea + QRubberBand* myTabRect; //!< tab bar rubber band + QRubberBand* myAreaRect; //!< workarea rubber band }; #ifdef WIN32 #pragma warning( default:4251 ) #endif -#endif +#endif // QTXWORKSTACK_H diff --git a/src/Qtx/QtxWorkstackAction.cxx b/src/Qtx/QtxWorkstackAction.cxx new file mode 100644 index 000000000..4a4cb0f79 --- /dev/null +++ b/src/Qtx/QtxWorkstackAction.cxx @@ -0,0 +1,367 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxWorkstackAction.cxx +// Author: Sergey TELKOV + +#include "QtxWorkstackAction.h" + +#include "QtxWorkstack.h" + +#include +#include + +/*! + \class QtxWorkstackAction + \brief Implements actions group for menu Windows with standard operations, like + "Split vertical", "Split horizontal", etc. +*/ + +/*! + \brief Constructor. + \param ws workstack + \param parent parent object (owner of the action) +*/ +QtxWorkstackAction::QtxWorkstackAction( QtxWorkstack* ws, QObject* parent ) +: QtxActionSet( parent ), + myWorkstack( ws ), + myWindowsFlag( true ) +{ + insertAction( new QtxAction( tr( "Split the active window on two vertical parts" ), + tr( "Split vertically" ), 0, this ), SplitVertical ); + insertAction( new QtxAction( tr( "Split the active window on two horizontal parts" ), + tr( "Split horizontally" ), 0, this ), SplitHorizontal ); + + connect( this, SIGNAL( triggered( int ) ), this, SLOT( onTriggered( int ) ) ); + + setMenuActions( Standard ); +} + +/*! + \brief Destructor. +*/ +QtxWorkstackAction::~QtxWorkstackAction() +{ +} + +/*! + \brief Get workstack. + \return parent workstack +*/ +QtxWorkstack* QtxWorkstackAction::workstack() const +{ + return myWorkstack; +} + +/*! + \brief Set actions to be visible in the menu. + + Actions, which IDs are set in \a flags parameter, will be shown in the + menu bar. Other actions will not be shown. + + \param flags ORed together actions flags +*/ +void QtxWorkstackAction::setMenuActions( const int flags ) +{ + action( SplitVertical )->setVisible( flags & SplitVertical ); + action( SplitHorizontal )->setVisible( flags & SplitHorizontal ); + myWindowsFlag = flags & Windows; +} + +/*! + \brief Get menu actions which are currently visible in the menu bar. + \return ORed together actions flags + \sa setMenuActions() +*/ +int QtxWorkstackAction::menuActions() const +{ + int ret = 0; + ret = ret | ( action( SplitVertical )->isVisible() ? SplitVertical : 0 ); + ret = ret | ( action( SplitHorizontal )->isVisible() ? SplitHorizontal : 0 ); + ret = ret | ( myWindowsFlag ? Windows : 0 ); + return ret; +} + +/*! + \brief Get keyboard accelerator for the specified action. + \param id menu action ID + \return keyboard accelerator of menu item or 0 if there is no such action +*/ +int QtxWorkstackAction::accel( const int id ) const +{ + int a = 0; + if ( action( id ) ) + a = action( id )->shortcut(); + return a; +} + +/*! + \brief Get icon for the specified action. + + If \a id is invalid, null icon is returned. + + \param id menu action ID + \return menu item icon +*/ +QIcon QtxWorkstackAction::icon( const int id ) const +{ + QIcon ico; + if ( action( id ) ) + ico = action( id )->icon(); + return ico; +} + +/*! + \brief Get menu item text for the specified action. + \param id menu action ID + \return menu item text or null QString if there is no such action +*/ +QString QtxWorkstackAction::text( const int id ) const +{ + QString txt; + if ( action( id ) ) + txt = action( id )->text(); + return txt; +} + +/*! + \brief Get status bar tip for the specified action. + \param id menu action ID + \return status bar tip menu item or null QString if there is no such action +*/ +QString QtxWorkstackAction::statusTip( const int id ) const +{ + QString txt; + if ( action( id ) ) + txt = action( id )->statusTip(); + return txt; +} + +/*! + \brief Set keyboard accelerator for the specified action. + \param id menu action ID + \param a new keyboard accelerator +*/ +void QtxWorkstackAction::setAccel( const int id, const int a ) +{ + if ( action( id ) ) + action( id )->setShortcut( a ); +} + +/*! + \brief Set menu item icon for the specified action. + \param id menu action ID + \param ico new menu item icon +*/ +void QtxWorkstackAction::setIcon( const int id, const QIcon& icon ) +{ + if ( action( id ) ) + action( id )->setIcon( icon ); +} + +/*! + \brief Set menu item text for the specified action. + \param id menu action ID + \param txt new menu item text +*/ +void QtxWorkstackAction::setText( const int id, const QString& txt ) +{ + if ( action( id ) ) + action( id )->setText( txt ); +} + +/*! + \brief Set menu item status bar tip for the specified action. + \param id menu action ID + \param txt new menu item status bar tip +*/ +void QtxWorkstackAction::setStatusTip( const int id, const QString& txt ) +{ + if ( action( id ) ) + action( id )->setStatusTip( txt ); +} + +/*! + \brief Process action activated by the user. + \param type action ID +*/ +void QtxWorkstackAction::perform( const int type ) +{ + switch ( type ) + { + case SplitVertical: + splitVertical(); + break; + case SplitHorizontal: + splitHorizontal(); + break; + } +} + +/*! + \brief Split the window area in the workstack in the vertical direction. +*/ +void QtxWorkstackAction::splitVertical() +{ + QtxWorkstack* ws = workstack(); + if ( ws ) + ws->splitVertical(); +} + +/*! + \brief Split the window area in the workstack in the horizontal direction. +*/ +void QtxWorkstackAction::splitHorizontal() +{ + QtxWorkstack* ws = workstack(); + if ( ws ) + ws->splitHorizontal(); +} + +/*! + \brief Called when action is added to the menu bar. + \param w menu bar widget this action is being added to +*/ +void QtxWorkstackAction::addedTo( QWidget* w ) +{ + QtxActionSet::addedTo( w ); + + QMenu* pm = ::qobject_cast( w ); + if ( pm ) + connect( pm, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) ); +} + +/*! + \brief Called when action is removed from the menu bar. + \param w menu bar widget this action is being removed from +*/ +void QtxWorkstackAction::removedFrom( QWidget* w ) +{ + QtxActionSet::removedFrom( w ); + + QMenu* pm = ::qobject_cast( w ); + if ( pm ) + disconnect( pm, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) ); +} + +/*! + \brief Update all menu action state. +*/ +void QtxWorkstackAction::updateContent() +{ + bool count = workstack() ? workstack()->splitWindowList().count() > 1 : 0; + action( SplitVertical )->setEnabled( count ); + action( SplitHorizontal )->setEnabled( count ); + + updateWindows(); +} + +/*! + \brief Update actions which refer to the opened child windows. +*/ +void QtxWorkstackAction::updateWindows() +{ + QtxWorkstack* ws = workstack(); + if ( !ws ) + return; + + QList lst = actions(); + for ( QList::iterator it = lst.begin(); it != lst.end(); ++it ) + { + int id = actionId( *it ); + if ( id >= Windows ) + removeAction( *it ); + } + + bool base = action( SplitVertical )->isVisible() || action( SplitHorizontal )->isVisible(); + + QList items; + QMap map; + if ( menuActions() & Windows ) + { + int index = 1; + QWidgetList wList = ws->windowList(); + for ( QWidgetList::iterator it = wList.begin(); it != wList.end(); ++it, index++ ) + { + QWidget* wid = *it; + QAction* a = new QtxAction( wid->windowTitle(), wid->windowTitle(), 0, this, true ); + a->setChecked( wid == ws->activeWindow() ); + items.append( a ); + map.insert( a, Windows + index ); + } + + if ( base && !items.isEmpty() ) + { + QAction* sep = new QtxAction( this ); + sep->setSeparator( true ); + items.prepend( sep ); + map.insert( sep, Windows ); + } + } + + if ( !items.isEmpty() ) + insertActions( items ); + + for ( QMap::const_iterator itr = map.begin(); itr != map.end(); ++itr ) + setActionId( itr.key(), itr.value() ); +} + +/*! + \brief Called when parent menu is about to show. + + Updates all menu items. +*/ +void QtxWorkstackAction::onAboutToShow() +{ + QMenu* pm = ::qobject_cast( sender() ); + if ( pm ) + updateContent(); +} + +/*! + \brief Called when menu item corresponding to some child window is activated. + + Activates correposponding child window. + + \param idx menu item index +*/ +void QtxWorkstackAction::activateItem( const int idx ) +{ + QtxWorkstack* ws = workstack(); + if ( !ws ) + return; + + QWidgetList wList = ws->windowList(); + if ( idx >= 0 && idx < (int)wList.count() ) + wList.at( idx )->setFocus(); +} + +/*! + \brief Called when menu item is activated by the user. + + Perform the corresponding action. + + \param id menu item identifier +*/ +void QtxWorkstackAction::onTriggered( int id ) +{ + if ( id < Windows ) + perform( id ); + else + activateItem( id - Windows - 1 ); +} diff --git a/src/Qtx/QtxWorkstackAction.h b/src/Qtx/QtxWorkstackAction.h new file mode 100644 index 000000000..a9228a507 --- /dev/null +++ b/src/Qtx/QtxWorkstackAction.h @@ -0,0 +1,89 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// 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. +// +// 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: QtxWorkstackAction.h +// Author: Sergey TELKOV + +#ifndef QTXWORKSTACKACTION_H +#define QTXWORKSTACKACTION_H + +#include "QtxActionSet.h" + +class QtxWorkstack; + +#ifdef WIN32 +#pragma warning( disable:4251 ) +#endif + +class QTX_EXPORT QtxWorkstackAction : public QtxActionSet +{ + Q_OBJECT + +public: + //! Actions (menu items) ID + enum { SplitVertical = 0x0001, //!< "Split window vertically" operation + SplitHorizontal = 0x0002, //!< "Split window horizontally" operation + Windows = 0x0010, //!< A list of child windows menu items + Split = SplitVertical | SplitHorizontal, + Standard = Split | Windows }; + + QtxWorkstackAction( QtxWorkstack*, QObject* = 0 ); + virtual ~QtxWorkstackAction(); + + QtxWorkstack* workstack() const; + + int menuActions() const; + void setMenuActions( const int ); + + QIcon icon( const int ) const; + QString text( const int ) const; + int accel( const int ) const; + QString statusTip( const int ) const; + + void setAccel( const int, const int ); + void setIcon( const int, const QIcon& ); + void setText( const int, const QString& ); + void setStatusTip( const int, const QString& ); + + void perform( const int ); + +private slots: + void onAboutToShow(); + void onTriggered( int ); + +protected: + virtual void addedTo( QWidget* ); + virtual void removedFrom( QWidget* ); + +private: + void updateContent(); + void updateWindows(); + void splitVertical(); + void splitHorizontal(); + void activateItem( const int ); + +private: + QtxWorkstack* myWorkstack; //!< parent workstack + bool myWindowsFlag; //!< "show child windows items" flag +}; + +#ifdef WIN32 +#pragma warning( default:4251 ) +#endif + +#endif