Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Viewer/LtsDataView/lts_data_view.cpp
T

1325 lines
40 KiB
C++
Executable File

/**
* @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
*/
#include "lts_data_view.h"
#include "ui_lts_data_view.h"
#include "search_model.h"
#include "abstract_display_widget.h"
#include "tree_view.h"
#include "tree_view_delegate.h"
#include "icon_view_delegate.h"
#include "data_delegate.h"
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <LtsUtilsSettings/settings.h>
#include <QtGui/QClipboard>
#include <QtWidgets/QComboBox>
#include <QtCore/QFile>
#include <QtWidgets/QFileDialog>
#include <QtGui/QKeyEvent>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStyledItemDelegate>
#include <QtCore/QTimer>
#include <QScroller>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonDocument>
#include <QtCore/QDebug>
#include <utility>
/// get the list of visual index as they are display
namespace LtsDataView
{
static const QString s_columSettingSuffix = QStringLiteral("_ColSetting");
static const QString s_colSettingIndexStr = QStringLiteral("index");
static const QString s_colSettingVisiStr = QStringLiteral("visible");
static const QString s_ColumnOrganiserSettingStr = QStringLiteral("ColumnOrganiserSetting");
#include <LtsUtilsSettings/settings.h>
LtsDataView::LtsDataView(QWidget *parent)
: QWidget(parent)
, m_ui(new Ui::LtsDataView)
, m_columnFilterProxy(nullptr)
, m_searchModel(new SearchModel(this))
, m_bOwnProxy(false)
{
m_ui->setupUi(this);
m_ui->tableView->setAlternatingRowColors(true);
m_ui->tableView->setAllColumnsShowFocus(true);
m_ui->tbColumnOrganiser->setVisible(false);
m_ui->tbColumnOrganiser->setEnabled(false);
#ifndef LTS_DEBUG
m_ui->lblRows->setHidden(true);
// m_ui->tbCsvExport->hide();
#endif
m_ui->searchView->setItemDelegate(new TreeViewDelegate(this));
m_ui->tableView->setItemDelegate(new DataDelegate(this));
connect(m_ui->tbCustom, &QPushButton::clicked,
this, &LtsDataView::LtsDataView::selectCustomView);
connect(m_ui->tbTable, &QPushButton::clicked,
this, &LtsDataView::LtsDataView::selectTableView);
connect(m_ui->tableView, &TreeView::signalCopyToClipBoard,
this, &LtsDataView::LtsDataView::slotCopyToClipboard, Qt::QueuedConnection); // event should pass before this slot can be entered
connect(m_ui->tbCopy, &QPushButton::clicked,
this, &LtsDataView::LtsDataView::slotCopyToClipboard);
connect(m_ui->tbCsvExport, &QPushButton::clicked,
this, &LtsDataView::LtsDataView::slotCsvExport);
connect(m_ui->tbColumnOrganiser, &QPushButton::clicked,
this, &LtsDataView::LtsDataView::slotColumnOrganiserDialog);
#ifdef TABLET_MODE
const QList<QWidget *> scrollWidgets = findChildren<QWidget *>();
for (QWidget *widget : scrollWidgets)
{
QVariant isConst = widget->property("const");
if (isConst.isValid() && isConst.toBool())
continue;
addTouchScroll(widget);
}
#endif
selectTableView();
}
LtsDataView::~LtsDataView()
{
delete m_ui;
}
void LtsDataView::setModel(QAbstractItemModel *model, const std::function<AbstractDisplayWidget*()> &customDisplayWidgetCreator)
{
Q_ASSERT(model);
if (!customDisplayWidgetCreator) // no custom widgets? pretend to be a pure table view by hiding the ability to swap between views
{
m_ui->tbCustom->setEnabled(false); // disable custom view
m_ui->tbCustom->hide();
m_ui->tbTable->hide();
m_ui->line->hide();
selectTableView();
}
else
{
IconViewDelegate *delegate = new IconViewDelegate(this);
delegate->setDisplayWidgetCreator(customDisplayWidgetCreator);
m_ui->customView->setItemDelegate(delegate); // does not take ownership of delegate ...
}
LtsWidgets::LtsColumnFilterProxyModel *proxy = qobject_cast<LtsWidgets::LtsColumnFilterProxyModel *>(model);
if (m_bOwnProxy)
delete m_columnFilterProxy;
if (proxy)
{
m_columnFilterProxy = proxy;
m_bOwnProxy = false;
}
else
{
Q_ASSERT_X(!qobject_cast<QSortFilterProxyModel*>(model),
__FUNCTION__,
"Don't pass plain QSortFilterProxyModel to LtsDataView::setModel - it will not work as expected. Derive from LtsColumnFilterProxyModel instead");
m_columnFilterProxy = new LtsWidgets::LtsColumnFilterProxyModel(this);
m_columnFilterProxy->setSourceModel(model);
m_bOwnProxy = true;
}
m_searchModel->setSourceModel(model);
connect(m_searchModel, &SearchModel::stringFilterForColumnChanged,
m_columnFilterProxy, &LtsWidgets::LtsColumnFilterProxyModel::onSetColumnStringFilter);
connect(m_searchModel, &SearchModel::dataFilterForColumnChanged,
m_columnFilterProxy, &LtsWidgets::LtsColumnFilterProxyModel::onSetColumnDataFilter);
m_ui->searchView->setModel(m_searchModel);
m_ui->tableView->setModel(m_columnFilterProxy);
m_ui->customView->setModel(m_columnFilterProxy);
m_ui->searchView->show();
// Main Model
connect(m_columnFilterProxy, &QAbstractItemModel::rowsInserted,
this, &LtsDataView::slotRowCountChanged);
connect(m_columnFilterProxy, &QAbstractItemModel::rowsRemoved,
this, &LtsDataView::slotRowCountChanged);
connect(m_columnFilterProxy, &QAbstractItemModel::modelReset,
this, &LtsDataView::slotRowCountChanged);
connect(m_columnFilterProxy->sourceModel(), &QAbstractItemModel::rowsInserted,
this, &LtsDataView::slotRowCountChanged);
connect(m_columnFilterProxy->sourceModel(), &QAbstractItemModel::rowsRemoved,
this, &LtsDataView::slotRowCountChanged);
connect(m_columnFilterProxy->sourceModel(), &QAbstractItemModel::modelReset,
this, &LtsDataView::slotRowCountChanged);
// Selection Changed
// for example needed by OperatorDialog::enaDisa :
connect(m_ui->customView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &LtsDataView::signalSelectionChanged);
connect(m_ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &LtsDataView::signalSelectionChanged);
// : for example needed by OperatorDialog::enaDisa
connect(m_ui->customView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, [this](const QItemSelection &s, const QItemSelection &d) { emit selectionChanged(mapSelectionToSource(s), mapSelectionToSource(d)); });
connect(m_ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, [this](const QItemSelection &s, const QItemSelection &d) { emit selectionChanged(mapSelectionToSource(s), mapSelectionToSource(d)); });
// Activated
connect(m_ui->customView, &QAbstractItemView::activated,
this, [this](const QModelIndex &idx) { emit activated(mapToSource(idx)); });
connect(m_ui->tableView, &QAbstractItemView::activated,
this, [this](const QModelIndex &idx) { emit activated(mapToSource(idx)); });
// Entered (requires MouseTracking)
m_ui->customView->setMouseTracking(true);
connect(m_ui->customView, &QAbstractItemView::entered,
this, [this](const QModelIndex &index) { emit signalEntered(mapToSource(index)); });
m_ui->tableView->setMouseTracking(true);
connect(m_ui->tableView, &QAbstractItemView::entered,
this, [this](const QModelIndex &index) { emit signalEntered(mapToSource(index)); });
// Clicked
connect(m_ui->customView, &QAbstractItemView::clicked,
this, [this](const QModelIndex &idx) { emit clicked(mapToSource(idx)); });
connect(m_ui->tableView, &QAbstractItemView::clicked,
this, [this](const QModelIndex &idx) { emit clicked(mapToSource(idx)); });
// Double Clicked
connect(m_ui->customView, &QAbstractItemView::doubleClicked,
this, &LtsDataView::signalDoubleClicked);
connect(m_ui->tableView, &QAbstractItemView::doubleClicked,
this, &LtsDataView::signalDoubleClicked);
connect(m_ui->customView, &QAbstractItemView::doubleClicked,
this, [this](const QModelIndex &idx) { emit doubleClicked(mapToSource(idx)); });
connect(m_ui->tableView, &QAbstractItemView::doubleClicked,
this, [this](const QModelIndex &idx) { emit doubleClicked(mapToSource(idx)); });
// Search View
connect(m_ui->searchView->header(), &QHeaderView::sortIndicatorChanged,
this, &LtsDataView::slotSetSortIndicator);
connect(m_searchModel, &SearchModel::signalFilterChanged,
this, &LtsDataView::slotRowCountChanged);
connect(m_searchModel, &SearchModel::signalFilterChanged,
this, [this](){ emit filterChanged(); });
connect(m_ui->searchView->header(), &QHeaderView::sectionResized,
this, &LtsDataView::slotSectionResized);
connect(m_ui->searchView->header(), &QHeaderView::sectionMoved,
this, &LtsDataView::slotHeaderMoved);
connect(m_ui->searchView->header(), &QHeaderView::sectionHandleDoubleClicked,
this, &LtsDataView::slotResizeColumn, Qt::QueuedConnection); // wait until the header did a resize by header text
// Horizontal Scrollbar
connect(m_ui->searchView->horizontalScrollBar(), &QScrollBar::rangeChanged,
this, &LtsDataView::slotSetHorizontalRange, Qt::QueuedConnection); // queued to make sure pageStep is up-to-date
connect(m_ui->searchView->horizontalScrollBar(), &QScrollBar::sliderMoved,
this, &LtsDataView::slotSetHorizontalValue);
connect(m_ui->searchView->horizontalScrollBar(), &QScrollBar::valueChanged,
this, &LtsDataView::slotSetHorizontalValue);
connect(m_ui->horizontalScrollBar, &QScrollBar::sliderMoved,
m_ui->searchView->horizontalScrollBar(), &QScrollBar::setValue);
connect(m_ui->horizontalScrollBar, &QScrollBar::sliderMoved,
m_ui->tableView->horizontalScrollBar(), &QScrollBar::setValue);
connect(m_ui->horizontalScrollBar, &QScrollBar::valueChanged,
m_ui->searchView->horizontalScrollBar(), &QScrollBar::setValue); // when wheelEvent'ing on the scrollbar
connect(m_ui->horizontalScrollBar, &QScrollBar::valueChanged,
m_ui->tableView->horizontalScrollBar(), &QScrollBar::setValue); // when wheelEvent'ing on the scrollbar
connect(m_ui->tableView->horizontalScrollBar(), &QScrollBar::rangeChanged,
this, &LtsDataView::slotSetHorizontalRange, Qt::QueuedConnection); // queued to make sure pageStep is up-to-date
connect(m_ui->tableView->horizontalScrollBar(), &QScrollBar::sliderMoved,
this, &LtsDataView::slotSetHorizontalValue);
connect(m_ui->tableView->horizontalScrollBar(), &QScrollBar::valueChanged,
this, &LtsDataView::slotSetHorizontalValue); // when wheelEvent'ing on the scrollbar
// custom view has no horizontal scroll bar
// Vertical Scrollbar
connect(m_ui->customView->verticalScrollBar(), &QScrollBar::rangeChanged,
this, &LtsDataView::slotSetVerticalRange, Qt::QueuedConnection); // queued to make sure pageStep is up-to-date
connect(m_ui->customView->verticalScrollBar(), &QScrollBar::sliderMoved,
this, &LtsDataView::slotSetVerticalValue);
connect(m_ui->customView->verticalScrollBar(), &QScrollBar::valueChanged,
this, &LtsDataView::slotSetVerticalValue); // custom view uses setValue on wheelEvent, listen to that
connect(m_ui->tableView->verticalScrollBar(), &QScrollBar::rangeChanged,
this, &LtsDataView::slotSetVerticalRange, Qt::QueuedConnection); // queued to make sure pageStep is up-to-date
connect(m_ui->tableView->verticalScrollBar(), &QScrollBar::sliderMoved,
this, &LtsDataView::slotSetVerticalValue);
connect(m_ui->tableView->verticalScrollBar(), &QScrollBar::valueChanged,
this, &LtsDataView::slotSetVerticalValue); // when wheelEvent'ing on the scrollbar
connect(m_ui->verticalScrollBar, &QScrollBar::valueChanged,
m_ui->tableView->verticalScrollBar(), &QScrollBar::setValue);
connect(m_ui->verticalScrollBar, &QScrollBar::valueChanged,
m_ui->customView->verticalScrollBar(), &QScrollBar::setValue);
// search view has no vertical scroll bar
// for context menue: (but contextPolicy has to be set by user...)
QTreeView *treeView = m_ui->tableView;
connect(treeView, &QListView::customContextMenuRequested,
this, &LtsDataView::onCustomContextMenuRequested, Qt::UniqueConnection);
connect(m_ui->customView, &QListView::customContextMenuRequested,
this, &LtsDataView::onCustomContextMenuRequested, Qt::UniqueConnection);
// check if a column has a combobox search
for (int c = 0; c < model->columnCount(); ++c)
{
const QModelIndex idx = m_searchModel->index(0, c, QModelIndex());
const QVariant v = model->headerData(c, Qt::Horizontal, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
if (!v.isNull())
{
m_searchModel->setData(idx, false, Qt::DecorationRole);
m_searchModel->setData(idx, TreeViewDelegate::noFilterString(), Qt::DisplayRole);
}
}
// set minimim size for this data view to display custom widgets properly
// TODO: !
// AbstractDisplayWidget *dummy = customDisplayWidgetCreator();
// setMinimumSize(dummy->minimumWidth() + 40 + 100, dummy->minimumHeight() + 40 + 100); // FIXME: margin?
slotRowCountChanged(); // show row count
// hide h-scrollbar if not needed
if (m_ui->searchView->horizontalScrollBar()->maximum() == 0)
m_ui->horizontalScrollBar->hide();
setSortIndicator(0, Qt::AscendingOrder);
resizeHeadersByContent();
if (m_autoResizeToConent)
syncSearchHeaderAndTableContentColumnSize();
m_DebugModeColIds.clear();
}
QAbstractItemModel *LtsDataView::sourceModel() const
{
return m_columnFilterProxy ? m_columnFilterProxy->sourceModel() : nullptr;
}
LtsWidgets::LtsColumnFilterProxyModel *LtsDataView::proxyModel() const
{
return m_columnFilterProxy;
}
QItemSelectionModel *LtsDataView::selectionModel() const
{
return m_ui->tableView->selectionModel();
}
SearchModel *LtsDataView::searchModel() const
{
return m_searchModel;
}
QTreeView *LtsDataView::treeView()
{
return m_ui->tableView;
}
const QTreeView *LtsDataView::treeView() const
{
return m_ui->tableView;
}
QTreeView *LtsDataView::searchView()
{
return m_ui->searchView;
}
const QTreeView *LtsDataView::searchView() const
{
return m_ui->searchView;
}
QListView *LtsDataView::getCustomView()
{
return m_ui->customView;
}
QWidget *LtsDataView::customWidget() const
{
QLayout *hbl = m_ui->customWidget->layout();
if (hbl)
{
for (int i = 0; i < hbl->count(); ++i)
{
if (hbl->itemAt(i)->widget())
return hbl->itemAt(i)->widget();
}
}
return nullptr;
}
void LtsDataView::setCustomWidget(QWidget *customWidget)
{
QLayout *hbl = m_ui->customWidget->layout();
if (hbl)
{
while (hbl->count() > 0)
delete hbl->takeAt(0)->widget();
}
delete hbl;
hbl = new QHBoxLayout(m_ui->customWidget);
hbl->setContentsMargins(0, 0, 0, 0);
hbl->addWidget(customWidget);
m_ui->customWidget->setLayout(hbl);
update(); // TODO: noetig? macht doch qt automatisch bei layout aenderungen?
}
QModelIndexList LtsDataView::selectedRows(int column) const
{
if (m_ui->stackedWidget->currentIndex() == TABLE)
{
if (m_ui->tableView->selectionModel())
return mapToSource(m_ui->tableView->selectionModel()->selectedRows(column));
}
else
{
Q_ASSERT(column == 0);
if (m_ui->customView->selectionModel())
return mapToSource(m_ui->customView->selectionModel()->selectedIndexes());
}
return {};
}
void LtsDataView::selectRow(const QModelIndex &idxSource)
{
QModelIndex idx = m_bOwnProxy ? m_columnFilterProxy->mapFromSource(idxSource) : idxSource;
QItemSelectionModel *pSelection = m_ui->tableView->selectionModel();
if (idx.isValid() && pSelection)
pSelection->select(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
}
void LtsDataView::clearSelection()
{
if (m_ui->tableView)
m_ui->tableView->clearSelection();
if (m_ui->customView)
m_ui->customView->clearSelection();
}
void LtsDataView::setSelectionMode(QAbstractItemView::SelectionMode selectionMode)
{
m_ui->tableView->setSelectionMode(selectionMode);
m_ui->customView->setSelectionMode(selectionMode);
}
QAbstractItemView::SelectionMode LtsDataView::selectionMode() const
{
return m_ui->tableView->selectionMode();
}
QModelIndex LtsDataView::currentIndex() const
{
return mapToSource(currentView()->currentIndex());
}
void LtsDataView::setCurrentIndex(const QModelIndex &idxSource)
{
const QModelIndex &idx = mapFromSource(idxSource);
QAbstractItemView *view = currentView();
view->setCurrentIndex(idx);
view->scrollTo(idx, QTreeView::ScrollHint::PositionAtCenter);
}
void LtsDataView::scrollTo(const QModelIndex &idxSource)
{
QModelIndex idx = m_bOwnProxy ? m_columnFilterProxy->mapFromSource(idxSource) : idxSource;
if (idx.isValid())
m_ui->tableView->scrollTo(idx, QAbstractItemView::PositionAtCenter);
}
void LtsDataView::moveSection(int from, int to)
{
m_ui->searchView->header()->moveSection(from, to);
}
void LtsDataView::seamless()
{
// TODO: FIXME: quick hack
m_ui->tbCopy->setEnabled(false);
m_ui->tbCsvExport->setEnabled(false);
m_ui->tbCustom->setEnabled(false);
m_ui->tbTable->setEnabled(false);
delete m_ui->horizontalLayout; // does not delete its indirect children
m_ui->horizontalLayout = nullptr;
}
void LtsDataView::setViewHeaderMovable(bool state)
{
m_ui->searchView->header()->setSectionsMovable(state);
}
/*!
* \brief LtsDataView::saveTableSettings
* \param defaultSetting: if user want to save default setting of column
*/
void LtsDataView::saveTableSettings(bool defaultSetting)
{
//qWarning()<<"########### [saveTableSettings]...";
QJsonArray jsArr;
int colCount = m_ui->tableView->model()->columnCount();
for(int i=0; i<colCount; ++i)
{
int logicalIndex = defaultSetting ? i : m_ui->tableView->header()->logicalIndex(i); // if true save col default order reset visibility
bool visible = defaultSetting ? true : !m_ui->searchView->isColumnHidden(logicalIndex);
if (m_DebugModeColIds.contains(logicalIndex))
visible = false; //
QJsonObject column;
column[s_colSettingIndexStr] = logicalIndex;
column[s_colSettingVisiStr] = visible;
jsArr.append(column);
}
QJsonObject obj;
obj.insert(m_tableObjIdentifier, jsArr);
//qWarning()<<">>>[SAVE] Setting jsObj: -> "<<obj;
const QString identifier = m_tableObjIdentifier + s_columSettingSuffix;
LtsUtils::OperatorSettings::getInstance()->setValue(columnOrganiserGroup(), identifier, QVariant::fromValue(obj));
}
bool LtsDataView::restoreTableSettings()
{
//qCritical()<<"########### [restoreTableSettings]...";
LtsUtils::OperatorSettings* opSettings = LtsUtils::OperatorSettings::getInstance();
QJsonObject dataObj = opSettings->value(columnOrganiserGroup(), getOperatorColIdentifier()).toJsonObject();
if (dataObj.isEmpty())
{
qCritical()<<">>> [restoreTableSettings] Object EMPTY!!";
return false;
}
QJsonArray jsArr = dataObj.value(m_tableObjIdentifier).toArray();
qWarning()<<">>> [restoreTableSettings] jsData: "<<dataObj;
if (jsArr.isEmpty())
{
qCritical()<<">>> [restoreTableSettings] json array EMPTY!!";
return false;
}
int colIndex =0;
for(const QJsonValue &value: jsArr)
{
QJsonObject column = value.toObject();
int index = column[s_colSettingIndexStr].toInt();
bool visible = column[s_colSettingVisiStr].toBool();
if (m_DebugModeColIds.contains(index))
visible = false; // hide debug columns
//qWarning()<<"[restore]-> index: "<<index<<" visualIdx: "<<m_ui->searchView->header()->visualIndex(index)<<" visi: "<<visible;
m_ui->searchView->header()->moveSection(m_ui->searchView->header()->visualIndex(index), colIndex++);
m_ui->searchView->setColumnHidden(index, !visible);
}
return true;
}
/*!
* \brief LtsDataView::setColumnViewFromSetting
* This Method will is Call to set Column Table settings from what was saved in json
*/
void LtsDataView::setColumnViewFromSetting()
{
qWarning()<<"######### setColumnViewFromSetting ... ";
m_userChangedColumnPos = false; // on internal move section avoid saving column setting
bool brestore = restoreTableSettings();
if (!brestore)
qCritical()<<" [setColumnViewFromSetting] couldn't restore table settings";
m_userChangedColumnPos = true;
}
QString LtsDataView::getOperatorColIdentifier() const
{
return m_tableObjIdentifier + s_columSettingSuffix;
}
QString LtsDataView::columnOrganiserGroup() const
{
return s_ColumnOrganiserSettingStr;
}
/*!
* \brief LtsDataView::getColumnOrganiserSetting
* \return get vector of struct from column jsondata (struct: id, visibility,..)
*/
QVector<ColumnOrganiserInfo> LtsDataView::getColumnOrganiserSetting()
{
const QString identifier = m_tableObjIdentifier + s_columSettingSuffix;
LtsUtils::OperatorSettings* opSettings = LtsUtils::OperatorSettings::getInstance();
QJsonObject dataObj = opSettings->value(columnOrganiserGroup(), identifier).toJsonObject();
QJsonArray jsArr = dataObj.value(m_tableObjIdentifier).toArray();
QVector<ColumnOrganiserInfo> vecInfo;
vecInfo.reserve(jsArr.count());
for(const QJsonValue &value: jsArr)
{
ColumnOrganiserInfo ci;
QJsonObject column = value.toObject();
ci.logicalIndex = column[s_colSettingIndexStr].toInt();
ci.show = column[s_colSettingVisiStr].toBool();
vecInfo.push_back(ci);
}
return vecInfo;
}
/*!
* \brief LtsDataView::setColumnsOrganiserEnabled
* \param tableIdentifier: unique name for table using column Settings
* \param enable : set button for column Setting Widget visible
*/
void LtsDataView::setColumnsOrganiserEnabled(const QString &tableIdentifier, bool enable)
{
qWarning()<<"############## [setColumnsOrganiserEnabled]...";
m_tableObjIdentifier = tableIdentifier;
m_ui->tbColumnOrganiser->setVisible(enable);
m_ui->tbColumnOrganiser->setEnabled(enable);
if (!restoreTableSettings())
saveTableSettings();
m_userChangedColumnPos = enable;
}
/*!
* \brief LtsDataView::slotColumnOrganiserDialog
*/
void LtsDataView::slotColumnOrganiserDialog()
{
qWarning()<<"############# [slotColumnOrganiserDialog]...";
if (!m_ui->tbColumnOrganiser->isEnabled())
return;
auto vecInfo = getColumnOrganiserSetting();
if(vecInfo.isEmpty())
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Couldn't start Column Organiser Dialog"), tr("Column Organiser"));
return;
}
const int colCount = m_columnFilterProxy->columnCount();
/// set Column names for Dialog Widget
for( auto &ci : vecInfo)
{
if (ci.logicalIndex > colCount)
continue;
ci.name = m_columnFilterProxy->headerData(ci.logicalIndex, Qt::Horizontal).toString();
// hide columns displayed only in debug mode
// because column is marked for debug, user will not be able to hide or show this column
if (m_DebugModeColIds.contains(ci.logicalIndex))
{
ci.show = false;
ci.debugOnly = true;
}
}
LtsColumnsSettingWidget *dialog = new LtsColumnsSettingWidget(vecInfo, this);
//LtsColumnOrganiser *dialog = new LtsColumnOrganiser(vecInfo, this);
connect(dialog, &LtsColumnsSettingWidget::columnVisibilityChanged, this, &LtsDataView::updateColumnsVisibility);
connect(dialog, &LtsColumnsSettingWidget::columnsResetted, this, &LtsDataView::slotSetColumnsDefaultOrder);
dialog->setModal(true);
dialog->show();
}
void LtsDataView::setRootIsDecorated(bool isDecorated)
{
if (m_ui && m_ui->tableView)
m_ui->tableView->setRootIsDecorated(isDecorated);
}
bool LtsDataView::rootIsDecorated() const
{
if (m_ui && m_ui->tableView)
return m_ui->tableView->rootIsDecorated();
return false;
}
void LtsDataView::setAlternatingRowColors(bool enable)
{
m_ui->tableView->setAlternatingRowColors(enable);
}
bool LtsDataView::alternatingRowColors() const
{
return m_ui->tableView->alternatingRowColors();
}
void LtsDataView::setColumnCountVisible(bool bVisible)
{
m_ui->lblRows->setVisible(bVisible);
m_ui->lbRows->setVisible(bVisible);
}
bool LtsDataView::showColumnCount() const
{
return m_ui->lblRows->isVisible();
}
void LtsDataView::setToolButtonsVisible(bool bVisible)
{
m_ui->tbCsvExport->setVisible(bVisible);
m_ui->tbCopy->setVisible(bVisible);
m_ui->tbTable->setVisible(bVisible);
m_ui->tbCustom->setVisible(bVisible);
m_ui->line->setVisible(bVisible);
}
bool LtsDataView::toolButtonsVisible() const
{
return m_ui->tbCsvExport->isVisible() &&
m_ui->tbCopy->isVisible() &&
m_ui->tbTable->isVisible() &&
m_ui->tbCustom->isVisible();
}
void LtsDataView::setAllColumnsShowFocus(bool enable)
{
m_ui->tableView->setAllColumnsShowFocus(enable);
}
bool LtsDataView::allColumnsShowFocus() const
{
return m_ui->tableView->allColumnsShowFocus();
}
void LtsDataView::hideColumn(int column, bool debugMode)
{
if (debugMode)
m_DebugModeColIds.insert(column); // used in setting column order and visibility
setColumnHidden(column, true);
}
void LtsDataView::showColumn(int column)
{
setColumnHidden(column, false);
}
bool LtsDataView::isColumnHidden(int column) const
{
return m_ui->searchView->isColumnHidden(column);
}
void LtsDataView::setColumnHidden(int column, bool hide)
{
m_ui->searchView->setColumnHidden(column, hide);
m_ui->tableView->setColumnHidden(column, hide);
}
void LtsDataView::setAutoResizeToContent(bool enable)
{
m_autoResizeToConent = enable;
}
bool LtsDataView::autoResizeToContent() const
{
return m_autoResizeToConent;
}
void LtsDataView::resizeSection(int logicalIndex, int size)
{
m_ui->searchView->header()->resizeSection(logicalIndex, size);
}
void LtsDataView::resizeHeadersByContent()
{
for (int i = 0; i < m_ui->tableView->header()->count(); i++)
slotResizeColumn(i);
}
void LtsDataView::resizeColumnsToContent()
{
if (!m_columnFilterProxy)
return;
// Sync von Header und Table erfolgt mit Aufruf von syncSearchHeaderAndTableContentColumnSize() nachdem das Modell initialisiert wurde.
const int colCount = m_columnFilterProxy->columnCount();
for (int col = 0; col < colCount; ++col)
m_ui->tableView->header()->setSectionResizeMode(col, QHeaderView::ResizeToContents);
}
void LtsDataView::syncSearchHeaderAndTableContentColumnSize()
{
m_ui->searchView->header()->resizeSections(QHeaderView::ResizeToContents);
const int colCount = m_columnFilterProxy->columnCount();
for (int col = 0; col < colCount; ++col)
slotResizeColumn(col);
}
void LtsDataView::setRootIndex(const QModelIndex &srcIndex)
{
m_ui->searchView->setRootIndex((srcIndex));
m_ui->tableView->setRootIndex(m_columnFilterProxy->mapFromSource(srcIndex));
m_ui->customView->setRootIndex(m_columnFilterProxy->mapFromSource(srcIndex));
}
void LtsDataView::setSortIndicator(int logicalIndex, Qt::SortOrder order)
{
m_ui->searchView->header()->setSortIndicator(logicalIndex, order);
}
void LtsDataView::setSortIndicatorShown(bool show)
{
m_ui->searchView->header()->setSortIndicatorShown(show);
}
Qt::ContextMenuPolicy LtsDataView::contextMenuPolicyPerView(LtsDataView::Page page) const
{
if (!m_ui)
return Qt::NoContextMenu;
switch (page)
{
case TABLE:
if (m_ui->tableView)
return m_ui->tableView->contextMenuPolicy();
break;
case CUSTOM:
if (m_ui->customView)
return m_ui->customView->contextMenuPolicy();
}
return Qt::NoContextMenu;
}
void LtsDataView::setContextMenuPolicyPerView(LtsDataView::Page page, Qt::ContextMenuPolicy policy)
{
if (!m_ui)
return;
switch (page)
{
case TABLE:
if (m_ui->tableView)
m_ui->tableView->setContextMenuPolicy(policy);
break;
case CUSTOM:
if (m_ui->customView)
m_ui->customView->setContextMenuPolicy(policy);
break;
}
}
QModelIndex LtsDataView::mapToSource(const QModelIndex &mi) const
{
return m_columnFilterProxy ? m_columnFilterProxy->mapToSource(mi) : mi;
}
QModelIndex LtsDataView::mapFromSource(const QModelIndex &mi) const
{
return m_columnFilterProxy ? m_columnFilterProxy->mapFromSource(mi) : mi;
}
QModelIndexList LtsDataView::mapToSource(const QModelIndexList &mil) const
{
QModelIndexList sourced;
if (!m_columnFilterProxy)
return sourced;
sourced.reserve(mil.size());
for (const auto &mi : mil)
sourced.append(mapToSource(mi));
return sourced;
}
QItemSelection LtsDataView::mapSelectionToSource(const QItemSelection &is) const
{
return m_columnFilterProxy ? m_columnFilterProxy->mapSelectionToSource(is) : is;
}
bool LtsDataView::setInitialSearchContent(int section, const QVariant &filterData)
{
if (!m_searchModel || !m_columnFilterProxy)
{
Q_ASSERT(false);
return false;
}
const QVariant headerData = m_columnFilterProxy->headerData(section, Qt::Horizontal, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
const LtsWidgets::ComboboxFilterContent cfc(LtsWidgets::ComboboxFilterContent::fromVariant(headerData));
if (!cfc.isValid())
{
const QModelIndex index = m_searchModel->index(0, section, QModelIndex());
// assume it's a text search
m_searchModel->setData(index, filterData, Qt::DisplayRole);
m_searchModel->setData(index, filterData, Qt::EditRole);
return false;
}
for (const auto &d : cfc.data)
{
if (d.data == filterData)
{
const QModelIndex index = m_searchModel->index(0, section, QModelIndex());
m_searchModel->setData(index, d.text, Qt::DisplayRole);
m_searchModel->setData(index, d.data, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole);
return true;
}
}
return false;
}
void LtsDataView::setIconSize(const QSize &size)
{
m_ui->tableView->setIconSize(size);
}
QByteArray LtsDataView::saveState() const
{
return m_ui->searchView->header()->saveState();
}
bool LtsDataView::restoreState(const QByteArray &headerState)
{
bool ok = m_ui->searchView->header()->restoreState(headerState);
if (ok)
ok = m_ui->tableView->header()->restoreState(headerState);
return ok;
}
QString LtsDataView::createCsv() const
{
if (!m_columnFilterProxy)
return QString();
const QAbstractItemView *itemView = currentView();
const QModelIndexList selection = itemView->selectionModel()->selectedRows();
// create csv:
int cols = m_columnFilterProxy->columnCount();
QString csv;
QStringList csvLine;
for (auto i = selection.constBegin(); i != selection.constEnd(); ++i)
{
int row = (*i).row();
csvLine.clear();
for (int k = 0; k < cols; k++)
if (m_ui->stackedWidget->currentIndex() != TABLE || !m_ui->tableView->isColumnHidden(k))
csvLine.append(m_columnFilterProxy->data(m_columnFilterProxy->index(row, k)).toString());
csv += csvLine.join(QLatin1Char(';'));
csv += QStringLiteral("\n"); // FIXME: windows?
}
return csv;
}
void LtsDataView::addTouchScroll(QWidget *widget)
{
if (!widget)
return;
widget->setAttribute(Qt::WA_AcceptTouchEvents);
{
QScrollArea *sca = qobject_cast<QScrollArea *>(widget);
if (sca)
{
QScroller::grabGesture(sca->viewport(), QScroller::LeftMouseButtonGesture);
QScroller::grabGesture(sca, QScroller::LeftMouseButtonGesture);
return;
}
}
{
QAbstractItemView *aiv = qobject_cast<QAbstractItemView *>(widget);
if (aiv)
{
QScroller::grabGesture(aiv->viewport(), QScroller::LeftMouseButtonGesture);
QScroller::grabGesture(aiv, QScroller::LeftMouseButtonGesture);
aiv->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
aiv->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
return;
}
}
}
QAbstractItemView *LtsDataView::currentView() const
{
if (m_ui->stackedWidget->currentIndex() == TABLE)
return m_ui->tableView;
return m_ui->customView;
}
void LtsDataView::keyPressEvent(QKeyEvent *event) // CustomView events land here
{
if (QGuiApplication::queryKeyboardModifiers() == Qt::ControlModifier
&& event->key() == Qt::Key_C)
slotCopyToClipboard();
// Enter: Enter on numpad
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
emit signalEnterPressed();
QWidget::keyPressEvent(event);
}
void LtsDataView::selectTableView()
{
selectView(TABLE);
}
void LtsDataView::selectCustomView()
{
selectView(CUSTOM);
}
void LtsDataView::selectView(Page page)
{
m_ui->tbTable->setChecked(page == TABLE);
m_ui->tbCustom->setChecked(page == CUSTOM);
m_ui->stackedWidget->setCurrentIndex(page);
slotSetVerticalRange();
slotSetVerticalValue(m_ui->customView->verticalScrollBar()->value());
}
void LtsDataView::slotCopyToClipboard()
{
QApplication::clipboard()->setText(createCsv()); // finally copy to clipboard
}
void LtsDataView::collapseAll()
{
m_ui->tableView->collapseAll();
}
void LtsDataView::expandAll()
{
m_ui->tableView->expandAll();
}
void LtsDataView::expand(const QModelIndex &index)
{
m_ui->tableView->expand(index);
}
void LtsDataView::setSortingEnabled(bool enable)
{
m_ui->searchView->setSortingEnabled(enable);
m_ui->tableView->setSortingEnabled(enable);
}
void LtsDataView::slotSetSortIndicator(int logicalIndex, Qt::SortOrder order)
{
m_ui->tableView->header()->setSortIndicator(logicalIndex, order);
// TODO: needed since custom view rebuild?:
m_ui->customView->update();
emit sortOrderChanged(logicalIndex, order);
}
void LtsDataView::slotRowCountChanged()
{
if (m_columnFilterProxy && m_columnFilterProxy->sourceModel())
m_ui->lbRows->setText(tr("%1 of %2")
.arg(m_columnFilterProxy->rowCount())
.arg(m_columnFilterProxy->sourceModel()->rowCount()));
// customview: sometimes the gui is not updated if model is cleared:
// (Example: clear JumpPointModel by selecting a workspace WITHOUT JumpPoints)
// TODO: needed since custom view rebuild?:
if (m_ui->customView &&
m_columnFilterProxy &&
m_columnFilterProxy->sourceModel() &&
m_columnFilterProxy->sourceModel()->rowCount() == 0)
m_ui->customView->update();
}
void LtsDataView::slotSetHorizontalRange(int min, int max)
{
m_ui->searchView->horizontalScrollBar()->hide(); // always hide!
if (!min && !max) // no min, no max = not visible
m_ui->horizontalScrollBar->hide();
else
m_ui->horizontalScrollBar->show();
//qWarning() << "hori: min" << min << "max" << max;
m_ui->horizontalScrollBar->setRange(min, max);
m_ui->horizontalScrollBar->setPageStep(m_ui->searchView->horizontalScrollBar()->pageStep());
}
void LtsDataView::updateColumnsVisibility(const QVector<ColumnOrganiserInfo> &data)
{
const int colCount = m_columnFilterProxy->columnCount();
for(const auto &ci : data)
{
if(ci.logicalIndex >= colCount || ci.logicalIndex < 0)
continue;
m_ui->searchView->setColumnHidden(ci.logicalIndex, ci.hide());
}
// save setting
saveTableSettings();
}
void LtsDataView::slotSetColumnsDefaultOrder()
{
saveTableSettings(true);
m_userChangedColumnPos = false; // save is already done so avoid saving while restoring data
restoreTableSettings();
m_userChangedColumnPos = true;
}
void LtsDataView::slotSetHorizontalValue(int val)
{
m_ui->horizontalScrollBar->setValue(val);
}
void LtsDataView::slotSetVerticalRange(int , int )
{
// when custom view gets new data (dds data topic), table view and custom view send new ranges, only take the range of the active tab in stacked widget
m_ui->tableView->verticalScrollBar()->hide(); // always hide!
m_ui->customView->verticalScrollBar()->hide(); // always hide!
QScrollBar *whichScrollBar = m_ui->tableView->verticalScrollBar();
if (m_ui->stackedWidget->currentIndex() == CUSTOM)
whichScrollBar = m_ui->customView->verticalScrollBar();
int min = whichScrollBar->minimum();
int max = whichScrollBar->maximum();
int pagestep = whichScrollBar->pageStep();
if (!min && !max) // no min, no max = not visible
m_ui->verticalScrollBar->hide();
else
m_ui->verticalScrollBar->show();
// dont know which scrollbar it is
m_ui->verticalScrollBar->setRange(min, max);
m_ui->verticalScrollBar->setPageStep(pagestep);
}
void LtsDataView::slotSetVerticalValue(int val)
{
QScrollBar *caller = qobject_cast<QScrollBar *>(QObject::sender());
if (caller && caller->isVisible())
m_ui->verticalScrollBar->setVisible(caller->isVisible());
m_ui->verticalScrollBar->setValue(val);
}
void LtsDataView::slotSectionResized(int index, int oldSize, int newSize)
{
if (newSize == 0)
{
m_ui->tableView->setColumnHidden(index, true);
return;
}
if (oldSize == 0)
m_ui->tableView->setColumnHidden(index, false);
m_ui->tableView->setColumnWidth(index, newSize);
}
void LtsDataView::slotHeaderMoved(int logicalColumn, int oldColumn, int newColumn)
{
Q_UNUSED(logicalColumn);
m_ui->tableView->header()->moveSection(oldColumn, newColumn);
if (m_userChangedColumnPos)
{
qWarning()<<">>>> [updateColumnsVisibility]";
saveTableSettings();
}
}
void LtsDataView::slotCsvExport() // TODO: maybe save to dds (office/filemanagement) instead of hd?
{
if (!m_columnFilterProxy)
return;
QFileDialog dialog(this); // save dialog
//dialog.setFileMode(QFileDialog::ExistingFile); // single file selection
dialog.setNameFilter(tr("CSV File (*.csv)"));
dialog.setAcceptMode(QFileDialog::AcceptSave);
if (!dialog.exec())
return;
const QStringList fileNames = dialog.selectedFiles();
if (fileNames.isEmpty())
return;
QFile file;
file.setFileName(fileNames.first());
if (!file.open(QFile::ReadWrite))
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("File '%1' is not accessible").arg(fileNames.at(0)), tr("CSV Export"));
return;
}
QHeaderView* hdr = m_ui->tableView->header();
QMap<int, int> colsHeader; //<visualIndex, logicalIndex>
// create header csv
const int cols = m_columnFilterProxy->columnCount();
QStringList colsList;
colsList.reserve(cols);
for (int i = 0; i < cols; ++i)
{
if (m_ui->stackedWidget->currentIndex() != TABLE || !m_ui->tableView->isColumnHidden(i))
{
int visualIndex = hdr->visualIndex(i);
colsHeader[visualIndex] = i;
//colsList.append(m_columnFilterProxy->headerData(i, Qt::Horizontal).toString());
}
}
for (const int logicalIndex : std::as_const(colsHeader))
colsList.append(m_columnFilterProxy->headerData(logicalIndex, Qt::Horizontal).toString());
//qCritical() << "slotCsvExport: header colsList = " << colsList;
const QString columnCsv = colsList.join(QLatin1Char(';'));
file.write(columnCsv.toLocal8Bit()); // write header
file.write("\n");
// write csv body
//file.write(createCsv().toStdString().c_str());
// create body csv (with all rows)
// TODO: threaded? as this can take a while
const int rows = m_columnFilterProxy->rowCount();
QStringList rowsList;
rowsList.reserve(rows);
for (int row = 0; row < rows; ++row)
{
colsList.clear();
for (const int logicalIndex : std::as_const(colsHeader))
colsList.append(m_columnFilterProxy->data(m_columnFilterProxy->index(row, logicalIndex)).toString());
// for (int col = 0; col < cols; col++)
// if (m_ui->stackedWidget->currentIndex() != TABLE || !m_ui->tableView->isColumnHidden(col))
// colsList.append(m_columnFilterProxy->data(m_columnFilterProxy->index(row, col)).toString());
//qCritical() << "slotCsvExport: row = "<< row << ", colsList = " << colsList;
rowsList.append(colsList.join(QLatin1Char(';')));
}
const QString csvBody = rowsList.join(QLatin1Char('\n')); // TODO: windows?
file.write(csvBody.toLocal8Bit());
file.close();
LtsWidgets::LtsMessageDialog::showMessage(this, tr("CSV Export was successful"), tr("CSV Export"));
}
void LtsDataView::slotResizeColumn(int columnIndex)
{
m_ui->tableView->resizeColumnToContents(columnIndex);
QHeaderView *header = m_ui->searchView->header();
int minimumWidth = header->sectionSize(columnIndex);
int contentWidth = m_ui->tableView->columnWidth(columnIndex);
if (contentWidth > minimumWidth)
header->resizeSection(columnIndex, contentWidth);
else
m_ui->tableView->header()->resizeSection(columnIndex, minimumWidth);
}
void LtsDataView::onCustomContextMenuRequested(const QPoint &pos)
{
if (!m_ui)
return;
QModelIndex mi;
QPoint globalPos;
if (m_ui->stackedWidget->currentIndex() == CUSTOM)
{
if (m_ui->customView)
{
mi = m_ui->customView->indexAt(pos);
globalPos = m_ui->customView->mapToGlobal(pos);
} else if (m_ui->tableView)
{
mi = m_ui->tableView->indexAt(pos);
globalPos = m_ui->tableView->mapToGlobal(pos);
}
} else if (m_ui->stackedWidget->currentIndex() == TABLE)
{
if (m_ui->tableView)
{
mi = m_ui->tableView->indexAt(pos);
globalPos = m_ui->tableView->mapToGlobal(pos);
}
}
emit signalContextMenuRequested(globalPos, mapToSource(mi));
}
//void LtsDataView::setDelegate(std::function<AbstractDisplayWidget*()> delegateFunction)
//{
// m_ui->customView->setDelegate(delegateFunction);
//}
} // namespace LtsDataView