• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • kdeutils
  • Sitemap
  • Contact Us
 

kcalc

kcalcdisplay.cpp

Go to the documentation of this file.
00001 /*
00002     $Id: kcalcdisplay.cpp 701796 2007-08-19 10:51:37Z amth $
00003 
00004     KCalc, a scientific calculator for the X window system using the
00005     Qt widget libraries, available at no cost at http://www.troll.no
00006     
00007     Copyright (C) 1996 Bernd Johannes Wuebben   
00008                        wuebben@math.cornell.edu
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019 
00020     You should have received a copy of the GNU General Public License
00021     along with this program; if not, write to the Free Software
00022     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023 
00024 */
00025 
00026 #include <errno.h>
00027 #include <stdlib.h>
00028 #include <ctype.h>
00029 
00030 #include <QClipboard>
00031 #include <QMouseEvent>
00032 #include <QPainter>
00033 
00034 #include <kglobal.h>
00035 #include <klocale.h>
00036 #include <knotification.h>
00037 #include "kcalc_settings.h"
00038 #include "kcalcdisplay.h"
00039 #include "kcalcdisplay.moc"
00040 
00041 KCalcDisplay::KCalcDisplay(QWidget *parent)
00042   :QLabel(parent), _beep(false), _groupdigits(false), _button(0), _lit(false),
00043    _num_base(NB_DECIMAL), _precision(9),
00044    _fixed_precision(-1), _display_amount(0),
00045    selection_timer(new QTimer)
00046 {
00047     setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
00048     setAlignment(Qt::AlignRight | Qt::AlignVCenter);
00049     setFocus();
00050     setFocusPolicy(Qt::StrongFocus);
00051 
00052     QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed);
00053     sp.setHeightForWidth(false);
00054     setSizePolicy(sp);
00055 
00056     connect(this, SIGNAL(clicked()), this, SLOT(slotDisplaySelected()));
00057 
00058     connect(selection_timer, SIGNAL(timeout()),
00059         this, SLOT(slotSelectionTimedOut()));
00060 
00061     sendEvent(EventReset);
00062 }
00063 
00064 KCalcDisplay::~KCalcDisplay()
00065 {
00066     delete selection_timer;
00067 }
00068 
00069 bool KCalcDisplay::sendEvent(Event const event)
00070 {
00071     switch(event)
00072     {
00073     case EventReset:
00074         _display_amount = 0;
00075         _str_int = "0";
00076         _str_int_exp.clear();
00077 
00078         _eestate = false;
00079         _period = false;
00080         _neg_sign = false;
00081 
00082         updateDisplay();
00083 
00084         return true;
00085     case EventClear:
00086         return sendEvent(EventReset);
00087     case EventChangeSign:
00088         return changeSign();
00089     case EventError:
00090         updateDisplay();
00091 
00092         return true;
00093     default:
00094         return false;
00095     }
00096 }
00097 
00098 
00099 void KCalcDisplay::slotCut(void)
00100 {
00101     slotCopy();
00102     sendEvent(EventReset);
00103 }
00104 
00105 void KCalcDisplay::slotCopy(void)
00106 {
00107     QString txt;
00108     if (_num_base != NB_DECIMAL)
00109         txt = QLabel::text();
00110     else
00111         txt = _display_amount.toQString();
00112     if (_num_base == NB_HEX)
00113         txt.prepend( "0x" );
00114     (QApplication::clipboard())->setText(txt, QClipboard::Clipboard);
00115     (QApplication::clipboard())->setText(txt, QClipboard::Selection);
00116 }
00117 
00118 void KCalcDisplay::slotPaste(bool bClipboard)
00119 {
00120     QString tmp_str = (QApplication::clipboard())->text(bClipboard ? QClipboard::Clipboard : QClipboard::Selection);
00121 
00122     if (tmp_str.isNull())
00123     {
00124         if (_beep)  KNotification::beep();
00125         return;
00126     }
00127 
00128     NumBase tmp_num_base = _num_base;
00129 
00130     tmp_str = tmp_str.trimmed();
00131 
00132     if (tmp_str.startsWith("0x", Qt::CaseInsensitive)) tmp_num_base = NB_HEX;
00133 
00134     if (tmp_num_base != NB_DECIMAL)
00135     {
00136         bool was_ok;
00137         quint64 tmp_result = tmp_str.toULongLong(& was_ok, tmp_num_base);
00138 
00139         if (!was_ok)
00140         {
00141             setAmount(KNumber::NotDefined);
00142             if(_beep) KNotification::beep();
00143             return ;
00144         }
00145       
00146         setAmount(KNumber(tmp_result));
00147     } 
00148     else // _num_base == NB_DECIMAL && ! 
00149          // tmp_str.startsWith("0x",Qt::CaseInsensitive)
00150     {
00151         setAmount(KNumber(tmp_str));
00152         if (_beep  &&  _display_amount == KNumber::NotDefined)
00153             KNotification::beep();
00154 
00155     }
00156 }
00157 
00158 void KCalcDisplay::slotDisplaySelected(void)
00159 {
00160     if(_button == Qt::LeftButton) {
00161         if(_lit) {
00162             slotCopy();
00163             selection_timer->start(100);
00164         } else {
00165             selection_timer->stop();
00166         }
00167 
00168         invertColors();
00169     } else {
00170         slotPaste(false); // Selection
00171     }
00172 }
00173 
00174 void KCalcDisplay::slotSelectionTimedOut(void)
00175 {
00176     _lit = false;
00177     invertColors();
00178     selection_timer->stop();
00179 }
00180 
00181 void KCalcDisplay::invertColors()
00182 {
00183     QPalette tmp_palette;
00184     tmp_palette.setColor(backgroundRole(),
00185             palette().color(QPalette::WindowText));
00186     tmp_palette.setColor(foregroundRole(),
00187             palette().color(QPalette::Background));
00188     setPalette(tmp_palette);
00189 }
00190 
00191 
00192 
00193 void KCalcDisplay::mousePressEvent(QMouseEvent *e)
00194 {
00195     if(e->button() == Qt::LeftButton) {
00196         _lit = !_lit;
00197         _button = Qt::LeftButton;
00198     } else {
00199         _button = Qt::MidButton;
00200     }
00201     
00202     emit clicked();
00203 }
00204 
00205 void KCalcDisplay::setPrecision(int precision)
00206 {
00207     _precision = precision;
00208 }
00209 
00210 void KCalcDisplay::setFixedPrecision(int precision)
00211 {
00212     if (_fixed_precision > _precision)
00213         _fixed_precision = -1;
00214     else
00215         _fixed_precision = precision;
00216 }
00217 
00218 void KCalcDisplay::setBeep(bool flag)
00219 {
00220     _beep = flag;
00221 }
00222 
00223 void KCalcDisplay::setGroupDigits(bool flag)
00224 {
00225     _groupdigits = flag;
00226 }
00227 
00228 KNumber const & KCalcDisplay::getAmount(void) const
00229 {
00230     return _display_amount;
00231 }
00232 
00233 bool KCalcDisplay::setAmount(KNumber const & new_amount)
00234 {
00235     QString display_str;
00236 
00237     _str_int = "0";
00238     _str_int_exp.clear();
00239     _period = false;
00240     _neg_sign = false;
00241     _eestate = false;
00242 
00243     if (_num_base != NB_DECIMAL  &&  new_amount.type() != KNumber::SpecialType)
00244     {
00245         _display_amount = new_amount.integerPart();
00246         quint64 tmp_workaround = static_cast<quint64>(_display_amount);
00247 
00248         display_str = QString::number(tmp_workaround, _num_base).toUpper();
00249     }
00250     else // _num_base == NB_DECIMAL || new_amount.type() ==
00251          // KNumber::SpecialType
00252     {
00253         _display_amount = new_amount;
00254     
00255         display_str = _display_amount.toQString(KCalcSettings::precision(), _fixed_precision);
00256 #if 0
00257         else if (_display_amount > 1.0e+16)
00258             display_str = QCString().sprintf(PRINT_LONG_BIG, _precision + 1, _display_amount);
00259         else
00260             display_str = QCString().sprintf(PRINT_LONG_BIG, _precision, _display_amount);
00261 #endif
00262     }
00263 
00264     setText(display_str);
00265     emit changedAmount(_display_amount);
00266     return true;
00267     
00268 }
00269 
00270 void KCalcDisplay::setText(QString const &string)
00271 {
00272     QString localizedString = string;
00273 
00274     // If we aren't in decimal mode, we don't need to modify the string
00275     if (_num_base == NB_DECIMAL  &&  _groupdigits)
00276       // when input ends with "." (because uncomplete), the
00277       // formatNumber-method does not work; fix by hand by
00278       // truncating, formatting and appending again
00279       if (string.endsWith('.')) {
00280         localizedString.truncate(localizedString.length() - 1);
00281         localizedString = KGlobal::locale()->formatNumber(localizedString, false, 0); // Note: rounding happened already above!
00282         localizedString.append(KGlobal::locale()->decimalSymbol());
00283       } else
00284       localizedString = KGlobal::locale()->formatNumber(string, false, 0); // Note: rounding happened already above!
00285 
00286     QLabel::setText(localizedString);
00287     emit changedText(localizedString);
00288 }
00289 
00290 QString KCalcDisplay::text() const
00291 {
00292     if (_num_base != NB_DECIMAL)
00293         return QLabel::text();
00294     QString display_str = _display_amount.toQString(KCalcSettings::precision());
00295 
00296     return display_str;
00297     //  return QCString().sprintf(PRINT_LONG_BIG, 40, _display_amount);
00298 }
00299 
00300 /* change representation of display to new base (i.e. binary, decimal,
00301    octal, hexadecimal). The amount being displayed is changed to this
00302    base, but for now this amount can not be modified anymore (like
00303    being set with "setAmount"). Return value is the new base. */
00304 int KCalcDisplay::setBase(NumBase new_base)
00305 {
00306     CALCAMNT tmp_val = static_cast<quint64>(getAmount());
00307 
00308     switch(new_base)
00309     {
00310     case NB_HEX:
00311         _num_base   = NB_HEX;
00312         _period     = false;
00313         break;
00314     case NB_DECIMAL:
00315         _num_base   = NB_DECIMAL;
00316         break;
00317     case NB_OCTAL:
00318         _num_base   = NB_OCTAL;
00319         _period     = false;
00320         break;
00321     case NB_BINARY:
00322         _num_base   = NB_BINARY;
00323         _period     = false;
00324         break;
00325     default: // we shouldn't ever end up here
00326         _num_base   = NB_DECIMAL;
00327     }
00328 
00329     setAmount(static_cast<quint64>(tmp_val));
00330     
00331     return _num_base;
00332 }
00333 
00334 void KCalcDisplay::setStatusText(int i, const QString& text)
00335 {
00336     if (i < NUM_STATUS_TEXT)
00337         _str_status[i] = text;
00338     update();
00339 }
00340 
00341 bool KCalcDisplay::updateDisplay(void)
00342 {
00343     // Put sign in front.
00344     QString tmp_string;
00345     if(_neg_sign == true)
00346         tmp_string = '-' + _str_int;
00347     else
00348         tmp_string = _str_int;
00349 
00350     switch(_num_base)
00351     {
00352     case NB_BINARY:
00353         Q_ASSERT(_period == false  && _eestate == false);
00354         setText(tmp_string);
00355         _display_amount = static_cast<quint64>(STRTOUL(_str_int.toLatin1(), 0, 2));
00356         if (_neg_sign)
00357             _display_amount = -_display_amount;
00358         //str_size = cvb(_str_int, boh_work, DSP_SIZE);
00359         break;
00360       
00361     case NB_OCTAL:
00362         Q_ASSERT(_period == false  && _eestate == false);
00363         setText(tmp_string);
00364         _display_amount = static_cast<quint64>(STRTOUL(_str_int.toLatin1(), 0, 8));
00365         if (_neg_sign)
00366             _display_amount = -_display_amount;
00367         break;
00368         
00369     case NB_HEX:
00370         Q_ASSERT(_period == false  && _eestate == false);
00371         setText(tmp_string);
00372         _display_amount = static_cast<quint64>(STRTOUL(_str_int.toLatin1(), 0, 16));
00373         if (_neg_sign)
00374             _display_amount = -_display_amount;
00375         break;
00376       
00377     case NB_DECIMAL:
00378         if(_eestate == false)
00379         {
00380             setText(tmp_string);
00381             _display_amount = tmp_string;
00382         }
00383         else
00384         {
00385             if(_str_int_exp.isNull())
00386             {
00387                 // add 'e0' to display but not to conversion
00388                 _display_amount = tmp_string;
00389                 setText(tmp_string + "e0");
00390             }
00391             else
00392             {
00393                 tmp_string +=  'e' + _str_int_exp;
00394                 setText(tmp_string);
00395                 _display_amount = tmp_string;
00396             }
00397         }
00398         break;
00399       
00400     default:
00401       return false;
00402     }
00403     emit changedAmount(_display_amount);
00404     return true;
00405 }
00406 
00407 void KCalcDisplay::newCharacter(char const new_char)
00408 {
00409     // test if character is valid
00410     switch(new_char)
00411     {
00412     case 'e':
00413         // EE can be set only once and in decimal mode
00414         if (_num_base != NB_DECIMAL  ||
00415             _eestate == true)
00416         {
00417             if(_beep) KNotification::beep();
00418             return;
00419         }
00420         _eestate = true;
00421         break;
00422 
00423     case '.':
00424         // Period can be set only once and only in decimal
00425         // mode, also not in EE-mode
00426         if (_num_base != NB_DECIMAL  ||
00427             _period == true  ||
00428             _eestate == true)
00429         {
00430             if(_beep) KNotification::beep();
00431             return;
00432         }
00433         _period = true;
00434         break;
00435 
00436     case 'F':
00437     case 'E':
00438     case 'D':
00439     case 'C':
00440     case 'B':
00441     case 'A':
00442         if (_num_base == NB_DECIMAL)
00443         {
00444             if(_beep) KNotification::beep();
00445             return;
00446         }
00447         // no break
00448     case '9':
00449     case '8':
00450         if (_num_base == NB_OCTAL)
00451         {
00452             if(_beep) KNotification::beep();
00453             return;
00454         }
00455         // no break
00456     case '7':
00457     case '6':
00458     case '5':
00459     case '4':
00460     case '3':
00461     case '2':
00462         if (_num_base == NB_BINARY)
00463         {
00464             if(_beep) KNotification::beep();
00465             return;
00466         }
00467         // no break
00468     case '1':
00469     case '0':
00470         break;
00471 
00472     default:
00473         if(_beep) KNotification::beep();
00474         return;
00475     }
00476 
00477     // change exponent or mantissa
00478     if (_eestate)
00479     {
00480       // ignore ',' before 'e'. turn e.g. '123.e' into '123e'
00481       if (new_char == 'e'  &&  _str_int.endsWith( '.' ))
00482       {
00483         _str_int.truncate(_str_int.length() - 1);
00484         _period = false;
00485       }
00486 
00487       // 'e' only starts ee_mode, leaves strings unchanged
00488       if (new_char != 'e'  &&
00489           // do not add '0' if at start of exp
00490           !(_str_int_exp.isNull() && new_char == '0'))
00491             _str_int_exp.append(new_char);
00492     }
00493     else
00494     {
00495         // handle first character
00496         if (_str_int == "0")
00497         {
00498             switch(new_char)
00499             {
00500             case '.':
00501                 // display "0." not just "."
00502                 _str_int.append(new_char);
00503                 break;
00504             case 'e':
00505                 // display "0e" not just "e"
00506                 // "0e" does not make sense either, but...
00507                 _str_int.append(new_char);
00508                 break;
00509             default:
00510                 // no leading '0's
00511                 _str_int[0] = new_char;
00512             }
00513         }
00514         else
00515             _str_int.append(new_char);
00516     }
00517 
00518     updateDisplay();
00519 }
00520 
00521 void KCalcDisplay::deleteLastDigit(void)
00522 {
00523     // Only partially implemented !!
00524     if (_eestate)
00525     {
00526         if(_str_int_exp.isNull())
00527         {
00528             _eestate = false;
00529         }
00530         else
00531         {
00532             int length = _str_int_exp.length();
00533             if(length > 1)
00534             {
00535                 _str_int_exp.truncate(length-1);
00536             }
00537             else
00538             {
00539                 _str_int_exp = (char *)0;
00540             }
00541         }
00542     }
00543     else
00544     {
00545         int length = _str_int.length();
00546         if(length > 1)
00547         {
00548             if (_str_int[length-1] == '.')
00549                 _period = false;
00550             _str_int.truncate(length-1);
00551         }
00552         else
00553         {
00554             Q_ASSERT(_period == false);
00555             _str_int[0] = '0';
00556         }
00557     }
00558 
00559     updateDisplay();
00560 }
00561 
00562 // change Sign of display. Problem: Only possible here, when in input
00563 // mode. Otherwise return 'false' so that the kcalc_core can handle
00564 // things.
00565 bool KCalcDisplay::changeSign(void)
00566 {
00567     //stupid way, to see if in input_mode or display_mode
00568     if (_str_int == "0") return false;
00569 
00570     if(_eestate)
00571     {
00572         if(!_str_int_exp.isNull())
00573         {
00574             if (_str_int_exp[0] != '-')
00575                 _str_int_exp.prepend('-');
00576             else
00577                 _str_int_exp.remove('-');
00578         }
00579     }
00580     else
00581     {
00582         _neg_sign = ! _neg_sign;
00583     }
00584     
00585     updateDisplay();
00586 
00587     return true;
00588 }
00589 
00590 void KCalcDisplay::paintEvent(QPaintEvent *p)
00591 {
00592     QLabel::paintEvent(p);
00593     QPainter this_paint(this);
00594 
00595     // draw the status texts using half of the normal
00596     // font size but not smaller than 7pt
00597     QFont f(font());
00598     f.setPointSize(qMax((f.pointSize() / 2), 7));
00599     this_paint.setFont(f);
00600     QFontMetrics fm(f);
00601     uint w = fm.width("_____");
00602     uint h = fm.height();
00603 
00604     for (int i = 0; i < NUM_STATUS_TEXT; i++)
00605     {
00606         this_paint.drawText(5 + i * w, h, _str_status[i]);
00607     }
00608 }
00609 
00610 // Return the QLabel's normal size hint vertically expanded
00611 // by half the font height to make room for the status texts
00612 QSize KCalcDisplay::sizeHint() const
00613 {
00614     QFont f(font());
00615     f.setPointSize(qMax((f.pointSize() / 2), 7));
00616     QFontMetrics fm(f);
00617     return QLabel::sizeHint() + QSize(0, fm.height());
00618 }
00619 

kcalc

Skip menu "kcalc"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kdeutils

Skip menu "kdeutils"
  • ark
  • kcalc
  • kcharselect
  • kdelirc
  • kdessh
  • kdf
  • kfloppy
  • kgpg
  • kjots
  • klaptopdaemon
  • kmilo
  • ksim
  • ktimer
  • kwallet
  • superkaramba
Generated for kdeutils by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal