]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
Shortcut edit preferences functionality was added.
authorsan <san@opencascade.com>
Fri, 30 Dec 2011 07:34:46 +0000 (07:34 +0000)
committersan <san@opencascade.com>
Fri, 30 Dec 2011 07:34:46 +0000 (07:34 +0000)
14 files changed:
src/Qtx/Qtx.cxx
src/Qtx/Qtx.h
src/Qtx/Qtx.pro
src/Qtx/QtxFontEdit.cxx
src/Qtx/QtxFontEdit.h
src/Qtx/QtxMainWindow.cxx
src/Qtx/QtxMainWindow.h
src/Qtx/QtxPagePrefMgr.cxx
src/Qtx/QtxPagePrefMgr.h
src/Qtx/QtxPathListEdit.cxx
src/Qtx/QtxResourceMgr.cxx
src/Qtx/QtxResourceMgr.h
src/Qtx/QtxShortcutEdit.cxx [new file with mode: 0755]
src/Qtx/QtxShortcutEdit.h [new file with mode: 0755]

index 896eed39a77a45496321d60a107c17ecef571cdf..89f7e729cbd852a003d3cd86c90785956c39b44a 100755 (executable)
 #include <QRadialGradient>
 #include <QConicalGradient>
 
+#include <QtDebug>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <clocale>
+
+#define BICOLOR_CHANGE_HUE
 
 /*!
   \class Qtx
@@ -431,7 +436,7 @@ QString Qtx::library( const QString& str )
 */
 QString Qtx::tmpDir()
 {
-  char* tmpdir = ::getenv( "TEMP" );
+  const char* tmpdir = ::getenv( "TEMP" );
   if ( !tmpdir )
     tmpdir = ::getenv ( "TMP" );
   if ( !tmpdir )
@@ -624,6 +629,99 @@ QCompleter* Qtx::pathCompleter( const PathType type, const QString& filter )
   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
@@ -718,7 +816,7 @@ void Qtx::scaleColors( const int num, QColorList& lst )
 /*!
   \brief Scale the pixmap to the required size.
 
-  If \h is 0 (default) the value of \a w is used instead (to create
+  If \h is 0 (default) the value of \a w is used instead (to create
   square pixmap).
 
   \param icon pixmap to be resized
@@ -730,7 +828,7 @@ QPixmap Qtx::scaleIcon( const QPixmap& icon, const unsigned w, const unsigned h
 {
   QPixmap p;
   int aw = w, ah = h <= 0 ? w : h;
-  if ( icon.isNull() || aw <= 0 || ah <= 0 || aw == icon.width() && ah == icon.height() )
+  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 ) );
@@ -962,7 +1060,7 @@ QString Qtx::colorToString( const QColor& color )
   - "RR,GG,BB[,AA]" or "RR GG BB[ AA]" (\c RR, \c GG, \c BB
   and optional \c AA values represent red, green, blue and alpha
   components of the color in 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
@@ -1013,6 +1111,106 @@ bool Qtx::stringToColor( const QString& str, QColor& color )
   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
@@ -1191,7 +1389,7 @@ bool Qtx::stringToRadialGradient( const QString& str, QRadialGradient& gradient
 {
   bool success = false;
   QStringList vals = str.split( "|", QString::SkipEmptyParts );
-  if ( vals.count() > 5 && vals[0] == "radial" || vals[0] == "rg" ) 
+  if ( ( vals.count() > 5 && vals[0] == "radial" ) || vals[0] == "rg" ) 
   {
     // center, radius and focal point
     double cx, cy, r, fx, fy;
@@ -1245,7 +1443,7 @@ bool Qtx::stringToConicalGradient( const QString& str, QConicalGradient& gradien
 {
   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;
@@ -1286,34 +1484,108 @@ bool Qtx::stringToConicalGradient( const QString& str, QConicalGradient& gradien
   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
index 8e67524fcfbf4c04fe85629e8d9b5daa93cdb25b..907cb5afad0a89dee304443669203a0004871de2 100755 (executable)
@@ -23,7 +23,7 @@
 #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 )
@@ -96,6 +96,49 @@ public:
     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 );
@@ -123,6 +166,8 @@ public:
   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 );
@@ -142,6 +187,9 @@ public:
 
   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& );
@@ -150,7 +198,10 @@ public:
   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
index 1a3a451db5ec524acfee431619ab78ef6c81c5d0..afbc2f0da4cf815c976a1270f3bc0cdb2a69b59d 100644 (file)
@@ -6,6 +6,7 @@ include(../Common.pro)
 CONFIG += embed_manifest_exe
 
 win32:LIBS *= -L$(QTLIB)
+unix:LIBS *= -lGL
 win32:INCLUDEPATH *= $(QTINC) $(QTINC)\QtCore $(QTINC)\QtGui $(QTINC)\QtXml
 
 QT += xml
index 30970d8f14adc6335d66d8e1dc6b03570abe6e05..5db88d298e9be6db77ae40f074ce58ad274dba76 100644 (file)
@@ -57,7 +57,8 @@
 */
 QtxFontEdit::QtxFontEdit( const int feat, QWidget* parent )
 : QFrame( parent ),
-  myFeatures( feat )
+  myFeatures( feat ),
+  myMode( Native )
 {
   initialize();
 }
@@ -70,7 +71,8 @@ QtxFontEdit::QtxFontEdit( const int feat, QWidget* parent )
 */
 QtxFontEdit::QtxFontEdit( QWidget* parent )
 : QFrame( parent ),
-  myFeatures( All )
+  myFeatures( All ),
+  myMode( Native )
 {
   initialize();
 }
@@ -119,6 +121,7 @@ QFont QtxFontEdit::currentFont() const
   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;
 }
