// get the value as integer qint64 KCValue::asInteger() const { qint64 result = 0; if (type() == Integer) result = d->i; else if (type() == Float) result = static_cast<qint64>(floor(numToDouble(d->f))); else if (type() == Complex) result = static_cast<qint64>(floor(numToDouble(d->pc->real()))); return result; }
QTextStream& operator<<(QTextStream& ts, KCValue value) { ts << value.type(); switch (value.type()) { case KCValue::Empty: break; case KCValue::Boolean: ts << ": "; if (value.asBoolean()) ts << "TRUE"; else ts << "FALSE"; break; case KCValue::Integer: ts << ": " << value.asInteger(); break; case KCValue::Float: ts << ": " << (double) numToDouble(value.asFloat()); break; case KCValue::Complex: { const complex<KCNumber> complex(value.asComplex()); ts << ": " << (double) numToDouble(complex.real()); if (complex.imag() >= 0.0) ts << '+'; ts << (double) numToDouble(complex.imag()) << 'i'; break; } case KCValue::String: ts << ": " << value.asString(); break; case KCValue::Array: { ts << ": {" << value.asString(); const int cols = value.columns(); const int rows = value.rows(); for (int row = 0; row < rows; ++row) { for (int col = 0; col < cols; ++col) { ts << value.element(col, row); if (col < cols - 1) ts << ';'; } if (row < rows - 1) ts << '|'; } ts << '}'; break; } case KCValue::Error: ts << '(' << value.errorMessage() << ')'; break; default: break; } return ts; }
void TestValue::testAssignment() { Value* v1; Value* v2; // value assignment v1 = new Value(14.3l); v2 = new Value(true); *v2 = *v1; QCOMPARE(v1->type(), Value::Float); QCOMPARE(v2->type(), Value::Float); QCOMPARE(numToDouble(v1->asFloat()), 14.3l); QCOMPARE(numToDouble(v2->asFloat()), 14.3l); delete v1; delete v2; // test copying/detaching of string values (QString*) v1 = new Value("Hello"); v2 = new Value(true); *v2 = *v1; QCOMPARE(v1->type(), Value::String); QCOMPARE(v2->type(), Value::String); QCOMPARE(v1->asString(), QString("Hello")); QCOMPARE(v2->asString(), QString("Hello")); *v2 = Value(QString("World")); QCOMPARE(v1->asString(), QString("Hello")); QCOMPARE(v2->asString(), QString("World")); delete v1; delete v2; // test copying/detaching of arrays (ValueArray*) v1 = new Value(Value::Array); v1->setElement(0, 0, Value(1)); v1->setElement(0, 1, Value(2)); v2 = new Value(true); *v2 = *v1; QCOMPARE(v1->type(), Value::Array); QCOMPARE(v2->type(), Value::Array); QCOMPARE(v1->element(0, 0), Value(1)); QCOMPARE(v1->element(0, 1), Value(2)); QCOMPARE(v2->element(0, 0), Value(1)); QCOMPARE(v2->element(0, 1), Value(2)); v2->setElement(0, 0, Value(3)); QCOMPARE(v1->element(0, 0), Value(1)); QCOMPARE(v1->element(0, 1), Value(2)); QCOMPARE(v2->element(0, 0), Value(3)); QCOMPARE(v2->element(0, 1), Value(2)); delete v1; delete v2; }
// get the value as QVariant QVariant KCValue::asVariant() const { QVariant result; switch (d->type) { case KCValue::Empty: default: result = 0; break; case KCValue::Boolean: result = d->b; break; case KCValue::Integer: result = d->i; break; case KCValue::Float: result = (double) numToDouble(d->f); break; case KCValue::Complex: // FIXME: add support for complex numbers // pc = new complex<KCNumber>( *o.pc ); break; case KCValue::String: case KCValue::Error: result = *d->ps; break; case KCValue::Array: // FIXME: not supported yet //result = ValueArray( d->pa ); break; } return result; }
void TestValue::testCopy() { Value* v1; Value* v2; // copy value v1 = new Value(); *v1 = Value(14.3l); v2 = new Value(*v1); QCOMPARE(v1->type(), Value::Float); QCOMPARE(v2->type(), Value::Float); QCOMPARE(numToDouble(v1->asFloat()), 14.3l); QCOMPARE(numToDouble(v2->asFloat()), 14.3l); delete v1; delete v2; }
void TestValue::testFloat() { Value* v1; // floating-point value v1 = new Value(M_PI); QCOMPARE(v1->type(), Value::Float); QCOMPARE(numToDouble(v1->asFloat()), (long double) M_PI); *v1 = Value(false); // dummy *v1 = Value(14.03l); QCOMPARE(v1->type(), Value::Float); QCOMPARE(v1->isInteger(), false); QCOMPARE(v1->isFloat(), true); QCOMPARE(v1->isString(), false); QCOMPARE(v1->isNumber(), true); QCOMPARE(numToDouble(v1->asFloat()), 14.03l); delete v1; }
// get the value as time QTime KCValue::asTime(const KCCalculationSettings* settings) const { Q_UNUSED(settings); QTime dt; const int days = asInteger(); const int msecs = qRound(numToDouble(asFloat() - double(days)) * 86400000.0); // 24*60*60*1000 dt = dt.addMSecs(msecs); return dt; }
// get the value as date/time QDateTime KCValue::asDateTime(const KCCalculationSettings* settings) const { QDateTime datetime(settings->referenceDate(), QTime(), Qt::UTC); const int days = asInteger(); const int msecs = qRound((numToDouble(asFloat() - double(days))) * 86400000.0); // 24*60*60*1000 datetime = datetime.addDays(days); datetime = datetime.addMSecs(msecs); return datetime; }
// round to get at most 10-digits number static Value RoundNumber(const Value& v) { if(v.isNumber()) { double d = numToDouble(v.asFloat()); if(fabs(d) < DBL_EPSILON) d = 0.0; return Value( ROUND(d) ); } else return v; }
QVariant KCBindingModel::data(const QModelIndex& index, int role) const { if ((m_region.isEmpty()) || (role != Qt::EditRole && role != Qt::DisplayRole)) return QVariant(); const QPoint offset = m_region.firstRange().topLeft(); const KCSheet* sheet = m_region.firstSheet(); const KCValue value = sheet->cellStorage()->value(offset.x() + index.column(), offset.y() + index.row()); // KChart::KCValue is either: // - a double (interpreted as a value) // - a QString (interpreted as a label) // - a QDateTime (interpreted as a date/time value) // - Invalid (interpreted as empty) QVariant variant; switch (value.type()) { case KCValue::Float: case KCValue::Integer: if (value.format() == KCValue::fmt_DateTime || value.format() == KCValue::fmt_Date || value.format() == KCValue::fmt_Time) { variant.setValue<QDateTime>(value.asDateTime(sheet->map()->calculationSettings())); break; } case KCValue::Boolean: case KCValue::Complex: case KCValue::Array: variant.setValue<double>(numToDouble(value.asFloat())); break; case KCValue::String: case KCValue::Error: variant.setValue<QString>(value.asString()); break; case KCValue::Empty: case KCValue::CellRange: default: break; } //kDebug() << index.column() <<"," << index.row() <<"," << variant; return variant; }
void TestValue::testDate() { Value* v1; // check all (valid) dates from 1900 to 2050 // note: bail on first error immediately CalculationSettings calculationSettings; QDate refDate(1899, 12, 31); v1 = new Value(); bool date_error = 0; for (unsigned y = 1900; !date_error && y < 2050; y++) for (unsigned m = 1; !date_error && m <= 12; m++) for (unsigned d = 1; !date_error && d <= 31; d++) { QDate dv1 = QDate(y, m, d); if (!dv1.isValid()) continue; long double serialNo = -dv1.daysTo(refDate) + 1.0; *v1 = Value(Value(dv1, &calculationSettings)); QCOMPARE(numToDouble(v1->asFloat()), serialNo); date_error = v1->asFloat() != serialNo; } delete v1; }
uint qHash(const KCValue& value) { switch (value.type()) { case KCValue::Empty: case KCValue::CellRange: return 0; case KCValue::Boolean: return ::qHash(value.asBoolean()); case KCValue::Integer: return ::qHash(value.asInteger()); case KCValue::Float: return ::qHash((qint64)numToDouble(value.asFloat())); case KCValue::Complex: return ::qHash((qint64)value.asComplex().real()); case KCValue::String: return ::qHash(value.asString()); case KCValue::Array: return qHash(value.element(0, 0)); case KCValue::Error: return ::qHash(value.errorMessage()); } return 0; }
void ValidityDialog::init() { const KCMap *const map = m_selection->activeSheet()->map(); const KCCalculationSettings *settings = map->calculationSettings(); const KLocale* locale = settings->locale(); KCValidity validity = KCCell(m_selection->activeSheet(), m_selection->marker()).validity(); if (!validity.isEmpty()) { message->setPlainText(validity.message()); title->setText(validity.title()); QString tmp; switch (validity.restriction()) { case KCValidity::None: chooseType->setCurrentIndex(0); break; case KCValidity::KCNumber: chooseType->setCurrentIndex(1); if (validity.condition() >= 5) val_max->setText(tmp.setNum((double)numToDouble(validity.maximumValue().asFloat()))); val_min->setText(tmp.setNum((double)numToDouble(validity.minimumValue().asFloat()))); break; case KCValidity::Integer: chooseType->setCurrentIndex(2); if (validity.condition() >= 5) val_max->setText(tmp.setNum((double)numToDouble(validity.maximumValue().asFloat()))); val_min->setText(tmp.setNum((double)numToDouble(validity.minimumValue().asFloat()))); break; case KCValidity::TextLength: chooseType->setCurrentIndex(6); if (validity.condition() >= 5) val_max->setText(tmp.setNum((double)numToDouble(validity.maximumValue().asFloat()))); val_min->setText(tmp.setNum((double)numToDouble(validity.minimumValue().asFloat()))); break; case KCValidity::Text: chooseType->setCurrentIndex(3); break; case KCValidity::Date: chooseType->setCurrentIndex(4); val_min->setText(locale->formatDate(validity.minimumValue().asDate(settings), KLocale::ShortDate)); if (validity.condition() >= 5) val_max->setText(locale->formatDate(validity.maximumValue().asDate(settings), KLocale::ShortDate)); break; case KCValidity::Time: chooseType->setCurrentIndex(5); val_min->setText(locale->formatTime(validity.minimumValue().asTime(settings), true)); if (validity.condition() >= 5) val_max->setText(locale->formatTime(validity.maximumValue().asTime(settings), true)); break; case KCValidity::List: { chooseType->setCurrentIndex(7); const QStringList lst = validity.validityList(); QString tmp; for (QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) { tmp += (*it) + '\n'; } validityList->setText(tmp); } break; default : chooseType->setCurrentIndex(0); break; } chooseAction->setCurrentIndex(chooseAction->findData(QVariant::fromValue(validity.action()))); choose->setCurrentIndex(choose->findData(QVariant::fromValue(validity.condition()))); displayMessage->setChecked(validity.displayMessage()); allowEmptyCell->setChecked(validity.allowEmptyCell()); titleHelp->setText(validity.titleInfo()); messageHelp->setPlainText(validity.messageInfo()); displayHelp->setChecked(validity.displayValidationInformation()); } changeIndexType(chooseType->currentIndex()) ; changeIndexCond(choose->currentIndex()) ; }
bool KCValidity::testValidity(const KCCell* cell) const { bool valid = false; if (d->restriction != None) { //fixme if (d->allowEmptyCell && cell->userInput().isEmpty()) return true; if ((cell->value().isNumber() && (d->restriction == KCNumber || (d->restriction == Integer && numToDouble(cell->value().asFloat()) == ceil(numToDouble(cell->value().asFloat()))))) || (d->restriction == Time && cell->isTime()) || (d->restriction == Date && cell->isDate())) { switch (d->cond) { case KCConditional::Equal: valid = cell->value().equal(d->minValue); break; case KCConditional::DifferentTo: valid = !cell->value().equal(d->minValue); break; case KCConditional::Superior: valid = cell->value().greater(d->minValue); break; case KCConditional::Inferior: valid = cell->value().less(d->minValue); break; case KCConditional::SuperiorEqual: valid = (cell->value().compare(d->minValue)) >= 0; break; case KCConditional::InferiorEqual: valid = (cell->value().compare(d->minValue)) <= 0; break; case KCConditional::Between: valid = (cell->value().compare(d->minValue) >= 0 && cell->value().compare(d->maxValue) <= 0); break; case KCConditional::Different: valid = (cell->value().compare(d->minValue) < 0 || cell->value().compare(d->maxValue) > 0); break; default : break; } } else if (d->restriction == Text) { valid = cell->value().isString(); } else if (d->restriction == List) { //test int value if (cell->value().isString() && d->listValidity.contains(cell->value().asString())) valid = true; } else if (d->restriction == TextLength) { if (cell->value().isString()) { int len = cell->displayText().length(); const int min = d->minValue.asInteger(); const int max = d->maxValue.asInteger(); switch (d->cond) { case KCConditional::Equal: if (len == min) valid = true; break; case KCConditional::DifferentTo: if (len != min) valid = true; break; case KCConditional::Superior: if (len > min) valid = true; break; case KCConditional::Inferior: if (len < min) valid = true; break; case KCConditional::SuperiorEqual: if (len >= min) valid = true; break; case KCConditional::InferiorEqual: if (len <= min) valid = true; break; case KCConditional::Between: if (len >= min && len <= max) valid = true; break; case KCConditional::Different: if (len < min || len > max) valid = true; break; default : break; } } } } else { valid = true; } if (!valid) { if (d->displayMessage) { switch (d->action) { case Stop: KMessageBox::error((QWidget*)0, d->message, d->title); break; case Warning: if (KMessageBox::warningYesNo((QWidget*)0, d->message, d->title) == KMessageBox::Yes) { valid = true; } break; case Information: KMessageBox::information((QWidget*)0, d->message, d->title); valid = true; break; } } cell->sheet()->showStatusMessage(i18n("Validation for cell %1 failed", cell->fullName())); } return valid; }
void TestValue::testArray() { Value* v1; Value* v2; // array v1 = new Value(Value::Array); QCOMPARE(v1->type(), Value::Array); QCOMPARE(v1->columns(), (unsigned)1); QCOMPARE(v1->rows(), (unsigned)1); delete v1; // check empty value in array v1 = new Value(Value::Array); QCOMPARE(v1->type(), Value::Array); v2 = new Value(v1->element(0, 0)); QCOMPARE(v2->type(), Value::Empty); delete v1; // fill simple 1x1 array v1 = new Value(Value::Array); QCOMPARE(v1->type(), Value::Array); v2 = new Value(14.3l); v1->setElement(0, 0, *v2); delete v2; v2 = new Value(v1->element(0, 0)); QCOMPARE(v2->type(), Value::Float); QCOMPARE(numToDouble(v2->asFloat()), 14.3l); delete v2; delete v1; // stress test, array of 1000x1000 v1 = new Value(Value::Array); QCOMPARE(v1->type(), Value::Array); for (unsigned r = 0; r < 1000; r++) for (unsigned c = 0; c < 1000; c++) { int index = 1000 * r + c; v1->setElement(c, r, Value(index)); } int array_error = 0; for (unsigned c = 0; !array_error && c < 1000; c++) for (unsigned r = 0; !array_error && r < 1000; r++) { int index = 1000 * r + c; v2 = new Value(v1->element(c, r)); if (v2->type() != Value::Integer) array_error++; if (v2->asInteger() != index) array_error++; delete v2; } QCOMPARE(array_error, (int)0); delete v1; // assignment of array value v1 = new Value(Value::Array); QCOMPARE(v1->type(), Value::Array); v1->setElement(1, 1, Value(44.3l)); v1->setElement(0, 1, Value(34.3l)); v1->setElement(1, 0, Value(24.3l)); v1->setElement(0, 0, Value(14.3l)); v2 = new Value(*v1); // v2 is now also an array delete v1; v1 = new Value(v2->element(0, 0)); QCOMPARE(v1->type(), Value::Float); QCOMPARE(numToDouble(v1->asFloat()), 14.3l); delete v1; delete v2; // equality v1 = new Value(Value::Array); v2 = new Value(Value::Array); QCOMPARE(*v1, *v2); v1->setElement(0, 0, Value(1)); v1->setElement(0, 1, Value(2)); v2->setElement(0, 0, Value(1)); v2->setElement(0, 1, Value(2)); QCOMPARE(*v1, *v2); delete v1; delete v2; }