kcalc
kcalcdisplay.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00149
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);
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
00251
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
00275 if (_num_base == NB_DECIMAL && _groupdigits)
00276
00277
00278
00279 if (string.endsWith('.')) {
00280 localizedString.truncate(localizedString.length() - 1);
00281 localizedString = KGlobal::locale()->formatNumber(localizedString, false, 0);
00282 localizedString.append(KGlobal::locale()->decimalSymbol());
00283 } else
00284 localizedString = KGlobal::locale()->formatNumber(string, false, 0);
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
00298 }
00299
00300
00301
00302
00303
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:
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
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
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
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
00410 switch(new_char)
00411 {
00412 case 'e':
00413
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
00425
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
00448 case '9':
00449 case '8':
00450 if (_num_base == NB_OCTAL)
00451 {
00452 if(_beep) KNotification::beep();
00453 return;
00454 }
00455
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
00468 case '1':
00469 case '0':
00470 break;
00471
00472 default:
00473 if(_beep) KNotification::beep();
00474 return;
00475 }
00476
00477
00478 if (_eestate)
00479 {
00480
00481 if (new_char == 'e' && _str_int.endsWith( '.' ))
00482 {
00483 _str_int.truncate(_str_int.length() - 1);
00484 _period = false;
00485 }
00486
00487
00488 if (new_char != 'e' &&
00489
00490 !(_str_int_exp.isNull() && new_char == '0'))
00491 _str_int_exp.append(new_char);
00492 }
00493 else
00494 {
00495
00496 if (_str_int == "0")
00497 {
00498 switch(new_char)
00499 {
00500 case '.':
00501
00502 _str_int.append(new_char);
00503 break;
00504 case 'e':
00505
00506
00507 _str_int.append(new_char);
00508 break;
00509 default:
00510
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
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
00563
00564
00565 bool KCalcDisplay::changeSign(void)
00566 {
00567
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
00596
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
00611
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