@@ -130,11 +133,28 @@ QFont QtxFontEdit::currentFont() const
 */
 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() ) );
 }
 
 /*!
@@ -144,7 +164,10 @@ void QtxFontEdit::setCurrentFont( const QFont& fnt )
 */
 QString QtxFontEdit::fontFamily() const
 {
+  if ( myMode == Native )
   return myFamily->currentFont().family();
+  else
+    return myCustomFams->currentText();
 }
 
 /*!
@@ -168,7 +191,8 @@ int QtxFontEdit::fontScripting() const
 {
   return ( myB->isChecked() ? Bold : 0 ) |
          ( myI->isChecked() ? Italic : 0 ) |
-         ( myU->isChecked() ? Underline : 0 );
+         ( myU->isChecked() ? Underline : 0 ) |
+         ( myS->isChecked() ? Shadow : 0 ) ;
 }
 
 /*!
@@ -178,9 +202,18 @@ int QtxFontEdit::fontScripting() const
 */
 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.
@@ -209,6 +242,7 @@ void QtxFontEdit::setFontScripting( const int script )
   myB->setChecked( script & Bold );
   myI->setChecked( script & Italic );
   myU->setChecked( script & Underline );
+  myS->setChecked( script & Shadow );
 }
 
 /*!
@@ -218,11 +252,13 @@ void QtxFontEdit::updateState()
 {
   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 );
@@ -234,6 +270,9 @@ void QtxFontEdit::updateState()
 */
 void QtxFontEdit::onFontChanged( const QFont& /*f*/ )
 {
+  bool blocked = mySize->signalsBlocked();
+  mySize->blockSignals( true );
+
   int s = fontSize();
   mySize->clear();
 
@@ -244,6 +283,16 @@ void QtxFontEdit::onFontChanged( const QFont& /*f*/ )
   mySize->addItems( sizes );
 
   setFontSize( s );
+
+  mySize->blockSignals( blocked );
+
+  if ( !myFamily->signalsBlocked() )
+    emit( changed( currentFont() ) );
+}
+
+void QtxFontEdit::onPropertyChanged()
+{
+  emit( changed( currentFont() ) );
 }
 
 /*!
@@ -269,6 +318,7 @@ void QtxFontEdit::initialize()
   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 ) );
@@ -285,14 +335,159 @@ void QtxFontEdit::initialize()
   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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
index b0ef25eef217c3a8346337513ffffbc711012ba2..052303a6323863a833fbdccddbfc9f360478ba00 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <QFrame>
 
+class QComboBox;
 class QtxComboBox;
 class QToolButton;
 class QFontComboBox;
@@ -43,11 +44,18 @@ public:
     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 );
@@ -67,9 +75,22 @@ public:
   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();
@@ -80,7 +101,9 @@ private:
   QFontComboBox* myFamily;
   QToolButton*   myPreview;
   int            myFeatures;
-  QToolButton    *myB, *myI, *myU;
+  QToolButton    *myB, *myI, *myU, *myS;
+  int            myMode;
+  QComboBox*     myCustomFams;
 };
 
 #endif // QTXFONTEDIT_H
index 8e77da2e13ba5443e2326bbf055e3c7420d46422..dad786f4aa9a452b1c956e83d96ed9a72324e5b8 100644 (file)
 #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>
 
@@ -89,6 +93,131 @@ bool QtxMainWindow::Filter::eventFilter( QObject* o, QEvent* e )
   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
@@ -104,7 +233,10 @@ bool QtxMainWindow::Filter::eventFilter( QObject* o, QEvent* e )
 QtxMainWindow::QtxMainWindow( QWidget* parent, Qt::WindowFlags f )
 : QMainWindow( parent, f ),
   myMenuBar( 0 ),
-  myStatusBar( 0 )
+  myStatusBar( 0 ),
+  myOpaque( true ),
+  myResizer( 0 ),
+  myMouseMove( 0 )
 {
 }
 
@@ -213,6 +345,16 @@ void QtxMainWindow::setDockableStatusBar( const bool on )
   }
 }
 
+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
@@ -410,3 +552,53 @@ void QtxMainWindow::onDestroyed( QObject* obj )
   }
 }
 
+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;
+}
index 10accc407b3deee5c2e759d8639ce48b05572a39..d574cf024fcb59fd22aacc08a7e5c930fec0f4e3 100644 (file)
@@ -33,11 +33,15 @@ class QTX_EXPORT QtxMainWindow : public QMainWindow
   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 );
 
@@ -47,6 +51,9 @@ public:
   QString           storeGeometry() const;
   void              retrieveGeometry( const QString& );
 
+protected:
+  virtual bool      event( QEvent* );
+
 private slots:
   void              onDestroyed( QObject* );
 
@@ -56,6 +63,10 @@ private:
 private:
   QToolBar*         myMenuBar;       //!< dockable menu bar
   QToolBar*         myStatusBar;     //!< dockable status bar
+
+  bool              myOpaque;
+  Resizer*          myResizer;
+  QMouseEvent*      myMouseMove;
 };
 
 #endif // QTXMAINWINDOW_H
index cc8c5cefda0902109b901c6cdf47a9b74e15d333..f9b4221560ce443d4bab85c97918d826281ed2cf 100644 (file)
 #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>
@@ -2081,6 +2084,36 @@ void QtxPagePrefCheckItem::retrieve()
   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.
 
@@ -2094,7 +2127,9 @@ void QtxPagePrefCheckItem::retrieve()
 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();
@@ -2116,7 +2151,9 @@ QtxPagePrefEditItem::QtxPagePrefEditItem( const int type, const QString& title,
                                           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();
@@ -2153,6 +2190,54 @@ void QtxPagePrefEditItem::setInputType( const int type )
   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()
@@ -2169,13 +2254,7 @@ void QtxPagePrefEditItem::store()
 void QtxPagePrefEditItem::retrieve()
 {
   QString txt = getString();
-  if ( myEditor->validator() )
-  {
-    int pos = 0;
-    if ( myEditor->validator()->validate( txt, pos ) == QValidator::Invalid )
-      txt.clear();
-  }
-  myEditor->setText( txt );
+  fixupAndSet( myEditor, txt );
 }
 
 /*!
@@ -2188,6 +2267,10 @@ QVariant QtxPagePrefEditItem::optionValue( const QString& name ) const
 {
   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 );
 }
@@ -2205,6 +2288,14 @@ void QtxPagePrefEditItem::setOptionValue( const QString& name, const QVariant& v
     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 );
 }
@@ -2214,6 +2305,24 @@ void QtxPagePrefEditItem::setOptionValue( const QString& name, const QVariant& v
 */
 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() )
   {
@@ -2222,21 +2331,301 @@ void QtxPagePrefEditItem::updateEditor()
     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 );
 }
 
 /*!
@@ -2354,7 +2743,7 @@ QList<int> QtxPagePrefSelectItem::numbers() const
 }
 
 /*!
-  \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()
 */
