All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 "../../../common/CharEncodingConv.h"
29 #include "../../../dataaccess/dataset/DataSet.h"
30 #include "../../../dataaccess/dataset/ObjectIdSet.h"
31 #include "../../../dataaccess/utils/Utils.h"
32 #include "../../../datatype/Enums.h"
33 #include "../../../datatype/SimpleData.h"
34 #include "../../../memory/DataSet.h"
35 #include "../../../memory/DataSetItem.h"
36 #include "../Utils.h"
37 #include "DataSetTableModel.h"
38 #include "Promoter.h"
39 
40 // Qt
41 #include <QIcon>
42 #include <QMessageBox>
43 
44 bool IsPkey(const int& column, const std::vector<size_t>& pkeys)
45 {
46  std::vector<size_t>::const_iterator it;
47 
48  for(it=pkeys.begin(); it!=pkeys.end(); ++it)
49  if(*it == column)
50  return true;
51 
52  return false;
53 }
54 
55 QString ColumnType(const int& type)
56 {
57 
58  switch(type)
59  {
60  case te::dt::VOID_TYPE:
61  return QObject::tr("Void");
62  break;
63 
64  case te::dt::BIT_TYPE:
65  return QObject::tr("Bit");
66  break;
67 
68  case te::dt::CHAR_TYPE:
69  return QObject::tr("Char");
70  break;
71 
72  case te::dt::UCHAR_TYPE:
73  return QObject::tr("Unsigned char");
74  break;
75 
76  case te::dt::INT16_TYPE:
77  case te::dt::INT32_TYPE:
78  case te::dt::INT64_TYPE:
79  return QObject::tr("Integer");
80  break;
81 
85  return QObject::tr("Unsigned integer");
86  break;
87 
89  return QObject::tr("Boolean");
90  break;
91 
92  case te::dt::FLOAT_TYPE:
93  return QObject::tr("Float");
94  break;
95 
97  return QObject::tr("Double");
98  break;
99 
101  return QObject::tr("Numeric");
102  break;
103 
104  case te::dt::STRING_TYPE:
105  return QObject::tr("String");
106  break;
107 
109  return QObject::tr("Byte array");
110  break;
111 
113  return QObject::tr("Geometry");
114  break;
115 
117  return QObject::tr("Date time");
118  break;
119 
120  default:
121  return QObject::tr("Unknown");
122  break;
123  }
124 }
125 
126 class Editor
127 {
128  public:
130  {
131 
132  }
133 
134  void clear()
135  {
136  m_editions.clear();
137  }
138 
139  void setValue(const int& row, const int& column, const std::string& value)
140  {
141  std::pair<int, int> key(row, column);
142  m_editions[key] = value;
143  }
144 
145  bool isEdited(const int& row, const int& column) const
146  {
147  return m_editions.find(std::pair<int, int>(row, column)) != m_editions.end();
148  }
149 
150  std::string getValue(const int& row, const int& column)
151  {
152  return m_editions[std::pair<int, int>(row, column)];
153  }
154 
155  bool hasEditions() const
156  {
157  return !m_editions.empty();
158  }
159 
160  void getEditedDataSet(te::da::DataSet* in, te::mem::DataSet* out, std::vector< std::set<int> >& fields)
161  {
162  std::vector<int> rows;
163 
164  fields = getEditedLists(rows);
165 
166  // Creating the items
167  for(int i = 0; i < (int)rows.size(); ++i)
168  {
170  std::set<int> ef = fields[i];
171 
172  in->move(rows[i]);
173 
174  // For each property
175  for(int j = 0; j < (int) in->getNumProperties(); ++j)
176  {
177  bool edited = ef.find(j) != ef.end();
178 
179  if(!edited)
180  item->setValue(j, (in->isNull(j)) ? 0 : in->getValue(j).release());
181  else
182  {
183  std::string data = getValue(rows[i], j);
184 
185  switch(in->getPropertyDataType(j))
186  {
187  case te::dt::INT16_TYPE:
188  item->setValue(j, new te::dt::Int16(atoi(data.c_str())));
189  break;
190 
191  case te::dt::INT32_TYPE:
192  item->setValue(j, new te::dt::Int32(atoi(data.c_str())));
193  break;
194 
195  case te::dt::INT64_TYPE:
196  item->setValue(j, new te::dt::Int64(atoi(data.c_str())));
197  break;
198 
199  case te::dt::FLOAT_TYPE:
200  item->setValue(j, new te::dt::Float(atof(data.c_str())));
201  break;
202 
203  case te::dt::DOUBLE_TYPE:
204  item->setValue(j, new te::dt::Double(atof(data.c_str())));
205  break;
206 
208  item->setValue(j, new te::dt::Numeric(data));
209  break;
210 
211  case te::dt::STRING_TYPE:
212  item->setValue(j, new te::dt::String(data));
213  break;
214 
215  default:
216  break;
217  }
218  }
219  }
220 
221  out->add(item);
222  }
223  }
224 
225  void columnsRemoved(const int& init, const int& final)
226  {
227  for(int i = init; i <= final; i++)
228  columnRemoved(i);
229  }
230 
231  void columnRemoved(const int& column)
232  {
233  std::map< std::pair<int, int>, std::string > aux;
234  std::map< std::pair<int, int>, std::string >::iterator it;
235 
236  for(it = m_editions.begin(); it != m_editions.end(); ++it)
237  {
238  int cE = it->first.second;
239 
240  if(cE == column)
241  continue;
242 
243  std::pair<int, int> rC = it->first;
244 
245  if(rC.second > column)
246  rC.second--;
247 
248  aux[rC] = it->second;
249  }
250 
251  m_editions = aux;
252  }
253 
254  protected:
255 
256  std::vector< std::set<int> > getEditedLists(std::vector<int>& rows)
257  {
258  std::vector< std::set<int> > res;
259 
260  if(!m_editions.empty())
261  {
262  std::set<int> subRes;
263  int current = m_editions.begin()->first.first;
264  rows.push_back(current);
265  std::map< std::pair<int, int>, std::string >::iterator it;
266 
267  for(it=m_editions.begin(); it!= m_editions.end(); ++it)
268  {
269  int cR = it->first.first;
270 
271  if(cR != current)
272  {
273  rows.push_back(cR);
274  res.push_back(subRes);
275  subRes.clear();
276  current = cR;
277  }
278 
279  subRes.insert(it->first.second);
280  }
281 
282  if(rows.size() != res.size())
283  res.push_back(subRes);
284  }
285 
286  return res;
287  }
288 
289  std::map< std::pair<int, int>, std::string > m_editions;
290 };
291 
293  : QAbstractTableModel(parent),
294  m_dataset(0),
295  m_currentRow(-1),
296  m_OIdsVisible(true),
297  m_enabled(true),
298  m_rowCount(0)
299 {
300  m_promoter = new Promoter;
301  m_editor.reset(new Editor);
302 }
303 
305 {
306  delete m_dataset;
307  delete m_promoter;
308 }
309 
311 {
312  beginResetModel();
313 
314  delete m_dataset;
315 
316  m_dataset = dset;
317 
318  m_encoding = enc;
319 
320  if(m_dataset)
321  m_dataset->moveFirst();
322 
323  if(clearEditor)
324  m_editor->clear();
325 
326  m_rowCount = (m_dataset == 0 || !m_enabled) ? 0 : (int)m_dataset->size();
327 
328  endResetModel();
329 }
330 
331 void te::qt::widgets::DataSetTableModel::setPkeysColumns(const std::vector<size_t>& pkeys)
332 {
333  m_pkeysColumns = pkeys;
334 }
335 
337 {
338  beginResetModel();
339 
340  m_promoter->promote(oids);
341 
342  endResetModel();
343 }
344 
346 {
347  return m_promoter;
348 }
349 
351 {
352  m_OIdsVisible = visible;
353 }
354 
356 {
358 
359  // Mounting oidset
360  std::vector<size_t>::iterator it;
361 
362  for(it=m_pkeysColumns.begin(); it!=m_pkeysColumns.end(); ++it)
363  oids->addProperty(m_dataset->getPropertyName(*it), *it, m_dataset->getPropertyDataType(*it));
364 
365  // Loading oid set.
366  int row;
367 
368  for(int i=initRow; i<=finalRow; i++)
369  {
370  row = (int)m_promoter->getLogicalRow(i);
371  m_dataset->move(row);
372 
373  oids->add(te::da::GenerateOID(m_dataset, oids->getPropertyNames()));
374  }
375 
376  oids->setExpressionByInClause();
377 
378  return oids;
379 }
380 
382 {
383  beginResetModel();
384 
385  m_enabled = enabled;
386 
387  m_rowCount = (m_enabled && m_dataset != 0) ? (int)m_dataset->size() : 0;
388 
389  endResetModel();
390 }
391 
393 {
394  m_isEditable = editable;
395 }
396 
397 std::auto_ptr<te::da::DataSet> te::qt::widgets::DataSetTableModel::getEditions(const te::da::DataSetType *type, std::vector< std::set<int> > &ps)
398 {
399  std::auto_ptr<te::da::DataSet> dset;
400  te::mem::DataSet* md = new te::mem::DataSet(type);
401 
402  m_editor->getEditedDataSet(m_dataset, md, ps);
403 
404  dset.reset(md);
405 
406  return dset;
407 }
408 
410 {
411  return m_editor->hasEditions();
412 }
413 
415 {
416  m_editor->clear();
417 }
418 
419 int te::qt::widgets::DataSetTableModel::rowCount(const QModelIndex & parent) const
420 {
421  return m_rowCount;
422 }
423 
424 int te::qt::widgets::DataSetTableModel::columnCount(const QModelIndex & parent) const
425 {
426  return (m_dataset == 0) ? 0 : (int) m_dataset->getNumProperties();
427 }
428 
429 QVariant te::qt::widgets::DataSetTableModel::data(const QModelIndex & index, int role) const
430 {
431  if(!index.isValid())
432  return QVariant();
433 
434  switch (role)
435  {
436  case Qt::TextAlignmentRole:
437  return (int)(Qt::AlignCenter);
438  break;
439 
440  case Qt::DisplayRole:
441  {
442  if(m_currentRow != index.row())
443  {
444  m_currentRow = index.row();
445 
446  int row = (int)m_promoter->getLogicalRow(m_currentRow);
447  m_dataset->move(row);
448  }
449 
450  if(m_editor->isEdited(m_promoter->getLogicalRow(index.row()), index.column()))
451  {
452  std::string f = m_editor->getValue(m_promoter->getLogicalRow(index.row()), index.column()).c_str();
453 
454  return te::qt::widgets::Convert2Qt(f, m_encoding);
455  }
456 
457  if(m_dataset->isNull(index.column()))
458  return QVariant();
459 
460  if(m_dataset->getPropertyDataType(index.column()) == te::dt::STRING_TYPE)
461  {
462  std::string value = m_dataset->getString(index.column());
463  te::common::CharEncoding encoding = m_dataset->getPropertyCharEncoding(index.column());
464  if (encoding == te::common::UNKNOWN_CHAR_ENCODING)
465  return value.c_str();
466  else
467  return Convert2Qt(value, encoding);
468  }
469  else
470  return m_dataset->getAsString(index.column(), 6).c_str();
471  }
472  break;
473 
474  case Qt::FontRole:
475  if(m_editor->isEdited(m_promoter->getLogicalRow(index.row()), index.column()))
476  {
477  QFont f;
478  f.setBold(true);
479  f.setItalic(true);
480  return f;
481  }
482  break;
483 
484  case Qt::EditRole:
485  return data(index, Qt::DisplayRole);
486  break;
487 
488  default:
489  break;
490  }
491 
492  return QVariant();
493 }
494 
495 QVariant te::qt::widgets::DataSetTableModel::headerData(int section, Qt::Orientation orientation, int role) const
496 {
497  if(orientation == Qt::Horizontal)
498  {
499  switch(role)
500  {
501  case Qt::DisplayRole:
502  return m_dataset->getPropertyName(section).c_str();
503  break;
504 
505  case Qt::DecorationRole:
506  return (m_OIdsVisible && IsPkey(section, m_pkeysColumns)) ?
507  QIcon::fromTheme("key") :
508  QVariant();
509  break;
510 
511  case Qt::ToolTipRole:
512  return m_dataset->getPropertyName(section).c_str() + QString(" : ") + ColumnType(m_dataset->getPropertyDataType(section));
513  break;
514 
515  default:
516  return QAbstractTableModel::headerData(section, orientation, role);
517  break;
518  }
519  }
520  else
521  {
522  switch (role)
523  {
524  case Qt::DisplayRole:
525  return section+1;
526  break;
527 
528  default:
529  return QAbstractTableModel::headerData(section, orientation, role);
530  break;
531  }
532  }
533 
534  return QVariant();
535 }
536 
537 Qt::ItemFlags te::qt::widgets::DataSetTableModel::flags(const QModelIndex & index) const
538 {
539  if (index.isValid() == false)
540  return 0;
541 
542  Qt::ItemFlags flags = QAbstractItemModel::flags(index);
543 
544  flags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable;
545 
546  if(m_isEditable && !IsPkey(index.column(), m_pkeysColumns))
547  flags |= Qt::ItemIsEditable;
548 
549  return flags;
550 }
551 
552 bool te::qt::widgets::DataSetTableModel::setData (const QModelIndex & index, const QVariant & value, int role)
553 {
554  if(role == Qt::EditRole)
555  {
556  try
557  {
558  switch(m_dataset->getPropertyDataType(index.column()))
559  {
560  case te::dt::INT16_TYPE:
561  case te::dt::UINT16_TYPE:
562  case te::dt::INT32_TYPE:
563  case te::dt::UINT32_TYPE:
564  case te::dt::INT64_TYPE:
565  case te::dt::UINT64_TYPE:
566  {
567  bool ok;
568  value.toInt(&ok);
569 
570  if(!ok)
571  throw te::common::Exception(tr("Invalid int value.").toStdString());
572  }
573  break;
574 
575  case te::dt::FLOAT_TYPE:
576  case te::dt::DOUBLE_TYPE:
578  {
579  bool ok;
580  value.toDouble(&ok);
581 
582  if(!ok)
583  throw te::common::Exception(tr("Invalid double value.").toStdString());
584  }
585  break;
586  }
587 
588  QString curV = data(index, Qt::DisplayRole).toString();
589  QString newV = value.toString();
590 
591  if(curV != newV)
592  {
594  std::string out = c.conv(newV.toStdString());
595  m_editor->setValue(m_promoter->getLogicalRow(index.row()), index.column(), out);
596  }
597 
598  return true;
599  }
600  catch(te::common::Exception& e)
601  {
602  QMessageBox::warning(0, tr("Edition Failure"), e.what());
603  return false;
604  }
605  }
606 
607  return true;
608 }
609 
610 bool te::qt::widgets::DataSetTableModel::insertColumns(int column, int count, const QModelIndex& parent)
611 {
612  beginInsertColumns(parent, column, column+count);
613 
614  endInsertColumns();
615 
616  return true;
617 }
618 
619 bool te::qt::widgets::DataSetTableModel::removeColumns(int column, int count, const QModelIndex& parent)
620 {
621  beginRemoveColumns(parent, column, column+count);
622 
623  m_editor->columnsRemoved(column, column+count);
624 
625  endRemoveColumns();
626 
627  return true;
628 }
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.
CharEncoding
Supported charsets (character encoding).
std::map< std::pair< int, int >, std::string > m_editions
TEDATAACCESSEXPORT ObjectId * GenerateOID(DataSet *dataset, const std::vector< std::string > &names)
Definition: Utils.cpp:446
QVariant data(const QModelIndex &index, int role) const
std::auto_ptr< Editor > m_editor
Pointer to editor.
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.
Definition: Exception.cpp:58
Defines an mechanism for logical ordering of rows.
bool removeColumns(int column, int count, const QModelIndex &parent=QModelIndex())
This class deals with character encoding/decoding.
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.
Definition: DataSet.cpp:172
virtual bool move(std::size_t i)=0
It moves the dataset internal pointer to a given position.
Implementation of a random-access dataset class for the TerraLib In-Memory Data Access driver...
Definition: DataSet.h:65
void getEditedDataSet(te::da::DataSet *in, te::mem::DataSet *out, std::vector< std::set< int > > &fields)
This class represents a set of unique ids created in the same context. i.e. from the same data set...
Definition: ObjectIdSet.h:55
virtual bool isNull(std::size_t i) const =0
It checks if the attribute value is NULL.
void setExpressionByInClause(const std::string source="")
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)
std::string conv(const std::string &src)
It converts the source string to a target charset.
void columnRemoved(const int &column)
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
virtual std::size_t getNumProperties() const =0
It returns the number of properties that composes an item of the dataset.
This class is designed to declare objects to be thrown as exceptions by TerraLib. ...
Definition: Exception.h:58
void setDataSet(te::da::DataSet *dset, te::common::CharEncoding enc, const bool &clearEditor=true)
Updates the data being used.
Promoter * m_promoter
Promoter to be used.
std::auto_ptr< te::da::DataSet > getEditions(const te::da::DataSetType *type, std::vector< std::set< int > > &ps)
Returns a memory dataset to be saved.
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...
Definition: DataSetItem.h:56
A dataset is the unit of information manipulated by the data access module of TerraLib.
Definition: DataSet.h:112
void setEnabled(const bool &enabled)
Enable or disable the dataset presentation.
void setEditable(const bool &editable)
Sets if the model is editable or not.
QVariant headerData(int section, Qt::Orientation orientation, int role) const
bool isEdited(const int &row, const int &column) const
Promoter * getPromoter()
Returns the pointer to the promoter being used.
TEQTWIDGETSEXPORT QColor Convert2Qt(const te::color::RGBAColor &color)
It converts a TerraLib Color to Qt Color.
Definition: Utils.cpp:232
const std::vector< std::string > & getPropertyNames() const
It returns the property names used to generated the oids.
void add(ObjectId *oid)
It adds an object id to this object id set.
Definition: ObjectIdSet.cpp:83
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 int getPropertyDataType(std::size_t i) const =0
It returns the underlying data type of the property at position pos.
virtual bool moveFirst()=0
It moves the internal pointer to the first item in the collection.
virtual std::auto_ptr< te::dt::AbstractData > getValue(std::size_t i) const
Method for retrieving any other type of data value stored in the data source.
Definition: DataSet.cpp:151
bool insertColumns(int column, int count, const QModelIndex &parent=QModelIndex())
QString ColumnType(const int &type)