kplato

kptdurationwidget.ui.h

00001 //
00002 // ui.h extension file, included from the uic-generated form implementation.
00003 //
00004 // If you wish to add, delete or rename functions or slots use
00005 // Qt Designer which will update this file, preserving your code. Create an
00006 // init() function in place of a constructor, and a destroy() function in
00007 // place of a destructor.
00008 //
00009 
00010 /* This file is part of the KDE project
00011    Copyright (C) 2004 - 2006 Dag Andersen <danders@get2net.dk>
00012 
00013    This library is free software; you can redistribute it and/or
00014    modify it under the terms of the GNU Library General Public
00015    License as published by the Free Software Foundation;
00016    version 2 of the License.
00017 
00018    This library is distributed in the hope that it will be useful,
00019    but WITHOUT ANY WARRANTY; without even the implied warranty of
00020    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021    Library General Public License for more details.
00022 
00023    You should have received a copy of the GNU Library General Public License
00024    along with this library; see the file COPYING.LIB.  If not, write to
00025    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00026  * Boston, MA 02110-1301, USA.
00027 */
00028 
00029 #include <kdebug.h>
00030 #include <kglobal.h>
00031 #include <klocale.h>
00032 
00033 #include <cmath>
00034 
00035 namespace KPlato
00036 {
00037 
00041 struct FieldDescriptor
00042 {
00043     // Which field is to my left, and what conversion factor separates us?
00044     QLineEdit *left;
00045     double leftScale;
00046     
00047     // Which field am I, and how am I formatted?
00048     QLineEdit *current;
00049     const char *format;
00050     
00051     // Which field is to my right, and what conversion factor separates us?
00052     QLineEdit *right;
00053     double rightScale;
00054     
00055     // If I am hidden, who else hides with me?
00056     QLabel *separator;
00057     
00058     // Used for calculating a correct duration
00059     double fullScale;
00060     double scale;
00061     
00062     // Used for displaying a unit behind each field
00063     QLabel *unit;
00064 };
00065 
00066 #define setField(f, l, ls, c, fmt, r, rs, s, fs, sc, u) \
00067 do \
00068 { \
00069     m_fields[f].left = l; \
00070     m_fields[f].leftScale = ls; \
00071     m_fields[f].current = c; \
00072     m_fields[f].format = fmt; \
00073     m_fields[f].right = r; \
00074     m_fields[f].rightScale = rs; \
00075     m_fields[f].separator = s; \
00076     m_fields[f].fullScale = fs; \
00077     m_fields[f].scale = sc; \
00078     m_fields[f].unit = u; \
00079 } while (0)
00080     
00081 void DurationWidget::init()
00082 {
00083     // Use the user's decimal point!
00084     m_decimalPoint = KGlobal::locale()->decimalSymbol();
00085     
00086     //NOTE: 
00087     //      This isn't as flexible/general as Shaheed once made it.
00088     //      It's now a long list of hacks.
00089     //      Introducing double in scales and allowing leftscale/scale/rightscale
00090     //      *NOT* to be multiples of each other increases the complexity and also
00091     //      introduces rounding errors. (eg. hour = 60 minutes, day = 7,5 hours)
00092     //
00093     //      If you know how, please make a better solution!
00094     //
00095     // Any field can be entered as an integer or a floating point value. Whatever
00096     // is entered is treated as follows:
00097     //
00098     //    - any fractional part is moved right one field
00099     //
00100     //    - any overflow from the integer part is carried left one field
00101     //
00102     // and the process repeated until the rightmost and leftmost fields are reached.
00103     QRegExp re(QString("\\d{1,10}|\\d{1,7}\\") + m_decimalPoint + 
00104         QString("\\d{0,10}|\\d{0,7}\\") + m_decimalPoint + 
00105         QString("\\d{1,3}"));
00106     m_validator = new QRegExpValidator(re, this);
00107     m_ddd->setValidator(m_validator);
00108     m_hh->setValidator(m_validator);
00109     m_mm->setValidator(m_validator);
00110     m_ss->setValidator(m_validator);
00111     m_ms->setValidator(m_validator);
00112     
00113     m_ddUnit->hide();
00114     m_hhUnit->hide();
00115     m_mmUnit->hide();
00116     m_ssUnit->hide();
00117     m_msUnit->hide();
00118     
00119     m_fields = new FieldDescriptor[5];    
00120     setField(0, NULL, 0, m_ddd, "%u", m_hh, 24, m_hhSpace, 24, 24, m_ddUnit);
00121     setField(1, m_ddd, 24, m_hh, "%02u", m_mm, 60, m_mmColon, 60, 60, m_hhUnit);
00122     setField(2, m_hh, 60, m_mm, "%02u", m_ss, 60, NULL, 60, 60, m_mmUnit);
00123     setField(3, m_mm, 60, m_ss, "%02u", m_ms, 1000, m_ssColon, 60, 60, m_ssUnit);
00124     setField(4, m_ss, 1000, m_ms, "%03u", NULL, 0, m_dot, 1000, 1000, m_msUnit);
00125 }
00126 
00127 void DurationWidget::destroy()
00128 {
00129     delete m_fields;
00130     //delete m_validator;  //QWidget takes care of this
00131 }
00132 
00133 Q_INT64 DurationWidget::setValueMilliseconds(Q_INT64 milliseconds)
00134 {
00135     unsigned sc = (unsigned)m_fields[4].leftScale;
00136     Q_INT64 secs = milliseconds / sc;
00137     Q_INT64 ms = milliseconds % sc;
00138     QString tmp;
00139     tmp.sprintf(m_fields[4].format, ms);
00140     m_fields[4].current->setText(tmp);
00141     return secs;
00142 }
00143 
00144 Q_INT64 DurationWidget::setValueSeconds(Q_INT64 seconds)
00145 {
00146     unsigned sc = (unsigned)m_fields[3].leftScale;
00147     Q_INT64 mins = seconds / sc;
00148     Q_INT64 s = seconds % sc;
00149     QString tmp;
00150     tmp.sprintf(m_fields[3].format, s);
00151     m_fields[3].current->setText(tmp);
00152     return mins;
00153 }
00154 
00155 Q_INT64 DurationWidget::setValueMinutes(Q_INT64 mins)
00156 {
00157     unsigned sc = (unsigned)m_fields[2].leftScale;
00158     Q_INT64 hours = mins / sc;
00159     Q_INT64 m = mins % sc;
00160     QString tmp;
00161     tmp.sprintf(m_fields[2].format, m);
00162     m_fields[2].current->setText(tmp);
00163     return hours;
00164 }
00165 
00166 // NOTE: Input is minutes and also returns minutes!
00167 Q_INT64 DurationWidget::setValueHours(Q_INT64 mins)
00168 {
00169     if (m_fields[1].current->isHidden())
00170         return mins;
00171     unsigned sc = (unsigned)m_fields[1].rightScale;
00172     Q_INT64 hours = (Q_INT64)(mins / sc);
00173     Q_INT64 m = mins - (Q_INT64)(hours * sc);
00174     //kdDebug()<<k_funcinfo<<"mins="<<mins<<" -> hours="<<hours<<" rem="<<m<<endl;
00175     QString tmp;
00176     tmp.sprintf(m_fields[1].format, hours);
00177     m_fields[1].current->setText(tmp);
00178     return m;
00179 }
00180 
00181 // NOTE: Input is minutes and also returns minutes!
00182 Q_INT64 DurationWidget::setValueDays(Q_INT64 mins)
00183 {
00184     if (m_fields[0].current->isHidden())
00185         return mins;
00186     double sc = m_fields[1].rightScale * m_fields[0].rightScale;
00187     Q_INT64 days = (Q_INT64)(mins / sc);
00188     Q_INT64 m = mins - (Q_INT64)(days * sc);
00189     //kdDebug()<<k_funcinfo<<"mins="<<mins<<" -> days="<<days<<" rem="<<m<<endl;
00190     QString tmp;
00191     tmp.sprintf(m_fields[0].format, days);
00192     m_fields[0].current->setText(tmp);
00193     return m;
00194 }
00195 
00196 void DurationWidget::setValue(const KPlato::Duration &newDuration)
00197 {
00198     Q_INT64 value = newDuration.milliseconds();
00199     //kdDebug()<<k_funcinfo<<f<<": value="<<value<<endl;
00200     value = setValueMilliseconds(value); // returns seconds
00201     value = setValueSeconds(value); // returns minutes
00202     // Now call days first to allow for fractional scales
00203     value = setValueDays(value); // NOTE  returns minutes
00204     value = setValueHours(value); // NOTE  returns minutes
00205     value = setValueMinutes(value); // returns hours: Should be 0
00206     if (value > 0) kdError()<<k_funcinfo<<"Remainder > 0: "<<value<<endl;
00207     
00208     emit valueChanged();
00209 }
00210 
00211 Duration DurationWidget::value() const
00212 {
00213     Duration d;
00214     int i=0;
00215     if (!m_fields[i].current->isHidden() &&
00216         m_fields[i].scale > 0 &&
00217         m_fields[i].scale <= m_fields[i].fullScale)
00218     {
00219         double v = m_fields[i].current->text().toDouble();
00220         v = v * m_fields[i].scale / m_fields[i].fullScale;;
00221         d.addMilliseconds((Q_INT64)(v*(1000*60*60*24)));
00222     }
00223     ++i;
00224     if (!m_fields[i].current->isHidden() &&
00225         m_fields[i].scale > 0 &&
00226         m_fields[i].scale <= m_fields[i].fullScale)
00227     {
00228         double v = m_fields[i].current->text().toDouble();
00229         v = v * m_fields[i].scale / m_fields[i].fullScale;;
00230         d.addMilliseconds((Q_INT64)(v*(1000*60*60)));
00231     }
00232     ++i;
00233     if (!m_fields[i].current->isHidden() &&
00234         m_fields[i].scale > 0 &&
00235         m_fields[i].scale <= m_fields[i].fullScale)
00236     {
00237         double v = m_fields[i].current->text().toDouble();
00238         v = v * m_fields[i].scale / m_fields[i].fullScale;;
00239         d.addMilliseconds((Q_INT64)(v*(1000*60)));
00240     }
00241     ++i;
00242     if (!m_fields[i].current->isHidden() &&
00243         m_fields[i].scale > 0 &&
00244         m_fields[i].scale <= m_fields[i].fullScale)
00245     {
00246         double v = m_fields[i].current->text().toDouble();
00247         v = v * m_fields[i].scale / m_fields[i].fullScale;;
00248         d.addMilliseconds((Q_INT64)(v*(1000)));
00249     }
00250     ++i;
00251     if (!m_fields[i].current->isHidden())
00252     {
00253         Q_INT64 v = m_fields[i].current->text().toUInt();
00254         d.addMilliseconds(v);
00255     }
00256     return d;
00257 }
00258 
00259 void DurationWidget::dddLostFocus()
00260 {
00261     handleLostFocus(0);
00262     emit valueChanged();
00263 }
00264 
00265 void DurationWidget::hhLostFocus( )
00266 {
00267     handleLostFocus(1);
00268     emit valueChanged();
00269 }
00270 
00271 void DurationWidget::mmLostFocus()
00272 {
00273     handleLostFocus(2);
00274     emit valueChanged();
00275 }
00276 
00277 void DurationWidget::ssLostFocus()
00278 {
00279     handleLostFocus(3);
00280     emit valueChanged();
00281 }
00282 
00283 void DurationWidget::msLostFocus()
00284 {
00285     handleLostFocus(4);
00286     emit valueChanged();
00287 }
00288 
00289 void DurationWidget::handleLostFocus(
00290     int field)
00291 {
00292     // Get our own info, and that of our left and right neighbours.
00293     QLineEdit *left = m_fields[field].left;
00294     double leftScale = m_fields[field].leftScale; 
00295     const char *leftFormat = left ? m_fields[field - 1].format : NULL; 
00296     QLineEdit *current = m_fields[field].current; 
00297     const char *currentFormat = m_fields[field].format;
00298     QLineEdit *right = m_fields[field].right;
00299     double rightScale = m_fields[field].rightScale; 
00300     const char *rightFormat = right ? m_fields[field + 1].format : NULL;
00301     
00302     // avoid possible crash
00303     if (leftScale == 0)
00304         leftScale = 1;
00305         
00306     // Get the text and start processing...
00307     QString newValue(current->text());
00308     double v = KGlobal::locale()->readNumber(newValue);
00309     unsigned currentValue = 0;
00310     QString tmp;
00311     //kdDebug()<<k_funcinfo<<field<<": value="<<v<<" v="<<v<<endl;
00312     if (left && v >= leftScale)
00313     {
00314         //kdDebug()<<k_funcinfo<<field<<": value="<<v<<" leftScale="<<leftScale<<endl;
00315         // Carry overflow, recurse as required.
00316         tmp.sprintf(leftFormat, (unsigned)(v / leftScale));
00317         left->setText(tmp);
00318         handleLostFocus(field - 1);
00319 
00320         // Get remainder.
00321         v = v - (tmp.toUInt() * leftScale);
00322         newValue = KGlobal::locale()->formatNumber(v);
00323     }
00324     int point = newValue.find(m_decimalPoint);
00325     if (point != -1)
00326     {
00327         //HACK doubles may be rounded(at fractions > 6 digits on my system)
00328         int p;
00329         double frac = fraction(newValue, &p);
00330         if (right && frac > 0.0)
00331         {
00332             //kdDebug()<<k_funcinfo<<field<<": value="<<newValue<<" rightScale="<<rightScale<<" frac="<<frac<<" ("<<newValue.mid(point)<<")"<<endl;
00333             // Propagate fraction
00334             v = rightScale * (frac*power(10.0, -p));
00335             frac = fraction(KGlobal::locale()->formatNumber(v, 19), 0);
00336             //kdDebug()<<k_funcinfo<<field<<": v="<<v<<" ("<<(unsigned)v<<") rest="<<frac<<endl;
00337             if (frac > 0.0)
00338             {
00339                 tmp = KGlobal::locale()->formatNumber(v, 19);
00340                 right->setText(tmp);
00341                 handleLostFocus(field + 1);
00342             } else {
00343                 tmp.sprintf(rightFormat, (unsigned)(v));
00344                 right->setText(tmp);
00345             }
00346             
00347         }
00348         // TODO keep fraction for last shown field
00349         newValue = newValue.left(point);
00350     }
00351     currentValue = newValue.toUInt();
00352     tmp.sprintf(currentFormat, currentValue);
00353     current->setText(tmp);
00354 }
00355 
00356 // Set which fields are visible.
00357 void DurationWidget::setVisibleFields( int fieldMask )
00358 {
00359     int i;
00360     for (i = 0; i < 5; i++)
00361     {
00362         bool visible = ((fieldMask >> i) & 1) == 1;
00363         
00364         // Set the visibility of the fields, and of any associated separator.
00365         if (visible)
00366         {
00367             m_fields[i].current->show();
00368             if (m_fields[i].separator)
00369             {
00370                 m_fields[i].separator->show();
00371             }
00372             if (m_fields[i].unit)
00373             {
00374                 m_fields[i].unit->show();
00375      }
00376         }
00377         else
00378         {
00379             m_fields[i].current->hide();
00380             if (m_fields[i].separator)
00381             {
00382                 m_fields[i].separator->hide();
00383             }
00384             if (m_fields[i].unit)
00385             {
00386                 m_fields[i].unit->hide();
00387      }
00388         }
00389     }
00390 }
00391 
00392 // Retreive the visible fields.
00393 int DurationWidget::visibleFields()
00394 {
00395     int i;
00396     int fieldMask = 0;
00397     for (i = 0; i < 5; i++)
00398     {
00399         if (m_fields[i].current->isHidden())
00400         {   
00401             fieldMask |= (1 << i);
00402         }
00403     }
00404     return fieldMask;
00405 }
00406 
00407 void DurationWidget::setFieldLeftscale(int f, double ls)
00408 {
00409     m_fields[f].leftScale = ls;
00410 }
00411 
00412 void DurationWidget::setFieldRightscale(int f, double rs)
00413 {
00414     m_fields[f].rightScale = rs;
00415 }
00416 
00417 void DurationWidget::setFieldScale(int f, double scale)
00418 {
00419     m_fields[f].scale = scale;
00420 }
00421 
00422 void DurationWidget::setFieldUnit(int f, QString unit)
00423 {
00424     if (m_fields[f].unit)
00425     {
00426  m_fields[f].unit->setText(unit);
00427     }
00428 }
00429 
00430 double DurationWidget::power(double m, int e) {
00431     int c = e > 0 ? e : -e;
00432     double value = 1;
00433     for (int i=0; i < c; ++i) {
00434         value = e > 0 ? value * m : value / m;
00435     }
00436     return value;
00437 }
00438 
00439 double DurationWidget::fraction(QString number, int *exp) {
00440     int point = number.find(m_decimalPoint);
00441     if (point == -1) {
00442         return 0.0;
00443     }
00444     QString v;
00445     if (exp) {
00446         v = number.mid(point+m_decimalPoint.length());
00447         *exp = v.length();
00448         
00449     } else {
00450          v = number.mid(point);
00451     }
00452     return KGlobal::locale()->readNumber(v);
00453 }
00454 
00455 }  //KPlato namespace
KDE Home | KDE Accessibility Home | Description of Access Keys