ConfigDataTableModel.cpp
Go to the documentation of this file.
1 #include <DatabaseUtils/GUI/ConfigDataTableModel.h>
2 #include <DatabaseUtils/DAQConfig/DBColumnParams.h>
3 #include <DatabaseUtils/DAQConfig/DBColumnUtils.h>
4 #include <DatabaseUtils/DAQConfig/NamedConfigUtils.h>
5 #include <DatabaseUtils/SimpleParameterSet.h>
6 #include <NovaDAQUtilities/EnvVarCache.h>
7 #include <NovaDAQUtilities/HexUtils.h>
8 #include <NovaDAQUtilities/EnvVarCache.h>
9 #include <QtGui/QtGui>
10 #include <boost/lexical_cast.hpp>
11 #include <boost/algorithm/string.hpp>
12 #include <iomanip>
13 
14 // ************************************************************
15 // PLEASE NOTE that this class is very specific to the DAQ configuration
16 // system. In particular, it assumes that the configuration data that it
17 // will be used with A) will not use inheritance and B) will allow
18 // multiple rows per named subsystem configuration.
19 // ************************************************************
20 
21 namespace NOVADB = nova::database;
22 using namespace dbutils::daqconfig;
23 
24 namespace dbutils {
25 namespace gui {
26 
27 // ************************************************************
28 // constructor/destructor
29 // ************************************************************
30 
31 ConfigDataTableModel::
32 ConfigDataTableModel(const std::string& tableDefinitionFileName,
33  QObject *parent)
34  : QAbstractItemModel(parent)
35 {
36  _dbTablePtr.reset(new NOVADB::Table(tableDefinitionFileName.c_str()));
38  novadaq::EnvVarCache::getInstance().getEnvVar("NOVADAQ_ENVIRONMENT");
39  _dbTablePtr->SetDetector(detName);
40 
41  std::string dbUser =
42  novadaq::EnvVarCache::getInstance().getEnvVar("CFGMGR_DB_USER");
43  if (dbUser.length() > 0) {
44  _dbTablePtr->SetUser(dbUser);
45  }
46 }
47 
48 
49 // ************************************************************
50 // the following methods do *not* have implementations in
51 // QAbstractItemModel, so they need to be implemented here
52 // (or in subclasses)
53 // ************************************************************
54 
55 int ConfigDataTableModel::columnCount(const QModelIndex & /* parent */) const
56 {
57  return _rootItem->columnCount();
58 }
59 
60 QVariant ConfigDataTableModel::data(const QModelIndex &index, int role) const
61 {
62  if (!index.isValid()) {return QVariant();}
63  //std::cout << "Role = " << role << std::endl;
64 
65  if (role == Qt::BackgroundRole) {
66  TreeItem *item = _getItem(index);
67  if (item->isDirty() || item->isNew()) {
68  QColor yellow("yellow");
69  QBrush brush(yellow);
70  return brush;
71  }
72  }
73 
74  if (role != Qt::DisplayRole && role != Qt::EditRole)
75  return QVariant();
76 
77  TreeItem *item = _getItem(index);
78 
79  return item->data(index.column());
80 }
81 
82 QModelIndex ConfigDataTableModel::index(int row, int column,
83  const QModelIndex &parent) const
84 {
85  if (parent.isValid() && parent.column() != 0) {
86  return QModelIndex();
87  }
88 
89  TreeItem *parentItem = _getItem(parent);
90 
91  TreeItem *childItem = parentItem->child(row);
92  if (childItem)
93  return createIndex(row, column, childItem);
94  else
95  return QModelIndex();
96 }
97 
98 QModelIndex ConfigDataTableModel::parent(const QModelIndex &index) const
99 {
100  if (!index.isValid()) {return QModelIndex();}
101 
102  TreeItem *childItem = _getItem(index);
103  TreeItem *parentItem = childItem->parent();
104 
105  if (parentItem == _rootItem.get())
106  return QModelIndex();
107 
108  return createIndex(parentItem->childNumber(), 0, parentItem);
109 }
110 
111 int ConfigDataTableModel::rowCount(const QModelIndex &parent) const
112 {
113  TreeItem *parentItem = _getItem(parent);
114 
115  return parentItem->childCount();
116 }
117 
118 
119 // ************************************************************
120 // the following methods *do* have implementations in QAbstractItemModel,
121 // but want to customize the implementation
122 // ************************************************************
123 
124 Qt::ItemFlags ConfigDataTableModel::flags(const QModelIndex &index) const
125 {
126  if (!index.isValid())
127  return 0;
128 
129  return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
130 }
131 
132 QVariant ConfigDataTableModel::
133 headerData(int section, Qt::Orientation orientation, int role) const
134 {
135  if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
136  return _rootItem->data(section);
137 
138  return QVariant();
139 }
140 
141 bool ConfigDataTableModel::insertRows(int position, int rows, const QModelIndex &parent)
142 {
143  TreeItem *parentItem = _getItem(parent);
144 
145  beginInsertRows(parent, position, position + rows - 1);
146 
147  bool status = parentItem->insertChildren(position, rows,
148  _rootItem->columnCount());
149  if (status) {
150  emit aChangeWasMade();
151  }
152 
153  endInsertRows();
154 
155  return status;
156 }
157 
158 bool ConfigDataTableModel::removeRows(int position, int rows, const QModelIndex &parent)
159 {
160  TreeItem *parentItem = _getItem(parent);
161 
162  beginRemoveRows(parent, position, position + rows - 1);
163 
164  bool status = parentItem->removeChildren(position, rows);
165  if (status) {
166  emit aChangeWasMade();
167  }
168 
169  endRemoveRows();
170 
171  return status;
172 }
173 
174 bool ConfigDataTableModel::setData(const QModelIndex &index,
175  const QVariant &value,
176  int role)
177 {
178  if (role != Qt::EditRole)
179  return false;
180 
181  TreeItem *item = _getItem(index);
182  QVariant oldValue = item->data(index.column());
183  if (value == oldValue) {
184  return false;
185  }
186 
187  bool result = item->setData(index.column(), value);
188 
189  if (result) {
190  item->markDirty();
191 
192  if (item->childCount() > 0) {
193  this->removeRows(0, item->childCount(), index);
194  }
195 
196  emit dataChanged(index, index);
197  emit aChangeWasMade();
198  }
199 
200  return result;
201 }
202 
203 bool ConfigDataTableModel::setHeaderData(int section, Qt::Orientation orientation,
204  const QVariant &value, int role)
205 {
206  if (role != Qt::EditRole || orientation != Qt::Horizontal)
207  return false;
208 
209  bool result = _rootItem->setData(section, value);
210 
211  if (result)
212  emit headerDataChanged(orientation, section, section);
213 
214  return result;
215 }
216 
217 
218 // ************************************************************
219 // the following methods are unique to this class and its children
220 // ************************************************************
221 
223 loadData(const std::vector<int64_t>& subsystemConfigIdList)
224 {
225  if (! _dbTablePtr->GetConnection()) {return false;}
226  if (! _dbTablePtr->ExistsInDB()) {return false;}
227 
228  // populate the root item with the DB table column names
229  _dataColumnNames.clear();
230  _dataColumnTypes.clear();
231  QVector<QVariant> rootData;
232  std::vector<std::string> columnNames = _dbTablePtr->GetColNames();
233  foreach (std::string colName, columnNames) {
234  if (DBColumnUtils::isInfrastructureColumn(colName)) {
235  continue;
236  }
237  if (DBColumnUtils::
238  isSubsystemConfigReferenceColumn(colName)) {
239  continue;
240  }
241 
242  _dataColumnNames.push_back(colName);
243  QString tmpQString(colName.c_str());
244  rootData << tmpQString;
245  _dataColumnTypes.push_back("unknown");
246  }
247 
248  if (_rootItem.get() != 0) {
249  QModelIndex dummyIndex;
250  this->removeRows(0, _rootItem->childCount(), dummyIndex);
251  }
252  _rootItem.reset(new TreeItem(rootData));
253  QModelIndex rootIndex = this->index(0, 0);
254 
255  // find the relevant DB entries and populate the rest of the data model
256  for (uint32_t cfgIdx = 0; cfgIdx<subsystemConfigIdList.size(); ++cfgIdx) {
257  _dbTablePtr->Clear();
258  _dbTablePtr->SetValidityRange(NamedConfigUtils::SUBSYSCFGID_COLUMN_NAME,
259  subsystemConfigIdList[cfgIdx]);
260  if (! _dbTablePtr->LoadFromDB()) {return false;}
261 
262  if (_dbTablePtr->NRow() > 0) {
263  int initialRowCount = _dbTablePtr->NRow();
264  insertRows(0, initialRowCount, rootIndex);
265 
266  for (int iRow = 0; iRow < initialRowCount; ++iRow) {
267  NOVADB::Row* rowPtr = _dbTablePtr->GetRow(iRow);
268 
269  // add the requested item
270  TreeItem* newItem = _rootItem->child(iRow);
271 
272  for (uint32_t iCol=0; iCol<_dataColumnNames.size(); ++iCol) {
273  std::string colName =
274  boost::to_lower_copy(_dataColumnNames[iCol]);
275 
277  NOVADB::Column* colPtr = rowPtr->Col(colName);
278  if (colPtr->IsNull()) {continue;}
279  if (! colPtr->Get(value)) {return false;}
280  std::string colType = colPtr->Type();
281  _dataColumnTypes[iCol] = colType;
282 
283  if (colType == "bool" || colType == "boolean") {
284  if (value == "t" || value == "1") {
285  value = "true";
286  }
287  else {
288  value = "false";
289  }
290  }
291 
292  if (colName == "mask") {
293  try {
294  if (colType == "bigint") {
295  value = novadaq::HexUtils::format(value, 16);
296  }
297  else {
298  value = novadaq::HexUtils::format(value, 8);
299  }
300  }
301  catch (...) {}
302  }
303 
304  newItem->setData(iCol, QVariant(value.c_str()));
305  }
306  }
307  }
308 
309  break; // TODO - handle a single subsysCfgId better
310  }
311 
312  _dbTablePtr->CloseConnection();
313  return true;
314 }
315 
317 {
318  if (_rootItem->isDirty()) {return true;}
319 
320  // loop over children, if any
321  for (int idx = 0; idx < _rootItem->childCount(); ++idx) {
322  TreeItem* childItem = _rootItem->child(idx);
323  if (childItem->isDirty() || childItem->isNew()) {return true;}
324  }
325 
326  return false;
327 }
328 
329 bool ConfigDataTableModel::saveChanges(const int64_t& subsystemConfigId)
330 {
331  if (! _dbTablePtr->GetConnection()) {return false;}
332  if (! _dbTablePtr->ExistsInDB()) {return false;}
333  _dbTablePtr->SetVerbosity(1);
334 
335  for (int idx = 0; idx < _rootItem->childCount(); ++idx) {
336  TreeItem* childItem = _rootItem->child(idx);
337 
338  boost::shared_ptr<NOVADB::Row> newRow(_dbTablePtr->NewRow());
339  newRow->Set(NamedConfigUtils::SUBSYSCFGID_COLUMN_NAME,
340  subsystemConfigId);
341 
342  for (uint32_t iCol = 0; iCol < _dataColumnNames.size(); ++iCol) {
343  std::string colName = boost::to_lower_copy(_dataColumnNames[iCol]);
344  std::string colType = boost::to_lower_copy(_dataColumnTypes[iCol]);
345 
346  std::string value = childItem->data(iCol).toString().toStdString();
347 
348  if (value.find("0x") != std::string::npos) {
349  try {
350  if (colType == "bigint") {
351  std::istringstream iss(value);
352  uint64_t u64Value;
353  iss >> std::hex >> u64Value;
354  int64_t i64Value = (int64_t) u64Value;
355  value = boost::lexical_cast<std::string>(i64Value);
356  }
357  else if (colType == "integer" || colType == "int") {
358  std::istringstream iss(value);
359  uint32_t u32Value;
360  iss >> std::hex >> u32Value;
361  int32_t i32Value = (int32_t) u32Value;
362  value = boost::lexical_cast<std::string>(i32Value);
363  }
364  }
365  catch (...) {}
366  }
367 
368  if (colType == "bool" || colType == "boolean") {
369  std::string valueCopy = boost::to_lower_copy(value);
370  if (valueCopy == "t" || valueCopy == "true" || valueCopy == "1") {
371  newRow->Set(colName, true);
372  }
373  else {
374  newRow->Set(colName, false);
375  }
376  }
377  else {
378  newRow->Set(colName, value);
379  }
380  }
381 
382  _dbTablePtr->AddRow(newRow.get());
383  }
384 
385  if (! _dbTablePtr->WriteToDB()) {return false;}
386 
387  _rootItem->markClean();
388  for (int idx = 0; idx < _rootItem->childCount(); ++idx) {
389  TreeItem* childItem = _rootItem->child(idx);
390  childItem->markClean();
391  childItem->markOld();
392  }
393  emit dataWasSaved();
394 
395  _dbTablePtr->CloseConnection();
396 
397  return true;
398 }
399 
401 {
402  QModelIndex parentIndex = this->index(0, 0);
403  beginInsertRows(parentIndex, 0, 0);
404 
405  bool status = _rootItem->insertChildren(0, 1, _rootItem->columnCount());
406  if (status) {
407  TreeItem* childItem = _rootItem->child(0);
408  childItem->markNew();
409  emit aChangeWasMade();
410  }
411 
412  endInsertRows();
413 
414  return status;
415 }
416 
418 addRowAfter(const QModelIndex &baseIndex)
419 {
420  if (! baseIndex.isValid()) {return false;}
421 
422  TreeItem *baseItem = this->_getItem(baseIndex);
423  int baseOffset = baseItem->childNumber();
424  int position = baseOffset + 1;
425 
426  QModelIndex parentIndex = this->parent(baseIndex);
427  TreeItem *parentItem = this->_getItem(parentIndex);
428 
429  beginInsertRows(parentIndex, position, position);
430 
431  bool status = parentItem->insertChildren(position, 1,
432  _rootItem->columnCount());
433  if (status) {
434  QModelIndex childIndex = this->index(position, 0, parentIndex);
435  if (childIndex.isValid()) {
436  TreeItem* childItem = this->_getItem(childIndex);
437 
438  for (int idx = 0; idx < parentItem->columnCount(); ++idx) {
439  childItem->setData(idx, baseItem->data(idx));
440  }
441 
442  childItem->markNew();
443  }
444  emit aChangeWasMade();
445  }
446 
447  endInsertRows();
448 
449  return status;
450 }
451 
453 deleteRow(const QModelIndex &baseIndex)
454 {
455  if (! baseIndex.isValid()) {return false;}
456 
457  TreeItem *baseItem = this->_getItem(baseIndex);
458  int baseOffset = baseItem->childNumber();
459  int position = baseOffset;
460 
461  QModelIndex parentIndex = this->parent(baseIndex);
462  TreeItem *parentItem = this->_getItem(parentIndex);
463 
464  beginRemoveRows(parentIndex, position, position);
465 
466  bool status = parentItem->removeChildren(position, 1);
467  if (status) {
468  _rootItem->markDirty();
469  emit aChangeWasMade();
470  }
471 
472  endRemoveRows();
473 
474  return status;
475 }
476 
478 {
479  return _dbTablePtr->Name();
480 }
481 
482 
483 // ************************************************************
484 // protected methods
485 // ************************************************************
486 
488 {
489  if (index.isValid()) {
490  TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
491  if (item) return item;
492  }
493  return _rootItem.get();
494 }
495 
497  std::vector<TreeItem*>& list) const
498 {
499  // add this item to the list if it has been modified
500  if (baseItem->isDirty() || baseItem->isNew()) {list.push_back(baseItem);}
501 
502  // loop over children, if any
503  for (int idx = 0; idx < baseItem->childCount(); ++idx) {
504  TreeItem* childItem = baseItem->child(idx);
505  this->_getModifiedItems(childItem, list);
506  }
507 }
508 
509 } // end of namespace gui
510 } // end of namespace dbutils
TreeItem * _getItem(const QModelIndex &index) const
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const
bool insertChildren(int position, int count, int columns)
Definition: TreeItem.cpp:94
virtual bool deleteRow(const QModelIndex &index)
std::vector< std::string > _dataColumnNames
int status
Definition: fabricate.py:1613
boost::shared_ptr< TreeItem > _rootItem
virtual bool addRowAfter(const QModelIndex &index)
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
int childCount() const
Definition: TreeItem.cpp:71
std::vector< std::string > _dataColumnTypes
static EnvVarCache & getInstance()
Definition: EnvVarCache.cpp:12
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
void _getModifiedItems(TreeItem *baseItem, std::vector< TreeItem * > &list) const
virtual QModelIndex parent(const QModelIndex &index) const
bool setData(int column, const QVariant &value)
Definition: TreeItem.cpp:125
int childNumber() const
Definition: TreeItem.cpp:76
virtual std::string getTableName() const
virtual Qt::ItemFlags flags(const QModelIndex &index) const
virtual bool removeRows(int position, int rows, const QModelIndex &parent=QModelIndex())
int columnCount() const
Definition: TreeItem.cpp:84
const XML_Char int const XML_Char * value
Definition: expat.h:331
virtual bool saveChanges(const int64_t &subsystemConfigId)
virtual bool insertRows(int position, int rows, const QModelIndex &parent=QModelIndex())
virtual QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
bool Get(T &val) const
Definition: Column.h:53
bool removeChildren(int position, int count)
Definition: TreeItem.cpp:113
bool isNew() const
Definition: TreeItem.h:79
std::string format(const int32_t &value, const int &ndigits=8)
Definition: HexUtils.cpp:14
tuple yellow
Definition: rootlogon.py:67
TreeItem * parent()
Definition: TreeItem.cpp:108
boost::shared_ptr< nova::database::Table > _dbTablePtr
bool isDirty() const
Definition: TreeItem.h:74
bool IsNull() const
Definition: Column.h:39
virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role=Qt::EditRole)
::xsd::cxx::tree::string< char, simple_type > string
Definition: Database.h:154
std::string getEnvVar(std::string name)
Definition: EnvVarCache.cpp:33
TreeItem * child(int number)
Definition: TreeItem.cpp:66
QVariant data(int column) const
Definition: TreeItem.cpp:89
virtual QVariant data(const QModelIndex &index, int role) const
std::string Type() const
Definition: Column.h:36
detName
Definition: mkDefs.py:106
virtual bool loadData(const std::vector< int64_t > &subsystemConfigIdList)
Column & Col(int i)
Definition: Row.h:51