#include <QRadialGradient>
#include <QConicalGradient>
+#include <QtDebug>
+
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <clocale>
+
+#define BICOLOR_CHANGE_HUE
/*!
\class Qtx
*/
QString Qtx::tmpDir()
{
- char* tmpdir = ::getenv( "TEMP" );
+ const char* tmpdir = ::getenv( "TEMP" );
if ( !tmpdir )
tmpdir = ::getenv ( "TMP" );
if ( !tmpdir )
return cmp;
}
+/*!
+ \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 Qtx::findEnvVar( const QString& str, int& start, int& len )
+{
+ QString varName;
+ len = 0;
+
+ QRegExp rx( "(^\\$\\{|[^\\$]\\$\\{)([a-zA-Z]+[a-zA-Z0-9_]*)(\\})|(^\\$\\(|[^\\$]\\$\\()([a-zA-Z]+[a-zA-Z0-9_]*)(\\))|(^\\$|[^\\$]\\$)([a-zA-Z]+[a-zA-Z0-9_]*)|(^%|[^%]%)([a-zA-Z]+[a-zA-Z0-9_]*)(%[^%]|%$)" );
+
+ int pos = rx.indexIn( str, start );
+ if ( pos != -1 )
+ {
+ int i = 1;
+ while ( i <= rx.numCaptures() && varName.isEmpty() )
+ {
+ QString capStr = rx.cap( i );
+ if ( !capStr.contains( "%" ) && !capStr.contains( "$" ) )
+ varName = capStr;
+ i++;
+ }
+
+ if ( !varName.isEmpty() )
+ {
+ int capIdx = i - 1;
+ start = rx.pos( capIdx );
+ int end = start + varName.length();
+ if ( capIdx > 1 && rx.cap( capIdx - 1 ).contains( QRegExp( "\\$|%" ) ) )
+ start = rx.pos( capIdx - 1 ) + rx.cap( capIdx - 1 ).indexOf( QRegExp( "\\$|%" ) );
+ if ( capIdx < rx.numCaptures() && !rx.cap( capIdx - 1 ).isEmpty() )
+ end++;
+ len = end - start;
+ }
+ }
+ return varName;
+}
+
+/*!
+ \brief Substitute environment variables by their values.
+
+ Environment variable is substituted by its value.
+
+ \param str string to be processed
+ \return processed string (with all substitutions made)
+*/
+QString Qtx::makeEnvVarSubst( const QString& str, const SubstMode mode )
+{
+ QString res = str;
+ if ( mode != Never )
+ {
+ QMap<QString, int> ignoreMap;
+
+ int start( 0 ), len( 0 );
+ while ( true )
+ {
+ QString envName = findEnvVar( res, start, len );
+ if ( envName.isNull() )
+ break;
+
+ QString newStr;
+ if ( ::getenv( envName.toLatin1() ) || mode == Always )
+ newStr = QString( ::getenv( envName.toLatin1() ) );
+
+ if ( newStr.isNull() )
+ {
+ if ( ignoreMap.contains( envName ) )
+ {
+ start += len;
+ continue;
+ }
+ ignoreMap.insert( envName, 0 );
+ }
+ res.replace( start, len, newStr );
+ }
+
+ res.replace( "$$", "$" );
+ res.replace( "%%", "%" );
+ }
+
+ return res;
+}
+
/*!
\brief Pack the specified color into integer RGB set.
\param c unpacked color
/*!
\brief Scale the pixmap to the required size.
- If \h is 0 (default) the value of \a w is used instead (to create
+ If \a h is 0 (default) the value of \a w is used instead (to create
square pixmap).
\param icon pixmap to be resized
{
QPixmap p;
int aw = w, ah = h <= 0 ? w : h;
- if ( icon.isNull() || aw <= 0 || ah <= 0 || aw == icon.width() && ah == icon.height() )
+ if ( icon.isNull() || aw <= 0 || ah <= 0 || ( aw == icon.width() && ah == icon.height() ) )
p = icon;
else
p = icon.fromImage( icon.toImage().scaled( aw, ah, Qt::KeepAspectRatio, Qt::SmoothTransformation ) );
- "RR,GG,BB[,AA]" or "RR GG BB[ AA]" (\c RR, \c GG, \c BB
and optional \c AA values represent red, green, blue and alpha
components of the color in decimal form)
- - #RRGGBB" - (\c RR, \c GG and \c BB values represent red, green and blue
+ - "#RRGGBB" - (\c RR, \c GG and \c BB values represent red, green and blue
components of the color in hexadecimal form)
- an integer value representing packed color components (see rgbSet())
- a name from the list of colors defined in the list of SVG color keyword names
return res;
}
+/*!
+ \brief Convert bi-color value to the string representation.
+
+ Bi-color value is specified as main color and integer delta
+ value that is used to calculate secondary color by changing
+ paremeters of the main color ("saturation" and "value"
+ components in HSV notation).
+
+ The resulting string consists of two sub-strings separated by
+ '|' symbol. The first part represents main color
+ (see colorToString() for more details), the second part is a
+ delta value.
+
+ Backward conversion can be done with stringToBiColor() method.
+
+ \param color color to be converted
+ \param delta delta value
+ \return string representation of the bi-color value
+
+ \sa stringToBiColor(), stringToColor()
+*/
+QString Qtx::biColorToString( const QColor& color, const int delta )
+{
+ return QString("%1|%2").arg( Qtx::colorToString( color ) ).arg( delta );
+}
+
+/*!
+ \brief Restore bi-color value from the string representation.
+
+ Bi-color value is specified as main color and integer delta
+ value that is used to calculate secondary color by changing
+ paremeters of the main color ("saturation" and "value"
+ components in HSV notation).
+
+ The parameter \a str should consist of two sub-strings separated
+ by '|' symbol. The first part represents main color
+ (see stringToColor() for more details), the second part is a
+ delta value.
+
+ Backward conversion can be done with biColorToString() method.
+
+ \param str string representation of the bi-color value
+ \param color resulting color value
+ \param delta resulting delta value
+ \return \c true if the conversion is successful and \c false otherwise
+
+ \sa biColorToString(), stringToColor(), rgbSet()
+*/
+bool Qtx::stringToBiColor( const QString& str, QColor& color, int& delta )
+{
+ QStringList data = str.split( "|", QString::KeepEmptyParts );
+ QColor c;
+ int d = 0;
+ bool ok = data.count() > 0 && Qtx::stringToColor( data[0], c );
+ bool dok = false;
+ if ( data.count() > 1 ) d = data[1].toInt( &dok );
+ ok = ok && dok;
+ color = ok ? c : QColor();
+ delta = ok ? d : 0;
+ return ok;
+}
+
+/*!
+ \brief Compute secondary color value from specified main color
+ and delta.
+
+ Secondary color is calculated by changing paremeters of the main
+ color ("saturation" and "value" components in HSV notation) using
+ specified delta.
+
+ If main color is invalid, result of the function is also invalid color.
+
+ \param color source main color
+ \param delta delta value
+ \return resulting secondary color
+
+ \sa biColorToString(), stringToBiColor()
+*/
+QColor Qtx::mainColorToSecondary( const QColor& color, int delta )
+{
+ QColor cs = color;
+ if ( cs.isValid() ) {
+ int val = qMin( 255, qMax( cs.value() + delta, 0 ) );
+ int sat = qMin( 255, qMax( cs.saturation() + delta-(val-cs.value()), 0 ) );
+#ifdef BICOLOR_CHANGE_HUE
+ const int BICOLOR_HUE_MAXDELTA = 40;
+ int dh = delta-(val-cs.value())-(sat-cs.saturation());
+ dh = qMin( BICOLOR_HUE_MAXDELTA, qAbs( dh ) ) * ( dh > 0 ? 1 : -1 );
+ //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-(sat-cs.saturation()), 0 ) );
+ //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-ds, 0 ) );
+ int hue = cs.hue() + dh;
+ if ( hue < 0 ) hue = 360 - hue;
+#else
+ int hue = cs.hue();
+#endif
+ cs.setHsv( hue, sat, val );
+ }
+ return cs;
+}
+
/*!
\brief Dump linear gradient to the string description.
\param gradient linear gradient to be converted
{
bool success = false;
QStringList vals = str.split( "|", QString::SkipEmptyParts );
- if ( vals.count() > 5 && vals[0] == "radial" || vals[0] == "rg" )
+ if ( ( vals.count() > 5 && vals[0] == "radial" ) || vals[0] == "rg" )
{
// center, radius and focal point
double cx, cy, r, fx, fy;
{
bool success = false;
QStringList vals = str.split( "|", QString::SkipEmptyParts );
- if ( vals.count() > 3 && vals[0] == "conical" || vals[0] == "cg" )
+ if ( ( vals.count() > 3 && vals[0] == "conical" ) || vals[0] == "cg" )
{
// center and angle
double cx, cy, a;
return success;
}
-/**
- * Cheque for existing any system printers
+/*!
+ \class Qtx::Localizer
+ \brief Localization helper
+
+ This helper class can be used to solve the localization problems,
+ usually related to the textual files reading/writing, namely when
+ floating point values are read / written with API functions.
+ The problem relates to such locale specific settings as decimal point
+ separator, thousands separator, etc.
+
+ To use the Localizer class, just create a local variable in the beginning
+ of the code where you need to read / write data from textual file(s).
+ The constructor of the class forces setting "C" locale temporariy.
+ The destructor switches back to the initial locale.
+
+ \code
+ Qtx::Localizer loc;
+ readSomething();
+ writeSomething();
+ \endcode
*/
-#if !defined(WIN32) && !defined(QT_NO_CUPS)
-#if QT_VERSION < 0x040303
-#include <QLibrary>
-#include <cups/cups.h>
+/*!
+ \brief Constructor. Forces "C" locale to be set.
+*/
+Qtx::Localizer::Localizer()
+{
+ myCurLocale = setlocale( LC_NUMERIC, 0 );
+ setlocale( LC_NUMERIC, "C" );
+}
-typedef int (*CupsGetDests)(cups_dest_t **dests);
-static CupsGetDests _cupsGetDests = 0;
-#endif
-#endif
-bool Qtx::hasAnyPrinters()
+/*!
+ \brief Destructor. Reverts back to the initial locale.
+*/
+Qtx::Localizer::~Localizer()
{
- bool aRes = true;
-#if !defined(WIN32) && !defined(QT_NO_CUPS)
-#if QT_VERSION < 0x040303
- QLibrary aCupsLib( QString( "cups" ), 2 );
- if ( !aCupsLib.load() )
- aRes = false;
- else {
- cups_dest_t *printers;
- _cupsGetDests = (CupsGetDests) aCupsLib.resolve("cupsGetDests");
- int prnCount = _cupsGetDests(&printers);
- aRes = prnCount > 0;
+ setlocale( LC_NUMERIC, myCurLocale.toLatin1().constData() );
}
-#endif
-#endif
- return aRes;
+
+#ifndef WIN32
+
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+
+/*!
+ \brief Open the default X display and returns pointer to it.
+ This method is available on Linux only.
+ \return Pointer to X display.
+ \sa getVisual()
+*/
+void* Qtx::getDisplay()
+{
+ static Display* pDisplay = NULL;
+ if ( !pDisplay )
+ pDisplay = XOpenDisplay( NULL );
+ return pDisplay;
+}
+
+/*!
+ \brief Returns pointer to X visual suitable for 3D rendering.
+ This method is available on Linux only.
+ \return Pointer to X visual.
+ \sa getDisplay()
+*/
+Qt::HANDLE Qtx::getVisual()
+{
+ Qt::HANDLE res = (Qt::HANDLE)NULL;
+
+ Display* pDisplay = (Display*)getDisplay();
+ if ( !pDisplay )
+ return res;
+
+ int errorBase;
+ int eventBase;
+
+ // Make sure OpenGL's GLX extension supported
+ if( !glXQueryExtension( pDisplay, &errorBase, &eventBase ) ){
+ qCritical( "Could not find glx extension" );
+ return res;
+ }
+
+ // Find an appropriate visual
+
+ int doubleBufferVisual[] = {
+ GLX_RGBA, // Needs to support OpenGL
+ GLX_DEPTH_SIZE, 16, // Needs to support a 16 bit depth buffer
+ GLX_DOUBLEBUFFER, // Needs to support double-buffering
+ None // end of list
+ };
+
+ // Try for the double-bufferd visual first
+ XVisualInfo *visualInfo = NULL;
+ visualInfo = glXChooseVisual( pDisplay, DefaultScreen(pDisplay), doubleBufferVisual );
+
+ if( visualInfo == NULL ){
+ qCritical( "Could not find matching glx visual" );
+ return res;
+ }
+
+ qDebug() << "Picked visual 0x" << hex << XVisualIDFromVisual( visualInfo->visual );
+ res = (Qt::HANDLE)( visualInfo->visual );
+
+ return res;
}
+#endif // WIN32
#define QTX_H
#if defined WIN32
-# if defined QTX_EXPORTS
+# if defined QTX_EXPORTS || defined qtx_EXPORTS
# define QTX_EXPORT _declspec( dllexport )
# else
# define QTX_EXPORT _declspec( dllimport )
AppropriateRole = Qt::UserRole + 100 //!< can be used to return \c true if data is appropriate
};
+ typedef enum {
+ Shown, //!< column should be always visible
+ Hidden, //!< column should be always hidden
+ Toggled //!< it should be possible to show/hide the column with help of popup menu
+ } Appropriate; //!< appropriate status
+
+ //! Environment variables substitution mode
+ typedef enum {
+ Always, //!< substitute environment variable by it's value if variable exists, and "" otherwise
+ Never, //!< keep environment variable as is without any substitution
+ Auto //!< substitute environment variable by it's value if variable exists, and keep it as is otherwise
+ } SubstMode;
+
+ //! object visibility state
+ typedef enum {
+ ShownState, //!< Object is shown in viewer
+ HiddenState, //!< Object is hidden in viewer
+ UnpresentableState, //!< Unpresentable object
+ } VisibilityState;
+
+ //! Header view flags
+ typedef enum {
+ ShowText = 0x001, //!< Show only text in the header
+ ShowIcon = 0x010, //!< Show only icon in the header
+ ShowAll = ShowText | ShowIcon //!< Show icon and text in the header
+ } HeaderViewFlags;
+
+ //Type of the custom data
+ typedef enum {
+ IdType
+ } CustomDataType;
+
+
+
+ class QTX_EXPORT Localizer
+ {
+ public:
+ Localizer();
+ ~Localizer();
+ private:
+ QString myCurLocale;
+ };
+
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 addSlash( const QString& );
static QCompleter* pathCompleter( const PathType, const QString& = QString() );
+ static QString findEnvVar( const QString&, int&, int& );
+ static QString makeEnvVarSubst( const QString&, const SubstMode = Auto );
static int rgbSet( const QColor& );
static int rgbSet( const int, const int, const int );
static QString colorToString( const QColor& );
static bool stringToColor( const QString&, QColor& );
+ static QString biColorToString( const QColor&, const int );
+ static bool stringToBiColor( const QString&, QColor&, int& );
+ static QColor mainColorToSecondary( const QColor&, int );
static QString gradientToString( const QLinearGradient& );
static QString gradientToString( const QRadialGradient& );
static bool stringToRadialGradient( const QString&, QRadialGradient& );
static bool stringToConicalGradient( const QString&, QConicalGradient& );
- static bool hasAnyPrinters();
+#ifndef WIN32
+ static void* getDisplay();
+ static Qt::HANDLE getVisual();
+#endif
};
#endif
CONFIG += embed_manifest_exe
win32:LIBS *= -L$(QTLIB)
+unix:LIBS *= -lGL
win32:INCLUDEPATH *= $(QTINC) $(QTINC)\QtCore $(QTINC)\QtGui $(QTINC)\QtXml
QT += xml
*/
QtxFontEdit::QtxFontEdit( const int feat, QWidget* parent )
: QFrame( parent ),
- myFeatures( feat )
+ myFeatures( feat ),
+ myMode( Native )
{
initialize();
}
*/
QtxFontEdit::QtxFontEdit( QWidget* parent )
: QFrame( parent ),
- myFeatures( All )
+ myFeatures( All ),
+ myMode( Native )
{
initialize();
}
fnt.setBold( script & Bold );
fnt.setItalic( script & Italic );
fnt.setUnderline( script & Underline );
+ fnt.setOverline( script & Shadow ); //addVtkFontPref( tr( "LABELS" ), valLblFontGr, "values_labeling_font" );
return fnt;
}
*/
void QtxFontEdit::setCurrentFont( const QFont& fnt )
{
+ myFamily->blockSignals( true );
+ myCustomFams->blockSignals( true );
+ mySize->blockSignals( true );
+ myB->blockSignals( true );
+ myI->blockSignals( true );
+ myU->blockSignals( true );
+
setFontFamily( fnt.family() );
setFontSize( fnt.pointSize() );
setFontScripting( ( fnt.bold() ? Bold : 0 ) |
( fnt.italic() ? Italic : 0 ) |
- ( fnt.underline() ? Underline : 0 ) );
+ ( fnt.underline() ? Underline : 0 ) |
+ ( fnt.overline() ? Shadow : 0 ) );
+
+ myFamily->blockSignals( false );
+ myCustomFams->blockSignals( false );
+ mySize->blockSignals( false );
+ myB->blockSignals( false );
+ myI->blockSignals( false );
+ myU->blockSignals( false );
+
+ emit( changed( currentFont() ) );
}
/*!
*/
QString QtxFontEdit::fontFamily() const
{
+ if ( myMode == Native )
return myFamily->currentFont().family();
+ else
+ return myCustomFams->currentText();
}
/*!
{
return ( myB->isChecked() ? Bold : 0 ) |
( myI->isChecked() ? Italic : 0 ) |
- ( myU->isChecked() ? Underline : 0 );
+ ( myU->isChecked() ? Underline : 0 ) |
+ ( myS->isChecked() ? Shadow : 0 ) ;
}
/*!
*/
void QtxFontEdit::setFontFamily( const QString& fam )
{
+ if ( myMode == Native )
+ {
myFamily->setCurrentFont( QFont( fam ) );
onFontChanged( myFamily->currentFont() );
}
+ else
+ {
+ myCustomFams->setCurrentIndex( myCustomFams->findText( fam ) );
+ if ( !myCustomFams->signalsBlocked() )
+ emit( changed( currentFont() ) );
+ }
+}
/*!
\brief Set font size.
myB->setChecked( script & Bold );
myI->setChecked( script & Italic );
myU->setChecked( script & Underline );
+ myS->setChecked( script & Shadow );
}
/*!
{
int feat = features();
- myFamily->setVisible( feat & Family );
+ myFamily->setVisible( ( feat & Family ) && myMode == Native );
+ myCustomFams->setVisible( ( feat & Family ) && myMode == Custom );
mySize->setVisible( feat & Size );
myB->setVisible( feat & Bold );
myI->setVisible( feat & Italic );
myU->setVisible( feat & Underline );
+ myS->setVisible( feat & Shadow );
myPreview->setVisible( feat & Preview );
mySize->setEditable( feat & UserSize );
*/
void QtxFontEdit::onFontChanged( const QFont& /*f*/ )
{
+ bool blocked = mySize->signalsBlocked();
+ mySize->blockSignals( true );
+
int s = fontSize();
mySize->clear();
mySize->addItems( sizes );
setFontSize( s );
+
+ mySize->blockSignals( blocked );
+
+ if ( !myFamily->signalsBlocked() )
+ emit( changed( currentFont() ) );
+}
+
+void QtxFontEdit::onPropertyChanged()
+{
+ emit( changed( currentFont() ) );
}
/*!
base->setSpacing( 5 );
base->addWidget( myFamily = new QFontComboBox( this ) );
+ base->addWidget( myCustomFams = new QComboBox( this ) );
base->addWidget( mySize = new QtxComboBox( this ) );
mySize->setInsertPolicy( QComboBox::NoInsert );
mySize->setValidator( new QIntValidator( 1, 250, mySize ) );
myU->setText( tr( "U" ) );
myU->setCheckable( true );
+ base->addWidget( myS = new QToolButton( this ) );
+ myS->setText( tr( "S" ) );
+ myS->setCheckable( true );
+
base->addWidget( myPreview = new QToolButton( this ) );
myPreview->setText( "..." );
myFamily->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
+ myCustomFams->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& ) ) );
+ connect( mySize, SIGNAL( currentIndexChanged( int ) ), this, SLOT( onPropertyChanged() ) );
+ connect( mySize, SIGNAL( editTextChanged( QString ) ), this, SLOT( onPropertyChanged() ) );
+ connect( myB, SIGNAL( toggled( bool ) ), this, SLOT( onPropertyChanged() ) );
+ connect( myI, SIGNAL( toggled( bool ) ), this, SLOT( onPropertyChanged() ) );
+ connect( myU, SIGNAL( toggled( bool ) ), this, SLOT( onPropertyChanged() ) );
+
+ myCustomFams->hide();
+ myS->hide();
updateState();
onFontChanged( currentFont() );
}
+
+/*!
+ \brief Specifies whether widget works in Native or Custom mode. Native mode
+ is intended for working with system fonts. Custom mode is intended for
+ working with manually defined set of fonts. Set of custom fonts can be
+ specified with setCustomFonts() method
+ \param mode mode from QtxFontEdit::Mode enumeration
+ \sa mode()
+*/
+void QtxFontEdit::setMode( const int mode )
+{
+ if ( myMode == mode )
+ return;
+
+ myMode = mode;
+
+ myFamily->setShown( myMode == Native );
+ myCustomFams->setShown( myMode == Custom );
+
+ updateGeometry();
+}
+
+/*!
+ \brief Verifies whether widget works in Native or Custom mode
+ \return Native or Custom mode
+ \sa setMode()
+*/
+int QtxFontEdit::mode() const
+{
+ return myMode;
+}
+
+/*!
+ \brief Sets list of custom fonts.
+ <b>This method is intended for working in Custom mode.</b>
+ \param fams list of families
+ \sa fonts(), setMode()
+*/
+void QtxFontEdit::setFonts( const QStringList& fams )
+{
+ QString currFam = myCustomFams->currentText();
+
+ myCustomFams->clear();
+ myCustomFams->addItems( fams );
+
+ int ind = myCustomFams->findText( currFam );
+ if ( ind != -1 )
+ myCustomFams->setCurrentIndex( ind );
+
+ setSizes( QList<int>() );
+}
+
+/*!
+ \brief Sets list of available font sizes.
+ <b>This method is intended for working in Custom mode.</b> The list of sizes can
+ be empty. In this case system generate listof size automatically from 8 till 72.
+ \param sizes list of sizes
+ \sa sizes(), setMode()
+*/
+void QtxFontEdit::setSizes( const QList<int>& sizes )
+{
+ QString currSize = mySize->currentText();
+
+ mySize->clear();
+ if ( !sizes.isEmpty() )
+ {
+ QStringList szList;
+ for ( QList<int>::const_iterator it = sizes.begin(); it != sizes.end(); ++it )
+ szList.append( QString::number( *it ) );
+ mySize->addItems( szList );
+ }
+ else
+ {
+ static QStringList defLst;
+ if ( defLst.isEmpty() )
+ {
+ QString str( "8 9 10 11 12 14 16 18 20 22 24 26 28 36 48 72" );
+ defLst = str.split( " " );
+ }
+ mySize->addItems( defLst );
+ }
+
+ int ind = mySize->findText( currSize );
+ if ( ind != -1 )
+ mySize->setCurrentIndex( ind );
+}
+
+/*!
+ \brief Gets list of custom fonts
+ \return list of families
+ \sa setFonts(), setMode()
+*/
+QStringList QtxFontEdit::fonts() const
+{
+ QStringList fams;
+ for ( int i = 0, n = myCustomFams->count(); i < n; i++ )
+ fams.append( myCustomFams->itemText( i ) );
+ return fams;
+}
+
+/*!
+ \brief Gets list of custom fonts
+ \return list of families
+ \sa setCustomFonts(), setMode()
+*/
+QList<int> QtxFontEdit::sizes() const
+{
+ QList<int> lst;
+ for ( int i = 0, n = mySize->count(); i < n; i++ )
+ lst.append( mySize->itemText( i ).toInt() );
+ return lst;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#include <QFrame>
+class QComboBox;
class QtxComboBox;
class QToolButton;
class QFontComboBox;
Bold = 0x08, //!< show 'bold' widget
Italic = 0x10, //!< show 'italic' widget
Underline = 0x20, //!< show 'underline' widget
- Preview = 0x40, //!< show font preview widget
+ Shadow = 0x40, //!< show 'shadow' widget
+ Preview = 0x80, //!< 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;
+ typedef enum
+ {
+ Native, //!< Native mode intended for working with system fonts
+ Custom //!< Custom mode intended for working with manually defined set of fonts
+ } Mode;
+
public:
QtxFontEdit( const int, QWidget* = 0 );
QtxFontEdit( QWidget* = 0 );
int features() const;
void setFeatures( const int );
+ void setMode( const int );
+ int mode() const;
+
+ void setFonts( const QStringList& );
+ QStringList fonts() const;
+
+ void setSizes( const QList<int>& = QList<int>() );
+ QList<int> sizes() const;
+
+signals:
+ void changed( const QFont& );
+
private slots:
void onPreview( bool );
void onFontChanged( const QFont& );
+ void onPropertyChanged();
private:
void initialize();
QFontComboBox* myFamily;
QToolButton* myPreview;
int myFeatures;
- QToolButton *myB, *myI, *myU;
+ QToolButton *myB, *myI, *myU, *myS;
+ int myMode;
+ QComboBox* myCustomFams;
};
#endif // QTXFONTEDIT_H
#include "QtxMainWindow.h"
#include "QtxToolBar.h"
-#include "QtxResourceMgr.h"
#include <QEvent>
+#include <QPoint>
+#include <QTimer>
+#include <QLayout>
#include <QMenuBar>
#include <QStatusBar>
+#include <QRubberBand>
+#include <QMouseEvent>
#include <QApplication>
#include <QDesktopWidget>
return QObject::eventFilter( o, e );
}
+/*!
+ \class QtxMainWindow::Resizer
+ \internal
+ \brief Internal object used to resize dock widgets.
+*/
+
+class QtxMainWindow::Resizer : public QObject
+{
+public:
+ Resizer( const QPoint&, const Qt::Orientation, QtxMainWindow* );
+ virtual ~Resizer();
+
+ QMouseEvent* finalEvent() const;
+ void setFinalEvent( QMouseEvent* );
+
+ void setPosition( const QPoint& );
+ virtual bool eventFilter( QObject*, QEvent* );
+
+private:
+ void setFilters( bool );
+
+private:
+ QPoint myPos;
+ QMainWindow* myMain;
+ QRubberBand* myRubber;
+ Qt::Orientation myOrient;
+ QMouseEvent* myFinEvent;
+};
+
+/*!
+ \brief Constructor.
+ \param mw parent main window
+*/
+QtxMainWindow::Resizer::Resizer( const QPoint& p, const Qt::Orientation o, QtxMainWindow* mw )
+: QObject( mw ),
+ myMain( mw ),
+ myOrient( o ),
+ myFinEvent( 0 )
+{
+ setFilters( true );
+
+ myRubber = new QRubberBand( QRubberBand::Line, 0 );
+
+ setPosition( p );
+
+ myRubber->show();
+};
+
+/*!
+ \brief Destructor.
+*/
+QtxMainWindow::Resizer::~Resizer()
+{
+ delete myRubber;
+
+ setFilters( false );
+}
+
+void QtxMainWindow::Resizer::setPosition( const QPoint& pos )
+{
+ myPos = pos;
+ if ( myRubber ) {
+ QRect r;
+ QPoint min = myMain->mapToGlobal( myMain->rect().topLeft() );
+ QPoint max = myMain->mapToGlobal( myMain->rect().bottomRight() );
+ if ( myOrient == Qt::Horizontal ) {
+ int p = qMax( qMin( myPos.y(), max.y() ), min.y() );
+ r = QRect( myMain->mapToGlobal( QPoint( 0, 0 ) ).x(), p - 1, myMain->width(), 3 );
+ }
+ else {
+ int p = qMax( qMin( myPos.x(), max.x() ), min.x() );
+ r = QRect( p - 1, myMain->mapToGlobal( QPoint( 0, 0 ) ).y(), 3, myMain->height() );
+ }
+ myRubber->setGeometry( r );
+ }
+}
+
+QMouseEvent* QtxMainWindow::Resizer::finalEvent() const
+{
+ return myFinEvent;
+}
+
+void QtxMainWindow::Resizer::setFinalEvent( QMouseEvent* e )
+{
+ myFinEvent = e;
+}
+
+/*!
+ \brief Event filter.
+
+ \param o recevier object
+ \param e event
+*/
+bool QtxMainWindow::Resizer::eventFilter( QObject* o, QEvent* e )
+{
+ if ( e->type() == QEvent::Timer ) {
+ if ( !finalEvent() )
+ return true;
+
+ setFilters( false );
+ QApplication::postEvent( myMain, finalEvent() );
+ myFinEvent = 0;
+ deleteLater();
+ }
+
+ return QObject::eventFilter( o, e );
+}
+
+void QtxMainWindow::Resizer::setFilters( bool on )
+{
+ if ( myMain ) {
+ if ( on )
+ myMain->layout()->installEventFilter( this );
+ else
+ myMain->layout()->removeEventFilter( this );
+ }
+
+ QTimer* t = qFindChild<QTimer*>( myMain->layout() );
+ if ( t ) {
+ if ( on )
+ t->installEventFilter( this );
+ else
+ t->removeEventFilter( this );
+ }
+}
/*!
\class QtxMainWindow
QtxMainWindow::QtxMainWindow( QWidget* parent, Qt::WindowFlags f )
: QMainWindow( parent, f ),
myMenuBar( 0 ),
- myStatusBar( 0 )
+ myStatusBar( 0 ),
+ myOpaque( true ),
+ myResizer( 0 ),
+ myMouseMove( 0 )
{
}
}
}
+bool QtxMainWindow::isOpaqueResize() const
+{
+ return myOpaque;
+}
+
+void QtxMainWindow::setOpaqueResize( bool on )
+{
+ myOpaque = on;
+}
+
/*!
\brief Dump main window geometry to the string.
\return string represenation of the window geometry
}
}
+bool QtxMainWindow::event( QEvent* e )
+{
+ if ( myResizer && e->type() == QEvent::MouseButtonRelease ) {
+ if ( myMouseMove ) {
+ QMainWindow::event( myMouseMove );
+ delete myMouseMove;
+ myMouseMove = 0;
+ }
+
+ QMouseEvent* me = static_cast<QMouseEvent*>( e );
+ myResizer->setFinalEvent( new QMouseEvent( me->type(), me->pos(), me->globalPos(),
+ me->button(), me->buttons(), me->modifiers() ) );
+ myResizer = 0;
+ return true;
+ }
+
+ if ( myResizer && e->type() == QEvent::MouseMove ) {
+ QMouseEvent* me = static_cast<QMouseEvent*>( e );
+ myMouseMove = new QMouseEvent( me->type(), me->pos(), me->globalPos(),
+ me->button(), me->buttons(), me->modifiers() );
+ myResizer->setPosition( me->globalPos() );
+ }
+
+ bool ok = QMainWindow::event( e );
+
+ if ( e->type() == QEvent::MouseButtonPress ) {
+ if ( !isOpaqueResize() && ok && testAttribute( Qt::WA_SetCursor ) ) {
+ bool status = true;
+ Qt::Orientation o;
+ switch ( cursor().shape() )
+ {
+ case Qt::SplitHCursor:
+ o = Qt::Vertical;
+ break;
+ case Qt::SplitVCursor:
+ o = Qt::Horizontal;
+ break;
+ default:
+ status = false;
+ break;
+ }
+ if ( status ) {
+ QMouseEvent* me = static_cast<QMouseEvent*>( e );
+ myResizer = new Resizer( me->globalPos(), o, this );
+ }
+ }
+ }
+
+ return ok;
+}
Q_OBJECT
class Filter;
+ class Resizer;
public:
QtxMainWindow( QWidget* = 0, Qt::WindowFlags = 0 );
virtual ~QtxMainWindow();
+ bool isOpaqueResize() const;
+ void setOpaqueResize( bool );
+
bool isDockableMenuBar() const;
void setDockableMenuBar( const bool );
QString storeGeometry() const;
void retrieveGeometry( const QString& );
+protected:
+ virtual bool event( QEvent* );
+
private slots:
void onDestroyed( QObject* );
private:
QToolBar* myMenuBar; //!< dockable menu bar
QToolBar* myStatusBar; //!< dockable status bar
+
+ bool myOpaque;
+ Resizer* myResizer;
+ QMouseEvent* myMouseMove;
};
#endif // QTXMAINWINDOW_H
#include "QtxGroupBox.h"
#include "QtxComboBox.h"
#include "QtxIntSpinBox.h"
+#include "QtxResourceMgr.h"
#include "QtxColorButton.h"
+#include "QtxShortcutEdit.h"
#include "QtxDoubleSpinBox.h"
#include <QtCore/QEvent>
+#include <QtGui/QIcon>
#include <QtGui/QLayout>
#include <QtGui/QToolBox>
#include <QtGui/QLineEdit>
for string, integer and double values.
*/
+static void fixupAndSet( QLineEdit* le, const QString& txt )
+{
+ if ( le ) {
+ QString val = txt;
+ if ( le->validator() ) {
+ const QDoubleValidator* de = dynamic_cast<const QDoubleValidator*>( le->validator() );
+ if ( de ) {
+ int dec = de->decimals();
+ int idx = val.lastIndexOf( QRegExp( QString("[.|%1]").arg( le->locale().decimalPoint () ) ) );
+ if ( idx >= 0 ) {
+ QString tmp = val.mid( idx+1 );
+ QString exp;
+ val = val.left( idx+1 );
+ idx = tmp.indexOf( QRegExp( QString("[e|E]") ) );
+ if ( idx >= 0 ) {
+ exp = tmp.mid( idx );
+ tmp = tmp.left( idx );
+ }
+ tmp.truncate( dec );
+ val = val + tmp + exp;
+ }
+ }
+ int pos = 0;
+ if ( le->validator()->validate( val, pos ) == QValidator::Invalid )
+ val.clear();
+ }
+ le->setText( val );
+ }
+}
+
/*!
\brief Constructor.
QtxPagePrefEditItem::QtxPagePrefEditItem( const QString& title, QtxPreferenceItem* parent,
const QString& sect, const QString& param )
: QtxPageNamedPrefItem( title, parent, sect, param ),
- myType( String )
+ myType( String ),
+ myDecimals( 1000 ),
+ myEchoMode( 0 )
{
setControl( myEditor = new QLineEdit() );
updateEditor();
QtxPreferenceItem* parent, const QString& sect,
const QString& param )
: QtxPageNamedPrefItem( title, parent, sect, param ),
- myType( type )
+ myType( type ),
+ myDecimals( 1000 ),
+ myEchoMode( 0 )
{
setControl( myEditor = new QLineEdit() );
updateEditor();
updateEditor();
}
+/*!
+ \brief Get number of digits after decimal point (for Double input type)
+ \return preference item decimals value
+ \sa setDecimals()
+*/
+int QtxPagePrefEditItem::decimals() const
+{
+ return myDecimals;
+}
+
+/*!
+ \brief Set number of digits after decimal point (for Double input type)
+ \param dec new preference item decimals value
+ \sa decimals()
+*/
+void QtxPagePrefEditItem::setDecimals( const int dec )
+{
+ if ( myDecimals == dec )
+ return;
+
+ myDecimals = dec;
+ updateEditor();
+}
+
+/*!
+ \brief Get the line edit's echo mode
+ \return preference item echo mode value
+ \sa setEchoMode()
+*/
+int QtxPagePrefEditItem::echoMode() const
+{
+ return myEchoMode;
+}
+
+/*!
+ \brief Set the line edit's echo mode
+ \param echo new preference item echo mode value
+ \sa echoMode()
+*/
+void QtxPagePrefEditItem::setEchoMode( const int echo )
+{
+ if ( myEchoMode == echo )
+ return;
+
+ myEchoMode = echo;
+ updateEditor();
+}
+
/*!
\brief Store preference item to the resource manager.
\sa retrieve()
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 );
+ fixupAndSet( myEditor, txt );
}
/*!
{
if ( name == "input_type" || name == "type" )
return inputType();
+ else if ( name == "precision" || name == "prec" || name == "decimals" )
+ return decimals();
+ else if ( name == "echo" || name == "echo_mode" || name == "echomode")
+ return echoMode();
else
return QtxPageNamedPrefItem::optionValue( name );
}
if ( val.canConvert( QVariant::Int ) )
setInputType( val.toInt() );
}
+ else if ( name == "precision" || name == "prec" || name == "decimals" ) {
+ if ( val.canConvert( QVariant::Int ) )
+ setDecimals( val.toInt() );
+ }
+ else if ( name == "echo" || name == "echo_mode" || name == "echomode") {
+ if ( val.canConvert( QVariant::Int ) )
+ setEchoMode( val.toInt() );
+ }
else
QtxPageNamedPrefItem::setOptionValue( name, val );
}
*/
void QtxPagePrefEditItem::updateEditor()
{
+ switch (myEchoMode)
+ {
+ case 0:
+ myEditor->setEchoMode(QLineEdit::Normal);
+ break;
+ case 1:
+ myEditor->setEchoMode(QLineEdit::NoEcho);
+ break;
+ case 2:
+ myEditor->setEchoMode(QLineEdit::Password);
+ break;
+ case 3:
+ myEditor->setEchoMode(QLineEdit::PasswordEchoOnEdit);
+ break;
+ default:
+ myEditor->setEchoMode(QLineEdit::Normal);
+ }
+
QValidator* val = 0;
switch ( inputType() )
{
break;
case Double:
val = new QDoubleValidator( myEditor );
+ dynamic_cast<QDoubleValidator*>( val )->setDecimals( myDecimals < 0 ? 1000 : myDecimals );
break;
default:
break;
}
- if ( !myEditor->text().isEmpty() && val )
+ QString txt = myEditor->text();
+ delete myEditor->validator();
+ myEditor->setValidator( val );
+ fixupAndSet( myEditor, txt );
+}
+
+/*!
+ \class QtxPagePrefSliderItem
+*/
+
+/*!
+ \brief Constructor.
+
+ Creates preference item with slider widget
+
+ \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
+*/
+QtxPagePrefSliderItem::QtxPagePrefSliderItem( const QString& title, QtxPreferenceItem* parent,
+ const QString& sect, const QString& param )
+: QtxPageNamedPrefItem( title, parent, sect, param )
{
- int pos = 0;
- QString str = myEditor->text();
- if ( val->validate( str, pos ) == QValidator::Invalid )
- myEditor->clear();
+ setControl( mySlider = new QSlider( Qt::Horizontal ) );
+ widget()->layout()->addWidget( myLabel = new QLabel( ) );
+
+ setMinimum( 0 );
+ setMaximum( 0 );
+ setSingleStep( 1 );
+ setPageStep( 1 );
+
+ mySlider->setTickPosition( QSlider::TicksBothSides );
+
+ connect (mySlider, SIGNAL(valueChanged(int)), this, SLOT(setIcon(int)));
+ updateSlider();
}
- delete myEditor->validator();
- myEditor->setValidator( val );
+/*!
+ \brief Destructor.
+*/
+QtxPagePrefSliderItem::~QtxPagePrefSliderItem()
+{
+}
+
+/*!
+ \brief Get slider preference item step value.
+ \return slider single step value
+ \sa setSingleStep()
+*/
+int QtxPagePrefSliderItem::singleStep() const
+{
+ return mySlider->singleStep();
+}
+
+/*!
+ \brief Get slider preference item step value.
+ \return slider page step value
+ \sa setPageStep()
+*/
+int QtxPagePrefSliderItem::pageStep() const
+{
+ return mySlider->pageStep();
+}
+
+/*!
+ \brief Get slider preference item minimum value.
+ \return slider minimum value
+ \sa setMinimum()
+*/
+int QtxPagePrefSliderItem::minimum() const
+{
+ return mySlider->minimum();
+}
+
+/*!
+ \brief Get slider preference item maximum value.
+ \return slider maximum value
+ \sa setMaximum()
+*/
+int QtxPagePrefSliderItem::maximum() const
+{
+ return mySlider->maximum();
+}
+
+/*!
+ \brief Get the list of the icons associated with the selection widget items
+ \return list of icons
+ \sa setIcons()
+*/
+QList<QIcon> QtxPagePrefSliderItem::icons() const
+{
+ return myIcons;
+}
+
+/*!
+ \brief Set slider preference item step value.
+ \param step new slider single step value
+ \sa step()
+*/
+void QtxPagePrefSliderItem::setSingleStep( const int& step )
+{
+ mySlider->setSingleStep( step );
+}
+
+/*!
+ \brief Set slider preference item step value.
+ \param step new slider single step value
+ \sa step()
+*/
+void QtxPagePrefSliderItem::setPageStep( const int& step )
+{
+ mySlider->setPageStep( step );
+}
+
+/*!
+ \brief Set slider preference item minimum value.
+ \param min new slider minimum value
+ \sa minimum()
+*/
+void QtxPagePrefSliderItem::setMinimum( const int& min )
+{
+ mySlider->setMinimum( min );
+ setIcon( mySlider->value() );
+}
+
+/*!
+ \brief Set slider preference item maximum value.
+ \param max new slider maximum value
+ \sa maximum()
+*/
+void QtxPagePrefSliderItem::setMaximum( const int& max )
+{
+ mySlider->setMaximum( max );
+ setIcon( mySlider->value() );
+}
+
+/*!
+ \brief Set the list of the icons to the selection widget items
+ \param icns new list of icons
+ \sa icons()
+*/
+void QtxPagePrefSliderItem::setIcons( const QList<QIcon>& icns )
+{
+ if ( icns.isEmpty() )
+ return;
+ myIcons = icns;
+ /*
+ QSize maxsize( 0, 0 );
+ for ( QList<QIcon>::const_iterator it = myIcons.begin(); it != myIcons.end(); ++it ) {
+ const QIcon& ico = *it;
+ if ( ico.isNull() )
+ continue;
+
+ maxsize = maxsize.expandedTo( ico.availableSizes().first() );
+ }
+ myLabel->setFixedSize( maxsize );
+ */
+ updateSlider();
+}
+
+/*!
+ \brief Store preference item to the resource manager.
+ \sa retrieve()
+*/
+void QtxPagePrefSliderItem::store()
+{
+ setInteger( mySlider->value() );
+}
+
+/*!
+ \brief Retrieve preference item from the resource manager.
+ \sa store()
+*/
+void QtxPagePrefSliderItem::retrieve()
+{
+ mySlider->setValue( getInteger( mySlider->value() ) );
+}
+
+/*!
+ \brief Get preference item option value.
+ \param name option name
+ \return property value or null integer if option is not set
+ \sa setOptionValue()
+*/
+QVariant QtxPagePrefSliderItem::optionValue( const QString& name ) const
+{
+ if ( name == "minimum" || name == "min" )
+ return minimum();
+ else if ( name == "maximum" || name == "max" )
+ return maximum();
+ else if ( name == "single_step" )
+ return singleStep();
+ else if ( name == "page_step" )
+ return pageStep();
+ else if ( name == "icons" || name == "pixmaps" )
+ {
+ QList<QVariant> lst;
+ QList<QIcon> ics = icons();
+ for ( QList<QIcon>::const_iterator it = ics.begin(); it != ics.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 QtxPagePrefSliderItem::setOptionValue( const QString& name, const QVariant& val )
+{
+ if ( val.canConvert( QVariant::Int ) )
+ {
+ if ( name == "minimum" || name == "min" )
+ setMinimum( val.toInt() );
+ else if ( name == "maximum" || name == "max" )
+ setMaximum( val.toInt() );
+ else if ( name == "single_step" )
+ setSingleStep( val.toInt() );
+ else if ( name == "page_step" )
+ setPageStep( val.toInt() );
+ else
+ QtxPageNamedPrefItem::setOptionValue( name, val );
+ }
+ else if ( name == "icons" || name == "pixmaps" )
+ setIcons( val );
+ else
+ QtxPageNamedPrefItem::setOptionValue( name, val );
+}
+
+void QtxPagePrefSliderItem::setIcon( int pos )
+{
+ int index = pos - mySlider->minimum();
+ if ( !myIcons.isEmpty() && index >= 0 && index < myIcons.size() && !myIcons[index].isNull() )
+ myLabel->setPixmap( myIcons[index].pixmap( /*myIcons[index].availableSizes().first()*/myLabel->size() ) );
+ else
+ myLabel->clear();
+}
+
+/*!
+ \brief Update slider widget.
+*/
+void QtxPagePrefSliderItem::updateSlider()
+{
+ int val = mySlider->value();
+ int stp = singleStep();
+ int ptp = pageStep();
+ int min = minimum();
+ int max = maximum();
+
+ control()->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
+ mySlider->setFocusPolicy(Qt::StrongFocus);
+
+ mySlider->setValue( val );
+ setSingleStep( stp );
+ setPageStep( ptp );
+ setMinimum( min );
+ setMaximum( max );
+
+ myLabel->setVisible( !myIcons.empty() );
+ widget()->layout()->setSpacing( !myIcons.empty() ? 6 : 0 );
+}
+
+/*!
+ \brief Set the list of the icons from the resource manager.
+ \param var new icons list
+ \internal
+*/
+void QtxPagePrefSliderItem::setIcons( const QVariant& var )
+{
+ if ( var.type() != QVariant::List )
+ return;
+
+ QList<QIcon> lst;
+ QList<QVariant> varList = var.toList();
+ for ( QList<QVariant>::const_iterator it = varList.begin(); it != varList.end(); ++it )
+ {
+ if ( (*it).canConvert<QIcon>() )
+ lst.append( (*it).value<QIcon>() );
+ else if ( (*it).canConvert<QPixmap>() )
+ lst.append( (*it).value<QPixmap>() );
+ else
+ lst.append( QIcon() );
+ }
+ setIcons( lst );
}
/*!
}
/*!
- \brief Get the list of the icons from the selection widget.
+ \brief Get the list of the icons associated with the selection widget.items
\return list of icons
\sa strings(), numbers(), setIcons()
*/
/*!
\brief Set the list of the values to the selection widget.
\param lst new list of values
- \sa strings(), setNumbers()
+ \sa strings(), setNumbers(), setIcons()
*/
void QtxPagePrefSelectItem::setStrings( const QStringList& lst )
{
}
/*!
- \brief Set the list of the values identifiers to the selection widget.
+ \brief Set the list of the values identifiers to the selection widget
\param ids new list of values IDs
- \sa numbers(), setStrings()
+ \sa numbers(), setStrings(), setIcons()
*/
void QtxPagePrefSelectItem::setNumbers( const QList<int>& ids )
{
int i = 0;
- for ( QList<int>::const_iterator it = ids.begin(); it != ids.end() && i < mySelector->count(); ++it, i++ )
+ for ( QList<int>::const_iterator it = ids.begin(); it != ids.end(); ++it, i++ ) {
+ if ( i >= mySelector->count() )
+ mySelector->addItem( QString( "" ) );
+
mySelector->setId( i, *it );
+ }
}
/*!
- \brief Set the list of the icons to the selection widget.
- \param lst new list of icons
- \sa numbers(), strings(), setIcons()
+ \brief Set the list of the icons to the selection widget items
+
+ Important: call this method after setStrings() or setNumbers()
+
+ \param icns new list of icons
+ \sa icons(), setStrings(), setNumbers()
*/
-void QtxPagePrefSelectItem::setIcons( const QList<QIcon>& icons )
+void QtxPagePrefSelectItem::setIcons( const QList<QIcon>& icns )
{
int i = 0;
- for ( QList<QIcon>::const_iterator it = icons.begin(); it != icons.end() && i < mySelector->count(); ++it, i++ )
+ for ( QList<QIcon>::const_iterator it = icns.begin(); it != icns.end() && i < mySelector->count(); ++it, i++ )
mySelector->setItemIcon( i, *it );
}
lst.append( *it );
return lst;
}
+ else if ( name == "icons" || name == "pixmaps" )
+ {
+ QList<QVariant> lst;
+ QList<QIcon> ics = icons();
+ for ( QList<QIcon>::const_iterator it = ics.begin(); it != ics.end(); ++it )
+ lst.append( *it );
+ return lst;
+ }
else
return QtxPageNamedPrefItem::optionValue( name );
}
setStrings( val );
else if ( name == "numbers" || name == "ids" || name == "indexes" )
setNumbers( val );
+ else if ( name == "icons" || name == "pixmaps" )
+ setIcons( val );
else
QtxPageNamedPrefItem::setOptionValue( name, val );
}
setNumbers( lst );
}
+/*!
+ \brief Set the list of the icons from the resource manager.
+ \param var new icons list
+ \internal
+*/
+void QtxPagePrefSelectItem::setIcons( const QVariant& var )
+{
+ if ( var.type() != QVariant::List )
+ return;
+
+ QList<QIcon> lst;
+ QList<QVariant> varList = var.toList();
+ for ( QList<QVariant>::const_iterator it = varList.begin(); it != varList.end(); ++it )
+ {
+ if ( (*it).canConvert<QIcon>() )
+ lst.append( (*it).value<QIcon>() );
+ else if ( (*it).canConvert<QPixmap>() )
+ lst.append( (*it).value<QPixmap>() );
+ else
+ lst.append( QIcon() );
+ }
+ setIcons( lst );
+}
+
/*!
\brief Update selector widget.
*/
return QVariant();
}
+/*!
+ \brief Get double spin box preference item precision value.
+ \return double spin box precision
+ \sa setPrecision()
+*/
+QVariant QtxPagePrefSpinItem::precision() const
+{
+ if ( QtxDoubleSpinBox* dsb = ::qobject_cast<QtxDoubleSpinBox*>( control() ) )
+ return dsb->decimals();
+ else
+ return QVariant();
+}
+
/*!
\brief Get spin box preference item minimum value.
\return spin box minimum value
}
}
+/*!
+ \brief Set double spin box preference item precision value.
+ \param step new double spin box precision value
+ \sa precision()
+*/
+void QtxPagePrefSpinItem::setPrecision( const QVariant& prec )
+{
+ if ( QtxDoubleSpinBox* dsb = ::qobject_cast<QtxDoubleSpinBox*>( control() ) )
+ {
+ if ( prec.canConvert( QVariant::Int ) ) {
+ dsb->setDecimals( qAbs( prec.toInt() ) );
+ dsb->setPrecision( prec.toInt() );
+ }
+ }
+}
+
/*!
\brief Set spin box preference item minimum value.
\param min new spin box minimum value
return maximum();
else if ( name == "step" )
return step();
+ else if ( name == "precision" )
+ return precision();
else if ( name == "prefix" )
return prefix();
else if ( name == "suffix" )
setMaximum( val );
else if ( name == "step" )
setStep( val );
+ else if ( name == "precision" )
+ setPrecision( val );
else if ( name == "prefix" )
{
if ( val.canConvert( QVariant::String ) )
{
QVariant val;
QVariant stp = step();
+ QVariant prec = precision();
QVariant min = minimum();
QVariant max = maximum();
control()->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
setStep( stp );
+ setPrecision( prec );
setMinimum( min );
setMaximum( max );
myFont->setFeatures( f );
}
+/*!
+ \brief Specifies whether widget works in Native or Custom mode. Native mode
+ is intended for working with system fonts. Custom mode is intended for
+ working with manually defined set of fonts. Set of custom fonts can be
+ specified with setFonts() method
+ \param mode mode from QtxFontEdit::Mode enumeration
+ \sa mode()
+*/
+void QtxPagePrefFontItem::setMode( const int mode )
+{
+ myFont->setMode( mode );
+}
+
+/*!
+ \brief Verifies whether widget works in Native or Custom mode
+ \return Native or Custom mode
+ \sa setMode()
+*/
+int QtxPagePrefFontItem::mode() const
+{
+ return myFont->mode();
+}
+
+/*!
+ \brief Sets list of custom fonts.
+ <b>This method is intended for working in Custom mode only.</b>
+ \param fams list of families
+ \sa fonts(), setMode()
+*/
+void QtxPagePrefFontItem::setFonts( const QStringList& fams )
+{
+ myFont->setFonts( fams );
+}
+
+/*!
+ \brief Gets list of custom fonts
+ \return list of families
+ \sa setFonts(), setMode()
+*/
+QStringList QtxPagePrefFontItem::fonts() const
+{
+ return myFont->fonts();
+}
+
+/*!
+ \brief Sets list of available font sizes.
+ <b>This method is intended for working in Custom mode only.</b> The list of sizes can
+ be empty. In this case system generate listof size automatically from 8 till 72.
+ \param sizes list of sizes
+ \sa sizes(), setMode()
+*/
+void QtxPagePrefFontItem::setSizes( const QList<int>& sizes )
+{
+ myFont->setSizes( sizes );
+}
+
+/*!
+ \brief Gets list of custom fonts
+ \return list of families
+ \sa setFonts(), setMode()
+*/
+QList<int> QtxPagePrefFontItem::sizes() const
+{
+ return myFont->sizes();
+}
+
/*!
\brief Store preference item to the resource manager.
\sa retrieve()
{
if ( name == "features" )
return features();
+ else if ( name == "mode" )
+ return mode();
+ else if ( name == "fonts" || name == "families" )
+ return fonts();
+ else if ( name == "sizes" )
+ {
+ QList<QVariant> lst;
+ QList<int> nums = sizes();
+ for ( QList<int>::const_iterator it = nums.begin(); it != nums.end(); ++it )
+ lst.append( *it );
+ return lst;
+ }
else
return QtxPageNamedPrefItem::optionValue( name );
}
if ( val.canConvert( QVariant::Int ) )
setFeatures( val.toInt() );
}
+ else if ( name == "mode" )
+ {
+ if ( val.canConvert( QVariant::Int ) )
+ setMode( val.toInt() );
+ }
+ else if ( name == "fonts" || name == "families" )
+ {
+ if ( val.canConvert( QVariant::StringList ) )
+ setFonts( val.toStringList() );
+ }
+ else if ( name == "sizes" )
+ {
+ if ( val.type() == QVariant::List )
+ {
+ QList<int> lst;
+ QList<QVariant> varList = val.toList();
+ for ( QList<QVariant>::const_iterator it = varList.begin(); it != varList.end(); ++it )
+ {
+ if ( (*it).canConvert( QVariant::Int ) )
+ lst.append( (*it).toInt() );
+ }
+ setSizes( lst );
+ }
+ }
else
QtxPageNamedPrefItem::setOptionValue( name, val );
}
myStyle->setCleared( true );
*/
}
+
+/*!
+ \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
+*/
+QtxPagePrefShortcutBtnsItem::QtxPagePrefShortcutBtnsItem( const QString& title, QtxPreferenceItem* parent, const QString& sect,
+ const QString& param ): QtxPageNamedPrefItem( title, parent, sect, param )
+{
+ setControl( myShortcut = new QtxShortcutEdit() );
+}
+
+/*!
+ \brief Destructor.
+*/
+QtxPagePrefShortcutBtnsItem::~QtxPagePrefShortcutBtnsItem()
+{
+}
+
+/*!
+ \brief Store preference item to the resource manager.
+ \sa retrieve()
+*/
+void QtxPagePrefShortcutBtnsItem::store()
+{
+ setString( myShortcut->shortcut().toString() );
+}
+
+/*!
+ \brief Retrieve preference item from the resource manager.
+ \sa store()
+*/
+void QtxPagePrefShortcutBtnsItem::retrieve()
+{
+ myShortcut->setShortcut( QKeySequence::fromString( getString() ) );
+}
+
+/*!
+ \brief Constructor.
+
+ Creates preference item for editing of key bindings
+
+ \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
+*/
+QtxPagePrefShortcutTreeItem::QtxPagePrefShortcutTreeItem( const QString& title, QtxPreferenceItem* parent,
+ const QString& sect, const QString& param )
+: QtxPageNamedPrefItem( title, parent, sect, param )
+{
+ myShortcutTree = new QtxShortcutTree();
+
+ // Retrieve shortcuts common sections from resources
+ QtxResourceMgr* resMgr = resourceMgr();
+ if ( resMgr ) {
+ QStringList sectionsList = resourceMgr()->subSections( sect, false );
+ myShortcutTree->setGeneralSections( sectionsList );
+ myShortcutTree->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
+ }
+
+ setControl( myShortcutTree );
+}
+
+/*!
+ \brief Destructor.
+*/
+QtxPagePrefShortcutTreeItem::~QtxPagePrefShortcutTreeItem()
+{
+}
+
+/*!
+ \brief Retrieve preference item from the resource manager.
+ \sa store()
+*/
+void QtxPagePrefShortcutTreeItem::retrieve()
+{
+ QtxResourceMgr* resMgr = resourceMgr();
+ if ( resMgr ) {
+ QString sect, param;
+ resource( sect, param );
+ QStringList secLst = resMgr->subSections( sect, false );
+ ShortcutMap aMap;
+ QStringList paramLst;
+ for ( int i = 0; i < secLst.size(); i++ ) {
+ QString section = sect + resMgr->sectionsToken() + secLst.at( i );
+ paramLst = resMgr->parameters( QStringList() << sect << secLst.at( i ) );
+ QMap<QString, QString> nameMap = paramToName( section );
+ for ( int j = 0; j < paramLst.size(); j++ ) {
+ QString action = nameMap.contains( paramLst.at( j ) ) ? nameMap[paramLst.at( j )] : paramLst.at( j );
+ resMgr->value( section, paramLst.at( j ), aMap[action], false );
+ }
+ myShortcutTree->setBindings( secLst.at( i ), aMap );
+ aMap.clear();
+ }
+ }
+}
+
+/*!
+ \brief Store preference item to the resource manager.
+ \sa retrieve()
+*/
+void QtxPagePrefShortcutTreeItem::store()
+{
+ QString aSection;
+ QStringList lst = myShortcutTree->sections();
+ QtxResourceMgr* resMgr = resourceMgr();
+
+ QString sect, param;
+ resource( sect, param );
+
+ if ( resMgr ) {
+ for ( int i = 0; i < lst.size(); i++ ) {
+ ShortcutMap* aMap( myShortcutTree->bindings( lst.at( i ) ) );
+ aSection = sect + resMgr->sectionsToken() + lst.at( i );
+ QMap<QString, QString> paramMap = nameToParam( aSection );
+ for ( ShortcutMap::const_iterator it = aMap->constBegin(); it != aMap->constEnd(); ++it ) {
+ QString param = paramMap.contains( it.key() ) ? paramMap[it.key()] : it.key();
+ resMgr->setValue( aSection, param, it.value() );
+ }
+ }
+ }
+}
+
+QMap<QString, QString> QtxPagePrefShortcutTreeItem::paramToName( const QString& sect ) const
+{
+ QMap<QString, QString> aMap;
+ QtxResourceMgr* resMgr = resourceMgr();
+ if ( resMgr ) {
+ QStringList paramLst = resMgr->parameters( sect );
+ for ( QStringList::iterator it = paramLst.begin(); it != paramLst.end(); ++it )
+ aMap.insert( *it, actionName( *it ) );
+ }
+
+ return aMap;
+}
+
+QMap<QString, QString> QtxPagePrefShortcutTreeItem::nameToParam( const QString& sect ) const
+{
+ QMap<QString, QString> aMap;
+ QtxResourceMgr* resMgr = resourceMgr();
+ if ( resMgr ) {
+ QStringList paramLst = resMgr->parameters( sect );
+ for ( QStringList::iterator it = paramLst.begin(); it != paramLst.end(); ++it )
+ aMap.insert( actionName( *it ), *it );
+ }
+
+ return aMap;
+}
+
+QtxShortcutTree* QtxPagePrefShortcutTreeItem::shortcutTree() const
+{
+ return myShortcutTree;
+}
+
+QString QtxPagePrefShortcutTreeItem::actionName( const QString& param ) const
+{
+ QString res = QApplication::tr( "", (const char*)param.toLatin1() );
+ return res.isEmpty() ? param : res;
+}
class QtxGroupBox;
class QtxComboBox;
class QtxColorButton;
+class QtxShortcutEdit;
+class QtxShortcutTree;
+class QSlider;
class QToolBox;
class QComboBox;
class QLineEdit;
int inputType() const;
void setInputType( const int );
+ int decimals() const;
+ void setDecimals( const int );
+
+ int echoMode() const;
+ void setEchoMode( const int );
+
virtual void store();
virtual void retrieve();
private:
int myType;
+ int myDecimals;
+ int myEchoMode;
QLineEdit* myEditor;
};
+class QTX_EXPORT QtxPagePrefSliderItem : public QObject,public QtxPageNamedPrefItem
+{
+ Q_OBJECT
+
+public:
+ QtxPagePrefSliderItem( const QString&, QtxPreferenceItem* = 0,
+ const QString& = QString(), const QString& = QString() );
+ virtual ~QtxPagePrefSliderItem();
+
+ int singleStep() const;
+ int pageStep() const;
+ int minimum() const;
+ int maximum() const;
+ QList<QIcon> icons() const;
+
+ void setSingleStep( const int& );
+ void setPageStep( const int& );
+ void setMinimum( const int& );
+ void setMaximum( const int& );
+ void setIcons( const QList<QIcon>& );
+
+ virtual void store();
+ virtual void retrieve();
+
+protected:
+ virtual QVariant optionValue( const QString& ) const;
+ virtual void setOptionValue( const QString&, const QVariant& );
+
+private slots:
+ void setIcon( int );
+
+private:
+ void updateSlider();
+ void setIcons( const QVariant& );
+
+private:
+ QSlider* mySlider;
+ QLabel* myLabel;
+ QList<QIcon> myIcons;
+};
+
class QTX_EXPORT QtxPagePrefSelectItem : public QtxPageNamedPrefItem
{
public:
void updateSelector();
void setStrings( const QVariant& );
void setNumbers( const QVariant& );
+ void setIcons( const QVariant& );
private:
int myType;
virtual ~QtxPagePrefSpinItem();
QVariant step() const;
+ QVariant precision() const;
QVariant minimum() const;
QVariant maximum() const;
QString specialValueText() const;
void setStep( const QVariant& );
+ void setPrecision( const QVariant& );
void setMinimum( const QVariant& );
void setMaximum( const QVariant& );
int features() const;
void setFeatures( const int );
+ void setMode( const int );
+ int mode() const;
+
+ void setFonts( const QStringList& );
+ QStringList fonts() const;
+
+ void setSizes( const QList<int>& = QList<int>() );
+ QList<int> sizes() const;
+
virtual void store();
virtual void retrieve();
QComboBox* myStyle;
};
+class QTX_EXPORT QtxPagePrefShortcutBtnsItem : public QtxPageNamedPrefItem
+{
+public:
+ QtxPagePrefShortcutBtnsItem( const QString&, QtxPreferenceItem* = 0,
+ const QString& = QString(), const QString& = QString() );
+ virtual ~QtxPagePrefShortcutBtnsItem();
+ virtual void store();
+ virtual void retrieve();
+
+private:
+ QtxShortcutEdit* myShortcut;
+};
+
+class QTX_EXPORT QtxPagePrefShortcutTreeItem : public QtxPageNamedPrefItem
+{
+public:
+ QtxPagePrefShortcutTreeItem( const QString&, QtxPreferenceItem* = 0,
+ const QString& = QString(), const QString& = QString() );
+ virtual ~QtxPagePrefShortcutTreeItem();
+
+ virtual void store();
+ virtual void retrieve();
+
+protected:
+ QtxShortcutTree* shortcutTree() const;
+ virtual QString actionName( const QString& ) const;
+
+private:
+ QMap<QString, QString> paramToName( const QString& ) const;
+ QMap<QString, QString> nameToParam( const QString& ) const;
+
+private:
+ QtxShortcutTree* myShortcutTree;
+};
+
#endif
\param option style option
\param index data model index
*/
-QWidget* QtxPathListEdit::Delegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option,
- const QModelIndex& index ) const
+QWidget* QtxPathListEdit::Delegate::createEditor( QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& ) const
{
return myPathEdit->createEditor( parent );
}
\param model data model
\param index data model index
*/
-void QtxPathListEdit::Delegate::setModelData( QWidget* editor, QAbstractItemModel* model,
- const QModelIndex& index ) const
+void QtxPathListEdit::Delegate::setModelData( QWidget* editor, QAbstractItemModel*, const QModelIndex& index ) const
{
myPathEdit->setModelData( editor, index );
}
\param option style option
\param rect selection rectangle
*/
-void QtxPathListEdit::Delegate::drawFocus( QPainter* painter, const QStyleOptionViewItem& option,
- const QRect& rect ) const
+void QtxPathListEdit::Delegate::drawFocus( QPainter* painter, const QStyleOptionViewItem& option, const QRect& ) const
{
QItemDelegate::drawFocus( painter, option, option.rect );
}
*/
QtxPathListEdit::QtxPathListEdit( const Qtx::PathType type, QWidget* parent )
: QFrame( parent ),
- myCompleter( 0 ),
myType( type ),
+ myCompleter( 0 ),
myDuplicate( false )
{
initialize();
*/
QtxPathListEdit::QtxPathListEdit( QWidget* parent )
: QFrame( parent ),
- myCompleter( 0 ),
myType( Qtx::PT_OpenFile ),
+ myCompleter( 0 ),
myDuplicate( false )
{
initialize();
#include "QtxResourceMgr.h"
#include "QtxTranslator.h"
+#include <QSet>
#include <QDir>
#include <QFile>
#include <QRegExp>
+#include <QFileInfo>
#include <QTextStream>
#include <QApplication>
+#include <QLibraryInfo>
#ifndef QT_NO_DOM
#include <QDomDocument>
#include <QDomElement>
#include <QDomNode>
#endif
+#include <QtDebug>
+
#include <stdlib.h>
/*!
QPixmap loadPixmap( const QString&, const QString&, const QString& ) const;
QTranslator* loadTranslator( const QString&, const QString&, const QString& ) const;
- QString environmentVariable( const QString&, int&, int& ) const;
QString makeSubstitution( const QString&, const QString&, const QString& ) const;
void clear();
return trans;
}
-/*!
- \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
-{
- QString varName;
- len = 0;
-
- QRegExp rx( "(^\\$\\{|[^\\$]\\$\\{)([a-zA-Z]+[a-zA-Z0-9_]*)(\\})|(^\\$\\(|[^\\$]\\$\\()([a-zA-Z]+[a-zA-Z0-9_]*)(\\))|(^\\$|[^\\$]\\$)([a-zA-Z]+[a-zA-Z0-9_]*)|(^%|[^%]%)([a-zA-Z]+[a-zA-Z0-9_]*)(%[^%]|%$)" );
-
- int pos = rx.indexIn( str, start );
- if ( pos != -1 )
- {
- int i = 1;
- while ( i <= rx.numCaptures() && varName.isEmpty() )
- {
- QString capStr = rx.cap( i );
- if ( !capStr.contains( "%" ) && !capStr.contains( "$" ) )
- varName = capStr;
- i++;
- }
-
- if ( !varName.isEmpty() )
- {
- int capIdx = i - 1;
- start = rx.pos( capIdx );
- int end = start + varName.length();
- if ( capIdx > 1 && rx.cap( capIdx - 1 ).contains( QRegExp( "\\$|%" ) ) )
- start = rx.pos( capIdx - 1 ) + rx.cap( capIdx - 1 ).indexOf( QRegExp( "\\$|%" ) );
- if ( capIdx < rx.numCaptures() && !rx.cap( capIdx - 1 ).isEmpty() )
- end++;
- len = end - start;
- }
- }
- return varName;
-}
-
/*!
\brief Substitute variables by their values.
int start( 0 ), len( 0 );
while ( true )
{
- QString envName = environmentVariable( res, start, len );
+ QString envName = Qtx::findEnvVar( res, start, len );
if ( envName.isNull() )
break;
protected:
virtual bool load( const QString&, QMap<QString, Section>& );
virtual bool save( const QString&, const QMap<QString, Section>& );
+
+private:
+ bool load( const QString&, QMap<QString, Section>&, QSet<QString>& );
};
/*!
*/
bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap<QString, Section>& secMap )
{
- QFile file( fname );
+ QSet<QString> importHistory;
+ return load( fname, secMap, importHistory );
+}
+
+
+/*!
+ \brief Load resources from xml-file.
+ \param fname resources file name
+ \param secMap resources map to be filled in
+ \param importHistory list of already imported resources files (to prevent import loops)
+ \return \c true on success or \c false on error
+*/
+bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap<QString, Section>& secMap, QSet<QString>& importHistory)
+{
+ QString aFName = fname.trimmed();
+ if ( !QFileInfo( aFName ).exists() )
+ {
+ if ( QFileInfo( aFName + ".ini" ).exists() )
+ aFName += ".ini";
+ else if ( QFileInfo( aFName + ".INI" ).exists() )
+ aFName += ".INI";
+ else
+ return false; // file does not exist
+ }
+ QFileInfo aFinfo( aFName );
+ aFName = aFinfo.canonicalFilePath();
+
+ if ( !importHistory.contains( aFName ) )
+ importHistory.insert( aFName );
+ else
+ return true; // already imported (prevent import loops)
+
+ QFile file( aFName );
if ( !file.open( QFile::ReadOnly ) )
- return false;
+ return false; // file is not accessible
QTextStream ts( &file );
if ( data.startsWith( comment ) )
continue;
- QRegExp rx( "^\\[([\\w\\s\\._]*)\\]$" );
+ QRegExp rx( "^\\[([^\\[\\]]*)\\]$" );
if ( rx.indexIn( data ) != -1 )
{
section = rx.cap( 1 );
if ( section.isEmpty() )
{
res = false;
- qWarning( "Empty section in line %d", line );
+ qWarning() << "QtxResourceMgr: Empty section in line:" << line;
}
}
- else if ( data.contains( "=" ) && !section.isEmpty() )
+ else if ( data.contains( separator ) && !section.isEmpty() )
{
int pos = data.indexOf( separator );
QString key = data.left( pos ).trimmed();
QString val = data.mid( pos + 1 ).trimmed();
secMap[section].insert( key, val );
}
+ else if ( section == "import" )
+ {
+ QFileInfo impFInfo( data );
+ if ( impFInfo.isRelative() )
+ impFInfo.setFile( aFinfo.absoluteDir(), data );
+
+ QMap<QString, Section> impMap;
+ if ( !load( impFInfo.absoluteFilePath(), impMap, importHistory ) )
+ {
+ qDebug() << "QtxResourceMgr: Error with importing file:" << data;
+ }
+ else
+ {
+ QMap<QString, Section>::const_iterator it = impMap.constBegin();
+ for ( ; it != impMap.constEnd() ; ++it )
+ {
+ if ( !secMap.contains( it.key() ) )
+ {
+ // insert full section
+ secMap.insert( it.key(), it.value() );
+ }
+ else
+ {
+ // insert all parameters from the section
+ Section::ConstIterator paramIt = it.value().begin();
+ for ( ; paramIt != it.value().end() ; ++paramIt )
+ {
+ if ( !secMap[it.key()].contains( paramIt.key() ) )
+ secMap[it.key()].insert( paramIt.key(), paramIt.value() );
+ }
+ }
+ }
+ }
+ }
else
{
res = false;
- section.isEmpty() ? qWarning( "Current section is empty" ) : qWarning( "Error in line: %d", line );
+ if ( section.isEmpty() )
+ qWarning() << "QtxResourceMgr: Current section is empty";
+ else
+ qWarning() << "QtxResourceMgr: Error in line:" << line;
}
}
*/
bool QtxResourceMgr::IniFormat::save( const QString& fname, const QMap<QString, Section>& secMap )
{
+ if ( !Qtx::mkDir( QFileInfo( fname ).absolutePath() ) )
+ return false;
+
QFile file( fname );
if ( !file.open( QFile::WriteOnly ) )
return false;
QString docTag() const;
QString sectionTag() const;
QString parameterTag() const;
+ QString importTag() const;
QString nameAttribute() const;
QString valueAttribute() const;
+
+ bool load( const QString&, QMap<QString, Section>&, QSet<QString>& );
};
/*!
*/
bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap<QString, Section>& secMap )
{
+ QSet<QString> importHistory;
+ return load( fname, secMap, importHistory );
+}
+
+/*!
+ \brief Load resources from xml-file.
+ \param fname resources file name
+ \param secMap resources map to be filled in
+ \param importHistory list of already imported resources files (to prevent import loops)
+ \return \c true on success and \c false on error
+*/
+bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap<QString, Section>& secMap, QSet<QString>& importHistory )
+{
+ QString aFName = fname.trimmed();
+ if ( !QFileInfo( aFName ).exists() )
+ {
+ if ( QFileInfo( aFName + ".xml" ).exists() )
+ aFName += ".xml";
+ else if ( QFileInfo( aFName + ".XML" ).exists() )
+ aFName += ".XML";
+ else
+ return false; // file does not exist
+ }
+ QFileInfo aFinfo( aFName );
+ aFName = aFinfo.canonicalFilePath();
+
+ if ( !importHistory.contains( aFName ) )
+ importHistory.insert( aFName );
+ else
+ return true; // already imported (prevent import loops)
+
bool res = false;
#ifndef QT_NO_DOM
- QFile file( fname );
+ QFile file( aFName );
if ( !file.open( QFile::ReadOnly ) )
{
- qDebug( "File '%s' cannot be opened", (const char*)fname.toLatin1() );
+ qDebug() << "QtxResourceMgr: File is not accessible:" << aFName;
return false;
}
if ( !res )
{
- qDebug( "File is empty" );
+ qDebug() << "QtxResourceMgr: File is empty:" << aFName;
return false;
}
QDomElement root = doc.documentElement();
if ( root.isNull() || root.tagName() != docTag() )
{
- qDebug( "Invalid root" );
+ qDebug() << "QtxResourceMgr: Invalid root in file:" << aFName;
return false;
}
{
QString paramName = paramElem.attribute( nameAttribute() );
QString paramValue = paramElem.attribute( valueAttribute() );
-
secMap[section].insert( paramName, paramValue );
}
else
{
- qDebug( "Invalid parameter element" );
+ qDebug() << "QtxResourceMgr: Invalid parameter element in file:" << aFName;
res = false;
}
}
{
res = paramNode.isComment();
if( !res )
- qDebug( "Node isn't element nor comment" );
+ qDebug() << "QtxResourceMgr: Node is neither element nor comment in file:" << aFName;
}
paramNode = paramNode.nextSibling();
}
}
+ else if ( sectElem.tagName() == importTag() && sectElem.hasAttribute( nameAttribute() ) )
+ {
+ QFileInfo impFInfo( sectElem.attribute( nameAttribute() ) );
+ if ( impFInfo.isRelative() )
+ impFInfo.setFile( aFinfo.absoluteDir(), sectElem.attribute( nameAttribute() ) );
+
+ QMap<QString, Section> impMap;
+ if ( !load( impFInfo.absoluteFilePath(), impMap, importHistory ) )
+ {
+ qDebug() << "QtxResourceMgr: Error with importing file:" << sectElem.attribute( nameAttribute() );
+ }
+ else
+ {
+ QMap<QString, Section>::const_iterator it = impMap.constBegin();
+ for ( ; it != impMap.constEnd() ; ++it )
+ {
+ if ( !secMap.contains( it.key() ) )
+ {
+ // insert full section
+ secMap.insert( it.key(), it.value() );
+ }
+ else
+ {
+ // insert all parameters from the section
+ Section::ConstIterator paramIt = it.value().begin();
+ for ( ; paramIt != it.value().end() ; ++paramIt )
+ {
+ if ( !secMap[it.key()].contains( paramIt.key() ) )
+ secMap[it.key()].insert( paramIt.key(), paramIt.value() );
+ }
+ }
+ }
+ }
+ }
else
{
- qDebug( "Invalid section" );
+ qDebug() << "QtxResourceMgr: Invalid section in file:" << aFName;
res = false;
}
}
{
res = sectNode.isComment(); // if it's a comment -- let it be, pass it..
if( !res )
- qDebug( "Node isn't element nor comment" );
+ qDebug() << "QtxResourceMgr: Node is neither element nor comment in file:" << aFName;
}
sectNode = sectNode.nextSibling();
#endif
if ( res )
- qDebug( "File '%s' is loaded successfully", (const char*)fname.toLatin1() );
+ qDebug() << "QtxResourceMgr: File" << fname << "is loaded successfully";
return res;
}
#ifndef QT_NO_DOM
+ if ( !Qtx::mkDir( QFileInfo( fname ).absolutePath() ) )
+ return false;
+
QFile file( fname );
if ( !file.open( QFile::WriteOnly ) )
return false;
return tag;
}
+/*!
+ \brief Get import tag name
+ \return XML import tag name
+*/
+QString QtxResourceMgr::XmlFormat::importTag() const
+{
+ QString tag = option( "import_tag" );
+ if ( tag.isEmpty() )
+ tag = QString( "import" );
+ return tag;
+}
+
/*!
\brief Get parameter tag's "name" attribute name
\return XML parameter tag's "name" attribute name
if ( status )
res->mySections = sections;
else
- qDebug( "QtxResourceMgr: Could not load resource file \"%s\"", (const char*)res->myFileName.toLatin1() );
+ qDebug() << "QtxResourceMgr: Can't load resource file:" << res->myFileName;
return status;
}
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.
+
+ When retrieving preferences, it is sometimes helpful to ignore values coming from the
+ user preference file and take into account only global preferences.
+ To do this, use setWorkingMode() method passing QtxResourceMgr::IgnoreUserValues enumerator
+ as parameter.
Resources manager operates with such terms like options, sections and parameters.
Parametets are named application resources, for example, application preferences like
myCheckExist( true ),
myDefaultPix( 0 ),
myIsPixmapCached( true ),
- myIsIgnoreUserValues( false )
+ myHasUserValues( true ),
+ myWorkingMode( AllowUserValues )
{
QString envVar = !resVarTemplate.isEmpty() ? resVarTemplate : QString( "%1Resources" );
if ( envVar.contains( "%1" ) )
Prepare the resources containers and load resources (if \a autoLoad is \c true).
\param autoLoad if \c true (default) then all resources are loaded
- \param loadUser if \c true (default) then user settings are also loaded
*/
-void QtxResourceMgr::initialize( const bool autoLoad, const bool loadUser ) const
+void QtxResourceMgr::initialize( const bool autoLoad ) const
{
if ( !myResources.isEmpty() )
return;
QtxResourceMgr* that = (QtxResourceMgr*)this;
- if ( loadUser && !userFileName( appName() ).isEmpty() )
+ if ( !userFileName( appName() ).isEmpty() )
that->myResources.append( new Resources( that, userFileName( appName() ) ) );
+ that->myHasUserValues = myResources.count() > 0;
+
for ( QStringList::ConstIterator it = myDirList.begin(); it != myDirList.end(); ++it )
{
QString path = Qtx::addSlash( *it ) + globalFileName( appName() );
}
/*!
- \brief Set "ignore user values" option value.
-
- If this option is \c true, then all resources loaded from user home directory are ignored.
+ \brief Get current working mode.
- \param val new option value
- \sa ignoreUserValues()
+ \return current working mode
+ \sa setWorkingMode(), value(), hasValue(), hasSection(), setValue()
*/
-void QtxResourceMgr::setIgnoreUserValues( const bool val )
+QtxResourceMgr::WorkingMode QtxResourceMgr::workingMode() const
{
- myIsIgnoreUserValues = val;
+ return myWorkingMode;
}
/*!
- \brief Get "ignore user values" option value.
+ \brief Set resource manager's working mode.
+
+ The resource manager can operate in the following working modes:
+ * AllowUserValues : methods values(), hasValue(), hasSection() take into account user values (default)
+ * IgnoreUserValues : methods values(), hasValue(), hasSection() do not take into account user values
+
+ Note, that setValue() method always put the value to the user settings file.
- \return "ignore user values" option value
- \sa setIgnoreUserValues()
+ \param mode new working mode
+ \sa workingMode(), value(), hasValue(), hasSection(), setValue()
*/
-bool QtxResourceMgr::ignoreUserValues() const
+void QtxResourceMgr::setWorkingMode( WorkingMode mode )
{
- return myIsIgnoreUserValues;
+ myWorkingMode = mode;
}
/*!
fVal.setItalic( true );
else if ( curval == QString( "underline" ) )
fVal.setUnderline( true );
+ else if ( curval == QString( "shadow" ) || curval == QString( "overline" ) )
+ fVal.setOverline( true );
else
{
bool isOk = false;
bool ok = false;
ResList::ConstIterator it = myResources.begin();
- if ( ignoreUserValues() )
+ if ( myHasUserValues && workingMode() == IgnoreUserValues )
++it;
for ( ; it != myResources.end() && !ok; ++it )
initialize();
bool ok = false;
- for ( ResList::ConstIterator it = myResources.begin(); it != myResources.end() && !ok; ++it )
+
+ ResList::ConstIterator it = myResources.begin();
+ if ( myHasUserValues && workingMode() == IgnoreUserValues )
+ ++it;
+
+ for ( ; it != myResources.end() && !ok; ++it )
ok = (*it)->hasValue( sect, name );
return ok;
initialize();
bool ok = false;
- for ( ResList::ConstIterator it = myResources.begin(); it != myResources.end() && !ok; ++it )
+
+ ResList::ConstIterator it = myResources.begin();
+ if ( myHasUserValues && workingMode() == IgnoreUserValues )
+ ++it;
+
+ for ( ; it != myResources.end() && !ok; ++it )
ok = (*it)->hasSection( sect );
return ok;
fontDescr.append( "Italic" );
if ( val.underline() )
fontDescr.append( "Underline" );
+ if ( val.overline() )
+ fontDescr.append( "Overline" );
fontDescr.append( QString( "%1" ).arg( val.pointSize() ) );
setResource( sect, name, fontDescr.join( "," ) );
if ( !fmt )
return false;
+ if ( myResources.isEmpty() || !myHasUserValues )
+ return false;
+
Resources* r = myResources[0];
if ( !r )
return false;
if ( !fmt )
return false;
- if ( myResources.isEmpty() )
+ if ( myResources.isEmpty() || !myHasUserValues )
return true;
return fmt->save( myResources[0] );
{
initialize();
- QMap<QString, int> map;
- for ( ResList::ConstIterator it = myResources.begin(); it != myResources.end(); ++it )
+ QSet<QString> set;
+
+ ResList::ConstIterator it = myResources.begin();
+ if ( myHasUserValues && workingMode() == IgnoreUserValues )
+ ++it;
+
+ QStringList res;
+ for ( ; it != myResources.end(); ++it )
{
QStringList lst = (*it)->sections();
- for ( QStringList::ConstIterator itr = lst.begin(); itr != lst.end(); ++itr )
- map.insert( *itr, 0 );
+ for ( QStringList::ConstIterator itr = lst.begin(); itr != lst.end(); ++itr ) {
+ QString sect = *itr;
+ if ( !set.contains( sect ) ) {
+ set.insert( sect );
+ res.append( sect );
+ }
+ }
}
- QStringList res;
- for ( QMap<QString, int>::ConstIterator iter = map.begin(); iter != map.end(); ++iter )
- res.append( iter.key() );
-
return res;
}
+/*!
+ \brief Get all sections names matching specified regular expression.
+ \param re searched regular expression
+ \return list of sections names
+*/
+QStringList QtxResourceMgr::sections(const QRegExp& re) const
+{
+ return sections().filter( re );
+}
+
+/*!
+ \brief Get all sections names with the prefix specified by passed
+ list of parent sections names.
+
+ Sub-sections are separated inside the section name by the sections
+ separator token, for example "splash:color:label".
+
+ \param names parent sub-sections names
+ \return list of sections names
+*/
+QStringList QtxResourceMgr::sections(const QStringList& names) const
+{
+ QStringList nm = names;
+ nm << ".+";
+ QRegExp re( QString( "^%1$" ).arg( nm.join( sectionsToken() ) ) );
+ return sections( re );
+}
+
+/*!
+ \brief Get list of sub-sections names for the specified parent section name.
+
+ Sub-sections are separated inside the section name by the sections
+ separator token, for example "splash:color:label".
+
+ \param section parent sub-section name
+ \param full if \c true return full names of child sub-sections, if \c false,
+ return only top-level sub-sections names
+ \return list of sub-sections names
+*/
+QStringList QtxResourceMgr::subSections(const QString& section, const bool full) const
+{
+ QStringList names = sections( QStringList() << section );
+ QMutableListIterator<QString> it( names );
+ while ( it.hasNext() ) {
+ QString name = it.next().mid( section.size() + 1 ).trimmed();
+ if ( name.isEmpty() ) {
+ it.remove();
+ continue;
+ }
+ if ( !full )
+ name = name.split( sectionsToken() ).first();
+ it.setValue( name );
+ }
+ /*
+ names.removeDuplicates();
+ */
+ QSet<QString> set;
+ QStringList simpleList;
+ for ( QStringList::iterator it = names.begin(); it != names.end(); ++it ) {
+ if ( !set.contains( *it ) ) {
+ set.insert( *it );
+ simpleList.append( *it );
+ }
+ }
+ names = simpleList;
+ names.sort();
+ return names;
+}
+
/*!
\brief Get all parameters name in specified section.
\param sec section name
#endif
PMap pmap;
- ResList::ConstIterator it = myResources.end();
- while ( it != myResources.begin() )
+ Resources* ur = !myResources.isEmpty() && workingMode() == IgnoreUserValues ? myResources[0] : 0;
+
+ QListIterator<Resources*> it( myResources );
+ it.toBack();
+ while ( it.hasPrevious() )
{
- --it;
- QStringList lst = (*it)->parameters( sec );
+ Resources* r = it.previous();
+ if ( r == ur ) break;
+ QStringList lst = r->parameters( sec );
+
for ( QStringList::ConstIterator itr = lst.begin(); itr != lst.end(); ++itr )
+#if defined(QTX_NO_INDEXED_MAP)
+ if ( !pmap.contains( *itr ) ) pmap.insert( *itr, 0 );
+#else
pmap.insert( *itr, 0, false );
+#endif
}
- QStringList res;
- for ( PMap::ConstIterator iter = pmap.begin(); iter != pmap.end(); ++iter )
- res.append( iter.key() );
+ return pmap.keys();
+}
- return res;
+/*!
+ \brief Get all parameters name in specified
+ list of sub-sections names.
+
+ Sub-sections are separated inside the section name by the sections
+ separator token, for example "splash:color:label".
+
+ \param names parent sub-sections names
+ \return list of settings names
+*/
+QStringList QtxResourceMgr::parameters( const QStringList& names ) const
+{
+ return parameters( names.join( sectionsToken() ) );
}
/*!
QString QtxResourceMgr::path( const QString& sect, const QString& prefix, const QString& name ) const
{
QString res;
- for ( ResList::ConstIterator it = myResources.begin(); it != myResources.end() && res.isEmpty(); ++it )
+
+ ResList::ConstIterator it = myResources.begin();
+ if ( myHasUserValues && workingMode() == IgnoreUserValues )
+ ++it;
+
+ for ( ; it != myResources.end() && res.isEmpty(); ++it )
res = (*it)->path( sect, prefix, name );
return res;
}
\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.
+ it can be changed by setting the "res_section_name" resources manager option.
\return section corresponding to the resources directories
\sa option(), setOption()
\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.
+ it can be changed by setting the "lang_section_name" resources manager option.
\return section corresponding to the application language settings
\sa option(), setOption()
return res;
}
+/*!
+ \brief Get sections separator token.
+
+ By default, sections separator token is colon symbol ":" but
+ it can be changed by setting the "section_token" resources manager option.
+
+ \return string corresponding to the current section separator token
+ \sa option(), setOption()
+*/
+QString QtxResourceMgr::sectionsToken() const
+{
+ QString res = option( "section_token" );
+ if ( res.isEmpty() )
+ res = QString( ":" );
+ return res;
+}
+
/*!
\brief Get default pixmap.
initialize();
QPixmap pix;
- for ( ResList::ConstIterator it = myResources.begin(); it != myResources.end() && pix.isNull(); ++it )
+
+ ResList::ConstIterator it = myResources.begin();
+ if ( myHasUserValues && workingMode() == IgnoreUserValues )
+ ++it;
+
+ for ( ; it != myResources.end() && pix.isNull(); ++it )
pix = (*it)->loadPixmap( resSection(), prefix, name );
if ( pix.isNull() )
pix = defPix;
return pix;
}
-/*!
- \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.
-
- 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 pref parameter which defines translation context (for example, package name)
- \param l language name
-
- \sa resSection(), langSection(), loadTranslators()
-*/
-void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l )
-{
- loadLanguage( true, pref, l );
-}
-
/*!
\brief Load translation files according to the specified language.
By default, settings from the user preferences file are also loaded (if user resource file is valid,
see userFileName()). To avoid loading user settings, pass \c false as first parameter.
- \param loadUser if \c true then user settings are also loaded
\param pref parameter which defines translation context (for example, package name)
\param l language name
\sa resSection(), langSection(), loadTranslators()
*/
-void QtxResourceMgr::loadLanguage( const bool loadUser, const QString& pref, const QString& l )
+void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l )
{
- initialize( true, loadUser );
+ initialize( true );
QMap<QChar, QString> substMap;
substMap.insert( 'A', appName() );
if ( lang.isEmpty() )
{
lang = QString( "en" );
- qWarning( "Language not specified. Assumed: %s", (const char*)lang.toLatin1() );
+ qWarning() << "QtxResourceMgr: Language not specified. Assumed:" << lang;
}
substMap.insert( 'L', lang );
if ( trList.isEmpty() )
{
trList.append( "%P_msg_%L.qm" );
- qWarning( "Translators not defined. Assumed: %s", (const char*)trList[0].toLatin1() );
+ qWarning() << "QtxResourceMgr: Translators not defined. Assumed:" << trList[0];
}
QStringList prefixList;
else
prefixList = parameters( resSection() );
+ if ( pref.isEmpty() && lang != "en" ) {
+ // load Qt resources
+ QString qt_translations = QLibraryInfo::location( QLibraryInfo::TranslationsPath );
+ QString qt_dir_trpath;
+ if ( ::getenv( "QTDIR" ) )
+ qt_dir_trpath = QString( ::getenv( "QTDIR" ) );
+ if ( !qt_dir_trpath.isEmpty() )
+ qt_dir_trpath = QDir( qt_dir_trpath ).absoluteFilePath( "translations" );
+
+ QTranslator* trans = new QtxTranslator( 0 );
+ if ( trans->load( QString("qt_%1").arg( lang ), qt_translations ) || trans->load( QString("qt_%1").arg( lang ), qt_dir_trpath ) )
+ QApplication::instance()->installTranslator( trans );
+ }
+
for ( QStringList::ConstIterator iter = prefixList.begin(); iter != prefixList.end(); ++iter )
{
QString prefix = *iter;
initialize();
ResList lst;
- for ( ResList::Iterator iter = myResources.begin(); iter != myResources.end(); ++iter )
+
+ ResList::ConstIterator iter = myResources.begin();
+ if ( myHasUserValues && workingMode() == IgnoreUserValues )
+ ++iter;
+
+ for ( ; iter != myResources.end(); ++iter )
lst.prepend( *iter );
QTranslator* trans = 0;
QTranslator* trans = 0;
- ResList::ConstIterator it = myResources.end();
- while ( it != myResources.begin() )
+ Resources* ur = !myResources.isEmpty() && workingMode() == IgnoreUserValues ? myResources[0] : 0;
+
+ QListIterator<Resources*> it( myResources );
+ it.toBack();
+ while ( it.hasPrevious() )
{
- --it;
- trans = (*it)->loadTranslator( resSection(), prefix, name );
+ Resources* r = it.previous();
+ if ( r == ur ) break;
+
+ trans = r->loadTranslator( resSection(), prefix, name );
if ( trans )
{
if ( !myTranslator[prefix].contains( trans ) )
{
initialize();
- if ( !myResources.isEmpty() )
+ if ( !myResources.isEmpty() && myHasUserValues )
myResources.first()->setValue( sect, name, val );
}
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)
+ \param for_load boolean flag indicating that file is opened for loading or saving (not used in default implementation)
\return user configuration file name
\sa globalFileName()
*/
QString fileName;
QString pathName = QDir::homePath();
+ QString cfgAppName = QApplication::applicationName();
+ if ( !cfgAppName.isEmpty() )
+ pathName = Qtx::addSlash( Qtx::addSlash( pathName ) + QString( ".config" ) ) + cfgAppName;
+
#ifdef WIN32
fileName = QString( "%1.%2" ).arg( appName ).arg( currentFormat() );
#else
typedef IMap<QString, QString> Section; //!< resource section
#endif
+ //! Working mode; defines a way how resource manager handles user preferences
+ typedef enum {
+ AllowUserValues, //!< User values are processed by the resource manager
+ IgnoreUserValues //!< User values are ignored by the resource manager
+ } WorkingMode;
+
public:
QtxResourceMgr( const QString&, const QString& = QString() );
virtual ~QtxResourceMgr();
void clear();
- void setIgnoreUserValues( const bool = true );
- bool ignoreUserValues() const;
+ WorkingMode workingMode() const;
+ void setWorkingMode( WorkingMode );
bool value( const QString&, const QString&, int& ) const;
bool value( const QString&, const QString&, double& ) const;
QString resSection() const;
QString langSection() const;
+ QString sectionsToken() const;
QPixmap loadPixmap( const QString&, const QString& ) const;
QPixmap loadPixmap( const QString&, const QString&, const bool ) const;
QPixmap loadPixmap( const QString&, const QString&, const QPixmap& ) const;
void loadLanguage( const QString& = QString(), const QString& = QString() );
- void loadLanguage( const bool, const QString& = QString(), const QString& = QString() );
void raiseTranslators( const QString& );
void removeTranslators( const QString& );
bool save();
QStringList sections() const;
+ QStringList sections(const QRegExp&) const;
+ QStringList sections(const QStringList&) const;
+ QStringList subSections(const QString&, const bool = true) const;
QStringList parameters( const QString& ) const;
+ QStringList parameters( const QStringList& ) const;
void refresh();
virtual QString globalFileName( const QString& ) const;
private:
- void initialize( const bool = true, const bool = true ) const;
+ void initialize( const bool = true ) const;
QString substMacro( const QString&, const QMap<QChar, QString>& ) const;
private:
QPixmap* myDefaultPix; //!< default icon
bool myIsPixmapCached; //!< "cached pixmaps" flag
- bool myIsIgnoreUserValues; //!< "ignore user values" flag
+ bool myHasUserValues; //!< \c true if user preferences has been read
+ WorkingMode myWorkingMode; //!< working mode
friend class QtxResourceMgr::Format;
};
--- /dev/null
+// Copyright (C) 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// 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
+//
+
+#include "QtxShortcutEdit.h"
+
+#include <QWidget>
+#include <QLayout>
+#include <QList>
+
+#include <QToolButton>
+#include <QLineEdit>
+#include <QTableWidgetItem>
+#include <QMessageBox>
+
+#include <QKeyEvent>
+#include <QKeySequence>
+
+#define COLUMN_SIZE 300
+
+static const char* delete_icon[] = {
+"16 16 3 1",
+"` c #810000",
+" c none",
+"# c #ffffff",
+" ",
+" ",
+" ``# ``# ",
+" ````# ``# ",
+" ````# ``# ",
+" ```# `# ",
+" `````# ",
+" ```# ",
+" `````# ",
+" ```# ``# ",
+" ```# ``# ",
+" ```# `# ",
+" ```# `# ",
+" `# `# ",
+" ",
+" "
+};
+
+/*!
+ \brief Constructor
+ \param parent parent widget
+*/
+QtxShortcutEdit::QtxShortcutEdit( QWidget* parent )
+: QFrame( parent )
+{
+ initialize();
+ myShortcut->installEventFilter(this);
+}
+
+/*!
+ \brief Destructor
+*/
+QtxShortcutEdit::~QtxShortcutEdit()
+{
+}
+
+/*!
+ \brief Sets custom shortcut
+ \param seq a key sequence describes a combination of keys
+ \sa shortcut()
+*/
+void QtxShortcutEdit::setShortcut( const QKeySequence& seq )
+{
+ QString txt = seq.toString();
+ myPrevShortcutText = txt;
+ myShortcut->setText( txt );
+}
+
+/*!
+ \brief Gets custom shortcut
+ \return a key sequence describes a combination of keys
+ \sa setShortcut()
+*/
+QKeySequence QtxShortcutEdit::shortcut()
+{
+ return QKeySequence::fromString( myShortcut->text() );
+}
+
+/*!
+ \brief Gets the key sequence from keys that were pressed
+ \param e a key event
+ \return a string representation of the key sequence
+*/
+QString QtxShortcutEdit::parseEvent( QKeyEvent* e )
+{
+ bool isShiftPressed = e->modifiers() & Qt::ShiftModifier;
+ bool isControlPressed = e->modifiers() & Qt::ControlModifier;
+ bool isAltPressed = e->modifiers() & Qt::AltModifier;
+ bool isMetaPressed = e->modifiers() & Qt::MetaModifier;
+ bool isModifiersPressed = isShiftPressed || isControlPressed || isAltPressed || isMetaPressed;
+ int result=0;
+ if( isControlPressed )
+ result += Qt::CTRL;
+ if( isAltPressed )
+ result += Qt::ALT;
+ if( isShiftPressed )
+ result += Qt::SHIFT;
+ if( isMetaPressed )
+ result += Qt::META;
+
+ int aKey = e->key();
+ if ( ( isValidKey( aKey ) && isModifiersPressed ) || ( ( aKey >= Qt::Key_F1 ) && ( aKey <= Qt::Key_F12 ) ) )
+ result += aKey;
+
+ return QKeySequence( result ).toString();
+}
+
+/*!
+ \brief Check if the key event contains a 'valid' key
+ \param aKey the code of the key
+ \return \c true if the key is 'valid'
+*/
+
+bool QtxShortcutEdit::isValidKey( int aKey )
+{
+ if ( aKey == Qt::Key_Underscore || aKey == Qt::Key_Escape ||
+ ( aKey >= Qt::Key_Backspace && aKey <= Qt::Key_Delete ) ||
+ ( aKey >= Qt::Key_Home && aKey <= Qt::Key_PageDown ) ||
+ ( aKey >= Qt::Key_F1 && aKey <= Qt::Key_F12 ) ||
+ ( aKey >= Qt::Key_Space && aKey <= Qt::Key_Asterisk ) ||
+ ( aKey >= Qt::Key_Comma && aKey <= Qt::Key_Question ) ||
+ ( aKey >= Qt::Key_A && aKey <= Qt::Key_AsciiTilde ) )
+ return true;
+ return false;
+}
+
+/*!
+ \brief Called when "Clear" button is clicked.
+*/
+void QtxShortcutEdit::onCliked()
+{
+ myShortcut->setText( "" );
+}
+
+/*!
+ \brief Called when myShortcut loses focus.
+*/
+void QtxShortcutEdit::onEditingFinished()
+{
+ if ( myShortcut->text().endsWith("+") )
+ myShortcut->setText( myPrevShortcutText );
+}
+
+/*!
+ \brief Custom event filter.
+ \param obj event receiver object
+ \param event event
+ \return \c true if further event processing should be stopped
+*/
+bool QtxShortcutEdit::eventFilter(QObject* obj, QEvent* event)
+{
+ if ( obj == myShortcut ) {
+ if (event->type() == QEvent::KeyPress ) {
+ QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
+ QString text = parseEvent( keyEvent );
+ if ( keyEvent->key() == Qt::Key_Delete || keyEvent->key() == Qt::Key_Backspace )
+ onCliked();
+ if ( text != "" )
+ myShortcut->setText( text );
+ return true;
+ }
+ if ( event->type() == QEvent::KeyRelease ) {
+ if ( myShortcut->text().endsWith("+") )
+ myShortcut->setText( myPrevShortcutText );
+ else myPrevShortcutText = myShortcut->text();
+
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ \brief Perform internal intialization.
+*/
+void QtxShortcutEdit::initialize()
+{
+ myPrevShortcutText = QString();
+
+ QHBoxLayout* base = new QHBoxLayout( this );
+ base->setMargin( 0 );
+ base->setSpacing( 5 );
+
+ base->addWidget( myShortcut = new QLineEdit( this ) );
+
+ QToolButton* deleteBtn = new QToolButton();
+ deleteBtn->setIcon( QPixmap( delete_icon ) );
+ base->addWidget( deleteBtn );
+
+ myShortcut->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
+ deleteBtn->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
+
+ connect( deleteBtn, SIGNAL( clicked() ), this, SLOT( onCliked() ) );
+ connect( myShortcut, SIGNAL( editingFinished() ), this, SLOT( onEditingFinished() ) );
+}
+
+/*!
+ \brief Constructor
+ \param parent parent widget
+*/
+QtxShortcutTree::QtxShortcutTree( QWidget * parent ) : QTreeWidget( parent )
+{
+ setColumnCount( 2 );
+ setSelectionMode( QAbstractItemView::SingleSelection );
+ setColumnWidth ( 0, COLUMN_SIZE);
+ setSortingEnabled(false);
+ headerItem()->setHidden ( true );
+
+ this->installEventFilter(this);
+ connect( this, SIGNAL( currentItemChanged ( QTreeWidgetItem*, QTreeWidgetItem* ) ), this, SLOT( onCurrentItemChanged ( QTreeWidgetItem*, QTreeWidgetItem* ) ) );
+
+}
+
+/*!
+ \brief Destructor
+*/
+QtxShortcutTree::~QtxShortcutTree(){}
+
+/*!
+ \brief Custom event filter.
+ \param obj event receiver object
+ \param event event
+ \return \c true if further event processing should be stopped
+*/
+bool QtxShortcutTree::eventFilter(QObject* obj, QEvent* event)
+{
+ if ( currentItem() && currentItem()->isSelected() ) {
+
+ if (event->type() == QEvent::KeyPress ) {
+ QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
+ QString text = QtxShortcutEdit::parseEvent( keyEvent );
+ if ( keyEvent->key() == Qt::Key_Delete || keyEvent->key() == Qt::Key_Backspace )
+ currentItem()->setText( 1, "" );
+ if ( text != "" ) {
+ if ( text.endsWith( "+" ) || checkUniqueness( currentItem(), text ) )
+ currentItem()->setText( 1, text );
+ }
+ return true;
+ }
+ if ( event->type() == QEvent::KeyRelease ) {
+ if ( currentItem()->text( 1 ).endsWith( "+" ) )
+ currentItem()->setText( 1, myPrevBindings[ currentItem()->parent()->text( 0 ) ][ currentItem()->text( 0 ) ] );
+ else myPrevBindings[ currentItem()->parent()->text( 0 ) ][ currentItem()->text( 0 ) ] = currentItem()->text( 1 );
+
+ return true;
+ }
+ }
+ return false;
+}
+
+/*!
+ \brief Called when the current item changes.
+ \param cur the current item
+ \param prev the previous current item
+*/
+void QtxShortcutTree::onCurrentItemChanged( QTreeWidgetItem* cur, QTreeWidgetItem* prev )
+{
+ if ( prev && prev->text( 1 ).endsWith( "+" ) )
+ prev->setText( 1, myPrevBindings[ prev->parent()->text( 0 ) ][ prev->text( 0 ) ] );
+}
+
+/*!
+ \brief Set key bindings to the tree
+ \param title the name of top-level item
+ \param theShortcutMap map of key bindings
+*/
+void QtxShortcutTree::setBindings( const QString& title, const ShortcutMap& theShortcutMap )
+{
+ QTreeWidgetItem* item= new QTreeWidgetItem();
+ QFont font = item->font(0);
+ font.setBold(true);
+
+ if ( findItems( title, Qt::MatchFixedString ).isEmpty() ) {
+ item->setText( 0, title );
+ item->setFont( 0, font );
+ addTopLevelItem( item );
+ item->setFlags( Qt::ItemIsEnabled );
+ } else {
+ item = findItems( title, Qt::MatchFixedString ).first();
+ item->takeChildren();
+ }
+ for( ShortcutMap::const_iterator it = theShortcutMap.constBegin(); it != theShortcutMap.constEnd(); ++it )
+ item->addChild( new QTreeWidgetItem( QStringList() << it.key() << it.value() ) );
+ myPrevBindings.insert( title, theShortcutMap);
+}
+
+/*!
+ \brief Get all sections names.
+ \return list of section names
+*/
+QStringList QtxShortcutTree::sections() const
+{
+ QStringList lst;
+ for( int i = 0; i < topLevelItemCount(); i++ )
+ lst << topLevelItem( i )->text( 0 );
+ return lst;
+}
+
+ShortcutMap* QtxShortcutTree::bindings( const QString& sec ) const
+{
+ ShortcutMap* aMap = new ShortcutMap();
+ QTreeWidgetItem* item = findItems( sec, Qt::MatchFixedString ).first();
+ int nbChildren = item->childCount();
+
+ for( int i = 0; i < nbChildren; i++ ) {
+ QTreeWidgetItem* child = item->child(i);
+ aMap->insert( child->text( 0 ), child->text( 1 ) );
+ }
+
+ return aMap;
+}
+
+void QtxShortcutTree::focusOutEvent ( QFocusEvent* event )
+{
+ QWidget::focusOutEvent( event );
+ if ( currentItem() && currentItem()->isSelected() )
+ currentItem()->setText( 1, myPrevBindings[ currentItem()->parent()->text( 0 ) ][ currentItem()->text( 0 ) ] );
+}
+
+/*!
+ \brief Set the list of shortcuts general sections.
+
+ Key combinations in general sections should not intersect
+ with any other key combinations.
+
+ \param sectionsList list of common section names
+*/
+void QtxShortcutTree::setGeneralSections( const QStringList& sectionsList )
+{
+ myGeneralSections = sectionsList;
+}
+
+/*!
+ \brief Check uniqueness of the shortcut.
+ \param item current item of the shortcut tree
+ \param shortcut shortcut appointed for the current item
+ \return \c true if the given shortcut is allowed
+*/
+bool QtxShortcutTree::checkUniqueness( QTreeWidgetItem* item, const QString& shortcut )
+{
+ // List of sections to check shortcut intersections
+ QStringList sectionsList;
+
+ // Current section
+ QString currentSection = currentItem()->parent()->text( 0 );
+
+ // If the current section is general
+ if ( myGeneralSections.contains(currentSection) ) {
+ sectionsList = sections();
+ int currentSectionIndex = sectionsList.indexOf(currentSection);
+ sectionsList.move( currentSectionIndex, 0);
+ }
+ else {
+ sectionsList = myGeneralSections;
+ sectionsList.prepend(currentSection);
+ }
+
+ // Iterate on sections
+ QStringList::const_iterator it;
+ for( it = sectionsList.constBegin(); it != sectionsList.constEnd(); ++it ) {
+ QString section = *it;
+
+ // Iterate on actual section
+ QTreeWidgetItem* sectionRoot = findItems( section, Qt::MatchFixedString ).first();
+ int nbChildren = sectionRoot->childCount();
+
+ for( int i = 0; i < nbChildren; i++ ) {
+ QTreeWidgetItem* child = sectionRoot->child(i);
+
+ if ( (child != item) && (shortcut == child->text( 1 )) ) {
+ bool res = QMessageBox::warning( parentWidget(), tr("Warning"),
+ tr("The \"%1\" shortcut has already used by the \"%2\" action.\n")
+ .arg(shortcut, section + ":" + child->text( 0 ) ) +
+ tr("Do you want to reassign it from that action to the current one?"),
+ QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes;
+ if (res)
+ child->setText( 1, "" );
+ return res;
+ }
+ }
+ }
+
+ return true;
+}
--- /dev/null
+// Copyright (C) 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// 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
+//
+
+#ifndef QTXSHORTCUTEDIT_H
+#define QTXSHORTCUTEDIT_H
+
+#include "Qtx.h"
+
+#include <QFrame>
+#include <QTreeWidget>
+
+class QLineEdit;
+class QPushButton;
+class QTreeWidgetItem;
+
+typedef QMap< QString, QString > ShortcutMap;
+
+class QTX_EXPORT QtxShortcutEdit : public QFrame
+{
+ Q_OBJECT
+
+public:
+ QtxShortcutEdit( QWidget* = 0 );
+ virtual ~QtxShortcutEdit();
+ void setShortcut( const QKeySequence& );
+ QKeySequence shortcut();
+ static QString parseEvent( QKeyEvent* );
+ static bool isValidKey( int );
+
+
+private slots:
+ void onCliked();
+ void onEditingFinished();
+
+protected:
+ virtual bool eventFilter( QObject*, QEvent* );
+
+private:
+ void initialize();
+
+private:
+ QLineEdit* myShortcut;
+ QString myPrevShortcutText;
+};
+
+class QTX_EXPORT QtxShortcutTree : public QTreeWidget
+{
+ Q_OBJECT
+
+public:
+ QtxShortcutTree( QWidget * parent = 0 );
+ virtual ~QtxShortcutTree();
+ void setBindings( const QString&, const ShortcutMap& );
+ ShortcutMap* bindings( const QString& ) const;
+ QStringList sections() const;
+ void setGeneralSections( const QStringList& );
+
+protected:
+ virtual bool eventFilter( QObject*, QEvent* );
+ virtual void focusOutEvent( QFocusEvent* );
+ virtual bool checkUniqueness( QTreeWidgetItem*, const QString& );
+
+private slots:
+ void onCurrentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* );
+
+private:
+ QMap< QString, ShortcutMap > myPrevBindings;
+ QStringList myGeneralSections;
+};
+
+#endif // QTXSHORTCUTEDIT_H