1 /***************************************************************************
2  *   This file is part of the Lime Report project                          *
3  *   Copyright (C) 2015 by Alexander Arin                                  *
4  *   arin_a@bk.ru                                                          *
5  *                                                                         *
6  **                   GNU General Public License Usage                    **
7  *                                                                         *
8  *   This library is free software: you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation, either version 3 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *   You should have received a copy of the GNU General Public License     *
13  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
14  *                                                                         *
15  **                  GNU Lesser General Public License                    **
16  *                                                                         *
17  *   This library is free software: you can redistribute it and/or modify  *
18  *   it under the terms of the GNU Lesser General Public License as        *
19  *   published by the Free Software Foundation, either version 3 of the    *
20  *   License, or (at your option) any later version.                       *
21  *   You should have received a copy of the GNU Lesser General Public      *
22  *   License along with this library.                                      *
23  *   If not, see <http://www.gnu.org/licenses/>.                           *
24  *                                                                         *
25  *   This library is distributed in the hope that it will be useful,       *
26  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
27  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
28  *   GNU General Public License for more details.                          *
29  ****************************************************************************/
30 #include "lrdatadesignintf.h"
31 
32 #include <QSqlQueryModel>
33 #include <QSqlRecord>
34 #include <QSqlError>
35 #include <stdexcept>
36 #include <QStringList>
37 #include "lrdatasourcemanager.h"
38 
39 namespace LimeReport{
40 
ModelHolder(QAbstractItemModel * model,bool owned)41 ModelHolder::ModelHolder(QAbstractItemModel *model, bool owned /*false*/)
42 {
43     ModelToDataSource* mh = new ModelToDataSource(model,owned);
44     m_dataSource = mh;
45     m_owned=owned;
46     connect(mh, SIGNAL(modelStateChanged()), this, SIGNAL(modelStateChanged()));
47 }
48 
~ModelHolder()49 ModelHolder::~ModelHolder(){
50     delete m_dataSource;
51 }
52 
dataSource(IDataSource::DatasourceMode mode)53 IDataSource * ModelHolder::dataSource(IDataSource::DatasourceMode mode)
54 {
55     Q_UNUSED(mode);
56     return m_dataSource;
57 }
58 
QueryHolder(QString queryText,QString connectionName,DataSourceManager * dataManager)59 QueryHolder::QueryHolder(QString queryText, QString connectionName, DataSourceManager *dataManager)
60     : m_queryText(queryText), m_connectionName(connectionName),
61       m_mode(IDataSource::RENDER_MODE), m_dataManager(dataManager), m_prepared(true)
62 {
63     extractParams();
64 }
65 
~QueryHolder()66 QueryHolder::~QueryHolder(){}
67 
runQuery(IDataSource::DatasourceMode mode)68 bool QueryHolder::runQuery(IDataSource::DatasourceMode mode)
69 {
70     m_mode = mode;
71 
72     QSqlDatabase db = QSqlDatabase::database(m_connectionName);
73     QSqlQuery query(db);
74 
75     if (!db.isValid()) {
76         setLastError(QObject::tr("Invalid connection! %1").arg(m_connectionName));
77         return false;
78     }
79 
80     extractParams();
81     if (!m_prepared) return false;
82 
83     query.prepare(m_preparedSQL);
84     fillParams(&query);
85     query.exec();
86 
87     QSqlQueryModel *model = new QSqlQueryModel;
88     model->setQuery(query);
89 
90     while (model->canFetchMore())
91         model->fetchMore();
92 
93     if (model->lastError().isValid()){
94         if (m_dataSource)
95            m_dataSource.clear();
96         setLastError(model->lastError().text());
97         delete model;
98         return false;
99     } else { setLastError("");}
100 
101     setDatasource(IDataSource::Ptr(new ModelToDataSource(model,true)));
102     return true;
103 }
104 
connectionName()105 QString QueryHolder::connectionName()
106 {
107     return m_connectionName;
108 }
109 
setConnectionName(QString connectionName)110 void QueryHolder::setConnectionName(QString connectionName)
111 {
112     m_connectionName=connectionName;
113 }
114 
invalidate(IDataSource::DatasourceMode mode,bool dbWillBeClosed)115 void QueryHolder::invalidate(IDataSource::DatasourceMode mode, bool dbWillBeClosed){
116     QSqlDatabase db = QSqlDatabase::database(m_connectionName);
117     if (!db.isValid() || dbWillBeClosed){
118         setLastError(QObject::tr("Invalid connection! %1").arg(m_connectionName));
119         m_dataSource.clear();
120     } else {
121         runQuery(mode);
122     }
123 
124 }
125 
update()126 void QueryHolder::update()
127 {
128     runQuery(m_mode);
129 }
130 
setDatasource(IDataSource::Ptr value)131 void QueryHolder::setDatasource(IDataSource::Ptr value){
132     m_dataSource.clear();
133     m_dataSource=value;
134 }
135 
fillParams(QSqlQuery * query)136 void QueryHolder::fillParams(QSqlQuery *query)
137 {
138     foreach(QString param,m_aliasesToParam.keys()){
139         QVariant value;
140         if (param.contains(".")){
141             value = dataManager()->fieldData(m_aliasesToParam.value(param));
142             param=param.right(param.length()-param.indexOf('.')-1);
143         } else {
144             value = dataManager()->variable(m_aliasesToParam.value(param));
145         }
146         if (value.isValid() || m_mode == IDataSource::DESIGN_MODE)
147             query->bindValue(':'+param,value);
148     }
149 }
150 
extractParams()151 void QueryHolder::extractParams()
152 {
153     m_preparedSQL =  dataManager()->replaceVariables(m_queryText, m_aliasesToParam);
154     m_prepared = true;
155 }
156 
replaceVariables(QString query)157 QString QueryHolder::replaceVariables(QString query)
158 {
159     return dataManager()->replaceVariables(query, m_aliasesToParam);
160 }
161 
queryText()162 QString QueryHolder::queryText()
163 {
164     return m_queryText;
165 }
166 
setQueryText(QString queryText)167 void QueryHolder::setQueryText(QString queryText)
168 {
169     m_queryText=queryText;
170     m_prepared = false;
171 }
172 
dataSource(IDataSource::DatasourceMode mode)173 IDataSource* QueryHolder::dataSource(IDataSource::DatasourceMode mode)
174 {
175     if ((m_mode != mode && m_mode == IDataSource::DESIGN_MODE) || m_dataSource==0) {
176         m_mode = mode;
177         runQuery(mode);
178     }
179     if (m_dataSource)
180         return m_dataSource.data();
181     else return 0;
182 }
183 
184 // QueryHolder
185 
186 // ModelToDataSource
187 
ModelToDataSource(QAbstractItemModel * model,bool owned)188 ModelToDataSource::ModelToDataSource(QAbstractItemModel* model, bool owned)
189     : QObject(), m_model(model), m_owned(owned), m_curRow(-1), m_lastError("")
190 {
191     Q_ASSERT(model);
192     if (model){
193         while (model->canFetchMore(QModelIndex()))
194             model->fetchMore(QModelIndex());
195         connect(model, SIGNAL(destroyed()), this, SLOT(slotModelDestroed()));
196         connect(model, SIGNAL(modelReset()), this, SIGNAL(modelStateChanged()));
197     }
198 }
199 
~ModelToDataSource()200 ModelToDataSource::~ModelToDataSource()
201 {
202     if ((m_owned) && m_model!=0)
203         delete m_model;
204 }
205 
next()206 bool ModelToDataSource::next()
207 {
208     if (isInvalid()) return false;
209     if (m_curRow<(m_model->rowCount())) {
210         if (bof()) m_curRow++;
211         m_curRow++;
212         return true;
213     } else return false;
214 }
215 
hasNext()216 bool ModelToDataSource::hasNext()
217 {
218     if (isInvalid()) return false;
219     return m_curRow<m_model->rowCount()-1;
220 }
221 
prior()222 bool ModelToDataSource::prior()
223 {
224     if (isInvalid()) return false;
225     if (m_curRow>-1){
226         if (eof()) m_curRow--;
227         m_curRow--;
228         return true;
229     } else return false;
230 }
231 
first()232 void ModelToDataSource::first()
233 {
234     m_curRow=0;
235 }
236 
last()237 void ModelToDataSource::last()
238 {
239     if (isInvalid()) m_curRow=0;
240     else m_curRow=m_model->rowCount()-1;
241 }
242 
eof()243 bool ModelToDataSource::eof()
244 {
245     if (isInvalid()) return true;
246     return (m_curRow==m_model->rowCount())||(m_model->rowCount()==0);
247 }
248 
bof()249 bool ModelToDataSource::bof()
250 {
251     if (isInvalid()) return true;
252     return (m_curRow==-1)||(m_model->rowCount()==0);
253 }
254 
data(const QString & columnName)255 QVariant ModelToDataSource::data(const QString &columnName)
256 {
257     if (isInvalid()) return QVariant();
258     return m_model->data(m_model->index(currentRow(),columnIndexByName(columnName)));
259 }
260 
dataByRowIndex(const QString & columnName,int rowIndex)261 QVariant ModelToDataSource::dataByRowIndex(const QString &columnName, int rowIndex)
262 {
263     if (m_model->rowCount() > rowIndex)
264         return m_model->data(m_model->index(rowIndex, columnIndexByName(columnName)));
265     return QVariant();
266 }
267 
dataByKeyField(const QString & columnName,const QString & keyColumnName,QVariant keyData)268 QVariant ModelToDataSource::dataByKeyField(const QString& columnName, const QString& keyColumnName, QVariant keyData)
269 {
270    for( int i=0; i < m_model->rowCount(); ++i ){
271       if (m_model->data(m_model->index(i, columnIndexByName(keyColumnName))) == keyData){
272           return m_model->data(m_model->index(i, columnIndexByName(columnName)));
273       }
274    }
275    return QVariant();
276 }
277 
columnCount()278 int ModelToDataSource::columnCount()
279 {
280     if (isInvalid()) return 0;
281     return m_model->columnCount();
282 }
283 
columnNameByIndex(int columnIndex)284 QString ModelToDataSource::columnNameByIndex(int columnIndex)
285 {
286     if (isInvalid()) return "";
287     QString result = m_model->headerData(columnIndex,Qt::Horizontal, Qt::UserRole).isValid()?
288                      m_model->headerData(columnIndex,Qt::Horizontal, Qt::UserRole).toString():
289                      m_model->headerData(columnIndex,Qt::Horizontal).toString();
290     return  result;
291 }
292 
columnIndexByName(QString name)293 int ModelToDataSource::columnIndexByName(QString name)
294 {
295     if (isInvalid()) return 0;
296     for(int i=0;i<m_model->columnCount();i++){
297         QString columnName = m_model->headerData(i,Qt::Horizontal, Qt::UserRole).isValid()?
298                     m_model->headerData(i,Qt::Horizontal, Qt::UserRole).toString():
299                     m_model->headerData(i,Qt::Horizontal).toString();
300         if (columnName.compare(name,Qt::CaseInsensitive)==0)
301             return i;
302     }
303     return -1;
304 }
305 
lastError()306 QString ModelToDataSource::lastError()
307 {
308     return m_lastError;
309 }
310 
model()311 QAbstractItemModel * ModelToDataSource::model()
312 {
313     return m_model;
314 }
315 
currentRow()316 int ModelToDataSource::currentRow()
317 {
318     if (eof()) return m_curRow-1;
319     if (bof()) return m_curRow+1;
320     return m_curRow;
321 }
322 
isInvalid() const323 bool ModelToDataSource::isInvalid() const
324 {
325     return m_model==0;
326 }
327 
slotModelDestroed()328 void ModelToDataSource::slotModelDestroed()
329 {
330     m_model = 0;
331     m_lastError = tr("model is destroyed");
332     emit modelStateChanged();
333 }
334 
ConnectionDesc(QSqlDatabase db,QObject * parent)335 ConnectionDesc::ConnectionDesc(QSqlDatabase db, QObject *parent)
336     : QObject(parent), m_connectionName(db.connectionName()), m_connectionHost(db.hostName()), m_connectionDriver(db.driverName()),
337       m_databaseName(db.databaseName()), m_user(db.userName()), m_password(db.password()), m_port(-1), m_autoconnect(false),
338       m_internal(false), m_keepDBCredentials(true)
339 {}
340 
ConnectionDesc(QObject * parent)341 ConnectionDesc::ConnectionDesc(QObject *parent)
342     :QObject(parent),m_connectionName(""),m_connectionHost(""), m_connectionDriver(""),
343       m_databaseName(""), m_user(""), m_password(""), m_port(-1), m_autoconnect(false),
344       m_internal(false), m_keepDBCredentials(true)
345 {}
346 
create(QSqlDatabase db,QObject * parent)347 ConnectionDesc::Ptr ConnectionDesc::create(QSqlDatabase db, QObject *parent)
348 {
349     return Ptr(new ConnectionDesc(db,parent));
350 }
351 
setName(const QString & value)352 void ConnectionDesc::setName(const QString &value)
353 {
354     if (m_connectionName!=value) emit nameChanged(m_connectionName,value);
355     m_connectionName=value;
356 }
357 
isEqual(const QSqlDatabase & db)358 bool ConnectionDesc::isEqual(const QSqlDatabase &db)
359 {
360     return (db.databaseName() == m_databaseName) &&
361            (db.driverName() == m_connectionDriver) &&
362            (db.hostName() == m_connectionHost) &&
363            (db.connectionName() == m_connectionName) &&
364            (db.userName() == m_user) &&
365             (db.password() == m_password);
366 }
367 
connectionNameForUser(const QString & connectionName)368 QString ConnectionDesc::connectionNameForUser(const QString &connectionName)
369 {
370     return connectionName.compare(QSqlDatabase::defaultConnection) == 0 ? tr("defaultConnection") : connectionName;
371 }
372 
connectionNameForReport(const QString & connectionName)373 QString ConnectionDesc::connectionNameForReport(const QString &connectionName)
374 {
375     return connectionName.compare(tr("defaultConnection")) == 0 ? QSqlDatabase::defaultConnection : connectionName;
376 }
377 
port() const378 int ConnectionDesc::port() const
379 {
380     return m_port;
381 }
382 
setPort(int port)383 void ConnectionDesc::setPort(int port)
384 {
385     m_port = port;
386 }
387 
keepDBCredentials() const388 bool ConnectionDesc::keepDBCredentials() const
389 {
390     return m_keepDBCredentials;
391 }
392 
setKeepDBCredentials(bool keepDBCredentals)393 void ConnectionDesc::setKeepDBCredentials(bool keepDBCredentals)
394 {
395     m_keepDBCredentials = keepDBCredentals;
396 }
397 
QueryDesc(QString queryName,QString queryText,QString connection)398 QueryDesc::QueryDesc(QString queryName, QString queryText, QString connection)
399     :m_queryName(queryName), m_queryText(queryText), m_connectionName(connection)
400 {}
401 
SubQueryHolder(QString queryText,QString connectionName,QString masterDatasource,DataSourceManager * dataManager)402 SubQueryHolder::SubQueryHolder(QString queryText, QString connectionName, QString masterDatasource, DataSourceManager* dataManager)
403     : QueryHolder(queryText, connectionName, dataManager), m_masterDatasource(masterDatasource)/*, m_invalid(false)*/
404 {
405     extractParams();
406 }
407 
setMasterDatasource(const QString & value)408 void SubQueryHolder::setMasterDatasource(const QString &value)
409 {
410     if (dataManager()->dataSource(value)){
411         m_masterDatasource = value;
412     }
413 }
414 
extractParams()415 void SubQueryHolder::extractParams()
416 {
417     if (!dataManager()->containsDatasource(m_masterDatasource)){
418         setLastError(QObject::tr("Master datasource \"%1\" not found!").arg(m_masterDatasource));
419         setPrepared(false);
420     } else {
421         m_preparedSQL = replaceFields(replaceVariables(queryText()));
422         setPrepared(true);
423     }
424 }
425 
extractField(QString source)426 QString SubQueryHolder::extractField(QString source)
427 {
428     if (source.contains('.')) {
429         return source.right(source.length()-(source.indexOf('.')+1));
430     }
431     return source;
432 }
433 
replaceFields(QString query)434 QString SubQueryHolder::replaceFields(QString query)
435 {
436     return dataManager()->replaceFields(query, m_aliasesToParam);
437 }
438 
SubQueryDesc(QString queryName,QString queryText,QString connection,QString masterDatasourceName)439 SubQueryDesc::SubQueryDesc(QString queryName, QString queryText, QString connection, QString masterDatasourceName)
440     :QueryDesc(queryName,queryText,connection), m_masterDatasourceName(masterDatasourceName)
441 {
442 }
443 
createElement(const QString & collectionName,const QString &)444 QObject *ProxyDesc::createElement(const QString &collectionName, const QString &)
445 {
446     if (collectionName=="fields"){
447         FieldMapDesc* fieldMapDesc = new FieldMapDesc;
448         m_maps.append(fieldMapDesc);
449         return fieldMapDesc;
450     }
451     return 0;
452 }
453 
elementsCount(const QString & collectionName)454 int ProxyDesc::elementsCount(const QString &collectionName)
455 {
456     Q_UNUSED(collectionName)
457     return m_maps.count();
458 }
459 
elementAt(const QString & collectionName,int index)460 QObject *ProxyDesc::elementAt(const QString &collectionName, int index)
461 {
462     Q_UNUSED(collectionName)
463     return m_maps.at(index);
464 }
465 
ProxyHolder(ProxyDesc * desc,DataSourceManager * dataManager)466 ProxyHolder::ProxyHolder(ProxyDesc* desc, DataSourceManager* dataManager)
467     :m_model(0), m_desc(desc), m_lastError(""), m_mode(IDataSource::RENDER_MODE),
468      m_invalid(false), m_dataManager(dataManager)
469 {}
470 
masterDatasource()471 QString ProxyHolder::masterDatasource()
472 {
473     if (m_desc) return m_desc->master();
474     return QString();
475 }
476 
filterModel()477 void ProxyHolder::filterModel()
478 {
479     if (!m_datasource){
480 
481         if (dataManager()){
482             IDataSource* master = dataManager()->dataSource(m_desc->master());
483             IDataSource* child = dataManager()->dataSource(m_desc->child());
484             if (master&&child){
485                 m_model = new MasterDetailProxyModel(dataManager());
486                 connect(child->model(),SIGNAL(destroyed()), this, SLOT(slotChildModelDestoroyed()));
487                 m_model->setSourceModel(child->model());
488                 m_model->setMaster(m_desc->master());
489                 m_model->setChildName(m_desc->child());
490                 m_model->setFieldsMap(m_desc->fieldsMap());
491                 try{
492                     m_model->rowCount();
493                     m_datasource = IDataSource::Ptr(new ModelToDataSource(m_model,true));
494                 } catch (ReportError& exception) {
495                     m_lastError = exception.what();
496                 }
497                 m_invalid = false;
498                 m_lastError.clear();
499             } else {
500                 m_lastError.clear();
501                 if(!master) m_lastError+=QObject::tr("Master datasouce \"%1\" not found!").arg(m_desc->master());
502                 if(!child) m_lastError+=((m_lastError.isEmpty())?QObject::tr("Child"):QObject::tr(" and child "))+
503                                           QObject::tr("datasouce \"%1\" not found!").arg(m_desc->child());
504             }
505         }
506     } else {
507         if (!isInvalid()){
508             m_model->invalidate();
509             m_datasource->first();
510         }
511     }
512 }
513 
dataSource(IDataSource::DatasourceMode mode)514 IDataSource *ProxyHolder::dataSource(IDataSource::DatasourceMode mode)
515 {
516     if ((m_mode != mode && m_mode == IDataSource::DESIGN_MODE) || m_datasource==0) {
517         m_mode = mode;
518         m_datasource.clear();
519         filterModel();
520     }
521     return m_datasource.data();
522 }
523 
invalidate(IDataSource::DatasourceMode mode,bool dbWillBeClosed)524 void ProxyHolder::invalidate(IDataSource::DatasourceMode mode, bool dbWillBeClosed)
525 {
526     Q_UNUSED(mode)
527     Q_UNUSED(dbWillBeClosed);
528     if (m_model && m_model->isInvalid()){
529         m_invalid = true;
530         m_lastError = tr("Datasource has been invalidated");
531     } else {
532         filterModel();
533     }
534 }
535 
slotChildModelDestoroyed()536 void ProxyHolder::slotChildModelDestoroyed(){
537     m_datasource.clear();
538     m_model = 0;
539 }
540 
addFieldsCorrelation(const FieldsCorrelation & fieldsCorrelation)541 void ProxyDesc::addFieldsCorrelation(const FieldsCorrelation& fieldsCorrelation)
542 {
543     m_maps.append(new FieldMapDesc(fieldsCorrelation));
544 }
545 
setMaster(QString name)546 void MasterDetailProxyModel::setMaster(QString name){
547     m_masterName=name;
548 }
549 
isInvalid() const550 bool MasterDetailProxyModel::isInvalid() const
551 {
552     if (m_masterName.isEmpty() || m_childName.isEmpty()) return true;
553     IDataSource* masterData = dataManager()->dataSource(m_masterName);
554     IDataSource* childData = dataManager()->dataSource(m_childName);
555     if (!masterData || !childData) return true;
556     return masterData->isInvalid() || childData->isInvalid();
557 }
558 
filterAcceptsRow(int source_row,const QModelIndex & source_parent) const559 bool MasterDetailProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
560 {
561     Q_UNUSED(source_parent)
562     foreach (FieldMapDesc* fieldCorrelation, *m_maps) {
563         QVariant master = masterData(fieldCorrelation->master());
564         QVariant detail = sourceData(fieldCorrelation->detail(),source_row);
565         if (master==detail)
566             return true;
567     }
568     return false;
569 }
570 
fieldIndexByName(QString fieldName) const571 int MasterDetailProxyModel::fieldIndexByName(QString fieldName) const
572 {
573     for(int i=0;i<sourceModel()->columnCount();++i){
574         QString sourceFieldName = sourceModel()->headerData(i,Qt::Horizontal,Qt::UserRole).isValid()?
575                             sourceModel()->headerData(i,Qt::Horizontal,Qt::UserRole).toString():
576                             sourceModel()->headerData(i,Qt::Horizontal).toString();
577         if (sourceFieldName.compare(fieldName,Qt::CaseInsensitive)==0){
578            return i;
579         }
580     }
581     return -1;
582 }
583 
sourceData(QString fieldName,int row) const584 QVariant MasterDetailProxyModel::sourceData(QString fieldName, int row) const
585 {
586     int fieldIndex = fieldIndexByName(fieldName);
587     if (fieldIndex!=-1){
588         return sourceModel()->index(row,fieldIndex).data();
589     } else {
590         throw ReportError(
591             tr("Field: \"%1\" not found in \"%2\" child datasource").arg(fieldName).arg(m_childName)
592         );
593     }
594 }
595 
masterData(QString fieldName) const596 QVariant MasterDetailProxyModel::masterData(QString fieldName) const
597 {
598     IDataSource* master = dataManager()->dataSource(m_masterName);
599     if (master){
600         int columnIndex = master->columnIndexByName(fieldName);
601         if (columnIndex!=-1){
602             return master->data(fieldName);
603         } else {
604             throw ReportError(
605                 tr("Field: \"%1\" not found in \"%2\" master datasource").arg(fieldName).arg(m_masterName)
606             );
607         }
608     }
609     return QVariant();
610 }
611 
next()612 bool CallbackDatasource::next(){
613     if (!m_eof){
614         bool nextRowExists = checkNextRecord(m_currentRow);
615         if (m_currentRow>-1){
616             if (!m_getDataFromCache && nextRowExists){
617                 for (int i = 0; i < m_columnCount; ++i ){
618                     m_valuesCache[columnNameByIndex(i)] = data(columnNameByIndex(i));
619                 }
620 
621             }
622         }
623         if (!nextRowExists){
624             m_eof = true;
625             return false;
626         }
627         m_currentRow++;
628         bool result = true;
629         if (!m_getDataFromCache)
630             emit changePos(CallbackInfo::Next,result);
631         m_getDataFromCache = false;
632         if (m_rowCount != -1){
633             if (m_rowCount > 0 && m_currentRow < m_rowCount){
634                 m_eof = false;
635             } else {
636                 m_eof = true;
637             }
638             return !m_eof;
639         } else {
640             m_eof = !result;
641             return result;
642         }
643     } else return false;
644 }
645 
prior()646 bool CallbackDatasource::prior(){
647      if (m_currentRow !=-1) {
648         if (!m_getDataFromCache && !m_valuesCache.isEmpty()){
649             m_getDataFromCache = true;
650             m_currentRow--;
651             m_eof = false;
652             return true;
653         } else {
654             return false;
655         }
656      } else {
657          return false;
658      }
659 }
660 
first()661 void CallbackDatasource::first(){
662     m_currentRow = 0;
663     m_getDataFromCache = false;
664     m_eof=checkIfEmpty();
665     bool result=false;
666 
667     QVariant rowCount;
668     CallbackInfo info;
669     info.dataType = CallbackInfo::RowCount;
670     emit getCallbackData(info,rowCount);
671     if (rowCount.isValid()) m_rowCount = rowCount.toInt();
672 
673     emit changePos(CallbackInfo::First,result);
674     if (m_rowCount>0) m_eof = false;
675     else m_eof = !result;
676 }
677 
callbackData(const QString & columnName,int row)678 QVariant CallbackDatasource::callbackData(const QString& columnName, int row)
679 {
680     CallbackInfo info;
681     QVariant result;
682     info.dataType = CallbackInfo::ColumnData;
683     info.columnName = columnName;
684     info.index = row;
685     emit getCallbackData(info, result);
686     return result;
687 }
688 
data(const QString & columnName)689 QVariant CallbackDatasource::data(const QString& columnName)
690 {
691     QVariant result;
692     if (!bof())
693     {
694         if (!m_getDataFromCache){
695             result = callbackData(columnName, m_currentRow);
696         } else {
697             result = m_valuesCache[columnName];
698         }
699     }
700     return result;
701 }
702 
dataByRowIndex(const QString & columnName,int rowIndex)703 QVariant CallbackDatasource::dataByRowIndex(const QString &columnName, int rowIndex)
704 {
705     int backupCurrentRow = m_currentRow;
706     QVariant result = QVariant();
707     first();
708     for (int i = 0; i < rowIndex && !eof(); ++i, next()){}
709     if (!eof()) result = callbackData(columnName, rowIndex);
710     first();
711     if (backupCurrentRow != -1){
712         for (int i = 0; i < backupCurrentRow; ++i)
713             next();
714     }
715     return result;
716 }
717 
dataByKeyField(const QString & columnName,const QString & keyColumnName,QVariant keyData)718 QVariant CallbackDatasource::dataByKeyField(const QString& columnName, const QString& keyColumnName, QVariant keyData)
719 {
720     int backupCurrentRow = m_currentRow;
721     QVariant result = QVariant();
722 
723     m_currentRow = m_lastKeyRow;
724     if (next()){
725         for (int i = 0; i < 10; ++i){
726             QVariant key = callbackData(keyColumnName, m_currentRow);
727             if (key == keyData){
728                 result = callbackData(columnName, m_currentRow);
729                 m_lastKeyRow = m_currentRow;
730                 m_currentRow = backupCurrentRow;
731                 return result;
732             }
733             if (!next()) break;
734         }
735     }
736 
737     first();
738     if (!checkIfEmpty()){
739         do {
740             QVariant key = callbackData(keyColumnName, m_currentRow);
741             if (key == keyData){
742                 result = callbackData(columnName, m_currentRow);
743                 m_lastKeyRow = m_currentRow;
744                 m_currentRow = backupCurrentRow;
745                 return result;
746             }
747         } while (next());
748     }
749 
750     m_currentRow = backupCurrentRow;
751     return result;
752 }
753 
columnCount()754 int CallbackDatasource::columnCount(){
755     CallbackInfo info;
756     if (m_columnCount == -1){
757         QVariant columnCount;
758         info.dataType = CallbackInfo::ColumnCount;
759         emit getCallbackData(info,columnCount);
760         if (columnCount.isValid()){
761             m_columnCount = columnCount.toInt();
762         }
763         if (m_columnCount != -1){
764             for(int i=0;i<m_columnCount;++i) {
765                 QVariant columnName;
766                 info.dataType = CallbackInfo::ColumnHeaderData;
767                 info.index = i;
768                 emit getCallbackData(info,columnName);
769                 if (columnName.isValid())
770                     m_headers.append(columnName.toString());
771             }
772         } else {
773             int currIndex = 0;
774             do {
775                 QVariant columnName;
776                 info.dataType = CallbackInfo::ColumnHeaderData;
777                 info.index = currIndex;
778                 emit getCallbackData(info,columnName);
779                 if (columnName.isValid()){
780                     m_headers.append(columnName.toString());
781                     currIndex++;
782                 } else break;
783             } while (true);
784         }
785     }
786     if (m_headers.size()>0) m_columnCount = m_headers.size();
787     return m_columnCount;
788 }
789 
columnNameByIndex(int columnIndex)790 QString CallbackDatasource::columnNameByIndex(int columnIndex)
791 {
792     if (columnIndex < m_headers.size())
793         return m_headers[columnIndex];
794     else return QString();
795 }
796 
columnIndexByName(QString name)797 int CallbackDatasource::columnIndexByName(QString name)
798 {
799     for (int i=0;i<m_headers.size();++i) {
800         if (m_headers[i].compare(name, Qt::CaseInsensitive) == 0)
801             return i;
802     }
803 //    if (m_headers.size()==0){
804 //        QVariant data;
805 //        bool hasNextRow;
806 //        emit getData(m_currentRow, name, data, hasNextRow);
807 //        if (data.isValid()) return 0;
808 //    }
809     return -1;
810 }
811 
checkNextRecord(int recordNum)812 bool CallbackDatasource::checkNextRecord(int recordNum){
813     if (bof()) checkIfEmpty();
814     if (m_rowCount > 0) {
815         return (recordNum < (m_rowCount-1));
816     } else {
817         QVariant result = false;
818         CallbackInfo info;
819         info.dataType = CallbackInfo::HasNext;
820         info.index = recordNum;
821         emit getCallbackData(info,result);
822         return result.toBool();
823     }
824 }
825 
checkIfEmpty()826 bool CallbackDatasource::checkIfEmpty(){
827     if (m_rowCount == 0) {
828         return true;
829     } else {
830         QVariant isEmpty = true;
831         QVariant recordCount = 0;
832         CallbackInfo info;
833         info.dataType = CallbackInfo::RowCount;
834         emit getCallbackData(info, recordCount);
835         if (recordCount.toInt()>0) {
836             m_rowCount = recordCount.toInt();
837             return false;
838         }
839         info.dataType = CallbackInfo::IsEmpty;
840         emit getCallbackData(info,isEmpty);
841         return isEmpty.toBool();
842     }
843 }
844 
name() const845 QString CSVDesc::name() const
846 {
847     return m_csvName;
848 }
849 
setName(const QString & csvName)850 void CSVDesc::setName(const QString &csvName)
851 {
852     m_csvName = csvName;
853 }
854 
csvText() const855 QString CSVDesc::csvText() const
856 {
857     return m_csvText;
858 }
859 
setCsvText(const QString & csvText)860 void CSVDesc::setCsvText(const QString &csvText)
861 {
862     m_csvText = csvText;
863     emit cvsTextChanged(m_csvName, m_csvText);
864 }
865 
separator() const866 QString CSVDesc::separator() const
867 {
868     return m_separator;
869 }
870 
setSeparator(const QString & separator)871 void CSVDesc::setSeparator(const QString &separator)
872 {
873     m_separator = separator;
874 }
875 
firstRowIsHeader() const876 bool CSVDesc::firstRowIsHeader() const
877 {
878     return m_firstRowIsHeader;
879 }
880 
setFirstRowIsHeader(bool firstRowIsHeader)881 void CSVDesc::setFirstRowIsHeader(bool firstRowIsHeader)
882 {
883     m_firstRowIsHeader = firstRowIsHeader;
884 }
885 
updateModel()886 void CSVHolder::updateModel()
887 {
888     m_model.clear();
889     QString sep = (separator().compare("\\t") == 0) ? "\t" : separator();
890     bool firstRow = true;
891     QList<QStandardItem*> columns;
892     QStringList headers;
893     foreach(QString line, m_csvText.split('\n')){
894         columns.clear();
895         foreach(QString item, line.split(sep)){
896             columns.append(new QStandardItem(item));
897             if (firstRow && m_firstRowIsHeader) headers.append(item);
898         }
899 
900         if (firstRow){
901             if (!headers.isEmpty()){
902                 m_model.setHorizontalHeaderLabels(headers);
903                 firstRow = false;
904             } else {
905                 m_model.appendRow(columns);
906             }
907         } else {
908             m_model.appendRow(columns);
909         }
910 
911     }
912 
913 
914 }
915 
firsRowIsHeader() const916 bool CSVHolder::firsRowIsHeader() const
917 {
918     return m_firstRowIsHeader;
919 }
920 
setFirsRowIsHeader(bool firstRowIsHeader)921 void CSVHolder::setFirsRowIsHeader(bool firstRowIsHeader)
922 {
923     m_firstRowIsHeader = firstRowIsHeader;
924 }
925 
CSVHolder(const CSVDesc & desc,DataSourceManager * dataManager)926 CSVHolder::CSVHolder(const CSVDesc &desc, DataSourceManager *dataManager)
927     : m_csvText(desc.csvText()),
928       m_separator(desc.separator()),
929       m_dataManager(dataManager),
930       m_firstRowIsHeader(desc.firstRowIsHeader())
931 {
932     m_dataSource = IDataSource::Ptr(new ModelToDataSource(&m_model, false));
933     updateModel();
934 }
935 
setCSVText(QString csvText)936 void CSVHolder::setCSVText(QString csvText)
937 {
938     m_csvText = csvText;
939     updateModel();
940 }
941 
separator() const942 QString CSVHolder::separator() const
943 {
944     return m_separator;
945 }
946 
setSeparator(const QString & separator)947 void CSVHolder::setSeparator(const QString &separator)
948 {
949     m_separator = separator;
950     updateModel();
951 }
952 
dataSource(IDataSource::DatasourceMode mode)953 IDataSource *CSVHolder::dataSource(IDataSource::DatasourceMode mode)
954 {
955     Q_UNUSED(mode);
956     return m_dataSource.data();
957 }
958 
959 } //namespace LimeReport
960