@@ -2369,7 +2758,7 @@ QList<QIcon> QtxPagePrefSelectItem::icons() const
 /*!
   \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 )
 {
@@ -2378,26 +2767,33 @@ 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 );
 }
 
@@ -2478,6 +2874,14 @@ QVariant QtxPagePrefSelectItem::optionValue( const QString& name ) const
       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 );
 }
@@ -2499,6 +2903,8 @@ void QtxPagePrefSelectItem::setOptionValue( const QString& name, const QVariant&
     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 );
 }
@@ -2536,6 +2942,30 @@ void QtxPagePrefSelectItem::setNumbers( const QVariant& var )
   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.
 */
@@ -2659,6 +3089,19 @@ QVariant QtxPagePrefSpinItem::step() const
     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
@@ -2753,6 +3196,22 @@ void QtxPagePrefSpinItem::setStep( const QVariant& step )
   }
 }
 
+/*!
+  \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
@@ -2870,6 +3329,8 @@ QVariant QtxPagePrefSpinItem::optionValue( const QString& name ) const
     return maximum();
   else if ( name == "step" )
     return step();
+  else if ( name == "precision" )
+    return precision();
   else if ( name == "prefix" )
     return prefix();
   else if ( name == "suffix" )
@@ -2899,6 +3360,8 @@ void QtxPagePrefSpinItem::setOptionValue( const QString& name, const QVariant& v
     setMaximum( val );
   else if ( name == "step" )
     setStep( val );
+  else if ( name == "precision" )
+    setPrecision( val );
   else if ( name == "prefix" )
   {
     if ( val.canConvert( QVariant::String ) )
@@ -2925,6 +3388,7 @@ void QtxPagePrefSpinItem::updateSpinBox()
 {
   QVariant val;
   QVariant stp = step();
+  QVariant prec = precision();
   QVariant min = minimum();
   QVariant max = maximum();
 
@@ -2948,6 +3412,7 @@ void QtxPagePrefSpinItem::updateSpinBox()
   control()->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
 
   setStep( stp );
+  setPrecision( prec );
   setMinimum( min );
   setMaximum( max );
 
@@ -3137,6 +3602,72 @@ void QtxPagePrefFontItem::setFeatures( const int f )
   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()
@@ -3165,6 +3696,18 @@ QVariant QtxPagePrefFontItem::optionValue( const QString& name ) const
 {
   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 );
 }
@@ -3182,6 +3725,30 @@ void QtxPagePrefFontItem::setOptionValue( const QString& name, const QVariant& v
     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 );
 }
@@ -3828,3 +4395,165 @@ void QtxPagePrefStyleItem::retrieve()
     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;
+}
index 922cc94f523d44b5b473efd67a122809dba172b5..bdaa048ce81d1a9fb9c2e50eb3899f3fc6c60876 100644 (file)
@@ -36,7 +36,10 @@ class QtxFontEdit;
 class QtxGroupBox;
 class QtxComboBox;
 class QtxColorButton;
+class QtxShortcutEdit;
+class QtxShortcutTree;
 
+class QSlider;
 class QToolBox;
 class QComboBox;
 class QLineEdit;
@@ -404,6 +407,12 @@ public:
   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();
 
@@ -416,9 +425,52 @@ private:
 
 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:
@@ -453,6 +505,7 @@ private:
   void             updateSelector();
   void             setStrings( const QVariant& );
   void             setNumbers( const QVariant& );
+  void             setIcons( const QVariant& );
 
 private:
   int              myType;
@@ -472,6 +525,7 @@ public:
   virtual ~QtxPagePrefSpinItem();
 
   QVariant         step() const;
+  QVariant         precision() const;
   QVariant         minimum() const;
   QVariant         maximum() const;
 
@@ -480,6 +534,7 @@ public:
   QString          specialValueText() const;
 
   void             setStep( const QVariant& );
+  void             setPrecision( const QVariant& );
   void             setMinimum( const QVariant& );
   void             setMaximum( const QVariant& );
 
@@ -548,6 +603,15 @@ public:
   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();
 
@@ -668,4 +732,39 @@ private:
   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
index 0c3adfedee9c4d662a3c4a0aba038231bc76cae3..82e9cf6cc1c8233b2e9fa8f606d6beaa84d6249a 100644 (file)
@@ -206,8 +206,7 @@ QtxPathListEdit::Delegate::~Delegate()
   \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 );
 }
@@ -219,8 +218,7 @@ QWidget* QtxPathListEdit::Delegate::createEditor( QWidget* parent, const QStyleO
   \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 );
 }
@@ -268,8 +266,7 @@ void QtxPathListEdit::Delegate::paint( QPainter* painter, const QStyleOptionView
   \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 );
 }
@@ -306,8 +303,8 @@ void QtxPathListEdit::Delegate::drawFocus( QPainter* painter, const QStyleOption
 */
 QtxPathListEdit::QtxPathListEdit( const Qtx::PathType type, QWidget* parent )
 : QFrame( parent ),
-  myCompleter( 0 ),
   myType( type ),
+  myCompleter( 0 ),
   myDuplicate( false )
 {
   initialize();
@@ -323,8 +320,8 @@ QtxPathListEdit::QtxPathListEdit( const Qtx::PathType type, QWidget* parent )
 */
 QtxPathListEdit::QtxPathListEdit( QWidget* parent )
 : QFrame( parent ),
-  myCompleter( 0 ),
   myType( Qtx::PT_OpenFile ),
+  myCompleter( 0 ),
   myDuplicate( false )
 {
   initialize();
index 2640b7ce503747a1edbcaba37ce078e923c80b86..f834f3b11a1846240b2dc15d63f7e3e070685f0e 100644 (file)
 #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>
 
 /*!
@@ -62,7 +67,6 @@ public:
   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();
@@ -403,54 +407,6 @@ QTranslator* QtxResourceMgr::Resources::loadTranslator( const QString& sect, con
   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.
 
@@ -472,7 +428,7 @@ QString QtxResourceMgr::Resources::makeSubstitution( const QString& str, const Q
   int start( 0 ), len( 0 );
   while ( true )
   {
-    QString envName = environmentVariable( res, start, len );
+    QString envName = Qtx::findEnvVar( res, start, len );
     if ( envName.isNull() )
       break;
 
@@ -516,6 +472,9 @@ public:
 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>& );
 };
 
 /*!
@@ -541,9 +500,41 @@ QtxResourceMgr::IniFormat::~IniFormat()
 */
 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 );
 
@@ -575,27 +566,64 @@ bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap<QString, Sectio
     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;
     }
   }
 
@@ -612,6 +640,9 @@ bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap<QString, Sectio
 */
 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;
@@ -655,8 +686,11 @@ private:
   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>& );
 };
 
 /*!
@@ -682,14 +716,45 @@ QtxResourceMgr::XmlFormat::~XmlFormat()
 */
 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;
   }
 
@@ -700,14 +765,14 @@ bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap<QString, Sectio
 
   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;
   }
 
@@ -733,12 +798,11 @@ bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap<QString, Sectio
             {
               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;
            }
           }
@@ -746,15 +810,49 @@ bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap<QString, Sectio
          {
            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;
       }
     }
@@ -762,7 +860,7 @@ bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap<QString, Sectio
     {
       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();
@@ -771,7 +869,7 @@ bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap<QString, Sectio
 #endif
 
   if ( res )
-    qDebug( "File '%s' is loaded successfully", (const char*)fname.toLatin1() );
+    qDebug() << "QtxResourceMgr: File" << fname << "is loaded successfully";
   return res;
 }
 
@@ -787,6 +885,9 @@ bool QtxResourceMgr::XmlFormat::save( const QString& fname, const QMap<QString,
 
 #ifndef QT_NO_DOM
 
+  if ( !Qtx::mkDir( QFileInfo( fname ).absolutePath() ) )
+    return false;
+
   QFile file( fname );
   if ( !file.open( QFile::WriteOnly ) )
     return false;
@@ -857,6 +958,18 @@ QString QtxResourceMgr::XmlFormat::parameterTag() const
   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
@@ -961,7 +1074,7 @@ bool QtxResourceMgr::Format::load( Resources* res )
   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;
 }
@@ -1049,8 +1162,11 @@ bool QtxResourceMgr::Format::save( Resources* res )
   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
