Back to index

scribus-ng  1.3.4.dfsg+svn20071115
mspinbox.cpp
Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 /***************************************************************************
00008                           mspinbox.cpp  -  description
00009                              -------------------
00010     begin                : Sat Jun 16 2001
00011     copyright            : (C) 2001 by Franz Schmid
00012     email                : Franz.Schmid@altmuehlnet.de
00013  ***************************************************************************/
00014 
00015 /***************************************************************************
00016  *                                                                         *
00017  *   This program is free software; you can redistribute it and/or modify  *
00018  *   it under the terms of the GNU General Public License as published by  *
00019  *   the Free Software Foundation; either version 2 of the License, or     *
00020  *   (at your option) any later version.                                   *
00021  *                                                                         *
00022  ***************************************************************************/
00023 
00024 #include "mspinbox.h"
00025 #include "mspinbox.moc"
00026 #include <qapplication.h>
00027 #include <qlineedit.h>
00028 #include <qregexp.h>
00029 #include <cmath>
00030 #include "fparser.h"
00031 #include "units.h"
00032 
00033 
00034 MSpinBox::MSpinBox(QWidget *pa, int s):QSpinBox(pa)
00035 {
00036        setParameters(s);
00037        setValidator(0);
00038        ed = editor();
00039        QSpinBox::setLineStep(Decimals);
00040        oldLineStep = 0;
00041        currLineStep = Decimals;
00042        readOnly=false;
00043        edited = false;
00044     connect( ed, SIGNAL(textChanged(const QString&)), SLOT(textChanged()) );
00045 }
00046 
00047 MSpinBox::MSpinBox(double minValue, double maxValue, QWidget *pa, int s):QSpinBox(pa)
00048 {
00049        setParameters(s);
00050        setValidator(0);
00051        ed = editor();
00052        QSpinBox::setLineStep(Decimals);
00053        oldLineStep=0;
00054        currLineStep = Decimals;
00055        setMinValue(minValue);
00056        setMaxValue(maxValue);
00057        readOnly=false;
00058        edited = false;
00059     connect( ed, SIGNAL(textChanged(const QString&)), SLOT(textChanged()) );
00060 }
00061 
00062 MSpinBox::MSpinBox(QWidget *parent, const char * name): QSpinBox(parent, name)
00063 {
00064        setParameters(666); // pv - dummy setup for designer's constructor
00065        setValidator(0);
00066        ed = editor();
00067        QSpinBox::setLineStep(Decimals); // pv - dummy setup for designer's constructor
00068        oldLineStep=0;
00069        currLineStep = Decimals;
00070        readOnly=false;
00071        edited = false;
00072        connect( ed, SIGNAL(textChanged(const QString&)), SLOT(textChanged()) );
00073 }
00074 
00075 MSpinBox::~MSpinBox()
00076 {
00077        if (ed)
00078               disconnect( ed, SIGNAL(textChanged(const QString&)));
00079 }
00080 
00081 void MSpinBox::setParameters( int s )
00082 {
00083        if (s>=0 && s <=unitGetMaxIndex())
00084        {
00085               Width=s;
00086               Decimals=static_cast<int>(pow(10.0, s));
00087        }
00088        else
00089        {
00090               Width = 2;
00091               Decimals = 100;
00092        }
00093        edited = false;
00094        m_tabAdvance = true;
00095 }
00096 
00097 void MSpinBox::setTabAdvance(bool enable)
00098 {
00099        m_tabAdvance = enable;
00100 }
00101 
00102 bool MSpinBox::eventFilter( QObject* ob, QEvent* ev )
00103 {
00104        bool retval = false;
00105 /* Adding this to be sure that the IM* events are processed correctly i.e not intercepted by our KeyPress/Release handlers */
00106        if ((ev->type() == QEvent::IMStart) || (ev->type() == QEvent::IMCompose) || (ev->type() == QEvent::IMEnd))
00107               return QSpinBox::eventFilter(ob, ev);
00108        if ( ev->type() == QEvent::KeyPress )
00109        {
00110               QKeyEvent* k = (QKeyEvent*)ev;
00111               bool shiftB=k->state() & ShiftButton;
00112               bool controlB=k->state() & ControlButton;
00113               if (k->key() == Key_Shift && !controlB)
00114               {
00115                      QSpinBox::setLineStep(QMAX(currLineStep / 10, 1));
00116                      retval = true;
00117                      qApp->sendEvent( this, ev );
00118                      return retval;
00119               }
00120               else if (k->key() == Key_Control && !shiftB)
00121               {
00122                      QSpinBox::setLineStep(QMAX(currLineStep * 10, 1));
00123                      retval = true;
00124                      qApp->sendEvent( this, ev );
00125                      return retval;
00126               }
00127               else if ((k->key() == Key_Control && shiftB) || (k->key() == Key_Shift && controlB))
00128               {
00129                      QSpinBox::setLineStep(QMAX(currLineStep / 100, 1));
00130                      retval = true;
00131                      qApp->sendEvent( this, ev );
00132                      return retval;
00133               }
00134               else if ((k->key() == Key_Return) || (k->key() == Key_Enter) || (k->key() == Key_Tab))
00135               {
00136                      if (!m_tabAdvance)
00137                      {
00138                             QSpinBox::interpretText();
00139                             return true;
00140                      }
00141               }
00142        }
00143        if (ev->type() == QEvent::KeyRelease )
00144        {
00145               QKeyEvent* k = (QKeyEvent*)ev;
00146               bool shiftB=k->stateAfter() & ShiftButton;
00147               bool controlB=k->stateAfter() & ControlButton;
00148               if ((k->key() == Key_Shift && !controlB) || (k->key() == Key_Control && !shiftB))
00149               {
00150                      QSpinBox::setLineStep(currLineStep);
00151                      retval = true;
00152                   qApp->sendEvent( this, ev );
00153                      return retval;
00154               }
00155               else if (k->key() == Key_Shift && controlB)
00156               {
00157                      QSpinBox::setLineStep(QMAX(currLineStep * 10, 1));
00158                      retval = true;
00159                      qApp->sendEvent( this, ev );
00160                      return retval;
00161               }
00162               else if (k->key() == Key_Control && shiftB)
00163               {
00164                      QSpinBox::setLineStep(QMAX(currLineStep / 10, 1));
00165                      retval = true;
00166                      qApp->sendEvent( this, ev );
00167                      return retval;
00168               }
00169        }
00170        if ( ev->type() == QEvent::Wheel )
00171        {
00172               //If read only dont spin
00173               if (readOnly)
00174                      return false;
00175               QWheelEvent* k = (QWheelEvent*)ev;
00176               bool shiftB=k->state() & ShiftButton;
00177               bool controlB=k->state() & ControlButton;
00178               if (shiftB && !controlB)
00179               {
00180                      QSpinBox::setLineStep(QMAX(currLineStep / 10, 1));
00181                      retval = true;
00182                      qApp->sendEvent( this, ev );
00183                      return retval;
00184               } 
00185               else if (!shiftB && controlB)
00186               {
00187                      QSpinBox::setLineStep(QMAX(currLineStep * 10, 1));
00188                      retval = true;
00189                   qApp->sendEvent( this, ev );
00190                      return retval;
00191               }
00192               else if (shiftB && controlB)
00193               {
00194                      QSpinBox::setLineStep(QMAX(currLineStep / 100, 1));
00195                      retval = true;
00196                   qApp->sendEvent( this, ev );
00197                      return retval;
00198               }
00199               else
00200               if (!shiftB && !controlB)
00201               {
00202                      QSpinBox::setLineStep(currLineStep);
00203                      retval = true;
00204                      qApp->sendEvent( this, ev );
00205                      return retval;
00206               }
00207        }
00208        return QSpinBox::eventFilter(ob, ev);
00209 }
00210 
00211 QString MSpinBox::mapValueToText(int value)
00212 {
00213        QString s;
00214 //     debug outputs for strange designer's behaviour. See (parent, name) constructor for more info - PV
00215 //     qDebug("setting s");
00216 //     qDebug(QString("params %1 %2 %3 %4<-").arg(value).arg(Decimals).arg(Width).arg(name()));
00217        s.setNum(static_cast<double>(value) / Decimals, 'f', Width);
00218        return s;
00219 }
00220 
00221 int MSpinBox::mapTextToValue(bool *)
00222 {
00223        FunctionParser fp;
00224        setFPConstants(fp);
00225        QString ts = text().lower();
00226        QString su = suffix().stripWhiteSpace().lower();
00227        ts.replace(",", ".");
00228        ts.replace("%", "");
00229        int pos = ts.length();
00230        while (pos > 0)
00231        {
00232               pos = ts.findRev(".", pos);
00233               if (pos >= 0) 
00234               {
00235                      if (pos < static_cast<int>(ts.length()))
00236                      {
00237                             if (!ts[pos+1].isDigit())
00238                                    ts.insert(pos+1, "0 ");
00239                      }
00240                      pos--;
00241               }
00242        }
00243        if (ts.endsWith("."))
00244               ts.append("0");
00245        
00246        //Get all our units strings
00247        QString trStrPT=unitGetStrFromIndex(SC_PT);
00248        QString trStrMM=unitGetStrFromIndex(SC_MM);
00249        QString trStrIN=unitGetStrFromIndex(SC_IN);
00250        QString trStrP =unitGetStrFromIndex(SC_P);
00251        QString trStrCM=unitGetStrFromIndex(SC_CM);
00252        QString trStrC =unitGetStrFromIndex(SC_C);
00253        QString strPT=unitGetUntranslatedStrFromIndex(SC_PT);
00254        QString strMM=unitGetUntranslatedStrFromIndex(SC_MM);
00255        QString strIN=unitGetUntranslatedStrFromIndex(SC_IN);
00256        QString strP =unitGetUntranslatedStrFromIndex(SC_P);
00257        QString strCM=unitGetUntranslatedStrFromIndex(SC_CM);
00258        QString strC =unitGetUntranslatedStrFromIndex(SC_C);
00259        //CB FParser doesn't handle unicode well/at all.
00260        //So, instead of just getting the translated strings and
00261        //sticking them in as variables in the parser, if they are
00262        //not the same as the untranslated version, then we replace them.
00263        //We lose the ability for now to have some strings in languages 
00264        //that might use them in variables.
00265        //To return to previous functionality, remove the follow replacement ifs,
00266        //S&R in the trStr* assignments trStrPT->strPT and remove the current str* ones. 
00267        //IE, send the translated strings through to the regexp.
00268        if (trStrPT.localeAwareCompare(strPT)!=0)
00269               ts.replace(trStrPT, strPT);
00270        if (trStrMM.localeAwareCompare(strMM)!=0)
00271               ts.replace(trStrMM, strMM);
00272        if (trStrIN.localeAwareCompare(strIN)!=0)
00273               ts.replace(trStrIN, strIN);
00274        if (trStrP.localeAwareCompare(strP)!=0)
00275               ts.replace(trStrP, strP);
00276        if (trStrCM.localeAwareCompare(strCM)!=0)
00277               ts.replace(trStrCM, strCM);
00278        if (trStrC.localeAwareCompare(strC)!=0)
00279               ts.replace(trStrC, strC);
00280        //Replace in our typed text all of the units strings with *unitstring
00281        QRegExp rx("\\b(\\d+)\\s*("+strPT+"|"+strP+"|"+strMM+"|"+strC+"|"+strCM+"|"+strIN+")\\b");
00282        pos = 0;
00283        while (pos >= 0) {
00284               pos = rx.search(ts, pos);
00285               if (pos >= 0) {
00286                      QString replacement = rx.cap(1) + "*" + rx.cap(2);
00287                      ts.replace(pos, rx.cap(0).length(), replacement);
00288               }
00289        }
00290        //Get the index of our suffix
00291        int toConvertToIndex=unitIndexFromString(su);
00292        //Add in the fparser constants using our unit strings, and the conversion factors.
00293        fp.AddConstant(strPT.local8Bit().data(), value2value(1.0, SC_PT, toConvertToIndex));
00294        fp.AddConstant(strMM.local8Bit().data(), value2value(1.0, SC_MM, toConvertToIndex));
00295        fp.AddConstant(strIN.local8Bit().data(), value2value(1.0, SC_IN, toConvertToIndex));
00296        fp.AddConstant(strP.local8Bit().data(), value2value(1.0, SC_P, toConvertToIndex));
00297        fp.AddConstant(strCM.local8Bit().data(), value2value(1.0, SC_CM, toConvertToIndex));
00298        fp.AddConstant(strC.local8Bit().data(), value2value(1.0, SC_C, toConvertToIndex));
00299        int ret = fp.Parse(ts.latin1(), "", true);
00300        if (ret >= 0)
00301               return 0;
00302        double erg = fp.Eval(NULL);
00303        return qRound(erg*Decimals);
00304 }
00305 
00306 void MSpinBox::textChanged()
00307 {
00308        edited = true;
00309 }
00310 
00311 void MSpinBox::stepDown()
00312 {
00313        if ((wrapping()) &&  (QSpinBox::value()-lineStep() < QSpinBox::minValue()) )
00314        {
00315               if ( edited )
00316                      QSpinBox::interpretText();
00317               QSpinBox::setValue( QSpinBox::maxValue() - (QSpinBox::maxValue() % lineStep()));
00318        }
00319        else
00320               QSpinBox::stepDown();
00321 }
00322 
00323 void MSpinBox::setValues(double min, double max, int deci, double val)
00324 {
00325        setDecimals(deci);
00326        setMinValue(min);
00327        setMaxValue(max);
00328        setValue(val);
00329        edited = false;
00330 }
00331 
00332 void MSpinBox::getValues(double *min, double *max, int *deci, double *val)
00333 {
00334        *deci = Decimals;
00335        *min = static_cast<double>(QSpinBox::minValue()) / Decimals;
00336        *max = static_cast<double>(QSpinBox::maxValue()) / Decimals;
00337        *val = static_cast<double>(QSpinBox::value()) / Decimals;
00338 }
00339 
00340 void MSpinBox::setDecimals(int deci)
00341 {
00342        Decimals = deci;
00343        QSpinBox::setLineStep(Decimals);
00344        currLineStep = Decimals;
00345        if (deci < 10)
00346               Width = 0;
00347        if ((deci > 9) && (deci < 100))
00348               Width = 1;
00349        if ((deci > 99) && (deci < 1000))
00350               Width = 2;
00351        if ((deci > 999) && (deci < 10000))
00352               Width = 3;
00353        if (deci > 9999)
00354               Width = 4;
00355 }
00356 
00357 void MSpinBox::setMaxValue(double val)
00358 {
00359        QSpinBox::setMaxValue(qRound(val*Decimals));
00360 }
00361 
00362 void MSpinBox::setMinValue(double val)
00363 {
00364        QSpinBox::setMinValue(qRound(val*Decimals));
00365 }
00366 
00367 void MSpinBox::setValue(double val)
00368 {
00369        QSpinBox::setValue(qRound(val*Decimals));
00370        edited = false;
00371 }
00372 
00373 void MSpinBox::setLineStepM(int val)
00374 {
00375        QSpinBox::setLineStep( val * Decimals );
00376        currLineStep = val * Decimals;
00377 }
00378 
00379 double MSpinBox::value()
00380 {
00381        return static_cast<double>(QSpinBox::value()) / Decimals;
00382 }
00383 
00384 double MSpinBox::minValue()
00385 {
00386        return static_cast<double>(QSpinBox::minValue()) / Decimals;
00387 }
00388 
00389 double MSpinBox::maxValue()
00390 {
00391        return static_cast<double>(QSpinBox::maxValue()) / Decimals;
00392 }
00393 
00394 void MSpinBox::setReadOnly( bool ro )
00395 {
00396        if (readOnly!=ro) 
00397        {
00398               if (!readOnly && ro) {
00399                      oldLineStep=QSpinBox::lineStep();
00400                      QSpinBox::setLineStep( 0 );
00401               }
00402               else if (readOnly && !ro) {
00403                      QSpinBox::setLineStep( oldLineStep );
00404                      oldLineStep=0;
00405               }
00406               ed->setReadOnly( ro );
00407               readOnly=ro;
00408        }
00409 }
00410 
00411 bool MSpinBox::isReadOnly() const
00412 {
00413        return readOnly;
00414 }
00415 
00416 void MSpinBox::setNewUnit(double oldUnitRatio, double newUnitRatio, int unitIndex)
00417 {
00418        double oldVal = value() / oldUnitRatio;
00419        double oldMax = maxValue() / oldUnitRatio;
00420        double oldMin = minValue() / oldUnitRatio;
00421        setSuffix(unitGetSuffixFromIndex(unitIndex));
00422        setDecimals(unitGetDecimalsFromIndex(unitIndex));
00423        setMinValue(oldMin * newUnitRatio);
00424        setMaxValue(oldMax * newUnitRatio);
00425        setValue(oldVal * newUnitRatio);
00426 }
00427 
00428 void MSpinBox::setConstants(const QMap<QString, double>& newConstants)
00429 {
00430        functionParserConstants=newConstants;
00431 }
00432 
00433 void MSpinBox::setFPConstants(FunctionParser &fp)
00434 {
00435        if (functionParserConstants.isEmpty())
00436               return;
00437               
00438        fp.AddConstant("old", static_cast<double>(QSpinBox::value()) / Decimals);
00439        QMap<QString, double>::Iterator itend=functionParserConstants.end();
00440        QMap<QString, double>::Iterator it=functionParserConstants.begin();
00441        while(it!=itend)
00442        {
00443               fp.AddConstant(it.key().local8Bit().data(), it.data());
00444               ++it;
00445        }
00446 }