File indexing completed on 2023-10-03 06:50:25
0001 /************************************************************************************* 0002 * Copyright (C) 2007-2009 by Aleix Pol <aleixpol@kde.org> * 0003 * Copyright (C) 2010-2012 by Percy Camilo T. Aucahuasi <percy.camilo.ta@gmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or * 0006 * modify it under the terms of the GNU General Public License * 0007 * as published by the Free Software Foundation; either version 2 * 0008 * of the License, or (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the Free Software * 0017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 0018 *************************************************************************************/ 0019 0020 #include "plotsmodel.h" 0021 0022 #include "plotsfactory.h" 0023 #include "plotitem.h" 0024 0025 #include "analitza/analitzautils.h" 0026 #include <analitza/variables.h> 0027 #include <analitzaplot/functiongraph.h> 0028 0029 #include <QDebug> 0030 #include <QIcon> 0031 #include <QPixmap> 0032 #include <QCoreApplication> 0033 #include <QRandomGenerator> 0034 0035 using namespace Analitza; 0036 0037 PlotsModel::PlotsModel(QObject* parent) 0038 : QAbstractListModel(parent) 0039 , m_resolution(500) 0040 , m_namingCount(0) 0041 {} 0042 0043 PlotsModel::~PlotsModel() 0044 { 0045 clear(); 0046 } 0047 0048 QHash<int, QByteArray> PlotsModel::roleNames() const 0049 { 0050 auto ret = QAbstractListModel::roleNames(); 0051 ret.insert(DescriptionRole, "description"); 0052 return ret; 0053 } 0054 0055 void PlotsModel::clear() 0056 { 0057 if (!m_items.isEmpty()) { 0058 beginRemoveRows(QModelIndex(), 0, m_items.count()-1); 0059 qDeleteAll(m_items); 0060 m_items.clear(); 0061 endRemoveRows(); 0062 } 0063 } 0064 0065 Qt::ItemFlags PlotsModel::flags(const QModelIndex & index) const 0066 { 0067 if(index.isValid()) 0068 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable; 0069 else 0070 return Qt::NoItemFlags; 0071 } 0072 0073 QVariant PlotsModel::headerData(int section, Qt::Orientation orientation, int role) const 0074 { 0075 if(role==Qt::DisplayRole && orientation==Qt::Horizontal) { 0076 switch(section) 0077 { 0078 case 0: return QCoreApplication::translate("@title:column", "Name"); 0079 case 1: return QCoreApplication::translate("@title:column", "Plot"); 0080 } 0081 } 0082 0083 return QAbstractListModel::headerData(section, orientation, role); 0084 } 0085 0086 QVariant PlotsModel::data(const QModelIndex & index, int role) const 0087 { 0088 if(!index.isValid() || index.row()>=m_items.count()) 0089 return QVariant(); 0090 0091 PlotItem *tmpcurve = m_items.at(index.row()); 0092 0093 switch(role) 0094 { 0095 case Qt::DisplayRole: 0096 case Qt::EditRole: 0097 switch(index.column()) 0098 { 0099 case 0: return tmpcurve->name(); 0100 case 1: return tmpcurve->display(); 0101 } 0102 break; 0103 case Qt::DecorationRole: 0104 if(index.column()==0) 0105 { 0106 QPixmap ico(16, 16); 0107 ico.fill(tmpcurve->color()); 0108 return QIcon(ico); 0109 } 0110 else 0111 return QIcon::fromTheme(tmpcurve->iconName()); 0112 case Qt::ToolTipRole: 0113 return tmpcurve->name(); 0114 case Qt::StatusTipRole: 0115 return tmpcurve->typeName(); 0116 case Qt::CheckStateRole: 0117 if(index.column()==0) 0118 return tmpcurve->isVisible() ? Qt::Checked : Qt::Unchecked; 0119 break; 0120 case DimensionRole: 0121 return int(tmpcurve->spaceDimension()); 0122 case PlotRole: 0123 return QVariant::fromValue<PlotItem*>(tmpcurve); 0124 case DescriptionRole: 0125 return tmpcurve->display(); 0126 } 0127 0128 0129 return QVariant(); 0130 } 0131 0132 bool PlotsModel::setData(const QModelIndex& index, const QVariant& value, int role) 0133 { 0134 if (!index.isValid()) 0135 return false; 0136 0137 switch(role) 0138 { 0139 case Qt::EditRole: 0140 switch(index.column()) 0141 { 0142 case 0: { 0143 //FIXME: actually I think the name should be stored in the model instead of plotItem 0144 //if there was another plot with that name, it shouldn't be accepted 0145 QString newName = value.toString(); 0146 if(!newName.isEmpty()) { 0147 m_items[index.row()]->setName(newName); 0148 emit dataChanged(index, index); 0149 } 0150 return !newName.isEmpty(); 0151 } 0152 case 1: { 0153 Analitza::Expression valexp = AnalitzaUtils::variantToExpression(value); 0154 PlotItem* it = m_items[index.row()]; 0155 0156 PlotBuilder plot = PlotsFactory::self()->requestPlot(valexp, it->spaceDimension()); 0157 if (plot.canDraw()) { 0158 if (m_items[index.row()]->expression() != valexp) { 0159 QColor color=it->color(); 0160 QString name=it->name(); 0161 delete m_items[index.row()]; 0162 m_items[index.row()] = plot.create(color, name); 0163 } 0164 0165 emit dataChanged(index, index); 0166 0167 return true; 0168 } 0169 return false; 0170 } 0171 } //fallthrough 0172 case Qt::CheckStateRole: 0173 m_items[index.row()]->setVisible(value.toBool()); 0174 return true; 0175 case Qt::DecorationRole: 0176 m_items[index.row()]->setColor(value.value<QColor>()); 0177 return true; 0178 } 0179 0180 return false; 0181 } 0182 0183 int PlotsModel::rowCount(const QModelIndex & parent) const 0184 { 0185 if(parent.isValid()) 0186 return 0; 0187 else 0188 return m_items.size(); 0189 } 0190 0191 int PlotsModel::columnCount(const QModelIndex& parent) const 0192 { 0193 Q_UNUSED(parent); 0194 return 2; 0195 } 0196 0197 0198 bool PlotsModel::removeRows(int row, int count, const QModelIndex& parent) 0199 { 0200 Q_ASSERT(row<m_items.size()); 0201 if(parent.isValid()) 0202 return false; 0203 0204 beginRemoveRows(QModelIndex(), row, row+count-1); 0205 for (int i = 0; i < count; ++i) { 0206 delete m_items.takeAt(row); 0207 } 0208 endRemoveRows(); 0209 0210 return true; 0211 } 0212 0213 void PlotsModel::addPlot(PlotItem* it) 0214 { 0215 Q_ASSERT(it); 0216 0217 beginInsertRows(QModelIndex(), m_items.count(), m_items.count()); 0218 it->setModel(this); 0219 m_items.append(it); 0220 0221 if(FunctionGraph* g=dynamic_cast<FunctionGraph*>(it)) 0222 g->setResolution(m_resolution); 0223 endInsertRows(); 0224 0225 m_namingCount++; 0226 } 0227 0228 void PlotsModel::updatePlot(int row, PlotItem* it) 0229 { 0230 it->setModel(this); 0231 delete m_items[row]; 0232 m_items[row]=it; 0233 0234 QModelIndex idx = index(row); 0235 emit dataChanged(idx, idx); 0236 } 0237 0238 void PlotsModel::emitChanged(PlotItem* it) 0239 { 0240 int row = m_items.indexOf(it); 0241 QModelIndex idx = index(row); 0242 emit dataChanged(idx, idx); 0243 } 0244 0245 QModelIndex PlotsModel::indexForName(const QString& name) 0246 { 0247 const int rows = rowCount(); 0248 for(int i=0; i<rows; i++) { 0249 QModelIndex idx = index(i); 0250 if(idx.data().toString()==name) 0251 return idx; 0252 } 0253 return QModelIndex(); 0254 } 0255 0256 QString PlotsModel::freeId() const 0257 { 0258 return 'f'+QString::number(m_namingCount); 0259 } 0260 0261 void PlotsModel::setResolution(int res) 0262 { 0263 m_resolution = res; 0264 for(int i=0; i<rowCount(); i++) { 0265 FunctionGraph* g = dynamic_cast<FunctionGraph*>(m_items[i]); 0266 if(g) 0267 g->setResolution(res); 0268 } 0269 } 0270 0271 static QColor randomFunctionColor() { return QColor::fromHsv(QRandomGenerator::global()->bounded(255), 255, 225); } 0272 0273 QStringList PlotsModel::addFunction(const QString& expression, Dimension dim, const QSharedPointer<Analitza::Variables>& vars) 0274 { 0275 Analitza::Expression e(expression, Analitza::Expression::isMathML(expression)); 0276 0277 QString fname; 0278 do { 0279 fname = freeId(); 0280 } while(vars && vars->contains(fname)); 0281 QColor fcolor = randomFunctionColor(); 0282 0283 QStringList err; 0284 PlotBuilder req = PlotsFactory::self()->requestPlot(e, dim, vars); 0285 if(req.canDraw()) { 0286 auto it = req.create(fcolor, fname); 0287 0288 if(it->isCorrect()) 0289 addPlot(it); 0290 else { 0291 err = it->errors(); 0292 delete it; 0293 } 0294 } 0295 0296 return err; 0297 } 0298 0299 bool Analitza::PlotsModel::canAddFunction(const QString& expression, int _dim, const QSharedPointer<Analitza::Variables>& vars) 0300 { 0301 const Analitza::Dimension dim = static_cast<Analitza::Dimension>(_dim); 0302 Analitza::Expression e(expression, Analitza::Expression::isMathML(expression)); 0303 PlotBuilder req = PlotsFactory::self()->requestPlot(e, dim, vars); 0304 return req.canDraw(); 0305 }