"Professional CMake" book suggest the following: "Targets should build successfully with or without compiler support for precompiled headers. It should be considered an optimization, not a requirement. In particular, do not explicitly include a precompile header (e.g. stdafx.h) in the source code, let CMake force-include an automatically generated precompile header on the compiler command line instead. This is more portable across the major compilers and is likely to be easier to maintain. It will also avoid warnings being generated from certain code checking tools like iwyu (include what you use)." Therefore, removed the "#include <PreCompiled.h>" from sources, also there is no need for the "#ifdef _PreComp_" anymore
619 lines
22 KiB
C++
619 lines
22 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2015 Eivind Kvedalen <eivind@kvedalen.name> *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#include <QFont>
|
|
#include <QLocale>
|
|
|
|
|
|
#include <App/Document.h>
|
|
#include <Base/Interpreter.h>
|
|
#include <Base/Tools.h>
|
|
#include <Base/UnitsApi.h>
|
|
#include <Gui/Application.h>
|
|
#include <Gui/Command.h>
|
|
#include <Mod/Spreadsheet/App/Sheet.h>
|
|
|
|
#include "SheetModel.h"
|
|
|
|
|
|
using namespace SpreadsheetGui;
|
|
using namespace Spreadsheet;
|
|
using namespace App;
|
|
namespace sp = std::placeholders;
|
|
|
|
SheetModel::SheetModel(Sheet* _sheet, QObject* parent)
|
|
: QAbstractTableModel(parent)
|
|
, sheet(_sheet)
|
|
{
|
|
// NOLINTBEGIN
|
|
cellUpdatedConnection =
|
|
sheet->cellUpdated.connect(std::bind(&SheetModel::cellUpdated, this, sp::_1));
|
|
rangeUpdatedConnection =
|
|
sheet->rangeUpdated.connect(std::bind(&SheetModel::rangeUpdated, this, sp::_1));
|
|
// NOLINTEND
|
|
|
|
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
|
"User parameter:BaseApp/Preferences/Mod/Spreadsheet");
|
|
aliasBgColor =
|
|
QColor(QString::fromStdString(hGrp->GetASCII("AliasedCellBackgroundColor", "#feff9e")));
|
|
textFgColor = QColor(QString::fromStdString(hGrp->GetASCII("TextColor", "#000000")));
|
|
positiveFgColor =
|
|
QColor(QString::fromStdString(hGrp->GetASCII("PositiveNumberColor", "#000000")));
|
|
negativeFgColor =
|
|
QColor(QString::fromStdString(hGrp->GetASCII("NegativeNumberColor", "#000000")));
|
|
|
|
|
|
const QStringList alphabet {
|
|
QStringLiteral("A"), QStringLiteral("B"), QStringLiteral("C"), QStringLiteral("D"),
|
|
QStringLiteral("E"), QStringLiteral("F"), QStringLiteral("G"), QStringLiteral("H"),
|
|
QStringLiteral("I"), QStringLiteral("J"), QStringLiteral("K"), QStringLiteral("L"),
|
|
QStringLiteral("M"), QStringLiteral("N"), QStringLiteral("O"), QStringLiteral("P"),
|
|
QStringLiteral("Q"), QStringLiteral("R"), QStringLiteral("S"), QStringLiteral("T"),
|
|
QStringLiteral("U"), QStringLiteral("V"), QStringLiteral("W"), QStringLiteral("X"),
|
|
QStringLiteral("Y"), QStringLiteral("Z")};
|
|
|
|
for (const QString& letter : alphabet) {
|
|
columnLabels << letter;
|
|
}
|
|
|
|
for (const QString& left : alphabet) {
|
|
for (const QString& right : alphabet) {
|
|
columnLabels << left + right;
|
|
}
|
|
}
|
|
|
|
for (int i = 1; i <= maxRowCount; i++) {
|
|
rowLabels << QString::number(i);
|
|
}
|
|
}
|
|
|
|
SheetModel::~SheetModel()
|
|
{
|
|
cellUpdatedConnection.disconnect();
|
|
rangeUpdatedConnection.disconnect();
|
|
}
|
|
|
|
int SheetModel::rowCount(const QModelIndex& parent) const
|
|
{
|
|
Q_UNUSED(parent);
|
|
return maxRowCount;
|
|
}
|
|
|
|
int SheetModel::columnCount(const QModelIndex& parent) const
|
|
{
|
|
Q_UNUSED(parent);
|
|
return maxColumnCount;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
QVariant formatCellDisplay(QString value, const Cell* cell)
|
|
{
|
|
std::string alias;
|
|
static auto hGrpSpreadsheet =
|
|
App::GetApplication().GetUserParameter().GetGroup("BaseApp/Preferences/Mod/Spreadsheet");
|
|
if (cell->getAlias(alias) && hGrpSpreadsheet->GetBool("showAliasName", false)) {
|
|
QString formatStr = QString::fromStdString(
|
|
hGrpSpreadsheet->GetASCII("DisplayAliasFormatString", "%V = %A"));
|
|
if (formatStr.contains(QLatin1String("%V")) || formatStr.contains(QLatin1String("%A"))) {
|
|
formatStr.replace(QLatin1String("%A"), QString::fromStdString(alias));
|
|
formatStr.replace(QLatin1String("%V"), value);
|
|
return QVariant(formatStr);
|
|
}
|
|
}
|
|
return QVariant(value);
|
|
}
|
|
} // namespace
|
|
|
|
QVariant SheetModel::data(const QModelIndex& index, int role) const
|
|
{
|
|
static const Cell* emptyCell = new Cell(CellAddress(0, 0), nullptr);
|
|
int row = index.row();
|
|
int col = index.column();
|
|
const Cell* cell = sheet->getCell(CellAddress(row, col));
|
|
|
|
if (!cell) {
|
|
cell = emptyCell;
|
|
}
|
|
|
|
// #define DEBUG_DEPS
|
|
#ifdef DEBUG_DEPS
|
|
if (role == Qt::ToolTipRole) {
|
|
QString v;
|
|
|
|
std::set<std::string> deps = sheet->dependsOn(CellAddress(row, col));
|
|
std::set<std::string> provides;
|
|
|
|
sheet->providesTo(CellAddress(row, col), provides);
|
|
|
|
if (deps.size() > 0) {
|
|
v += QStringLiteral("Depends on:");
|
|
for (std::set<std::string>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
|
|
v += QStringLiteral("\n\t") + Tools::fromStdString(*i);
|
|
}
|
|
v += QStringLiteral("\n");
|
|
}
|
|
if (provides.size() > 0) {
|
|
v += QStringLiteral("Used by:");
|
|
for (std::set<std::string>::const_iterator i = provides.begin(); i != provides.end();
|
|
++i) {
|
|
v += QStringLiteral("\n\t") + Tools::fromStdString(*i);
|
|
}
|
|
v += QStringLiteral("\n");
|
|
}
|
|
return QVariant(v);
|
|
}
|
|
#else
|
|
if (!cell->hasException() && role == Qt::ToolTipRole) {
|
|
std::string alias;
|
|
if (cell->getAlias(alias)) {
|
|
return QVariant(QString::fromStdString(alias));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (cell->hasException()) {
|
|
switch (role) {
|
|
case Qt::ToolTipRole: {
|
|
QString txt(QString::fromStdString(cell->getException()).toHtmlEscaped());
|
|
return QVariant(QStringLiteral("<pre>%1</pre>").arg(txt));
|
|
}
|
|
case Qt::DisplayRole: {
|
|
#ifdef DEBUG_DEPS
|
|
return QVariant::fromValue(
|
|
QStringLiteral("#ERR: %1").arg(Tools::fromStdString(cell->getException())));
|
|
#else
|
|
std::string str;
|
|
if (cell->getStringContent(str)) {
|
|
return QVariant::fromValue(QString::fromUtf8(str.c_str()));
|
|
}
|
|
return QVariant::fromValue(QStringLiteral("#ERR"));
|
|
#endif
|
|
}
|
|
case Qt::ForegroundRole:
|
|
return QVariant::fromValue(QColor(255.0, 0, 0));
|
|
case Qt::TextAlignmentRole:
|
|
return QVariant(Qt::AlignVCenter | Qt::AlignLeft);
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Get edit value by querying the sheet
|
|
if (role == Qt::EditRole || role == Qt::StatusTipRole) {
|
|
std::string str;
|
|
|
|
if (cell->getStringContent(str)) {
|
|
return QVariant(QString::fromUtf8(str.c_str()));
|
|
}
|
|
return {};
|
|
}
|
|
|
|
// Get display value as computed property
|
|
std::string address = CellAddress(row, col).toString();
|
|
Property* prop = sheet->getPropertyByName(address.c_str());
|
|
|
|
if (role == Qt::BackgroundRole) {
|
|
Base::Color color;
|
|
|
|
if (cell->getBackground(color)) {
|
|
return QVariant::fromValue(
|
|
QColor(255.0 * color.r, 255.0 * color.g, 255.0 * color.b, 255.0 * color.a));
|
|
}
|
|
else {
|
|
std::string alias;
|
|
if (cell->getAlias(alias)) {
|
|
return QVariant::fromValue(aliasBgColor);
|
|
}
|
|
return {};
|
|
}
|
|
}
|
|
|
|
int qtAlignment = 0;
|
|
|
|
int alignment;
|
|
cell->getAlignment(alignment);
|
|
|
|
if (alignment & Cell::ALIGNMENT_LEFT) {
|
|
qtAlignment |= Qt::AlignLeft;
|
|
}
|
|
if (alignment & Cell::ALIGNMENT_HCENTER) {
|
|
qtAlignment |= Qt::AlignHCenter;
|
|
}
|
|
if (alignment & Cell::ALIGNMENT_RIGHT) {
|
|
qtAlignment |= Qt::AlignRight;
|
|
}
|
|
if (alignment & Cell::ALIGNMENT_TOP) {
|
|
qtAlignment |= Qt::AlignTop;
|
|
}
|
|
if (alignment & Cell::ALIGNMENT_VCENTER) {
|
|
qtAlignment |= Qt::AlignVCenter;
|
|
}
|
|
if (alignment & Cell::ALIGNMENT_BOTTOM) {
|
|
qtAlignment |= Qt::AlignBottom;
|
|
}
|
|
|
|
std::set<std::string> style;
|
|
if (role == Qt::FontRole && cell->getStyle(style)) {
|
|
QFont f;
|
|
|
|
for (const auto& i : style) {
|
|
if (i == "bold") {
|
|
f.setBold(true);
|
|
}
|
|
else if (i == "italic") {
|
|
f.setItalic(true);
|
|
}
|
|
else if (i == "underline") {
|
|
f.setUnderline(true);
|
|
}
|
|
}
|
|
|
|
return QVariant::fromValue(f);
|
|
}
|
|
|
|
auto dirtyCells = sheet->getCells()->getDirty();
|
|
auto dirty = (dirtyCells.find(CellAddress(row, col)) != dirtyCells.end());
|
|
|
|
if (!prop || dirty) {
|
|
switch (role) {
|
|
case Qt::ForegroundRole: {
|
|
return QColor(0,
|
|
0,
|
|
255.0); // TODO: Remove this hardcoded color, replace with preference
|
|
}
|
|
case Qt::TextAlignmentRole: {
|
|
qtAlignment = Qt::AlignHCenter | Qt::AlignVCenter;
|
|
return QVariant::fromValue(qtAlignment);
|
|
}
|
|
case Qt::DisplayRole:
|
|
if (cell->getExpression()) {
|
|
std::string str;
|
|
if (cell->getStringContent(str)) {
|
|
if (!str.empty() && str[0] == '=') {
|
|
// If this is a real computed value, indicate that a recompute is
|
|
// needed before we can display it
|
|
return QVariant(QLatin1String("#PENDING"));
|
|
}
|
|
else {
|
|
// If it's just a simple value, display the new value, but still
|
|
// format it as a pending value to indicate to the user that
|
|
// a recompute is needed
|
|
return QVariant(QString::fromUtf8(str.c_str()));
|
|
}
|
|
}
|
|
}
|
|
return {};
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
else if (prop->isDerivedFrom<App::PropertyString>()) {
|
|
/* String */
|
|
const App::PropertyString* stringProp = static_cast<const App::PropertyString*>(prop);
|
|
|
|
switch (role) {
|
|
case Qt::ForegroundRole: {
|
|
Base::Color color;
|
|
|
|
if (cell->getForeground(color)) {
|
|
return QVariant::fromValue(
|
|
QColor(255.0 * color.r, 255.0 * color.g, 255.0 * color.b, 255.0 * color.a));
|
|
}
|
|
else {
|
|
return QVariant(QColor(textFgColor));
|
|
}
|
|
}
|
|
case Qt::DisplayRole: {
|
|
QString v = QString::fromUtf8(stringProp->getValue());
|
|
return formatCellDisplay(v, cell);
|
|
}
|
|
case Qt::TextAlignmentRole: {
|
|
if (alignment & Cell::ALIGNMENT_HIMPLIED) {
|
|
qtAlignment &= ~(Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
|
|
qtAlignment |= Qt::AlignLeft;
|
|
}
|
|
if (alignment & Cell::ALIGNMENT_VIMPLIED) {
|
|
qtAlignment &= ~(Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
|
|
qtAlignment |= Qt::AlignVCenter;
|
|
}
|
|
return QVariant::fromValue(qtAlignment);
|
|
}
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
else if (prop->isDerivedFrom<App::PropertyQuantity>()) {
|
|
/* Number */
|
|
const App::PropertyQuantity* floatProp = static_cast<const App::PropertyQuantity*>(prop);
|
|
|
|
switch (role) {
|
|
case Qt::ForegroundRole: {
|
|
Base::Color color;
|
|
|
|
if (cell->getForeground(color)) {
|
|
return QVariant::fromValue(
|
|
QColor(255.0 * color.r, 255.0 * color.g, 255.0 * color.b, 255.0 * color.a));
|
|
}
|
|
else {
|
|
if (floatProp->getValue() < 0) {
|
|
return QVariant::fromValue(QColor(negativeFgColor));
|
|
}
|
|
else {
|
|
return QVariant::fromValue(QColor(positiveFgColor));
|
|
}
|
|
}
|
|
}
|
|
case Qt::TextAlignmentRole: {
|
|
if (alignment & Cell::ALIGNMENT_HIMPLIED) {
|
|
qtAlignment &= ~(Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
|
|
qtAlignment |= Qt::AlignRight;
|
|
}
|
|
if (alignment & Cell::ALIGNMENT_VIMPLIED) {
|
|
qtAlignment &= ~(Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
|
|
qtAlignment |= Qt::AlignVCenter;
|
|
}
|
|
return QVariant::fromValue(qtAlignment);
|
|
}
|
|
case Qt::DisplayRole: {
|
|
QString v;
|
|
const Base::Unit& computedUnit = floatProp->getUnit();
|
|
DisplayUnit displayUnit;
|
|
|
|
// Display locale specific decimal separator (#0003875,#0003876)
|
|
if (cell->getDisplayUnit(displayUnit)) {
|
|
if (computedUnit == Base::Unit::One || computedUnit == displayUnit.unit) {
|
|
QString number =
|
|
QLocale().toString(floatProp->getValue() / displayUnit.scaler,
|
|
'f',
|
|
Base::UnitsApi::getDecimals());
|
|
// QString number = QString::number(floatProp->getValue() /
|
|
// displayUnit.scaler);
|
|
v = number + QString::fromStdString(" " + displayUnit.stringRep);
|
|
}
|
|
else {
|
|
v = QStringLiteral("#ERR: unit");
|
|
}
|
|
}
|
|
else {
|
|
|
|
// When displaying a quantity then use the globally set scheme
|
|
// See: https://forum.freecad.org/viewtopic.php?f=3&t=50078
|
|
Base::Quantity value = floatProp->getQuantityValue();
|
|
v = QString::fromStdString(value.getUserString());
|
|
}
|
|
return formatCellDisplay(v, cell);
|
|
}
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
else if (prop->isDerivedFrom<App::PropertyFloat>()
|
|
|| prop->isDerivedFrom<App::PropertyInteger>()) {
|
|
/* Number */
|
|
double d {};
|
|
long l {};
|
|
bool isInteger = false;
|
|
if (prop->isDerivedFrom<App::PropertyFloat>()) {
|
|
d = static_cast<const App::PropertyFloat*>(prop)->getValue();
|
|
}
|
|
else {
|
|
isInteger = true;
|
|
l = static_cast<const App::PropertyInteger*>(prop)->getValue();
|
|
d = l;
|
|
}
|
|
|
|
switch (role) {
|
|
case Qt::ForegroundRole: {
|
|
Base::Color color;
|
|
|
|
if (cell->getForeground(color)) {
|
|
return QVariant::fromValue(
|
|
QColor(255.0 * color.r, 255.0 * color.g, 255.0 * color.b, 255.0 * color.a));
|
|
}
|
|
else {
|
|
if (d < 0) {
|
|
return QVariant::fromValue(QColor(negativeFgColor));
|
|
}
|
|
else {
|
|
return QVariant::fromValue(QColor(positiveFgColor));
|
|
}
|
|
}
|
|
}
|
|
case Qt::TextAlignmentRole: {
|
|
if (alignment & Cell::ALIGNMENT_HIMPLIED) {
|
|
qtAlignment &= ~(Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
|
|
qtAlignment |= Qt::AlignRight;
|
|
}
|
|
if (alignment & Cell::ALIGNMENT_VIMPLIED) {
|
|
qtAlignment &= ~(Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
|
|
qtAlignment |= Qt::AlignVCenter;
|
|
}
|
|
return QVariant::fromValue(qtAlignment);
|
|
}
|
|
case Qt::DisplayRole: {
|
|
QString v;
|
|
DisplayUnit displayUnit;
|
|
|
|
// Display locale specific decimal separator (#0003875,#0003876)
|
|
if (cell->getDisplayUnit(displayUnit)) {
|
|
QString number = QLocale().toString(d / displayUnit.scaler,
|
|
'f',
|
|
Base::UnitsApi::getDecimals());
|
|
// QString number = QString::number(d / displayUnit.scaler);
|
|
v = number + QString::fromStdString(" " + displayUnit.stringRep);
|
|
}
|
|
else if (!isInteger) {
|
|
v = QLocale::system().toString(d, 'f', Base::UnitsApi::getDecimals());
|
|
// v = QString::number(d);
|
|
}
|
|
else {
|
|
v = QString::number(l);
|
|
}
|
|
return formatCellDisplay(v, cell);
|
|
}
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
else if (prop->isDerivedFrom<App::PropertyPythonObject>()) {
|
|
auto pyProp = static_cast<const App::PropertyPythonObject*>(prop);
|
|
|
|
switch (role) {
|
|
case Qt::ForegroundRole: {
|
|
Base::Color color;
|
|
|
|
if (cell->getForeground(color)) {
|
|
return QVariant::fromValue(
|
|
QColor(255.0 * color.r, 255.0 * color.g, 255.0 * color.b, 255.0 * color.a));
|
|
}
|
|
else {
|
|
return QVariant(QColor(textFgColor));
|
|
}
|
|
}
|
|
case Qt::TextAlignmentRole: {
|
|
if (alignment & Cell::ALIGNMENT_HIMPLIED) {
|
|
qtAlignment &= ~(Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight);
|
|
qtAlignment |= Qt::AlignHCenter;
|
|
}
|
|
if (alignment & Cell::ALIGNMENT_VIMPLIED) {
|
|
qtAlignment &= ~(Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom);
|
|
qtAlignment |= Qt::AlignVCenter;
|
|
}
|
|
return QVariant::fromValue(qtAlignment);
|
|
}
|
|
case Qt::DisplayRole: {
|
|
Base::PyGILStateLocker lock;
|
|
std::string value;
|
|
try {
|
|
value = pyProp->getValue().as_string();
|
|
}
|
|
catch (Py::Exception&) {
|
|
Base::PyException e;
|
|
value = "#ERR: ";
|
|
value += e.what();
|
|
}
|
|
catch (Base::Exception& e) {
|
|
value = "#ERR: ";
|
|
value += e.what();
|
|
}
|
|
catch (...) {
|
|
value = "#ERR: unknown exception";
|
|
}
|
|
QString v = QString::fromUtf8(value.c_str());
|
|
return formatCellDisplay(v, cell);
|
|
}
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
QVariant SheetModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (role == Qt::SizeHintRole) {
|
|
const int width =
|
|
(orientation == Qt::Horizontal ? sheet->getColumnWidth(section)
|
|
: PropertyColumnWidths::defaultHeaderWidth);
|
|
const int height = (orientation == Qt::Horizontal ? PropertyRowHeights::defaultHeight
|
|
: sheet->getRowHeight(section));
|
|
return QSize {width, height};
|
|
}
|
|
if (role == Qt::DisplayRole) {
|
|
return (orientation == Qt::Horizontal ? columnLabels.at(section) : rowLabels.at(section));
|
|
}
|
|
return {};
|
|
}
|
|
|
|
void SheetModel::setCellData(QModelIndex index, QString str)
|
|
{
|
|
try {
|
|
CellAddress address(index.row(), index.column());
|
|
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Edit cell"));
|
|
// Because of possible complication of recursively escaped
|
|
// characters, let's take a shortcut and bypass the command
|
|
// interface for now.
|
|
|
|
sheet->setContent(address, str.toUtf8().constData());
|
|
Gui::Command::commitCommand();
|
|
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()");
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
e.reportException();
|
|
Gui::Command::abortCommand();
|
|
}
|
|
}
|
|
|
|
bool SheetModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
|
{
|
|
if (role == Qt::DisplayRole) {
|
|
// Nothing to do, it will get updated by the sheet in the application logic
|
|
}
|
|
else if (role == Qt::EditRole) {
|
|
CellAddress address(index.row(), index.column());
|
|
|
|
QString str = value.toString();
|
|
|
|
// Check to see if this is already the value in the cell, and skip the update if so
|
|
auto cell = sheet->getCell(address);
|
|
if (cell) {
|
|
std::string oldContent;
|
|
cell->getStringContent(oldContent);
|
|
if (str == QString::fromStdString(oldContent)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
QMetaObject::invokeMethod(this,
|
|
"setCellData",
|
|
Qt::QueuedConnection,
|
|
Q_ARG(QModelIndex, index),
|
|
Q_ARG(QString, str));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Qt::ItemFlags SheetModel::flags(const QModelIndex& /*index*/) const
|
|
{
|
|
return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
|
|
}
|
|
|
|
void SheetModel::cellUpdated(CellAddress address)
|
|
{
|
|
QModelIndex i = index(address.row(), address.col());
|
|
|
|
Q_EMIT dataChanged(i, i);
|
|
}
|
|
|
|
void SheetModel::rangeUpdated(const Range& range)
|
|
{
|
|
QModelIndex i = index(range.from().row(), range.from().col());
|
|
QModelIndex j = index(range.to().row(), range.to().col());
|
|
|
|
Q_EMIT dataChanged(i, j);
|
|
}
|
|
|
|
#include "moc_SheetModel.cpp"
|