CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxTreeItemModel.cpp
Go to the documentation of this file.
1 #include "cxTreeItemModel.h"
2 
3 //#include "cxBrowserWidget.h"
4 
5 #include <QTreeWidget>
6 #include <QTreeWidgetItem>
7 #include <QStringList>
8 #include <QVBoxLayout>
10 #include "cxViewService.h"
11 #include "cxRep.h"
12 #include "cxViewGroupData.h"
13 #include "cxTypeConversions.h"
14 #include "cxTreeRepository.h"
15 #include "cxLogger.h"
16 #include <QVariant>
17 #include "cxStringListProperty.h"
18 
19 namespace cx
20 {
21 
22 
23 
24 TreeItemModel::TreeItemModel(XmlOptionFile options, VisServicesPtr services, QObject* parent) :
25  QAbstractItemModel(parent),
26  mServices(services),
27  mOptions(options)
28 {
29  mSelectionModel = NULL;
30  mNameIndex = 1;
31  mColorIndex = 0;
32  mViewGroupIndex = 2;
33  mViewGroupCount = 3;
34 
35  this->createShowColumnsProperty();
36  this->onShowColumnsChanged();
37 
38  mRepository = TreeRepository::create(options.descend("repository"), services);
39  connect(mRepository.get(), &TreeRepository::invalidated, this, &TreeItemModel::beginResetModel);
40  connect(mRepository.get(), &TreeRepository::loaded, this, &TreeItemModel::loaded);
41  connect(mRepository.get(), &TreeRepository::changed, this, &TreeItemModel::onRepositoryChanged);
42 }
43 
44 void TreeItemModel::onRepositoryChanged(TreeNode* node)
45 {
46  if (node)
47  {
48 // CX_LOG_CHANNEL_DEBUG("CA") << "change on node=" << node->getName();
49 
50  QModelIndex index0 = this->createIndex(0, 0, node);
51  QModelIndex index1 = this->createIndex(0, mColumnCount, node);
52  emit dataChanged(index0, index1);
53  }
54  else
55  {
56 // CX_LOG_CHANNEL_DEBUG("CA") << "change on all";
57  emit dataChanged(QModelIndex(),QModelIndex());
58  }
59 }
60 
61 
63 {
64 // CX_LOG_CHANNEL_DEBUG("CA") << "TreeItemModel::buildTree() B";
65  this->beginResetModel();
66  mRepository->update();
67  this->endResetModel();
68 // CX_LOG_CHANNEL_DEBUG("CA") << "TreeItemModel::buildTree() E";
69 }
70 
71 void TreeItemModel::createShowColumnsProperty()
72 {
73  QStringList range = QStringList() << "color" << "vg0" << "vg1" << "vg2" << "vg3";
74  QStringList defvals = range;
75  defvals.pop_back();
76  defvals.pop_back();
77 
78  std::map<QString, QString> names;
79  names["color"] = "Color";
80  for (unsigned i=0; i<4; ++i)
81  names[QString("vg%1").arg(i)] = QString("View Group %1").arg(i);
82 
83 // QStringList range = QStringList() << "Color"
84 // << "View Group 0"
85 // << "View Group 1"
86 // << "View Group 2"
87 // << "View Group 3";
88  mShowColumnsProperty = StringListProperty::initialize("visible_columns",
89  "Columns",
90  "Select visible columns",
91  range,
92  range,
93  mOptions.getElement());
94  mShowColumnsProperty->setDisplayNames(names);
95  connect(mShowColumnsProperty.get(), &Property::changed, this, &TreeItemModel::onShowColumnsChanged);
96 }
97 
98 void TreeItemModel::onShowColumnsChanged()
99 {
100 // CX_LOG_CHANNEL_DEBUG("CA") << "TreeItemModel::onShowColumnsChanged()";
101  this->beginResetModel();
102 
103  int none = 1000;
104  QStringList cols = mShowColumnsProperty->getValue();
105 
106  mColumnCount = 0;
107  mNameIndex = mColumnCount++;
108  mColorIndex = cols.contains("color") ? mColumnCount++ : none;
109  mViewGroupCount = 0;
110  while (cols.contains(QString("vg%1").arg(mViewGroupCount)))
111  ++mViewGroupCount;
112  mViewGroupIndex = (mViewGroupCount>0) ? mColumnCount : none;
113  mColumnCount += mViewGroupCount;
114 
115 // CX_LOG_CHANNEL_DEBUG("CA") << "mColorIndex: " << mColorIndex;
116 // CX_LOG_CHANNEL_DEBUG("CA") << "mNameIndex: " << mNameIndex;
117 // CX_LOG_CHANNEL_DEBUG("CA") << "mViewGroupIndex: " << mViewGroupIndex;
118 // CX_LOG_CHANNEL_DEBUG("CA") << "mViewGroupCount: " << mViewGroupCount;
119 // CX_LOG_CHANNEL_DEBUG("CA") << "mColumnCount: " << mColumnCount;
120 
121 // this->endResetModel();
122 // emit hasBeenReset();
123 }
124 
125 
126 
127 void TreeItemModel::setSelectionModel(QItemSelectionModel* selectionModel)
128 {
129  mSelectionModel = selectionModel;
130  connect(mSelectionModel, &QItemSelectionModel::currentChanged,
131  this, &TreeItemModel::currentItemChangedSlot);
132 }
133 
135 {
136 }
137 
138 void TreeItemModel::currentItemChangedSlot(const QModelIndex& current, const QModelIndex& previous)
139 {
140  TreeNode *item = this->itemFromIndex(current);
141  if (!item)
142  return;
143  item->activate();
144  emit currentItemChanged();
145 }
146 
148 {
149  QModelIndex mi = mSelectionModel->currentIndex();
150  return this->getNodeFromIndex(mi);
151 }
152 
154 {
155  TreeNode *item = this->itemFromIndex(index);
156  if (!item)
157  return TreeNodePtr();
158  return mRepository->getNode(item->getUid());
159 }
160 
161 TreeNode* TreeItemModel::itemFromIndex(const QModelIndex& index) const
162 {
163  if (!index.isValid())
164  return mRepository->getTopNode().get();
165  else
166  return static_cast<TreeNode*>(index.internalPointer());
167 }
168 
169 int TreeItemModel::columnCount(const QModelIndex& parent) const
170 {
171  if (parent.isValid() && (parent.column() != mNameIndex)) // ignore for all but first column
172  return 0;
173  return mColumnCount;
174 }
175 
176 int TreeItemModel::rowCount(const QModelIndex& parent) const
177 {
178  if (parent.isValid() && (parent.column() != mNameIndex)) // ignore for all but first column
179  return 0;
180  TreeNode *parentItem = this->itemFromIndex(parent);
181  return parentItem->getVisibleChildren().size();
182 }
183 
184 QVariant TreeItemModel::data(const QModelIndex& index, int role) const
185 {
186  if (role==Qt::DisplayRole)
187  {
188  if (index.column()==mNameIndex)
189  {
190  TreeNode *item = this->itemFromIndex(index);
191  return item->getName();
192  }
193  }
194  if (role==Qt::CheckStateRole)
195  {
196  if (this->isViewGroupColumn(index.column()))
197  {
198  TreeNode *item = this->itemFromIndex(index);
199  return item->getViewGroupVisibility(this->viewGroupFromColumn(index.column()));
200  }
201  }
202  if (role==Qt::ToolTipRole || role==Qt::StatusTipRole)
203  {
204  TreeNode *item = this->itemFromIndex(index);
205  if (index.column()==mNameIndex)
206  return QString("%1 of type %2").arg(item->getName()).arg(item->getType());
207  if (this->isViewGroupColumn(index.column()))
208  return QString("Set visibility of %1 in view group %2")
209  .arg(item->getName()).arg(this->viewGroupFromColumn(index.column()));
210  }
211  if (role==Qt::DecorationRole)
212  {
213  TreeNode *item = this->itemFromIndex(index);
214  if (index.column()==mNameIndex)
215  return item->getIcon();
216  if (index.column()==mColorIndex)
217  {
218  if (item->getColor().canConvert<QColor>())
219  return this->getColorIcon(item->getColor().value<QColor>());
220  }
221  }
222  if (role==Qt::FontRole)
223  {
224  if (index.column()==mNameIndex)
225  {
226  TreeNode *item = this->itemFromIndex(index);
227  return item->getFont();
228  }
229  }
230  if (role==Qt::ForegroundRole)
231  {
232  if (index.column()==mNameIndex)
233  {
234  TreeNode *item = this->itemFromIndex(index);
235 // if (item->useColoredName())
236  {
237  QVariant color = item->getColor();
238  if (color.canConvert<QColor>())
239  {
240  QColor oldColor = color.value<QColor>().toHsv();
241  QColor newColor = this->adjustColorToContrastWithWhite(oldColor);
242  return newColor;
243  }
244  }
245  }
246  }
247  return QVariant();
248 }
249 
250 
251 bool TreeItemModel::setData(const QModelIndex& index, const QVariant& value, int role)
252 {
253  if (role==Qt::CheckStateRole)
254  {
255  if (this->isViewGroupColumn(index.column()))
256  {
257  TreeNode *item = this->itemFromIndex(index);
258  item->setViewGroupVisibility(this->viewGroupFromColumn(index.column()), value.value<int>());
259  }
260  return true;
261  }
262  return false;
263 }
264 
265 Qt::ItemFlags TreeItemModel::flags(const QModelIndex& index) const
266 {
267  if (index.column()>0)
268  return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
269  else
270  return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
271 }
272 
273 bool TreeItemModel::isViewGroupColumn(int col) const
274 {
275  return ( (0<=(col-mViewGroupIndex))
276  &&
277  ((col-mViewGroupIndex) < mViewGroupCount)
278  );
279 }
280 int TreeItemModel::viewGroupFromColumn(int col) const
281 {
282  return (col-mViewGroupIndex);
283 }
284 
285 QVariant TreeItemModel::headerData(int section, Qt::Orientation orientation, int role) const
286 {
287  if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
288  {
289  if (section==mNameIndex)
290  return " Item";
291  if (section==mColorIndex)
292  return ""; // keep short + out of the way of the toolbar button
293  if (this->isViewGroupColumn(section))
294  return QString("V%1").arg(this->viewGroupFromColumn(section));
295  }
296  return QVariant();
297 }
298 
299 QModelIndex TreeItemModel::index(int row, int column, const QModelIndex& parent) const
300 {
301  TreeNode *parentItem = this->itemFromIndex(parent);
302  std::vector<TreeNodePtr> children = parentItem->getVisibleChildren();
303  if (row < children.size())
304  {
305  return createIndex(row, column, children[row].get());
306  }
307  else
308  {
309  return QModelIndex();
310  }
311 }
312 
313 QModelIndex TreeItemModel::parent(const QModelIndex& index) const
314 {
315  TreeNode *childItem = this->itemFromIndex(index);
316 
317  if (!childItem)
318  return QModelIndex();
319 
320  TreeNode *parentItem = childItem->getVisibleParent().get();
321 
322  if (parentItem == mRepository->getTopNode().get())
323  return QModelIndex();
324 
325  // find row of parent within grandparent
326  TreeNodePtr grandParent = parentItem->getVisibleParent();
327  int row = 0;
328  if (grandParent)
329  {
330  std::vector<TreeNodePtr> parentSiblings = grandParent->getVisibleChildren();
331  for (row=0; row<parentSiblings.size(); ++row)
332  if (parentItem==parentSiblings[row].get())
333  break;
334  }
335 
336  return createIndex(row, mNameIndex, parentItem);
337 }
338 
339 QIcon TreeItemModel::getColorIcon(QColor color) const
340 {
341  QImage image(QSize(128,128), QImage::Format_RGBA8888);
342  QPainter painter(&image);
343  painter.fillRect(image.rect(), QColor("white"));
344  painter.setBrush(QBrush(color));
345  painter.drawRoundedRect(image.rect(), 75, 75, Qt::RelativeSize);
346 // painter.drawEllipse(image.rect());
347  return QIcon(QPixmap::fromImage(image));
348 }
349 
350 QColor TreeItemModel::adjustColorToContrastWithWhite(QColor color) const
351 {
352  // use some tricks in HSV space to get contrasting colors while
353  // keeping the original color as much as possible.
354  //
355  // for colors: strengthen the saturation: s' = s+(1-s)/2
356  // for for grayscale: lower value, or give up for whites:
357  // if s<0.1: v = max(0.7, v)
358  double h = color.hueF();
359  double s = color.hsvSaturationF();
360  double v = color.valueF();
361 
362  double isChromatic = s > 0.1; // our definition
363  if (isChromatic)
364  {
365  s = s+(1.0-s)/2;
366  }
367  else
368  {
369  v = std::min(0.6, v);
370  }
371 
372  return QColor::fromHsvF(h,s,v);
373 }
374 
375 
376 
377 }//end namespace cx
378 
void currentItemChanged()
boost::shared_ptr< TreeNode > TreeNodePtr
virtual std::vector< TreeNodePtr > getVisibleChildren() const =0
virtual QString getUid() const =0
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:40
virtual Qt::ItemFlags flags(const QModelIndex &index) const
TreeNodePtr getCurrentItem()
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
virtual QVariant getColor() const =0
virtual QModelIndex parent(const QModelIndex &index) const
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const
virtual QIcon getIcon() const =0
QDomElement getElement()
return the current element
static StringListPropertyPtr initialize(const QString &uid, QString name, QString help, QStringList value, QStringList range, QDomNode root=QDomNode())
virtual QString getType() const =0
TreeItemModel(XmlOptionFile options, VisServicesPtr services, QObject *parent=0)
virtual QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
virtual void setViewGroupVisibility(int index, bool value)=0
virtual QVariant getViewGroupVisibility(int index) const =0
virtual void activate()=0
static TreeRepositoryPtr create(XmlOptionFile options, VisServicesPtr services)
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
void changed()
emit when the underlying data value is changed: The user interface will be updated.
void changed(TreeNode *node=NULL)
virtual QString getName() const =0
virtual QVariant getFont() const =0
void setSelectionModel(QItemSelectionModel *selectionModel)
TreeNodePtr getNodeFromIndex(const QModelIndex &index)
virtual TreeNodePtr getVisibleParent() const =0
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Helper class for xml files used to store ssc/cx data.
XmlOptionFile descend(QString element) const
step one level down in the xml tree
Namespace for all CustusX production code.