DataSetTableModel.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/qt/widgets/table/DataSetTableModel.cpp
22 
23  \brief A model based on te::da::DataSet.
24 */
25 
26 // TerraLib
27 #include "../../../common/Exception.h"
28 #include "../../../dataaccess/dataset/DataSet.h"
29 #include "../../../dataaccess/dataset/ObjectIdSet.h"
30 #include "../../../dataaccess/utils/Utils.h"
31 #include "../../../datatype/Enums.h"
32 #include "../../../datatype/SimpleData.h"
33 #include "../../../memory/DataSet.h"
34 #include "../../../memory/DataSetItem.h"
35 #include "../Utils.h"
36 #include "DataSetTableModel.h"
37 #include "Promoter.h"
38 
39 // Qt
40 #include <QIcon>
41 #include <QMessageBox>
42 
43 bool IsPkey(const int& column, const std::vector<size_t>& pkeys)
44 {
45  std::vector<size_t>::const_iterator it;
46 
47  for(it=pkeys.begin(); it!=pkeys.end(); ++it)
48  if(*it == static_cast<size_t>(column))
49  return true;
50 
51  return false;
52 }
53 
54 QString ColumnType(const int& type)
55 {
56 
57  switch(type)
58  {
59  case te::dt::VOID_TYPE:
60  return QObject::tr("Void");
61 
62  case te::dt::BIT_TYPE:
63  return QObject::tr("Bit");
64 
65  case te::dt::CHAR_TYPE:
66  return QObject::tr("Char");
67 
68  case te::dt::UCHAR_TYPE:
69  return QObject::tr("Unsigned char");
70 
71  case te::dt::INT16_TYPE:
72  case te::dt::INT32_TYPE:
73  case te::dt::INT64_TYPE:
74  return QObject::tr("Integer");
75 
79  return QObject::tr("Unsigned integer");
80 
82  return QObject::tr("Boolean");
83 
84  case te::dt::FLOAT_TYPE:
85  return QObject::tr("Float");
86 
88  return QObject::tr("Double");
89 
91  return QObject::tr("Numeric");
92 
94  return QObject::tr("String");
95 
97  return QObject::tr("Byte array");
98 
100  return QObject::tr("Geometry");
101 
103  return QObject::tr("Date time");
104 
105  default:
106  return QObject::tr("Unknown");
107  }
108 }
109 
110 class Editor
111 {
112  public:
113  Editor() = default;
114 
115  void clear()
116  {
117  m_editions.clear();
118  }
119 
120  void setValue(const int& row, const int& column, const std::string& value)
121  {
122  std::pair<int, int> key(row, column);
123  m_editions[key] = value;
124  }
125 
126  bool isEdited(const int& row, const int& column) const
127  {
128  return m_editions.find(std::pair<int, int>(row, column)) != m_editions.end();
129  }
130 
131  std::string getValue(const int& row, const int& column)
132  {
133  return m_editions[std::pair<int, int>(row, column)];
134  }
135 
136  bool hasEditions() const
137  {
138  return !m_editions.empty();
139  }
140 
141  void getEditedDataSet(te::da::DataSet* in, te::mem::DataSet* out, std::vector< std::set<int> >& fields)
142  {
143  std::vector<int> rows;
144 
145  fields = getEditedLists(rows);
146 
147  // Creating the items
148  for(size_t i = 0; i < rows.size(); ++i)
149  {
151  std::set<int> ef = fields[i];
152 
153  in->move(static_cast<size_t>(rows[i]));
154 
155  // For each property
156  for(size_t j = 0; j < in->getNumProperties(); ++j)
157  {
158  bool edited = ef.find(static_cast<int>(j)) != ef.end();
159 
160  if(!edited)
161  item->setValue(j, (in->isNull(j)) ? nullptr : in->getValue(j).release());
162  else
163  {
164  std::string data = getValue(rows[i], static_cast<int>(j));
165 
166  switch(in->getPropertyDataType(j))
167  {
168  case te::dt::INT16_TYPE:
169  item->setValue(j, new te::dt::Int16(static_cast<short>(atoi(data.c_str()))));
170  break;
171 
172  case te::dt::INT32_TYPE:
173  item->setValue(j, new te::dt::Int32(atoi(data.c_str())));
174  break;
175 
176  case te::dt::INT64_TYPE:
177  item->setValue(j, new te::dt::Int64(atoi(data.c_str())));
178  break;
179 
180  case te::dt::FLOAT_TYPE:
181  item->setValue(j, new te::dt::Float(static_cast<float>(atof(data.c_str()))));
182  break;
183 
184  case te::dt::DOUBLE_TYPE:
185  item->setValue(j, new te::dt::Double(atof(data.c_str())));
186  break;
187 
189  item->setValue(j, new te::dt::Numeric(data));
190  break;
191 
192  case te::dt::STRING_TYPE:
193  item->setValue(j, new te::dt::String(data));
194  break;
195 
196  default:
197  break;
198  }
199  }
200  }
201 
202  out->add(item);
203  }
204  }
205 
206  void columnsRemoved(const int& init, const int& final)
207  {
208  for(int i = init; i <= final; i++)
209  columnRemoved(i);
210  }
211 
212  void columnRemoved(const int& column)
213  {
214  std::map< std::pair<int, int>, std::string > aux;
215  std::map< std::pair<int, int>, std::string >::iterator it;
216 
217  for(it = m_editions.begin(); it != m_editions.end(); ++it)
218  {
219  int cE = it->first.second;
220 
221  if(cE == column)
222  continue;
223 
224  std::pair<int, int> rC = it->first;
225 
226  if(rC.second > column)
227  rC.second--;
228 
229  aux[rC] = it->second;
230  }
231 
232  m_editions = aux;
233  }
234 
235  protected:
236 
237  std::vector< std::set<int> > getEditedLists(std::vector<int>& rows)
238  {
239  std::vector< std::set<int> > res;
240 
241  if(!m_editions.empty())
242  {
243  std::set<int> subRes;
244  int current = m_editions.begin()->first.first;
245  rows.push_back(current);
246  std::map< std::pair<int, int>, std::string >::iterator it;
247 
248  for(it=m_editions.begin(); it!= m_editions.end(); ++it)
249  {
250  int cR = it->first.first;
251 
252  if(cR != current)
253  {
254  rows.push_back(cR);
255  res.push_back(subRes);
256  subRes.clear();
257  current = cR;
258  }
259 
260  subRes.insert(it->first.second);
261  }
262 
263  if(rows.size() != res.size())
264  res.push_back(subRes);
265  }
266 
267  return res;
268  }
269 
270  std::map< std::pair<int, int>, std::string > m_editions;
271 };
272 
274  : QAbstractTableModel(parent),
275  m_dataset(nullptr),
276  m_currentRow(-1),
277  m_OIdsVisible(true),
278  m_enabled(true),
279  m_rowCount(0)
280 {
281  m_promoter = new Promoter;
282  m_editor.reset(new Editor);
283 }
284 
286 {
287  delete m_dataset;
288  delete m_promoter;
289 }
290 
292 {
293  beginResetModel();
294 
295  delete m_dataset;
296 
297  m_dataset = dset;
298 
299  if(m_dataset)
300  m_dataset->moveFirst();
301 
302  if(clearEditor)
303  m_editor->clear();
304 
305  m_rowCount = (m_dataset == nullptr || !m_enabled) ? 0 : static_cast<int>(m_dataset->size());
306 
307  endResetModel();
308 }
309 
310 void te::qt::widgets::DataSetTableModel::setPkeysColumns(const std::vector<size_t>& pkeys)
311 {
312  m_pkeysColumns = pkeys;
313 }
314 
316 {
317  beginResetModel();
318 
319  m_promoter->promote(oids);
320 
321  endResetModel();
322 }
323 
325 {
326  return m_promoter;
327 }
328 
330 {
331  m_OIdsVisible = visible;
332 }
333 
335 {
337 
338  // Mounting oidset
339  std::vector<size_t>::iterator it;
340 
341  for(it=m_pkeysColumns.begin(); it!=m_pkeysColumns.end(); ++it)
343 
344  // Loading oid set.
345  size_t row;
346 
347  for(size_t i=static_cast<size_t>(initRow); i<=static_cast<size_t>(finalRow); i++)
348  {
349  row = m_promoter->getLogicalRow(i);
350  m_dataset->move(row);
351 
353  }
354 
355  oids->setExpressionByInClause();
356 
357  return oids;
358 }
359 
361 {
362  beginResetModel();
363 
364  m_enabled = enabled;
365 
366  m_rowCount = (m_enabled && m_dataset != nullptr) ? static_cast<int>(m_dataset->size()) : 0;
367 
368  endResetModel();
369 }
370 
372 {
373  m_isEditable = editable;
374 }
375 
376 std::unique_ptr<te::da::DataSet> te::qt::widgets::DataSetTableModel::getEditions(const te::da::DataSetType *type, std::vector< std::set<int> > &ps)
377 {
378  std::unique_ptr<te::da::DataSet> dset;
379  te::mem::DataSet* md = new te::mem::DataSet(type);
380 
381  m_editor->getEditedDataSet(m_dataset, md, ps);
382 
383  dset.reset(md);
384 
385  return dset;
386 }
387 
389 {
390  return m_editor->hasEditions();
391 }
392 
394 {
395  m_editor->clear();
396 }
397 
398 int te::qt::widgets::DataSetTableModel::rowCount(const QModelIndex & /*parent*/) const
399 {
400  return m_rowCount;
401 }
402 
403 int te::qt::widgets::DataSetTableModel::columnCount(const QModelIndex & /*parent*/) const
404 {
405  return (m_dataset == nullptr) ? 0 : static_cast<int>(m_dataset->getNumProperties());
406 }
407 
408 QVariant te::qt::widgets::DataSetTableModel::data(const QModelIndex & index, int role) const
409 {
410  if(!index.isValid())
411  return QVariant();
412 
413  switch (role)
414  {
415  case Qt::TextAlignmentRole:
416  return (int)(Qt::AlignCenter);
417  break;
418 
419  case Qt::DisplayRole:
420  {
421  if(m_currentRow != index.row())
422  {
423  m_currentRow = index.row();
424 
426  m_dataset->move(row);
427  }
428 
429  if (m_editor->isEdited(static_cast<int>(m_promoter->getLogicalRow(index.row())), index.column()))
430  {
431  std::string value = m_editor->getValue(
432  static_cast<unsigned int>(m_promoter->getLogicalRow(index.row())),
433  index.column());
434 
435  return QString::fromUtf8(value.c_str());
436  }
437 
438  if(m_dataset->isNull(index.column()))
439  return QVariant();
440 
441  if(m_dataset->getPropertyDataType(index.column()) == te::dt::STRING_TYPE)
442  {
443  std::string value = m_dataset->getString(index.column());
444 
445  return QString::fromUtf8(value.c_str());
446  }
447  else
448  return m_dataset->getAsString(index.column(), 6).c_str();
449  }
450  break;
451 
452  case Qt::FontRole:
453  if (m_editor->isEdited(static_cast<int>(m_promoter->getLogicalRow(index.row())), index.column()))
454  {
455  QFont f;
456  f.setBold(true);
457  f.setItalic(true);
458  return f;
459  }
460  break;
461 
462  case Qt::EditRole:
463  return data(index, Qt::DisplayRole);
464  break;
465 
466  default:
467  break;
468  }
469 
470  return QVariant();
471 }
472 
473 QVariant te::qt::widgets::DataSetTableModel::headerData(int section, Qt::Orientation orientation, int role) const
474 {
475  if(orientation == Qt::Horizontal)
476  {
477  switch(role)
478  {
479  case Qt::DisplayRole:
480  return m_dataset->getPropertyName(section).c_str();
481  break;
482 
483  case Qt::DecorationRole:
484  return (m_OIdsVisible && IsPkey(section, m_pkeysColumns)) ?
485  QIcon::fromTheme("key") :
486  QVariant();
487  break;
488 
489  case Qt::ToolTipRole:
490  return m_dataset->getPropertyName(section).c_str() + QString(" : ") + ColumnType(m_dataset->getPropertyDataType(section));
491  break;
492 
493  default:
494  return QAbstractTableModel::headerData(section, orientation, role);
495  break;
496  }
497  }
498  else
499  {
500  switch (role)
501  {
502  case Qt::DisplayRole:
503  return section+1;
504  break;
505 
506  default:
507  return QAbstractTableModel::headerData(section, orientation, role);
508  break;
509  }
510  }
511 
512  return QVariant();
513 }
514 
515 Qt::ItemFlags te::qt::widgets::DataSetTableModel::flags(const QModelIndex & index) const
516 {
517  if (index.isValid() == false)
518  return nullptr;
519 
520  Qt::ItemFlags flags = QAbstractItemModel::flags(index);
521 
522  flags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable;
523 
524  if(m_isEditable && !IsPkey(index.column(), m_pkeysColumns))
525  flags |= Qt::ItemIsEditable;
526 
527  return flags;
528 }
529 
530 bool te::qt::widgets::DataSetTableModel::setData (const QModelIndex & index, const QVariant & value, int role)
531 {
532  if(role == Qt::EditRole)
533  {
534  try
535  {
536  switch(m_dataset->getPropertyDataType(index.column()))
537  {
538  case te::dt::INT16_TYPE:
539  case te::dt::UINT16_TYPE:
540  case te::dt::INT32_TYPE:
541  case te::dt::UINT32_TYPE:
542  case te::dt::INT64_TYPE:
543  case te::dt::UINT64_TYPE:
544  {
545  bool ok;
546  value.toInt(&ok);
547 
548  if(!ok)
549  throw te::common::Exception(tr("Invalid int value.").toUtf8().data());
550  }
551  break;
552 
553  case te::dt::FLOAT_TYPE:
554  case te::dt::DOUBLE_TYPE:
556  {
557  bool ok;
558  value.toDouble(&ok);
559 
560  if(!ok)
561  throw te::common::Exception(tr("Invalid double value.").toUtf8().data());
562  }
563  break;
564  }
565 
566  QString curV = data(index, Qt::DisplayRole).toString();
567  QString newV = value.toString();
568 
569  if(curV != newV)
570  {
571  std::string out = newV.toUtf8().data();
572  m_editor->setValue(static_cast<int>(m_promoter->getLogicalRow(index.row())), index.column(), out);
573  }
574 
575  return true;
576  }
577  catch(te::common::Exception& e)
578  {
579  QMessageBox::warning(nullptr, tr("Edition Failure"), e.what());
580  return false;
581  }
582  }
583 
584  return true;
585 }
586 
587 bool te::qt::widgets::DataSetTableModel::insertColumns(int column, int count, const QModelIndex& parent)
588 {
589  beginInsertColumns(parent, column, column+count);
590 
591  endInsertColumns();
592 
593  return true;
594 }
595 
596 bool te::qt::widgets::DataSetTableModel::removeColumns(int column, int count, const QModelIndex& parent)
597 {
598  beginRemoveColumns(parent, column, column+count);
599 
600  m_editor->columnsRemoved(column, column+count);
601 
602  endRemoveColumns();
603 
604  return true;
605 }
bool hasEditions() const
Returns true if there are unsaved editions.
std::string getValue(const int &row, const int &column)
int rowCount(const QModelIndex &parent) const
void discardEditions()
Discard editions.
A model based on te::da::DataSet.
std::map< std::pair< int, int >, std::string > m_editions
TEDATAACCESSEXPORT ObjectId * GenerateOID(DataSet *dataset, const std::vector< std::string > &names)
QVariant data(const QModelIndex &index, int role) const
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
A class that models the description of a dataset.
Definition: DataSetType.h:72
virtual const char * what() const
It outputs the exception message.
Defines an mechanism for logical ordering of rows.
std::unique_ptr< te::da::DataSet > getEditions(const te::da::DataSetType *type, std::vector< std::set< int > > &ps)
Returns a memory dataset to be saved.
bool removeColumns(int column, int count, const QModelIndex &parent=QModelIndex())
std::vector< size_t > m_pkeysColumns
Primary key columns.
void setPkeysColumns(const std::vector< size_t > &pkeys)
Sets the columns used as pkeys, for presentation purposes.
void setValue(std::size_t i, te::dt::AbstractData *value)
It sets the value of the i-th property.
te::da::ObjectIdSet * getObjectIdSet(const int &initRow, const int &finalRow)
Returns the ObjectIdSet begining with row initRow and ending in finalRow.
virtual ~DataSetTableModel()
Virtual destructor.
int columnCount(const QModelIndex &parent) const
void addProperty(const std::string &name, std::size_t pos, int type)
It adds a property that will be used to generate the unique ids.
Definition: ObjectIdSet.cpp:75
void showOIdsVisible(const bool &visible)
Shows an icon for indentify the columns that are used for identify objects.
void add(DataSetItem *item)
It adds a new item to the dataset and takes its ownership.
virtual bool move(std::size_t i)=0
It moves the dataset internal pointer to a given position.
virtual std::size_t size() const =0
It returns the collection size, if it is known.
Implementation of a random-access dataset class for the TerraLib In-Memory Data Access driver...
void getEditedDataSet(te::da::DataSet *in, te::mem::DataSet *out, std::vector< std::set< int > > &fields)
bool m_OIdsVisible
Oids icon visibility.
virtual int getPropertyDataType(std::size_t i) const =0
It returns the underlying data type of the property at position pos.
This class represents a set of unique ids created in the same context. i.e. from the same data set...
Definition: ObjectIdSet.h:55
bool m_isEditable
Flag that indicates if the model is editable.
void setExpressionByInClause(const std::string source="")
std::unique_ptr< Editor > m_editor
Pointer to editor.
void DataSet()
Qt::ItemFlags flags(const QModelIndex &index) const
std::vector< std::set< int > > getEditedLists(std::vector< int > &rows)
bool IsPkey(const int &column, const std::vector< size_t > &pkeys)
virtual std::string getAsString(std::size_t i, int precision=0) const
Method for retrieving a data value as a string plain representation.
void columnRemoved(const int &column)
void promote(const te::da::ObjectIdSet *oids)
Promotes the rows identified by oids primary keys.
Definition: Promoter.cpp:195
void promote(const te::da::ObjectIdSet *oids)
Promotes the rows identified by oids.
A class used for logical ordering of rows.
Definition: Promoter.h:69
This class is designed to declare objects to be thrown as exceptions by TerraLib. ...
Promoter * m_promoter
Promoter to be used.
bool hasEditions() const
DataSetTableModel(QObject *parent=0)
Constructor.
void columnsRemoved(const int &init, const int &final)
An implementation of the DatasetItem class for the TerraLib In-Memory Data Access driver...
A dataset is the unit of information manipulated by the data access module of TerraLib.
void setEnabled(const bool &enabled)
Enable or disable the dataset presentation.
void setEditable(const bool &editable)
Sets if the model is editable or not.
te::da::DataSet * m_dataset
The dataset being used.
QVariant headerData(int section, Qt::Orientation orientation, int role) const
virtual std::unique_ptr< te::dt::AbstractData > getValue(std::size_t i) const
Method for retrieving any other type of data value stored in the data source.
void setDataSet(te::da::DataSet *dset, const bool &clearEditor=true)
Updates the data being used.
int m_currentRow
An internal row pointer.
bool isEdited(const int &row, const int &column) const
Promoter * getPromoter()
Returns the pointer to the promoter being used.
Editor()=default
const std::vector< std::string > & getPropertyNames() const
It returns the property names used to generated the oids.
size_t getLogicalRow(const size_t &visualRow)
Returns the logical position of the row visualRow.
Definition: Promoter.cpp:185
void add(ObjectId *oid)
It adds an object id to this object id set.
Definition: ObjectIdSet.cpp:83
virtual bool isNull(std::size_t i) const =0
It checks if the attribute value is NULL.
A template for atomic data types (integers, floats, strings and others).
Definition: SimpleData.h:59
void setValue(const int &row, const int &column, const std::string &value)
virtual std::size_t getNumProperties() const =0
It returns the number of properties that composes an item of the dataset.
virtual std::string getPropertyName(std::size_t i) const =0
It returns the property name at position pos.
virtual bool moveFirst()=0
It moves the internal pointer to the first item in the collection.
virtual std::string getString(std::size_t i) const =0
Method for retrieving a string value attribute.
bool insertColumns(int column, int count, const QModelIndex &parent=QModelIndex())
QString ColumnType(const int &type)