@@ -1090,7 +1206,8 @@ QtxResourceMgr::QtxResourceMgr( const QString& appName, const QString& resVarTem
   myCheckExist( true ),
   myDefaultPix( 0 ),
   myIsPixmapCached( true ),
-  myIsIgnoreUserValues( false )
+  myHasUserValues( true ),
+  myWorkingMode( AllowUserValues )
 {
   QString envVar = !resVarTemplate.isEmpty() ? resVarTemplate : QString( "%1Resources" );
   if ( envVar.contains( "%1" ) )
@@ -1180,18 +1297,19 @@ QStringList QtxResourceMgr::dirList() const
   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() );
@@ -1238,27 +1356,31 @@ void QtxResourceMgr::clear()
 }
 
 /*!
-  \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;
 }
 
 /*!
@@ -1387,6 +1509,8 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, QFont& fVa
       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;
@@ -1501,7 +1625,7 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, QString& v
   bool ok = false;
  
   ResList::ConstIterator it = myResources.begin();
-  if ( ignoreUserValues() )
+  if ( myHasUserValues && workingMode() == IgnoreUserValues )
     ++it;
 
   for ( ; it != myResources.end() && !ok; ++it )
@@ -1710,7 +1834,12 @@ bool QtxResourceMgr::hasValue( const QString& sect, const QString& name ) const
   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;
@@ -1726,7 +1855,12 @@ bool QtxResourceMgr::hasSection( const QString& sect ) const
   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;
@@ -1812,6 +1946,8 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const Q
     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( "," ) );
@@ -2070,6 +2206,9 @@ bool QtxResourceMgr::import( const QString& fname )
   if ( !fmt )
     return false;
 
+  if ( myResources.isEmpty() || !myHasUserValues )
+    return false;
+
   Resources* r = myResources[0];
   if ( !r )
     return false;
@@ -2093,7 +2232,7 @@ bool QtxResourceMgr::save()
   if ( !fmt )
     return false;
 
-  if ( myResources.isEmpty() )
+  if ( myResources.isEmpty() || !myHasUserValues )
     return true;
 
   return fmt->save( myResources[0] );
@@ -2107,21 +2246,97 @@ QStringList QtxResourceMgr::sections() const
 {
   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
@@ -2138,20 +2353,40 @@ QStringList QtxResourceMgr::parameters( const QString& sec ) const
 #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() ) );
 }
 
 /*!
@@ -2171,7 +2406,12 @@ QStringList QtxResourceMgr::parameters( const QString& sec ) const
 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;
 }
@@ -2180,7 +2420,7 @@ QString QtxResourceMgr::path( const QString& sect, const QString& prefix, const
   \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()
@@ -2197,7 +2437,7 @@ QString QtxResourceMgr::resSection() const
   \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()
@@ -2210,6 +2450,23 @@ QString QtxResourceMgr::langSection() const
   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.
   
@@ -2284,39 +2541,18 @@ QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name,
   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.
 
@@ -2335,15 +2571,14 @@ void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l )
   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() );
@@ -2355,7 +2590,7 @@ void QtxResourceMgr::loadLanguage( const bool loadUser, const QString& pref, con
   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 );
@@ -2377,7 +2612,7 @@ void QtxResourceMgr::loadLanguage( const bool loadUser, const QString& pref, con
   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;
@@ -2386,6 +2621,20 @@ void QtxResourceMgr::loadLanguage( const bool loadUser, const QString& pref, con
   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;
@@ -2410,7 +2659,12 @@ void QtxResourceMgr::loadTranslators( const QString& prefix, const QStringList&
   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;
@@ -2442,11 +2696,16 @@ void QtxResourceMgr::loadTranslator( const QString& prefix, const QString& name
 
   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 ) )
@@ -2532,7 +2791,7 @@ void QtxResourceMgr::setResource( const QString& sect, const QString& name, cons
 {
   initialize();
 
-  if ( !myResources.isEmpty() )
+  if ( !myResources.isEmpty() && myHasUserValues )
     myResources.first()->setValue( sect, name, val );
 }
 
@@ -2550,7 +2809,7 @@ void QtxResourceMgr::setResource( const QString& sect, const QString& name, cons
   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()
 */
@@ -2559,6 +2818,10 @@ QString QtxResourceMgr::userFileName( const QString& appName, const bool /*for_l
   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
index 550c14e30503e26acffb35957cf16fa2583a412d..14514a28dc86455abdcf9df68b737a6d6bb32808 100644 (file)
@@ -60,6 +60,12 @@ public:
   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();
@@ -75,8 +81,8 @@ public:
 
   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;
@@ -133,12 +139,12 @@ public:
 
   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& );
@@ -152,7 +158,11 @@ public:
   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();
 
@@ -164,7 +174,7 @@ protected:
   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:
@@ -185,7 +195,8 @@ 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;
 };
diff --git a/src/Qtx/QtxShortcutEdit.cxx b/src/Qtx/QtxShortcutEdit.cxx
new file mode 100755 (executable)
index 0000000..3578e8f
--- /dev/null
@@ -0,0 +1,404 @@
+// 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;
+}
diff --git a/src/Qtx/QtxShortcutEdit.h b/src/Qtx/QtxShortcutEdit.h
new file mode 100755 (executable)
index 0000000..01ed17a
--- /dev/null
@@ -0,0 +1,87 @@
+// 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