Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+64
View File
@@ -0,0 +1,64 @@
#
# CMakeLists.txt for Data View
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-06-15
#
SET(ltsDataView_SRCS
lts_data_view_export.h
lts_data_view.h
lts_data_view.cpp
abstract_display_widget.h
abstract_display_widget.cpp
search_model.cpp
search_model.h
tree_view.cpp
tree_view.h
check_state_proxy_model.h
check_state_proxy_model.cpp
tree_view_delegate.cpp
tree_view_delegate.h
icon_view_delegate.cpp
icon_view_delegate.h
data_delegate.cpp
data_delegate.h
lts_columns_setting.cpp
lts_columns_setting.h
lts_columns_setting.cpp
lts_columns_setting.h
)
NGL_WRAP_UI(ltsDataView_SRCS
lts_data_view.ui
lts_columns_setting.ui
lts_columns_setting.ui
)
NGL_ADD_LIBRARY(WS LtsDataView SHARED ${ltsDataView_SRCS})
NGL_TARGET_LINK_LIBRARIES(LtsDataView
PRIVATE
LtsWidgets
LtsUtilsSettings
ngltools
PUBLIC
Qt5::Core
Qt5::Widgets
)
NGL_TARGET_INCLUDE_DIRECTORIES(LtsDataView
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_INSTALL_TARGET(LtsDataView)
# Test-Executable
NGL_ADD_EXECUTABLE(WS NO_TRANSLATION LtsDataViewTest test.h test.cpp)
NGL_TARGET_LINK_LIBRARIES(LtsDataViewTest
Qt5::Widgets
LtsDataView
LtsWidgets
)
+29
View File
@@ -0,0 +1,29 @@
/**
* @RDE_HEADER@
* Abstract Display Widget is an Abstract class to create Custom Display Widgets for the Custom View
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-06-15
*/
#include "abstract_display_widget.h"
#include <QModelIndex>
namespace LtsDataView
{
AbstractDisplayWidget::AbstractDisplayWidget(QWidget *parent)
: QWidget(parent)
{
setAutoFillBackground(true);
}
QVariant AbstractDisplayWidget::rowData(const QModelIndex &idx, int column, int role) const
{
const QModelIndex rowIdx(idx.column() == column ? idx : idx.model()->index(idx.row(), column));
return idx.model()->data(rowIdx, role);
}
} // namespace LtsDataView
+30
View File
@@ -0,0 +1,30 @@
/**
* @RDE_HEADER@
* Abstract Display Widget is an Abstract class to create Custom Display Widgets for the Custom View
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-06-15
*/
#pragma once
#include "lts_data_view_export.h"
#include <QWidget>
class QModelIndex;
namespace LtsDataView
{
class LTSDATAVIEW_EXPORT AbstractDisplayWidget : public QWidget
{
Q_OBJECT
public:
explicit AbstractDisplayWidget(QWidget *parent = nullptr);
virtual bool init(const QModelIndex &idx) = 0;
protected:
QVariant rowData(const QModelIndex &idx, int column, int role = Qt::DisplayRole) const;
};
} // namespace LtsDataView
+118
View File
@@ -0,0 +1,118 @@
/**
* @RDE_HEADER@
* Implementation of CheckStateProxyModel
* $Id$
* $HeadURL$
* $Author$
* Created by hjl/Christian Froebel, NLE, 2019-05-10
*/
#include "check_state_proxy_model.h"
namespace LtsDataView
{
Qt::ItemFlags CheckStateProxyModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return sourceModel()->flags(index); // delegate to source model for further processing if necessary
// Sets only the checkbox nodes on user checkable,
// checkbox leaves must be handled in source model.
QModelIndex sourceIndex = mapToSource(index);
Qt::ItemFlags fl = sourceModel()->flags(sourceIndex);
if (index.column() == 0)
return fl | Qt::ItemIsUserCheckable;
return fl;
}
QVariant CheckStateProxyModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
QModelIndex sourceIndex = mapToSource(index);
// delegate everything except CheckStateRole to source model
if (role != Qt::CheckStateRole)
return sourceModel()->data(sourceIndex, role);
// delegate a leaf too with CheckStateRole to source model
if (isLeaf(index))
return sourceModel()->data(sourceIndex, role);
// delegate to source model for further processing of further columns if necessary
if (index.column() != 0)
return sourceModel()->data(sourceIndex, role);
// sets the node checkboxes and decoration depending on the entries in the tree structure
int checkedCount = 0;
int childCount = rowCount(index);
for (int childRow = 0; childRow < childCount; ++childRow)
{
QModelIndex childIndex = this->index(childRow, 0, index);
Qt::CheckState checkState = data(childIndex, Qt::CheckStateRole).value<Qt::CheckState>();
if (checkState == Qt::PartiallyChecked)
return Qt::PartiallyChecked;
if (checkState == Qt::Checked)
++checkedCount;
}
if (checkedCount == childCount)
return Qt::Checked;
else if (checkedCount == 0)
return Qt::Unchecked;
else
return Qt::PartiallyChecked;
}
bool CheckStateProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
QModelIndex sourceIndex = mapToSource(index);
// delegate to source model for further processing of further columns if necessary
if (index.column() != 0)
return sourceModel()->setData(sourceIndex, value, role);
// delegate everything except CheckStateRole to source mode
if (role != Qt::CheckStateRole)
return sourceModel()->setData(sourceIndex, value, role);
if (isLeaf(index))
{
// delegate a leaf to source model
sourceModel()->setData(sourceIndex, value, role);
// update parents recursively here
QModelIndex idx = index.parent();
do
{
emit dataChanged(idx, idx, {Qt::CheckStateRole});
idx = idx.parent();
}
while (idx.isValid());
return true;
}
// update underlying children recursively (Additional nodes with leaves may also exist)
int childCount = rowCount(index);
for (int childRow = 0; childRow < childCount; ++childRow)
{
QModelIndex childIndex = this->index(childRow, 0, index);
setData(childIndex, value, Qt::CheckStateRole);
}
return true;
}
bool CheckStateProxyModel::isLeaf(const QModelIndex &index) const
{
QModelIndex sourceIndex = mapToSource(index);
return sourceModel()->flags(sourceIndex).testFlag(Qt::ItemIsUserCheckable);
}
} // namespace InfrastructureManagement
+60
View File
@@ -0,0 +1,60 @@
/**
* @RDE_HEADER@
* The model is used to handle CheckState Boxes in an LtsDataView (QTreeModel).
* Only the nodes of a TreeView are handled in this model. Leaves are forwarded to the transferred model and must be edited there.
* $Id$
* $HeadURL$
* $Author$
* Created by hjl/Christian Froebel, NLE, 2019-05-10
*/
#pragma once
#include <QIdentityProxyModel>
#include "lts_data_view_export.h"
namespace LtsDataView
{
class LTSDATAVIEW_EXPORT CheckStateProxyModel : public QIdentityProxyModel
{
public:
using QIdentityProxyModel::QIdentityProxyModel;
/**
* Handles the 'ItemIsUserCheckable' flags
* @param[in] sourceModel index
*
*/
Qt::ItemFlags flags(const QModelIndex &index) const override;
/**
* Handles the representation of data
* @param[in] sourceModel index
* @param[in] role role to which the data relates
*
*/
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
/**
* Handles the storage of data
* @param[in] index index
* @param[in] value value to be set
* @param[in] role role to which the data relates
*
*/
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
private:
/**
* Returns true if the item with the given index is an leaf
* @param[in] index item index whose information is requested
* will be internally mapped to source model data
*/
bool isLeaf(const QModelIndex &index) const;
}; // class CheckStateProxyModel
} // namespace LtsDataView
+31
View File
@@ -0,0 +1,31 @@
/**
* @RDE_HEADER@
* Renders complex types from model data to text for views
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, NLE, 2020-09-09
*/
#include "data_delegate.h"
#include <ngltools/ngltools_dtg.h>
#include <QDateTime>
namespace LtsDataView
{
DataDelegate::DataDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{}
QString DataDelegate::displayText(const QVariant &value, const QLocale &locale) const
{
if (value.type() == QVariant::Type::DateTime)
return DTG::toString(value.toDateTime());
return QStyledItemDelegate::displayText(value, locale);
}
} // namespace LtsDataView
+24
View File
@@ -0,0 +1,24 @@
#pragma once
/**
* @RDE_HEADER@
* Renders complex types from model data to text for views
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, NLE, 2020-09-09
*/
#include <QStyledItemDelegate>
namespace LtsDataView
{
class DataDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
DataDelegate(QObject *parent);
QString displayText(const QVariant &value, const QLocale &locale) const override;
};
} // namespace LtsDataView
+78
View File
@@ -0,0 +1,78 @@
#include "icon_view_delegate.h"
#include <QGraphicsDropShadowEffect>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QPainter>
#include <QDebug>
namespace LtsDataView
{
static constexpr int s_shadowRadius = 22;
void IconViewDelegate::setDisplayWidgetCreator(const std::function<AbstractDisplayWidget*()> &customDisplayWidgetCreator)
{
m_customDisplayWidgetCreator = customDisplayWidgetCreator;
QScopedPointer<AbstractDisplayWidget> dw(m_customDisplayWidgetCreator());
if (!dw)
{
qWarning() << "IconViewDelegate::setDisplayWidgetCreator: delegate is not a base of AbstractDisplayWidget!";
Q_ASSERT(false);
return;
}
m_displayWidgetSize = dw->size() + QSize(s_shadowRadius * 2, s_shadowRadius * 2);
}
QSize IconViewDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
{
return m_displayWidgetSize;
}
void IconViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QScopedPointer<AbstractDisplayWidget> dw(m_customDisplayWidgetCreator());
if (!dw)
{
qWarning() << "IconViewDelegate::paint: delegate is not a base of AbstractDisplayWidget!";
Q_ASSERT(false);
return;
}
if (!dw->init(index))
{
qWarning() << "IconViewDelegate::paint: delegate could not create ui";
return;
}
const auto dpr = dw->devicePixelRatioF();
QPixmap p(dw->size() * dpr);
p.setDevicePixelRatio(dpr);
QPainter myPainter(&p);
dw->render(&myPainter);
myPainter.end();
// drop shadow
QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect();
shadowEffect->setBlurRadius(s_shadowRadius);
shadowEffect->setOffset(0, 0); // center (shadow on all sides)
if (option.state & QStyle::State_Selected)
shadowEffect->setColor(dw->palette().light().color());
else
shadowEffect->setColor(dw->palette().shadow().color());
// draw pixmap & shadow
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(p);
item->setGraphicsEffect(shadowEffect);
// TODO: avoid creating a QGraphicsScene by using QGraphicsItem::paint()
QGraphicsScene scene;
scene.addItem(item);
scene.render(painter, option.rect, QRectF(-s_shadowRadius, -s_shadowRadius, option.rect.width(), option.rect.height()));
}
} // namespace LtsDataView
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include "abstract_display_widget.h"
#include <QStyledItemDelegate>
namespace LtsDataView
{
class IconViewDelegate final : public QStyledItemDelegate
{
Q_OBJECT
public:
using QStyledItemDelegate::QStyledItemDelegate;
void setDisplayWidgetCreator(const std::function<AbstractDisplayWidget*()> &customDisplayWidgetCreator);
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
private:
std::function<AbstractDisplayWidget*()> m_customDisplayWidgetCreator;
QSize m_displayWidgetSize;
};
} // namespace LtsDataView
+231
View File
@@ -0,0 +1,231 @@
/**
* @RDE_HEADER@
* LtsColumnsSettingWidget Organise table columns
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-03-19
*/
#include "lts_columns_setting.h"
#include "ui_lts_columns_setting.h"
#include<QDebug>
namespace LtsDataView
{
LtsColumnsSettingWidget::LtsColumnsSettingWidget(const QVector<ColumnOrganiserInfo> &columnInfoVec, QWidget *parent)
: LtsWidgets::LtsFramelessDialog(parent)
, m_ui(new Ui::LtsColumnsSetting)
{
m_ui->setupUi(this);
m_model = new ColumnOrganiserModel(this);
m_model->setModelData(columnInfoVec);
m_ui->tableView->setModel(m_model);
for(const auto &ci : columnInfoVec)
{
if (ci.debugOnly){
qDebug()<<">>>[LtsColumnsSettingWidgets] column to hide: id: "<<ci.logicalIndex;
m_ui->tableView->hideRow(ci.logicalIndex);
}
}
connect(m_ui->applyBtn, &QPushButton::clicked, this, &LtsColumnsSettingWidget::onApplyClicked);
connect(m_ui->cancelBtn, &QPushButton::clicked, this, &LtsColumnsSettingWidget::onAbortClicked);
connect(m_ui->resetBtn, &QPushButton::clicked, this, &LtsColumnsSettingWidget::onResetClicked);
}
LtsColumnsSettingWidget::~LtsColumnsSettingWidget()
{
delete m_ui;
}
void LtsColumnsSettingWidget::onResetClicked()
{
emit columnsResetted();
accept();
}
/*!
* \brief LtsColumnsSettingWidget::onApplyClicked
* send columns settings
*/
void LtsColumnsSettingWidget::onApplyClicked()
{
QVector<LtsDataView::ColumnOrganiserInfo> colInfoVec;
const int rowCount = m_ui->tableView->model()->rowCount();
colInfoVec.reserve(rowCount);
for(int row = 0; row < rowCount; ++row)
{
const ColumnOrganiserInfo ci = m_ui->tableView->model()->data(m_model->index(row,0),Qt::UserRole).value<ColumnOrganiserInfo>();
colInfoVec.push_back(ci);
}
emit columnVisibilityChanged(colInfoVec);
accept();
}
/*!
* \brief LtsColumnsSettingWidget::onAbortClicked
*/
void LtsColumnsSettingWidget::onAbortClicked()
{
reject();
}
/// TABLE MODEL FOR COLUMN SETTINGS
/*!
* \brief ColumnOrganiserModel::ColumnOrganiserModel
* \param parent
*/
ColumnOrganiserModel::ColumnOrganiserModel(QObject *parent)
:QAbstractTableModel(parent)
{
beginResetModel();
m_vecData.clear();
endResetModel();
}
/*!
* \brief ColumnOrganiserModel::setModelData
* \param infos
*/
void ColumnOrganiserModel::setModelData(const QVector<ColumnOrganiserInfo> &infos)
{
for(const auto &data : infos)
insertRow(data);
}
/*!
* \brief ColumnOrganiserModel::insertRow
* \param info
*/
void ColumnOrganiserModel::insertRow(const ColumnOrganiserInfo &info)
{
beginInsertRows(QModelIndex(), m_vecData.size(), m_vecData.size());
m_vecData.append(info);
endInsertRows();
}
/*!
* \brief ColumnOrganiserModel::columnCount
* \param parent
* \return
*/
int ColumnOrganiserModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return 1; // list of Column header as rows with on column
}
/*!
* \brief ColumnOrganiserModel::rowCount
* \param parent
* \return
*/
int ColumnOrganiserModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_vecData.count();
}
/*!
* \brief ColumnOrganiserModel::data
* \param index
* \param role
* \return
*/
QVariant ColumnOrganiserModel::data(const QModelIndex &index, int role) const
{
if ((role != Qt::DisplayRole &&
role != Qt::DecorationRole &&
role != Qt::EditRole &&
role != Qt::CheckStateRole &&
role != Qt::UserRole) || !index.isValid() || index.row() >= m_vecData.size())
return QVariant();
const ColumnOrganiserInfo ci = m_vecData.at(index.row());
if (role == Qt::CheckStateRole)
{
return ci.show;
}
if (role == Qt::DisplayRole)
return ci.name;
if (role == Qt::UserRole)
return QVariant::fromValue(ci);
return QVariant();
}
/*!
* \brief ColumnOrganiserModel::setData
* \param index
* \param value
* \param role
* \return
*/
bool ColumnOrganiserModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
Q_UNUSED(value)
if (role != Qt::EditRole && role != Qt::CheckStateRole)
return false;
ColumnOrganiserInfo &ci = m_vecData[index.row()];
if (role == Qt::CheckStateRole)
{
ci.show = !ci.show;
return true;
}
switch (index.column())
{
case 0:
return false;
}
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
return true;
}
/*!
* \brief ColumnOrganiserModel::flags
* \param index
* \return
*/
Qt::ItemFlags ColumnOrganiserModel::flags(const QModelIndex &index) const
{
auto f = QAbstractTableModel::flags(index);
if (!index.isValid())
return f;
if (index.column() == 0)
{
f.setFlag(Qt::ItemIsUserCheckable);
}
return f;
}
/*!
* \brief ColumnOrganiserModel::headerData
* \param section
* \param orientation
* \param role
* \return
*/
QVariant ColumnOrganiserModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal
&& role == Qt::DisplayRole)
{
if (section == 0)
return tr("Column Visibility");
}
return QAbstractTableModel::headerData(section, orientation, role);
}
}
+84
View File
@@ -0,0 +1,84 @@
/**
* @RDE_HEADER@
* LtsColumnsSetting Organise table columns
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-03-19
*/
#pragma once
#include <LtsDataView/lts_data_view_export.h>
#include "LtsWidgets/lts_frameless_dialog.h"
#include <QWidget>
#include <QDialog>
#include <QAbstractTableModel>
namespace Ui {
class LtsColumnsSetting;
}
namespace LtsDataView
{
struct ColumnOrganiserInfo
{
int logicalIndex; // logicalIndex
QString name;
bool show;
bool debugOnly = false; // column is only displayed in debug mode
bool hide() const {return !show;}
};
class ColumnOrganiserModel;
class LTSDATAVIEW_EXPORT LtsColumnsSettingWidget : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
explicit LtsColumnsSettingWidget(const QVector<ColumnOrganiserInfo> &columnInfoVec, QWidget *parent = nullptr);
~LtsColumnsSettingWidget();
signals:
void columnVisibilityChanged(const QVector<ColumnOrganiserInfo> &data);
void columnsResetted();
private slots:
void onResetClicked();
void onApplyClicked();
void onAbortClicked();
private:
Ui::LtsColumnsSetting *m_ui;
ColumnOrganiserModel *m_model;
};
class ColumnOrganiserModel final : public QAbstractTableModel
{
Q_OBJECT
public:
explicit ColumnOrganiserModel(QObject *parent = nullptr);
~ ColumnOrganiserModel(){}
void setModelData(const QVector<ColumnOrganiserInfo> &infos);
protected:
void insertRow(const ColumnOrganiserInfo &info);
int columnCount(const QModelIndex &parent = QModelIndex())const override;
int rowCount(const QModelIndex &parent = QModelIndex() ) const override;
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole)const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
private:
QVector<ColumnOrganiserInfo> m_vecData;
};
} // namespace LtsDataView
Q_DECLARE_METATYPE(LtsDataView::ColumnOrganiserInfo)
+71
View File
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LtsColumnsSetting</class>
<widget class="QWidget" name="LtsColumnsSetting">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="4">
<widget class="QTableView" name="tableView">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>121</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="resetBtn">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="applyBtn">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="cancelBtn">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
File diff suppressed because it is too large. Load diff
+225
View File
@@ -0,0 +1,225 @@
/**
* @RDE_HEADER@
* LtsDataView is the exported View, which contains and manages a Custom View and a Table View
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-06-15
*/
#pragma once
#include <LtsDataView/lts_data_view_export.h>
#include <LtsDataView/lts_columns_setting.h>
#include <QWidget>
#include <QAbstractItemView>
#include <QLineEdit>
#include <functional>
class QListView;
class QTreeView;
namespace Ui
{
class LtsDataView;
}
namespace LtsWidgets
{
class LtsColumnFilterProxyModel;
struct ColumnOrganiserInfo;
}
// TODO: doxy doku
namespace LtsDataView
{
class AbstractDisplayWidget;
class SearchModel;
class SearchLineEdit final : public QLineEdit
{
Q_OBJECT
public:
explicit SearchLineEdit(QWidget *parent)
: QLineEdit(parent)
{
setProperty("isSearchLineEdit", true);
}
};
class LTSDATAVIEW_EXPORT LtsDataView : public QWidget
{
Q_OBJECT
Q_PROPERTY(bool rootIsDecorated READ rootIsDecorated WRITE setRootIsDecorated)
Q_PROPERTY(bool showColumnCount READ showColumnCount WRITE setColumnCountVisible)
Q_PROPERTY(bool toolButtonsVisible READ toolButtonsVisible WRITE setToolButtonsVisible)
Q_PROPERTY(bool alternatingRowColors READ alternatingRowColors WRITE setAlternatingRowColors)
Q_PROPERTY(bool allColumnsShowFocus READ allColumnsShowFocus WRITE setAllColumnsShowFocus)
Q_PROPERTY(bool autoResizeToContent READ autoResizeToContent WRITE setAutoResizeToContent)
Q_PROPERTY(QAbstractItemView::SelectionMode selectionMode READ selectionMode WRITE setSelectionMode)
public:
enum Page
{
TABLE = 0,
CUSTOM = 1,
};
explicit LtsDataView(QWidget *parent = nullptr);
~LtsDataView();
/** once you set the model without a ADW, the view cannot switch back to double-view mode!
*
*/
void setModel(QAbstractItemModel *model, const std::function<AbstractDisplayWidget*()> &customDisplayWidgetCreator = nullptr);
QAbstractItemModel *sourceModel() const;
LtsWidgets::LtsColumnFilterProxyModel *proxyModel() const;
QItemSelectionModel *selectionModel() const;
SearchModel *searchModel() const;
QTreeView *treeView();
const QTreeView *treeView() const;
QTreeView *searchView();
const QTreeView *searchView() const;
QListView *getCustomView();
QWidget *customWidget() const;
void setCustomWidget(QWidget *customWidget); // not visible in seamless mode
QModelIndexList selectedRows(int column = 0) const; // TODO: returns indexes instead of rows if in custom view ... change naming?
void selectRow(const QModelIndex &idxSource);
void clearSelection();
void setSelectionMode(QAbstractItemView::SelectionMode selectionMode);
QAbstractItemView::SelectionMode selectionMode() const;
QModelIndex currentIndex() const;
void setCurrentIndex(const QModelIndex &idx); // also makes sure that the current index is visible (QAIV::scrollTo())
void scrollTo(const QModelIndex &idxSource);
void moveSection(int from, int to);
void seamless();
void setViewHeaderMovable(bool state);
void moveSections(const QMap<int, int> &list); /// logicalIndex (key) visualIndex(value)
void saveTableSettings(bool defaultSetting = false);/// if defaultSetting true, the default order of the table will be restore and save
bool restoreTableSettings();
QString getOperatorColIdentifier() const;
QVector<ColumnOrganiserInfo> getColumnOrganiserSetting();
QString columnOrganiserGroup() const;
void setColumnViewFromSetting();
void setColumnsOrganiserEnabled(const QString &tableIdentifier, bool enable = false);
void setRootIsDecorated(bool isDecorated);
bool rootIsDecorated() const;
void setAlternatingRowColors(bool enable);
bool alternatingRowColors() const;
void setColumnCountVisible(bool bVisible);
bool showColumnCount() const;
void setToolButtonsVisible(bool bVisible);
bool toolButtonsVisible() const;
void setAllColumnsShowFocus(bool enable);
bool allColumnsShowFocus() const;
void hideColumn(int column, bool debugMode = false);
void showColumn(int column);
bool isColumnHidden(int column) const;
void setColumnHidden(int column, bool hide);
void setAutoResizeToContent(bool enable);
bool autoResizeToContent() const;
void resizeSection(int logicalIndex, int size);
void resizeHeadersByContent();
void resizeColumnsToContent();
void syncSearchHeaderAndTableContentColumnSize();
void setRootIndex(const QModelIndex &srcIndex);
/**
* @brief See QHeaderview::setSortIndicator
*/
void setSortIndicator(int logicalIndex, Qt::SortOrder order);
void setSortIndicatorShown(bool show = true);
Qt::ContextMenuPolicy contextMenuPolicyPerView(Page page) const;
void setContextMenuPolicyPerView(Page page, Qt::ContextMenuPolicy policy);
QModelIndex mapFromSource(const QModelIndex &mi) const;
QModelIndex mapToSource(const QModelIndex &mi) const;
QModelIndexList mapToSource(const QModelIndexList &mil) const;
QItemSelection mapSelectionToSource(const QItemSelection &is) const;
bool setInitialSearchContent(int section, const QVariant &filterData);
void setIconSize(const QSize &size);
QByteArray saveState() const;
bool restoreState(const QByteArray &headerState);
private:
Ui::LtsDataView *m_ui;
LtsWidgets::LtsColumnFilterProxyModel *m_columnFilterProxy;
SearchModel *m_searchModel;
bool m_bOwnProxy;
bool m_autoResizeToConent{true};
QString m_tableObjIdentifier; // identifier for column Organiser
bool m_userChangedColumnPos = false;
QSet<int> m_DebugModeColIds; /// column which are only visible in debug mode
QString createCsv() const;
void addTouchScroll(QWidget *widget);
QAbstractItemView *currentView() const;
protected:
void keyPressEvent(QKeyEvent *event) override;
public slots:
void selectTableView();
void selectCustomView();
void selectView(Page page);
void slotCopyToClipboard();
void collapseAll();
void expandAll();
void expand(const QModelIndex &index);
void setSortingEnabled(bool enable);
void slotSetHorizontalRange(int, int);
void updateColumnsVisibility(const QVector<ColumnOrganiserInfo> &data);
void slotSetColumnsDefaultOrder();
private slots:
void slotSetSortIndicator(int logicalIndex, Qt::SortOrder order);
void slotRowCountChanged();
void slotSetHorizontalValue(int);
void slotSetVerticalRange(int x = 0, int y = 0);
void slotSetVerticalValue(int);
void slotSectionResized(int, int, int);
void slotHeaderMoved(int, int, int);
void slotCsvExport();
void slotResizeColumn(int columnIndex);
void onCustomContextMenuRequested(const QPoint &pos);
void slotColumnOrganiserDialog();
signals:
void signalEnterPressed();
void signalEntered(const QModelIndex &index);
// These are only emitted from the TableView
void clicked(const QModelIndex &index);
void doubleClicked(const QModelIndex &index);
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void activated(const QModelIndex &index);
// These are emitted from both
void signalSelectionChanged();
void signalDoubleClicked();
// signalContextMenuRequested requires setContextMenuPolicyPerView to be set
void signalContextMenuRequested(const QPoint &globalPos, const QModelIndex &indexSrc);
// custom signals (@Filip)
void filterChanged();
void sortOrderChanged(const int &column, const Qt::SortOrder &order);
};
} // namespace LtsDataView
+367
View File
@@ -0,0 +1,367 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LtsDataView</class>
<widget class="QWidget" name="LtsDataView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>556</width>
<height>350</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lblRows">
<property name="text">
<string>Rows:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbRows">
<property name="text">
<string notr="true">0</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="customWidget" native="true"/>
</item>
<item>
<widget class="QPushButton" name="tbColumnOrganiser">
<property name="whatsThis">
<string>Save selected line(s) as csv to a selected file with headers</string>
</property>
<property name="text">
<string>Column Setting</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tbCsvExport">
<property name="whatsThis">
<string>Save selected line(s) as csv to a selected file with headers</string>
</property>
<property name="text">
<string>CSV Export</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tbCopy">
<property name="whatsThis">
<string>Copy selected line(s) as csv to clipboard without headers</string>
</property>
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tbTable">
<property name="text">
<string>Table</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="tbCustom">
<property name="text">
<string>Custom</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="oneTableLayout" stretch="1,0">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="LtsDataView::TreeView" name="searchView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="autoScroll">
<bool>true</bool>
</property>
<property name="autoScrollMargin">
<number>16</number>
</property>
<property name="editTriggers">
<set>QAbstractItemView::CurrentChanged|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
<property name="alternatingRowColors">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectItems</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>true</bool>
</attribute>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>255</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="TableView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="LtsDataView::TreeView" name="tableView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="CustomView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListView" name="customView">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="movement">
<enum>QListView::Free</enum>
</property>
<property name="flow">
<enum>QListView::LeftToRight</enum>
</property>
<property name="spacing">
<number>0</number>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="QScrollBar" name="verticalScrollBar">
<property name="maximum">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QScrollBar" name="horizontalScrollBar">
<property name="maximum">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="nullWidget" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::TreeView</class>
<extends>QTreeView</extends>
<header location="global">tree_view.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>tableView</tabstop>
<tabstop>searchView</tabstop>
<tabstop>tbCsvExport</tabstop>
<tabstop>tbCopy</tabstop>
<tabstop>tbTable</tabstop>
<tabstop>tbCustom</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
+22
View File
@@ -0,0 +1,22 @@
/**
* Export definitions
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <QtCore/qglobal.h>
#ifndef LTSDATAVIEW_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define LTSDATAVIEW_EXPORT
# else
# if defined(MAKE_LTSDATAVIEW_LIB)
# define LTSDATAVIEW_EXPORT Q_DECL_EXPORT
# else
# define LTSDATAVIEW_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
+156
View File
@@ -0,0 +1,156 @@
/**
* @RDE_HEADER@
* Search Model for TableViews (has the ability to give the user a row for searching data)
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-03-14
*/
#include "search_model.h"
#include <QFont>
#include <QGuiApplication>
#include <QIcon>
#include <QPalette>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
namespace LtsDataView
{
SearchModel::SearchModel(QObject *parent)
: QAbstractItemModel(parent)
, m_searchIcon(QIcon(QStringLiteral("icon:show.svg")))
{
}
int SearchModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid()) return 0;
if (!m_sourceModel) return 0;
// no parent here - the given model index has nothing to do with the source model
return m_sourceModel->columnCount(QModelIndex());
}
int SearchModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) return 0;
if (!m_sourceModel) return 0;
return 1; // the search row
}
QVariant SearchModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
switch (role)
{
case Qt::DisplayRole: // Text
return m_displayData.value(index.column());
case Qt::EditRole: // Editor Text
return m_columnFilters.value(index.column());
case Qt::TextColorRole: // Text-Color
if (!m_columnFilters.contains(index.column()))
return QGuiApplication::palette().color(QPalette::Disabled, QPalette::ButtonText);
break;
case Qt::DecorationRole:
return m_hideDecorationColumns.contains(index.column()) ? QVariant() : m_searchIcon;
case Qt::BackgroundRole:
return QGuiApplication::palette().color(QPalette::Disabled, QPalette::AlternateBase);
case LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole:
return m_comboBoxData.value(index.column());
default:
break;
}
return QVariant();
}
QVariant SearchModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::FontRole)
{
QFont boldFont;
boldFont.setBold(true);
return boldFont;
}
return m_sourceModel ? m_sourceModel->headerData(section, orientation, role) : QVariant();
}
bool SearchModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!m_sourceModel || !index.isValid())
return false;
if (role == Qt::EditRole) // add / replace column filter when edited and in search row (row 0)
{
if (value.isNull())
m_columnFilters.remove(index.column());
else
m_columnFilters[index.column()] = value;
emit stringFilterForColumnChanged(value.toString(), index.column());
emit signalFilterChanged(); // must be called at last
emit dataChanged(index, index, {role});
return true; // done! (report a change, so that text keeps showing on search row)
}
if (role == Qt::DisplayRole)
{
if (value.isNull())
m_displayData.remove(index.column());
else
m_displayData[index.column()] = value;
emit dataChanged(index, index, {role});
return true;
}
if (role == LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)
{
if (value.isNull())
m_comboBoxData.remove(index.column());
else
m_comboBoxData[index.column()] = value;
emit dataFilterForColumnChanged(value, index.column());
emit signalFilterChanged(); // must be called at last
emit dataChanged(index, index, {role});
return true;
}
if (role == Qt::DecorationRole)
{
if (value.isNull())
m_hideDecorationColumns.remove(index.column());
else
m_hideDecorationColumns.insert(index.column());
emit dataChanged(index, index, {role});
}
return false;
}
void SearchModel::setSourceModel(QAbstractItemModel* sourceModel)
{
m_sourceModel = sourceModel;
m_columnFilters.clear();
emit dataChanged(QModelIndex(), QModelIndex()); // update view
}
Qt::ItemFlags SearchModel::flags(const QModelIndex &index) const
{
Q_UNUSED(index);
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
}
QModelIndex SearchModel::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid())
return QModelIndex();
return createIndex(row, column);
}
} // namespace LtsDataView
+53
View File
@@ -0,0 +1,53 @@
/**
* @RDE_HEADER@
* Search Model for TableViews (has the ability to give the user a row for searching data)
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-03-14
*/
#pragma once
#include <LtsDataView/lts_data_view_export.h>
#include <QAbstractItemModel>
#include <QSet>
#include <QString>
#include <QPointer>
namespace LtsDataView
{
class LTSDATAVIEW_EXPORT SearchModel final : public QAbstractItemModel
{
Q_OBJECT
public:
explicit SearchModel(QObject *parent = nullptr);
void setSourceModel(QAbstractItemModel* sourceModel);
QAbstractItemModel *sourceModel() const { return m_sourceModel; }
QVariant data(const QModelIndex &index, int role) const override final;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override final;
int columnCount(const QModelIndex &parent = QModelIndex()) const override final;
int rowCount(const QModelIndex &parent) const override final;
bool setData(const QModelIndex &index, const QVariant &value, int role) override final;
Qt::ItemFlags flags(const QModelIndex &index) const override final;
QModelIndex index(int row, int column, const QModelIndex &parent) const override final;
QModelIndex parent(const QModelIndex &child) const override final { (void)child; return QModelIndex(); }
signals:
void stringFilterForColumnChanged(const QString &newFilterString, int column);
void dataFilterForColumnChanged(const QVariant &newFilterData, int column);
void signalFilterChanged();
private:
QVariant m_searchIcon;
QPointer<QAbstractItemModel> m_sourceModel;
QHash<int, QVariant> m_columnFilters;
QHash<int, QVariant> m_displayData;
QHash<int, QVariant> m_comboBoxData;
QSet<int> m_hideDecorationColumns;
};
} // namespace LtsDataView
+103
View File
@@ -0,0 +1,103 @@
/**
* @RDE_HEADER@
* Test for LtsDataView and their AbstractDisplayWidgets
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-03-14
*/
#include "test.h"
#include <lts_data_view.h>
#include <QApplication>
#include <QDebug>
#include <QLabel>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QElapsedTimer>
#include <QScrollArea>
#include <QScroller>
Disp::Disp()
: LtsDataView::AbstractDisplayWidget(nullptr)
, m_label(new QLabel(this))
{
}
bool Disp::init(const QModelIndex &idx)
{
if (!idx.isValid())
return false;
m_label->setText(rowData(idx, 0).toString());
return true;
}
int main(int argc, char **argv)
{
QApplication app(argc,argv);
int rows = 20;
int cols = 7;
QElapsedTimer et;
et.start();
qWarning() << "creating" << rows << "items";
qWarning() << "wait..";
LtsDataView::LtsDataView *view = new LtsDataView::LtsDataView();
QStandardItemModel model;
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
{
QStandardItem *item = new QStandardItem(QStringLiteral("Item %1/%2").arg(r).arg(c));
model.setItem(r,c,item);
}
}
view->setModel(&model, [](){ return new Disp(); });
view->show();
#ifdef TABLET_MODE
auto widget = view;
if (widget)
{
widget->setAttribute(Qt::WA_AcceptTouchEvents);
{
QScrollArea *sca = qobject_cast<QScrollArea *>(widget);
if (sca)
{
qWarning() << widget << "is scroll area";
QScroller::grabGesture(sca->viewport(), QScroller::LeftMouseButtonGesture);
QScroller::grabGesture(sca, QScroller::LeftMouseButtonGesture);
}
else
{
QAbstractItemView *aiv = qobject_cast<QAbstractItemView *>(widget);
if (aiv)
{
qWarning() << widget << "is abst. item view";
QScroller::grabGesture(aiv->viewport(), QScroller::LeftMouseButtonGesture);
QScroller::grabGesture(aiv, QScroller::LeftMouseButtonGesture);
aiv->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
aiv->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
}
}
}
}
#endif
qWarning() << "took" << et.elapsed() << "ms";
return app.exec();
}
+28
View File
@@ -0,0 +1,28 @@
/**
* @RDE_HEADER@
* Search Model for TableViews (has the ability to give the user a row for searching data)
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-03-14
*/
#pragma once
#include "abstract_display_widget.h"
class QLabel;
class Disp : public LtsDataView::AbstractDisplayWidget
{
Q_OBJECT
public:
Disp();
bool init(const QModelIndex &idx) override;
private:
QLabel *m_label;
};
+82
View File
@@ -0,0 +1,82 @@
/**
* @RDE_HEADER@
* A QTreeView with some events catched
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-10-07
*/
#include "tree_view.h"
#include <QGuiApplication>
#include <QKeyEvent>
namespace LtsDataView
{
// needed until QTBUG-78726 is fixed
void TreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QVector<int> &roles)
{
QTreeView::dataChanged(topLeft, bottomRight, roles);
if (!m_toolTipPos.isNull() && (roles.isEmpty() || roles.contains(Qt::ToolTipRole)))
{
if (viewport()->mapToGlobal(m_toolTipPos) != QCursor::pos())
{
m_toolTipPos = QPoint();
return;
}
const QModelIndex index = indexAt(m_toolTipPos);
if (index.row() >= topLeft.row() && index.row() <= bottomRight.row() &&
index.column() >= topLeft.column() && index.column() <= bottomRight.column())
{
QHelpEvent he(QEvent::ToolTip, m_toolTipPos, viewport()->mapToGlobal(m_toolTipPos));
QTreeView::viewportEvent(&he);
m_toolTipPos = QPoint();
}
}
}
void TreeView::keyPressEvent(QKeyEvent *event)
{
if (QGuiApplication::keyboardModifiers() == Qt::ControlModifier
&& event->key() == Qt::Key_C)
emit signalCopyToClipBoard(); // queue !
QTreeView::keyPressEvent(event);
}
bool TreeView::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
{
if (trigger == QAbstractItemView::NoEditTriggers)
{
const QMouseEvent *me = dynamic_cast<QMouseEvent*>(event);
if (me && me->buttons().testFlag(Qt::LeftButton))
trigger = QAbstractItemView::AllEditTriggers;
}
return QTreeView::edit(index, trigger, event);
}
// needed until QTBUG-78726 is fixed
bool TreeView::viewportEvent(QEvent *event)
{
bool ret = QTreeView::viewportEvent(event);
if (event->type() == QEvent::ToolTip)
{
if (!ret)
{
QHelpEvent *he = static_cast<QHelpEvent*>(event);
m_toolTipPos = he->pos();
}
else
m_toolTipPos = QPoint();
}
return ret;
}
} // namespace LtsDataView
+37
View File
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* A QTreeView with some events catched
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-10-07
*/
#pragma once
#include <QTreeView>
namespace LtsDataView
{
class TreeView final : public QTreeView
{
Q_OBJECT
public:
using QTreeView::QTreeView;
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QVector<int> &roles) override;
protected:
void keyPressEvent(QKeyEvent *event) override;
bool edit(const QModelIndex &index, EditTrigger trigger, QEvent *event) override;
bool viewportEvent(QEvent *event) override;
signals:
void signalCopyToClipBoard();
private:
QPoint m_toolTipPos;
};
} // namespace LtsDataView
+152
View File
@@ -0,0 +1,152 @@
#include "lts_data_view.h"
#include "tree_view_delegate.h"
#include "search_model.h"
#include <QApplication>
#include <QComboBox>
#include <QTimer>
//#include <QDebug>
namespace LtsDataView
{
TreeViewDelegate::ComboBoxData TreeViewDelegate::comboBoxData(const QModelIndex &index)
{
const SearchModel *sm = qobject_cast<const SearchModel *>(index.model());
if (!sm)
return {};
const QAbstractItemModel *aim = sm->sourceModel();
if (!aim)
return {};
const QVariant val = aim->headerData(index.column(), Qt::Horizontal, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
return LtsWidgets::ComboboxFilterContent::fromVariant(val);
}
void TreeViewDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const ComboBoxData cbd = comboBoxData(index);
if (!cbd.isValid())
return QStyledItemDelegate::paint(painter, option, index);
const QWidget *const widget = option.widget;
QStyle* const style = widget ? widget->style() : QApplication::style();
QStyleOptionComboBox cbOption;
cbOption.rect = option.rect;
cbOption.direction = option.direction;
const auto currentData = index.data(LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
for (const auto &content : cbd.data)
{
if (content.data == currentData)
{
cbOption.currentIcon = content.icon;
break;
}
}
cbOption.currentText = index.data(Qt::DisplayRole).toString();
cbOption.fontMetrics = option.fontMetrics;
const int iconWidth = style->pixelMetric(QStyle::PM_SmallIconSize, nullptr, widget);
cbOption.iconSize = QSize(iconWidth, iconWidth);
cbOption.palette = option.palette;
cbOption.state = option.state;
cbOption.styleObject = option.styleObject;
style->drawComplexControl(QStyle::CC_ComboBox, &cbOption, painter, widget);
style->drawControl(QStyle::CE_ComboBoxLabel, &cbOption, painter, widget);
}
QWidget *TreeViewDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
Q_UNUSED(option);
const ComboBoxData cbd = comboBoxData(index);
if (cbd.isValid())
{
QComboBox *cbx = new QComboBox(parent);
for (const auto &content : cbd.data)
cbx->addItem(content.icon, content.text, content.data);
if (cbd.sortItems)
cbx->model()->sort(0);
cbx->insertItem(0, noFilterString());
connect(cbx, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &TreeViewDelegate::slotFinished);
QTimer::singleShot(0, cbx, &QComboBox::showPopup);
return cbx;
}
else
{
#ifdef TABLET_MODE
//qWarning() << "TABLET MODE !!!!!!!!";
// no line edit as it crashes
return nullptr;
#else
//qWarning() << "****NO**** TABLET MODE !!!!!!!!!!!!!!!!";
SearchLineEdit *edit = new SearchLineEdit(parent);
edit->setFrame(false);
connect(edit, &SearchLineEdit::editingFinished,
this, &TreeViewDelegate::slotFinished);
return edit;
#endif
}
}
void TreeViewDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
const ComboBoxData cbd = comboBoxData(index);
if (cbd.isValid())
{
QComboBox *cbx = qobject_cast<QComboBox *>(editor);
if (cbx)
{
// save the current data since it may change within setData() due to dataChanged() signals
const QString curTxt = cbx->currentText();
const QVariant curData = cbx->currentData();
model->setData(index, curData, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
model->setData(index, curTxt, Qt::DisplayRole);
}
}
else
{
SearchLineEdit *edit = qobject_cast<SearchLineEdit *>(editor);
if (edit)
{
model->setData(index, edit->text(), Qt::DisplayRole);
model->setData(index, edit->text(), Qt::EditRole);
}
}
}
void TreeViewDelegate::slotFinished()
{
QWidget *w = qobject_cast<QWidget *>(sender());
if (!w)
return;
emit commitData(w);
emit closeEditor(w);
}
void TreeViewDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
const ComboBoxData cbd = comboBoxData(index);
if (cbd.isValid())
{
QComboBox *cbx = qobject_cast<QComboBox *>(editor);
if (cbx)
{
const auto currentData = index.data(LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
cbx->setCurrentIndex(cbx->findData(currentData));
}
}
else
{
SearchLineEdit *edit = qobject_cast<SearchLineEdit *>(editor);
if (edit)
edit->setText(index.data().toString());
}
}
} // namespace LtsDataView
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <QStyledItemDelegate>
#include <QStyle>
namespace LtsDataView
{
class TreeViewDelegate final : public QStyledItemDelegate // needed to tell the QLineEdit to be as compact as possible while editing
{
Q_OBJECT
public:
using ComboBoxData = LtsWidgets::ComboboxFilterContent;
using QStyledItemDelegate::QStyledItemDelegate;
void paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const override;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const override;
static QString noFilterString() { return tr("<No filter>"); }
private:
static ComboBoxData comboBoxData(const QModelIndex &index);
private slots:
void slotFinished();
};
} // namespace LtsDataView