Skip to content
Snippets Groups Projects
Commit f20201e1 authored by Matthias Puchner's avatar Matthias Puchner
Browse files

add instrument tree model (for instrument library)

parent 2ab28dc6
No related branches found
No related tags found
1 merge request!320Implement instrument library editor
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file GUI/Views/ImportDataWidgets/InstrumentsTreeModel.cpp
//! @brief Implements class InstrumentsTreeModel
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2021
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
// ************************************************************************************************
#include "GUI/Models/InstrumentsTreeModel.h"
#include "GUI/Application/Application.h"
#include "GUI/Application/ApplicationSettings.h"
#include "GUI/Models/InstrumentItems.h"
#include "GUI/Models/InstrumentModel.h"
#include <QApplication>
#include <QtCore>
#include <QtGui>
InstrumentsTreeModel::InstrumentsTreeModel(QObject* parent, InstrumentModel* model)
: QAbstractItemModel(parent)
, m_model(model)
, m_visibleTypes(All)
, m_namesAreEditable(false)
, m_enableEmptyHeadlines(true)
{
connect(m_model, &InstrumentModel::modelAboutToBeReset, this, &InstrumentsTreeModel::clear,
Qt::UniqueConnection);
}
void InstrumentsTreeModel::enableEmptyHeadlines(bool b)
{
if (b != m_enableEmptyHeadlines) {
beginResetModel();
m_enableEmptyHeadlines = b;
endResetModel();
}
}
void InstrumentsTreeModel::setTypeEnabled(InstrumentType type, bool b)
{
if (m_visibleTypes.testFlag(type) != b) {
beginResetModel();
m_visibleTypes.setFlag(type, b);
endResetModel();
}
}
void InstrumentsTreeModel::refreshAfterModelChange()
{
// for (auto rank : m_visibleRanks) {
// if (!m_items[rank - 1].isEmpty()) {
// beginRemoveRows(indexOfHeadline(rank), 0, m_items[rank - 1].size() - 1);
// m_items[rank - 1] = m_model->InstrumentItems(rank);
// endRemoveRows();
// }
// }
//
// updateSubsriptions();
}
void InstrumentsTreeModel::clear()
{
beginResetModel();
endResetModel();
}
QList<InstrumentsTreeModel::InstrumentType> InstrumentsTreeModel::visibleTypes() const
{
QList<InstrumentsTreeModel::InstrumentType> result;
const auto forType = [&](InstrumentType type) {
if (m_visibleTypes.testFlag(type)
&& (m_enableEmptyHeadlines || !instruments(type).isEmpty()))
result << type;
};
forType(Gisas);
forType(OffSpecular);
forType(Specular);
forType(DepthProbe);
return result;
}
QVector<InstrumentItem*> InstrumentsTreeModel::instruments(InstrumentType type) const
{
switch (type) {
case Gisas:
return m_model->instrumentItems([](const InstrumentItem* p) {
return dynamic_cast<const GISASInstrumentItem*>(p) != nullptr;
});
case OffSpecular:
return m_model->instrumentItems([](const InstrumentItem* p) {
return dynamic_cast<const OffSpecularInstrumentItem*>(p) != nullptr;
});
case Specular:
return m_model->instrumentItems([](const InstrumentItem* p) {
return dynamic_cast<const SpecularInstrumentItem*>(p) != nullptr;
});
case DepthProbe:
return m_model->instrumentItems([](const InstrumentItem* p) {
return dynamic_cast<const DepthProbeInstrumentItem*>(p) != nullptr;
});
default:
return {};
}
}
InstrumentItem* InstrumentsTreeModel::topMostItem() const
{
for (auto t : visibleTypes())
if (auto instr = instruments(t); !instr.isEmpty())
return instr.first();
return nullptr;
}
QModelIndex InstrumentsTreeModel::indexOfHeadline(InstrumentType type) const
{
int row = 0;
for (auto t : visibleTypes()) {
if (t == type)
return createIndex(row, 0, nullptr);
row++;
}
return QModelIndex();
}
QModelIndex InstrumentsTreeModel::index(int row, int column, const QModelIndex& parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
if (!parent.isValid())
return createIndex(row, column, nullptr);
for (auto type : visibleTypes())
if (parent == indexOfHeadline(type))
return createIndex(row, column, instruments(type)[row]);
return QModelIndex();
}
QModelIndex InstrumentsTreeModel::parent(const QModelIndex& index) const
{
if (!index.isValid())
return QModelIndex();
if (index.internalPointer() == nullptr) // index is headline => no parent
return QModelIndex();
auto item = itemForIndex(index);
for (auto type : visibleTypes())
if (instruments(type).contains(item))
return indexOfHeadline(type);
return QModelIndex();
}
int InstrumentsTreeModel::columnCount(const QModelIndex& /*parent*/) const
{
return 1;
}
int InstrumentsTreeModel::rowCount(const QModelIndex& parent) const
{
if (!parent.isValid())
return visibleTypes().size();
// parent is a headline
for (auto type : visibleTypes())
if (parent == indexOfHeadline(type))
return instruments(type).size();
return 0;
}
QVariant InstrumentsTreeModel::data(const QModelIndex& index, int role) const
{
if (isHeadline(index)) {
QString title;
if (index == indexOfHeadline(Gisas))
title = "GISAS";
else if (index == indexOfHeadline(OffSpecular))
title = "OffSpecular";
else if (index == indexOfHeadline(Specular))
title = "Specular";
else if (index == indexOfHeadline(DepthProbe))
title = "DepthProbe";
switch (role) {
case Qt::DisplayRole:
return title;
case Qt::FontRole: {
QFont f(QApplication::font());
f.setPointSize(f.pointSize() * 1.5);
f.setBold(true);
return f;
}
case Qt::SizeHintRole: {
QFont f(QApplication::font());
f.setPointSize(f.pointSize() * 1.5);
f.setBold(true);
QSize s = QFontMetrics(f).boundingRect(title).size();
return QSize(s.width() * 2, s.height() * 2);
}
case Qt::TextAlignmentRole:
return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
case Qt::BackgroundRole:
return baApp->styleSheetPalette().headlineBackground;
case Qt::ForegroundRole:
return baApp->styleSheetPalette().headlineText;
default:
return QVariant();
}
}
if (role == Qt::ToolTipRole)
return QString();
const auto item = itemForIndex(index);
if (role == Qt::DisplayRole)
if (item->is<GISASInstrumentItem>())
return "<b>" + item->instrumentName() + "</b><br><br>This is a description!";
else
return item->instrumentName();
if (role == Qt::EditRole)
return item->instrumentName();
if (role == Qt::TextAlignmentRole)
return QVariant(Qt::AlignLeft | Qt::AlignTop);
if (role == Qt::DecorationRole) {
if (item->is<GISASInstrumentItem>())
return QIcon(":/images/gisas_instrument.svg");
if (item->is<OffSpecularInstrumentItem>())
return QIcon(":/images/offspec_instrument.svg");
if (item->is<SpecularInstrumentItem>())
return QIcon(":/images/specular_instrument.svg");
if (item->is<DepthProbeInstrumentItem>())
return QIcon(":/images/depth_instrument.svg");
}
return QVariant();
}
Qt::ItemFlags InstrumentsTreeModel::flags(const QModelIndex& index) const
{
if (isHeadline(index) || !index.isValid())
return Qt::NoItemFlags;
auto f = QAbstractItemModel::flags(index);
f |= Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
if (index.column() == 0 && m_namesAreEditable) // col 0 contains name of the data entry
f |= Qt::ItemIsEditable;
return f;
}
bool InstrumentsTreeModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (!index.isValid())
return false;
if (role == Qt::EditRole && index.column() == 0) {
itemForIndex(index)->setInstrumentName(value.toString());
emit dataChanged(index, index);
return true;
}
return false;
}
InstrumentItem* InstrumentsTreeModel::itemForIndex(const QModelIndex& index) const
{
if (!index.isValid())
return nullptr;
return reinterpret_cast<InstrumentItem*>(index.internalPointer());
}
QModelIndex InstrumentsTreeModel::indexForItem(InstrumentItem* item) const
{
if (item == nullptr)
return QModelIndex();
for (auto type : visibleTypes())
if (auto row = instruments(type).indexOf(item); row >= 0)
return createIndex(row, 0, item);
return QModelIndex();
}
bool InstrumentsTreeModel::isHeadline(const QModelIndex& index) const
{
if (!index.isValid())
return false;
return index.internalPointer() == nullptr;
}
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file GUI/Views/ImportDataWidgets/InstrumentsTreeModel.h
//! @brief Defines class InstrumentsTreeModel
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2021
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
// ************************************************************************************************
#ifndef BORNAGAIN_GUI_VIEWS_IMPORTDATAWIDGETS_INSTRUMENTSTREEMODEL_H
#define BORNAGAIN_GUI_VIEWS_IMPORTDATAWIDGETS_INSTRUMENTSTREEMODEL_H
#include <QAbstractItemModel>
#include <QSet>
class InstrumentModel;
class InstrumentItem;
//! Tree model for instrument item selection. Used e.g. for the instrument library.
class InstrumentsTreeModel : public QAbstractItemModel {
public:
InstrumentsTreeModel(QObject* parent, InstrumentModel* model);
enum InstrumentType {
None = 0x0,
Gisas = 0x1,
OffSpecular = 0x2,
Specular = 0x4,
DepthProbe = 0x8,
All = Gisas | OffSpecular | Specular | DepthProbe
};
Q_DECLARE_FLAGS(VisibleInstrumentTypes, InstrumentType)
void enableEmptyHeadlines(bool b);
void setTypeEnabled(InstrumentType type, bool b);
virtual QModelIndex index(int row, int column,
const QModelIndex& parent = QModelIndex()) const override;
virtual QModelIndex parent(const QModelIndex& index) const override;
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
virtual bool setData(const QModelIndex& index, const QVariant& value, int role) override;
InstrumentItem* itemForIndex(const QModelIndex& index) const;
QModelIndex indexForItem(InstrumentItem* item) const;
void refreshAfterModelChange();
//! The topmost visible item. Can be null of course.
InstrumentItem* topMostItem() const;
QModelIndex indexOfHeadline(InstrumentType type) const;
bool isHeadline(const QModelIndex& index) const;
private:
void clear();
QList<InstrumentType> visibleTypes() const;
QVector<InstrumentItem*> instruments(InstrumentType type) const;
private:
InstrumentModel* m_model = nullptr;
VisibleInstrumentTypes m_visibleTypes;
bool m_namesAreEditable;
bool m_enableEmptyHeadlines;
};
#endif // BORNAGAIN_GUI_VIEWS_IMPORTDATAWIDGETS_INSTRUMENTSTREEMODEL_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment