Skip to content

Commit

Permalink
add spreadsheet code file
Browse files Browse the repository at this point in the history
  • Loading branch information
leichaojian committed Nov 12, 2014
1 parent ab33bb6 commit 4a86ea0
Show file tree
Hide file tree
Showing 30 changed files with 2,574 additions and 0 deletions.
200 changes: 200 additions & 0 deletions spreadsheet/cell.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
#include "cell.h"

Cell::Cell()
{
//设置缓存为最新
setDirty();
}

QTableWidgetItem *Cell::clone() const
{
return new Cell(*this);
}

void Cell::setData(int role, const QVariant &value)
{
//通过特定的模式(role)来显示数据(value)
QTableWidgetItem::setData(role, value);
//编辑模式(EditRole)下,单元格需要重新计算
if (role == Qt::EditRole)
setDirty();
}

QVariant Cell::data(int role) const
{
//显示文本
if (role == Qt::DisplayRole) {
if (value().isValid()) {
return value().toString();
} else {
return "####";
}
} else if (role == Qt::TextAlignmentRole) {
//返回一个对齐方式
if (value().type() == QVariant::String) {
return int(Qt::AlignLeft | Qt::AlignVCenter);
} else {
return int(Qt::AlignRight | Qt::AlignVCenter);
}
} else {
return QTableWidgetItem::data(role);
}
}

void Cell::setFormula(const QString &formula)
{
setData(Qt::EditRole, formula);
}

QString Cell::formula() const
{
return data(Qt::EditRole).toString();
}

void Cell::setDirty()
{
cacheIsDirty = true;
}

const QVariant Invalid;

//得到单元格的数据
QVariant Cell::value() const
{
if (cacheIsDirty) {
cacheIsDirty = false;

QString formulaStr = formula();
//数据以单引号(')开头,则为字符串
if (formulaStr.startsWith('\'')) {
cachedValue = formulaStr.mid(1);
} else if (formulaStr.startsWith('=')) {
cachedValue = Invalid;
QString expr = formulaStr.mid(1);
expr.replace(" ", "");
expr.append(QChar::Null);

//为=号情况下,计算公式的值
int pos = 0;
cachedValue = evalExpression(expr, pos);
if (expr[pos] != QChar::Null)
cachedValue = Invalid;
} else {
//否则,为double类型
bool ok;
double d = formulaStr.toDouble(&ok);
if (ok) {
cachedValue = d;
} else {
cachedValue = formulaStr;
}
}
}
return cachedValue;
}

QVariant Cell::evalExpression(const QString &str, int &pos) const
{
QVariant result = evalTerm(str, pos);
while (str[pos] != QChar::Null) {
QChar op = str[pos];
if (op != '+' && op != '-')
return result;
++pos;

QVariant term = evalTerm(str, pos);
if (result.type() == QVariant::Double
&& term.type() == QVariant::Double) {
if (op == '+') {
result = result.toDouble() + term.toDouble();
} else {
result = result.toDouble() - term.toDouble();
}
} else {
result = Invalid;
}
}
return result;
}

QVariant Cell::evalTerm(const QString &str, int &pos) const
{
QVariant result = evalFactor(str, pos);
while (str[pos] != QChar::Null) {
QChar op = str[pos];
if (op != '*' && op != '/')
return result;
++pos;

QVariant factor = evalFactor(str, pos);
if (result.type() == QVariant::Double
&& factor.type() == QVariant::Double) {
if (op == '*') {
result = result.toDouble() * factor.toDouble();
} else {
if (factor.toDouble() == 0.0) {
result = Invalid;
} else {
result = result.toDouble() / factor.toDouble();
}
}
} else {
result = Invalid;
}
}
return result;
}

QVariant Cell::evalFactor(const QString &str, int &pos) const
{
QVariant result;
bool negative = false;

if (str[pos] == '-') {
negative = true;
++pos;
}

if (str[pos] == '(') {
++pos;
result = evalExpression(str, pos);
if (str[pos] != ')')
result = Invalid;
++pos;
} else {
QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
QString token;

while (str[pos].isLetterOrNumber() || str[pos] == '.') {
token += str[pos];
++pos;
}

if (regExp.exactMatch(token)) {
int column = token[0].toUpper().unicode() - 'A';
int row = token.mid(1).toInt() - 1;

Cell *c = static_cast<Cell *>(
tableWidget()->item(row, column));
if (c) {
result = c->value();
} else {
result = 0.0;
}
} else {
bool ok;
result = token.toDouble(&ok);
if (!ok)
result = Invalid;
}
}

if (negative) {
if (result.type() == QVariant::Double) {
result = -result.toDouble();
} else {
result = Invalid;
}
}
return result;
}
29 changes: 29 additions & 0 deletions spreadsheet/cell.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef CELL_H
#define CELL_H

#include <QTableWidgetItem>

class Cell : public QTableWidgetItem
{
public:
Cell();

QTableWidgetItem *clone() const;
void setData(int role, const QVariant &value);
QVariant data(int role) const;
void setFormula(const QString &formula);
QString formula() const;
void setDirty();

private:
QVariant value() const;
QVariant evalExpression(const QString &str, int &pos) const;
QVariant evalTerm(const QString &str, int &pos) const;
QVariant evalFactor(const QString &str, int &pos) const;

mutable QVariant cachedValue;
//如果缓存不是最新的,则cacheIsDirty=true
mutable bool cacheIsDirty;
};

#endif // CELL_H
65 changes: 65 additions & 0 deletions spreadsheet/finddialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "finddialog.h"

FindDialog::FindDialog(QWidget *parent) :
QDialog(parent)
{
label = new QLabel(tr("Find &what:"));
lineEdit = new QLineEdit;
label->setBuddy(lineEdit);

caseCheckBox = new QCheckBox(tr("Match &case"));
backwardCheckBox = new QCheckBox(tr("Search &backward"));

findButton = new QPushButton(tr("&Find"));
findButton->setDefault(true);
findButton->setEnabled(false);

closeButton = new QPushButton(tr("Close"));

connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SLOT(enableFindButton(const QString &)));
connect(findButton, SIGNAL(clicked()),
this, SLOT(findClicked()));
connect(closeButton, SIGNAL(clicked()),
this, SLOT(close()));

QHBoxLayout *topLeftLayout = new QHBoxLayout;
topLeftLayout->addWidget(label);
topLeftLayout->addWidget(lineEdit);

QVBoxLayout *leftLayout = new QVBoxLayout;
leftLayout->addLayout(topLeftLayout);
leftLayout->addWidget(caseCheckBox);
leftLayout->addWidget(backwardCheckBox);

QVBoxLayout *rightLayout = new QVBoxLayout;
rightLayout->addWidget(findButton);
rightLayout->addWidget(closeButton);
rightLayout->addStretch();

QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
setLayout(mainLayout);

setWindowTitle(tr("Find"));
setFixedHeight(sizeHint().height());
}

void FindDialog::findClicked()
{
QString text = lineEdit->text();
Qt::CaseSensitivity cs =
caseCheckBox->isChecked() ? Qt::CaseSensitive
: Qt::CaseInsensitive;
if (backwardCheckBox->isChecked()) {
emit findPrevious(text, cs);
} else {
emit findNext(text, cs);
}
}

void FindDialog::enableFindButton(const QString &text)
{
findButton->setEnabled(!text.isEmpty());
}
34 changes: 34 additions & 0 deletions spreadsheet/finddialog.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef FINDDIALOG_H
#define FINDDIALOG_H

#include <QDialog>
#include <QCheckBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QHBoxLayout>

class FindDialog : public QDialog
{
Q_OBJECT
public:
explicit FindDialog(QWidget *parent = 0);

signals:
void findNext(const QString &str, Qt::CaseSensitivity cs);
void findPrevious(const QString &str, Qt::CaseSensitivity cs);

public slots:
void findClicked();
void enableFindButton(const QString &text);

private:
QLabel *label;
QLineEdit *lineEdit;
QCheckBox *caseCheckBox;
QCheckBox *backwardCheckBox;
QPushButton *findButton;
QPushButton *closeButton;
};

#endif // FINDDIALOG_H
22 changes: 22 additions & 0 deletions spreadsheet/gotocelldialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <QtGui>

#include "gotocelldialog.h"

GoToCellDialog::GoToCellDialog(QWidget *parent)
: QDialog(parent)
{
setupUi(this);
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
lineEdit->setValidator(new QRegExpValidator(regExp, this));

connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}

void GoToCellDialog::on_lineEdit_textChanged()
{
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(
lineEdit->hasAcceptableInput());
}
20 changes: 20 additions & 0 deletions spreadsheet/gotocelldialog.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef GOTOCELLDIALOG_H
#define GOTOCELLDIALOG_H

#include <QDialog>
#include <QPushButton>

#include "ui_gotocelldialog.h"

class GoToCellDialog : public QDialog, public Ui::GoToCellDialog
{
Q_OBJECT

public:
GoToCellDialog(QWidget *parent = 0);

private slots:
void on_lineEdit_textChanged();
};

#endif
Loading

0 comments on commit 4a86ea0

Please sign in to comment.