1 /***************************************************************************
2  *   file klfunitinput.cpp
3  *   This file is part of the KLatexFormula Project.
4  *   Copyright (C) 2011 by Philippe Faist
5  *   philippe.faist at bluewin.ch
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU General Public License as published by  *
9  *   the Free Software Foundation; either version 2 of the License, or     *
10  *   (at your option) any later version.                                   *
11  *                                                                         *
12  *   This program is distributed in the hope that it will be useful,       *
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15  *   GNU General Public License for more details.                          *
16  *                                                                         *
17  *   You should have received a copy of the GNU General Public License     *
18  *   along with this program; if not, write to the                         *
19  *   Free Software Foundation, Inc.,                                       *
20  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
21  ***************************************************************************/
22 /* $Id: klfunitinput.cpp 604 2011-02-27 23:34:37Z phfaist $ */
23 
24 #include <math.h>
25 
26 #include <QDebug>
27 #include <QVariant>
28 #include <QStringList>
29 #include <QComboBox>
30 #include <QDoubleSpinBox>
31 #include <QEvent>
32 
33 #include "klfunitinput.h"
34 
35 
KLFUnitChooser(QWidget * parent)36 KLFUnitChooser::KLFUnitChooser(QWidget *parent)
37   : QComboBox(parent)
38 {
39   connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(internalCurrentIndexChanged(int)));
40 }
~KLFUnitChooser()41 KLFUnitChooser::~KLFUnitChooser()
42 {
43 }
44 
setUnits(const QString & unitstr)45 void KLFUnitChooser::setUnits(const QString& unitstr)
46 {
47   QStringList unitstrlist = unitstr.split(';');
48   QList<Unit> units;
49   int k;
50   for (k = 0; k < unitstrlist.size(); ++k) {
51     QStringList parts = unitstrlist[k].split('=');
52     if (parts.size() != 3) {
53       qWarning()<<KLF_FUNC_NAME<<": Invalid unit specification: "<<unitstrlist[k];
54       continue;
55     }
56     Unit u;
57     u.name = parts[0];
58     u.abbrev = parts[1];
59     u.factor = parts[2].toDouble();
60     units << u;
61   }
62   setUnits(units);
63 }
64 
setUnits(const QList<Unit> & unitlist)65 void KLFUnitChooser::setUnits(const QList<Unit>& unitlist)
66 {
67   clear(); // clear combo box
68   pUnits = unitlist;
69   int k;
70   for (k = 0; k < pUnits.size(); ++k) {
71     Unit u = pUnits[k];
72     // add this cbx item
73     addItem(u.name, QVariant::fromValue<Unit>(u));
74   }
75 }
76 
unitStringDescription() const77 QString KLFUnitChooser::unitStringDescription() const
78 {
79   QStringList l;
80   int k;
81   for (k = 0; k < pUnits.size(); ++k)
82     l << QString("%2=%3=%1").arg(pUnits[k].factor, 0, 'g').arg(pUnits[k].name, pUnits[k].abbrev);
83   return l.join(";");
84 }
85 
setCurrentUnit(const QString & unitname)86 void KLFUnitChooser::setCurrentUnit(const QString& unitname)
87 {
88   int k;
89   for (k = 0; k < count(); ++k) {
90     if (itemData(k).value<Unit>().name == unitname) {
91       setCurrentUnitIndex(k);
92       return;
93     }
94   }
95   qWarning()<<KLF_FUNC_NAME<<": unit "<<unitname<<" not found.";
96 }
setCurrentUnitAbbrev(const QString & unitAbbrev)97 void KLFUnitChooser::setCurrentUnitAbbrev(const QString& unitAbbrev)
98 {
99   int k;
100   for (k = 0; k < count(); ++k) {
101     if (itemData(k).value<Unit>().abbrev == unitAbbrev) {
102       setCurrentUnitIndex(k);
103       return;
104     }
105   }
106   qWarning()<<KLF_FUNC_NAME<<": unit abbrev. "<<unitAbbrev<<" not found.";
107 }
108 
109 // private
setCurrentUnitIndex(int k)110 void KLFUnitChooser::setCurrentUnitIndex(int k)
111 {
112   if (isEnabled()) {
113     setCurrentIndex(k);
114   } else {
115     pDelayedUnitSet = pUnits[k].name;
116     emit unitChanged(pUnits[k].name);
117     emit unitChanged(pUnits[k].factor);
118     emit unitChanged(pUnits[k].factor, pUnits[k].abbrev);
119   }
120 }
121 
changeEvent(QEvent * event)122 void KLFUnitChooser::changeEvent(QEvent *event)
123 {
124   if (event->type() == QEvent::EnabledChange) {
125     if (isEnabled() && !pDelayedUnitSet.isEmpty()) {
126       setCurrentUnit(pDelayedUnitSet);
127       pDelayedUnitSet = QString();
128     }
129   }
130   QComboBox::changeEvent(event);
131 }
132 
133 
internalCurrentIndexChanged(int index)134 void KLFUnitChooser::internalCurrentIndexChanged(int index)
135 {
136   if (index < 0 || index >= count())
137     return;
138 
139   Unit u = itemData(index).value<Unit>();
140   klfDbg("New unit selected : #"<<index<<" = "<<u.name) ;
141   emit unitChanged(u.name);
142   emit unitChanged(u.factor);
143   emit unitChanged(u.factor, u.abbrev);
144 }
145 
146 
147 // -------------------------
148 
149 
KLFUnitSpinBox(QWidget * parent)150 KLFUnitSpinBox::KLFUnitSpinBox(QWidget *parent)
151   : QDoubleSpinBox(parent)
152 {
153   pUnitFactor = 1.0f;
154   pShowUnitSuffix = true;
155   connect(this, SIGNAL(valueChanged(double)), this, SLOT(internalValueChanged(double)));
156 }
~KLFUnitSpinBox()157 KLFUnitSpinBox::~KLFUnitSpinBox()
158 {
159 }
160 
setUnit(double unitfactor)161 void KLFUnitSpinBox::setUnit(double unitfactor)
162 {
163   double curValue = value();
164   double curMinimum = minimum();
165   double curMaximum = maximum();
166   double curUnitFactor = pUnitFactor;
167   int curPrecision = decimals();
168 
169   klfDbg("unitfactor="<<unitfactor<<" cur: val="<<curValue<<",min="<<curMinimum<<",max="<<curMaximum
170 	 <<",prec="<<curPrecision) ;
171 
172   pUnitFactor = unitfactor;
173 
174   // calculate the right number of decimal places.
175   // due to round-off errors, we need to first determine how many decimals we started
176   // off with, then re-calculate the number of decimals.
177   int unitRefDecimals = curPrecision - (int)( log((double)curUnitFactor)/log((double)10.0)  + 0.5 );
178 
179   setDecimals(unitRefDecimals + (int)( log((double)pUnitFactor)/log((double)10.0) + 0.5 ) );
180 
181   // set the appropriate range
182   setMinimum(curMinimum * curUnitFactor / pUnitFactor);
183   setMaximum(curMaximum * curUnitFactor / pUnitFactor);
184 
185   // and set the value
186   setValue(curValue * curUnitFactor / pUnitFactor);
187 }
188 
setUnitWithSuffix(double unitfactor,const QString & suffix)189 void KLFUnitSpinBox::setUnitWithSuffix(double unitfactor, const QString& suffix)
190 {
191   setUnit(unitfactor);
192   if (pShowUnitSuffix)
193     setSuffix("  "+suffix);
194 }
195 
setValueInRefUnit(double value)196 void KLFUnitSpinBox::setValueInRefUnit(double value)
197 {
198   setValue(value / pUnitFactor);
199 }
200 
setShowUnitSuffix(bool show)201 void KLFUnitSpinBox::setShowUnitSuffix(bool show)
202 {
203   pShowUnitSuffix = show;
204 }
205 
206 
internalValueChanged(double valueInExtUnits)207 void KLFUnitSpinBox::internalValueChanged(double valueInExtUnits)
208 {
209   klfDbg("val in ext. units="<<valueInExtUnits<<"; our unitfactor="<<pUnitFactor) ;
210   emit valueInRefUnitChanged(valueInExtUnits / pUnitFactor);
211 }
212 
213 
214 
215 
216