619 lines
22 KiB
C++
619 lines
22 KiB
C++
#include "gtl_gui_log_viewer.h"
|
||
|
||
#include <QHeaderView>
|
||
#include <QLayout>
|
||
#include <QLabel>
|
||
#include <QSpacerItem>
|
||
#include <QSpinBox>
|
||
#include <QMessageBox>
|
||
|
||
namespace gtl
|
||
{
|
||
namespace gui
|
||
{
|
||
/* * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
*
|
||
* log_viewer
|
||
*/
|
||
log_viewer::log_viewer(QWidget *parent)
|
||
: QWidget{parent}
|
||
{
|
||
QVBoxLayout* mainLayout = new QVBoxLayout;
|
||
setLayout( mainLayout );
|
||
|
||
m_view = new MyTableVeiw(this);
|
||
m_view->verticalHeader()->setVisible(false);
|
||
m_view->setAutoScroll(false);
|
||
m_view->verticalHeader()->setDefaultSectionSize(5);
|
||
m_view->setSelectionMode(QAbstractItemView::ContiguousSelection);
|
||
|
||
// * * * * * * * * * * * * * * *
|
||
// * change color of selected cell
|
||
const QColor hlClr = Qt::white; // highlight color to set
|
||
const QColor txtClr = Qt::black; // highlighted text color to set
|
||
QPalette p = palette();
|
||
p.setColor(QPalette::Highlight, hlClr);
|
||
p.setColor(QPalette::HighlightedText, txtClr);
|
||
setPalette(p);
|
||
|
||
connect(m_view, &QTableView::clicked, this, &log_viewer::slt_table_click);
|
||
connect(m_view->verticalScrollBar(), &QScrollBar::rangeChanged, this, &log_viewer::slt_set_scroll_range);
|
||
connect(m_view->verticalScrollBar(), &QScrollBar::valueChanged, this, &log_viewer::slt_set_scroll_value);
|
||
|
||
m_model = new log_viewer_model(this);
|
||
connect(gtl::logger::getInstance(), >l::logger::sgn_send_to_viewer, m_model, &log_viewer_model::slt_append_string);
|
||
|
||
m_proxy_model = new filter_proxy_model(this);
|
||
m_proxy_model->setSourceModel(m_model);
|
||
|
||
m_view->setModel(m_proxy_model);
|
||
m_view->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch);
|
||
|
||
connect(m_model, &QAbstractTableModel::rowsAboutToBeInserted, this, &log_viewer::slt_rows_about_to_be_inserted);
|
||
connect(m_model, &QAbstractTableModel::rowsInserted, this, &log_viewer::slt_data_changed);
|
||
|
||
// * * * * * * * * * * * * * * *
|
||
// *
|
||
// * levels
|
||
// *
|
||
// * * * * * * * * * * * * * * *
|
||
m_cbb_level = new QComboBox();
|
||
connect(m_cbb_level, &QComboBox::currentIndexChanged, this, &log_viewer::slt_check_levels);
|
||
m_cbb_level->addItem("info");
|
||
m_cbb_level->addItem("warning");
|
||
m_cbb_level->addItem("error");
|
||
m_cbb_level->addItem("debug");
|
||
|
||
// * * * * * * * * * * * * * * *
|
||
// *
|
||
// * searc text
|
||
// *
|
||
// * * * * * * * * * * * * * * *
|
||
m_le_search_string = new QLineEdit();
|
||
m_le_search_string->setClearButtonEnabled(true);
|
||
m_le_search_string->setPlaceholderText("Search text ...");
|
||
connect(m_le_search_string, &QLineEdit::textChanged, this, &log_viewer::slt_update_search_string);
|
||
|
||
// * * * * * * * * * * * * * * *
|
||
// *
|
||
// * date time filter
|
||
// *
|
||
// * * * * * * * * * * * * * * *
|
||
QHBoxLayout* hl_date_time = new QHBoxLayout;
|
||
m_le_dt_from = new QLineEdit();
|
||
m_le_dt_from->setClearButtonEnabled(true);
|
||
m_action_le_dt_from = m_le_dt_from->addAction(this->style()->standardIcon(QStyle::SP_TitleBarNormalButton), QLineEdit::LeadingPosition);
|
||
m_le_dt_from->setPlaceholderText("from ...");
|
||
connect(m_action_le_dt_from, &QAction::triggered, this, &log_viewer::slt_dialog_set_datetime);
|
||
connect(m_le_dt_from, &QLineEdit::textChanged, this, &log_viewer::slt_update_dt);
|
||
|
||
|
||
m_le_dt_to = new QLineEdit();
|
||
m_le_dt_to->setClearButtonEnabled(true);
|
||
m_action_le_dt_to = m_le_dt_to->addAction(this->style()->standardIcon(QStyle::SP_TitleBarNormalButton), QLineEdit::LeadingPosition);
|
||
m_le_dt_to->setPlaceholderText("to ...");
|
||
connect(m_action_le_dt_to, &QAction::triggered, this, &log_viewer::slt_dialog_set_datetime);
|
||
connect(m_le_dt_to, &QLineEdit::textChanged, this, &log_viewer::slt_update_dt);
|
||
|
||
QLabel* l_date_time = new QLabel(" - ");
|
||
|
||
hl_date_time->addWidget(m_le_dt_from);
|
||
hl_date_time->addWidget(l_date_time);
|
||
hl_date_time->addWidget(m_le_dt_to);
|
||
|
||
// * * * * * * * * * * * * * * *
|
||
// *
|
||
// * btn reset search
|
||
// *
|
||
// * * * * * * * * * * * * * * *
|
||
m_b_reset_search = new QPushButton();
|
||
connect(m_b_reset_search, &QPushButton::clicked, this, &log_viewer::slt_reset_search);
|
||
m_b_reset_search->setText("Reset search");
|
||
|
||
// * * * * * * * * * * * * * * *
|
||
// *
|
||
// * btn clear data
|
||
// *
|
||
// * * * * * * * * * * * * * * *
|
||
m_b_clear_data = new QPushButton();
|
||
connect(m_b_clear_data, &QPushButton::clicked, [this]()
|
||
{
|
||
m_model->clear();
|
||
});
|
||
m_b_clear_data->setText("Clear");
|
||
|
||
QHBoxLayout* hl_common = new QHBoxLayout;
|
||
hl_common->addWidget(m_cbb_level);
|
||
hl_common->addWidget(m_le_search_string);
|
||
hl_common->addLayout(hl_date_time);
|
||
hl_common->addWidget(m_b_reset_search);
|
||
hl_common->addWidget(m_b_clear_data);
|
||
|
||
mainLayout->addLayout(hl_common);
|
||
mainLayout->addWidget(m_view);
|
||
}
|
||
|
||
void log_viewer::slt_check_levels(int index)
|
||
{
|
||
QString str_mass_filter = "";
|
||
|
||
switch(index)
|
||
{
|
||
case 0:
|
||
str_mass_filter += "INFO|WARNING|ERROR";
|
||
break;
|
||
|
||
case 1:
|
||
str_mass_filter += "WARNING|ERROR";
|
||
break;
|
||
|
||
case 2:
|
||
str_mass_filter += "ERROR";
|
||
break;
|
||
|
||
case 3:
|
||
str_mass_filter += "DEBUG";
|
||
break;
|
||
}
|
||
|
||
m_proxy_model->set_filter_level(str_mass_filter);
|
||
}
|
||
|
||
|
||
void log_viewer::slt_update_search_string(void)
|
||
{
|
||
if(m_le_search_string->text().isEmpty())
|
||
m_proxy_model->set_disable_search_string();
|
||
else
|
||
{
|
||
m_proxy_model->set_search_string(m_le_search_string->text());
|
||
m_proxy_model->set_enable_search_string();
|
||
}
|
||
}
|
||
|
||
|
||
void log_viewer::slt_reset_search(void)
|
||
{
|
||
m_le_search_string->setText("");
|
||
|
||
m_le_dt_from->setText("");
|
||
m_le_dt_to->setText("");
|
||
|
||
m_proxy_model->set_search_string("");
|
||
m_proxy_model->set_disable_search_string();
|
||
m_proxy_model->set_disable_date_filter();
|
||
}
|
||
|
||
|
||
void log_viewer::slt_dialog_set_datetime(void)
|
||
{
|
||
QAction *action_sender = (QAction *)sender();
|
||
|
||
QVBoxLayout* layout = new QVBoxLayout;
|
||
|
||
QTime timeNow = QTime::currentTime();
|
||
|
||
QSpacerItem *space_left = new QSpacerItem(10, 10, QSizePolicy::Expanding);
|
||
QSpacerItem *space_right = new QSpacerItem(10, 10, QSizePolicy::Expanding);
|
||
|
||
QLabel *l_hour = new QLabel(":");
|
||
QLabel *l_minute = new QLabel(":");
|
||
|
||
QSpinBox *hour = new QSpinBox();
|
||
hour->setMinimum(0);
|
||
hour->setMaximum(23);
|
||
hour->setValue(timeNow.hour());
|
||
|
||
QSpinBox *minute = new QSpinBox();
|
||
minute->setMinimum(0);
|
||
minute->setMaximum(59);
|
||
minute->setValue(timeNow.minute());
|
||
|
||
QSpinBox *second = new QSpinBox();
|
||
second->setMinimum(0);
|
||
second->setMaximum(59);
|
||
second->setValue(timeNow.second());
|
||
|
||
QHBoxLayout* layout_time = new QHBoxLayout;
|
||
|
||
layout_time->addSpacerItem(space_left);
|
||
layout_time->addWidget(hour);
|
||
layout_time->addWidget(l_hour);
|
||
layout_time->addWidget(minute);
|
||
layout_time->addWidget(l_minute);
|
||
layout_time->addWidget(second);
|
||
layout_time->addSpacerItem(space_right);
|
||
|
||
QPushButton *btn_ok = new QPushButton("&ОК");
|
||
btn_ok->setObjectName("btn_ok");
|
||
QPushButton *btn_cancel = new QPushButton("&Cancel");
|
||
btn_cancel->setObjectName("btn_cancel");
|
||
QHBoxLayout *layout_btn = new QHBoxLayout;
|
||
layout_btn->addWidget(btn_ok);
|
||
layout_btn->addWidget(btn_cancel);
|
||
|
||
m_calendar_widget = new QCalendarWidget(this);
|
||
|
||
layout->addWidget(m_calendar_widget);
|
||
layout->addLayout(layout_time);
|
||
layout->addLayout(layout_btn);
|
||
|
||
m_dialog_set_datetime = new QDialog(this);
|
||
m_dialog_set_datetime->setLayout(layout);
|
||
m_dialog_set_datetime->setWindowTitle("Select date and time");
|
||
|
||
connect(btn_ok, &QPushButton::clicked, m_dialog_set_datetime, &QDialog::accept);
|
||
connect(btn_cancel, &QPushButton::clicked, m_dialog_set_datetime, &QDialog::reject);
|
||
|
||
QString result_str;
|
||
if(m_dialog_set_datetime->exec() == QDialog::Accepted)
|
||
{
|
||
result_str = m_calendar_widget->selectedDate().toString("dd.MM.yyyy ") +
|
||
QString("%1:").arg(hour->value(), 2, 10, QLatin1Char('0')) +
|
||
QString("%1:").arg(minute->value(), 2, 10, QLatin1Char('0')) +
|
||
QString("%1").arg(second->value(), 2, 10, QLatin1Char('0'));
|
||
|
||
if(action_sender == m_action_le_dt_from)
|
||
m_le_dt_from->setText(result_str);
|
||
else if(action_sender == m_action_le_dt_to)
|
||
m_le_dt_to->setText(result_str);
|
||
}
|
||
}
|
||
|
||
void log_viewer::slt_update_dt(void)
|
||
{
|
||
if( (false == m_le_dt_from->text().isEmpty()) &&
|
||
(false == m_le_dt_to->text().isEmpty()) )
|
||
{
|
||
QDateTime dt_from = QDateTime::fromString(m_le_dt_from->text(), "dd.MM.yyyy hh:mm:ss");
|
||
QDateTime dt_to = QDateTime::fromString(m_le_dt_to->text(), "dd.MM.yyyy hh:mm:ss");
|
||
if(dt_from > dt_to)
|
||
{
|
||
QMessageBox::warning(this,
|
||
"Warning",
|
||
"Date From must be earlier than Date To",
|
||
QMessageBox::Ok,
|
||
QMessageBox::Ok );
|
||
m_proxy_model->set_disable_date_filter();
|
||
}
|
||
else
|
||
{
|
||
m_proxy_model->set_datetime_filter(dt_from, dt_to);
|
||
m_proxy_model->set_enable_date_filter();
|
||
}
|
||
}
|
||
else
|
||
m_proxy_model->set_disable_date_filter();
|
||
}
|
||
|
||
void log_viewer::slt_rows_about_to_be_inserted()
|
||
{
|
||
m_prev_index = m_view->currentIndex();
|
||
m_prev_value = m_view->verticalScrollBar()->value();
|
||
}
|
||
|
||
void log_viewer::slt_data_changed(void)
|
||
{
|
||
// this condition is necessary for the correct display of the last rows of the table
|
||
if((m_scroll_max - m_view->verticalScrollBar()->value()) > 4 )
|
||
m_view->scrollTo( m_prev_index, QAbstractItemView::PositionAtCenter );
|
||
else
|
||
m_view->scrollTo( m_prev_index, QAbstractItemView::PositionAtTop );
|
||
m_prev_value = m_view->verticalScrollBar()->value();
|
||
}
|
||
|
||
void log_viewer::slt_set_scroll_range(int min, int max)
|
||
{
|
||
m_scroll_min = min;
|
||
m_scroll_max = max;
|
||
}
|
||
|
||
void log_viewer::slt_table_click(const QModelIndex &index)
|
||
{
|
||
m_prev_index = index;
|
||
m_view->setCurrentIndex(index);
|
||
m_prev_value = m_view->verticalScrollBar()->value();
|
||
}
|
||
|
||
void log_viewer::slt_set_scroll_value()
|
||
{
|
||
int curr_value = m_view->verticalScrollBar()->value();
|
||
|
||
// if scroll in top position - then start autoscroll
|
||
if(curr_value == m_scroll_min)
|
||
{
|
||
m_prev_index = QModelIndex();
|
||
m_view->setCurrentIndex(m_prev_index);
|
||
m_prev_value = curr_value;
|
||
return;
|
||
}
|
||
|
||
// if not select cell
|
||
if(m_prev_index == QModelIndex())
|
||
{
|
||
m_prev_index = m_view->indexAt(m_view->rect().center());
|
||
m_view->setCurrentIndex(m_prev_index);
|
||
m_prev_value = curr_value;
|
||
}
|
||
|
||
// if move slider or page UP/DOWN
|
||
if(m_view->verticalScrollBar()->isSliderDown() || m_view->verticalScrollBar()->hasFocus() || m_view->verticalScrollBar()->underMouse())
|
||
{
|
||
if(m_prev_value < curr_value)
|
||
{
|
||
int row = m_prev_index.row() + (curr_value - m_prev_value);
|
||
if(row > m_scroll_max)
|
||
row = m_scroll_max;
|
||
m_prev_index = QModelIndex(m_view->model()->index(row, m_prev_index.column()));
|
||
m_view->setCurrentIndex(m_prev_index);
|
||
m_prev_value = curr_value;
|
||
}
|
||
else if(m_prev_value > curr_value)
|
||
{
|
||
int row = m_prev_index.row() - (m_prev_value - curr_value);
|
||
if(row < m_scroll_min)
|
||
row = m_scroll_min;
|
||
m_prev_index = QModelIndex(m_view->model()->index(row, m_prev_index.column()));
|
||
m_view->setCurrentIndex(m_prev_index);
|
||
m_prev_value = curr_value;
|
||
}
|
||
else
|
||
{
|
||
m_prev_value = curr_value;
|
||
}
|
||
}
|
||
else // if mouse whell active
|
||
{
|
||
if(m_view->flag_whell_rotate == MyTableVeiw::Rotate::DOWN)
|
||
{
|
||
m_view->flag_whell_rotate = MyTableVeiw::Rotate::NONE;
|
||
if(m_prev_value < curr_value)
|
||
{
|
||
int row = m_prev_index.row() + (curr_value - m_prev_value);
|
||
if(row > m_scroll_max)
|
||
row = m_scroll_max;
|
||
m_prev_index = QModelIndex(m_view->model()->index(row, m_prev_index.column()));
|
||
m_view->setCurrentIndex(m_prev_index);
|
||
m_prev_value = curr_value;
|
||
}
|
||
else
|
||
{
|
||
m_prev_value = curr_value;
|
||
}
|
||
|
||
}
|
||
else if(m_view->flag_whell_rotate ==MyTableVeiw::Rotate::UP)
|
||
{
|
||
m_view->flag_whell_rotate = MyTableVeiw::Rotate::NONE;
|
||
if(m_prev_value > curr_value)
|
||
{
|
||
int row = m_prev_index.row() - (m_prev_value - curr_value);
|
||
if(row < m_scroll_min)
|
||
row = m_scroll_min;
|
||
m_prev_index = QModelIndex(m_view->model()->index(row, m_prev_index.column()));
|
||
m_view->setCurrentIndex(m_prev_index);
|
||
m_prev_value = curr_value;
|
||
}
|
||
else
|
||
{
|
||
m_prev_value = curr_value;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
*
|
||
* MySortFilterProxyModel
|
||
*/
|
||
filter_proxy_model::filter_proxy_model(QObject *parent)
|
||
: QSortFilterProxyModel(parent)
|
||
{
|
||
m_filter_level = "INFO|WARNING|ERROR|DEBUG";
|
||
m_search_string = "";
|
||
m_enable_text_search = false;
|
||
m_enable_date_filter = false;
|
||
}
|
||
|
||
bool filter_proxy_model::filterAcceptsRow(int sourceRow,
|
||
const QModelIndex &sourceParent) const
|
||
{
|
||
// TEXT TAG: find rows containing search strings in Tag and Text
|
||
if(m_enable_text_search)
|
||
{
|
||
if(false == m_search_string.isEmpty())
|
||
{
|
||
QModelIndex indexTag = sourceModel()->index(sourceRow, 3, sourceParent);
|
||
QModelIndex indexText = sourceModel()->index(sourceRow, 4, sourceParent);
|
||
if( (false == (sourceModel()->data(indexTag).toString().contains(m_search_string, Qt::CaseInsensitive))) &&
|
||
(false == (sourceModel()->data(indexText).toString().contains(m_search_string, Qt::CaseInsensitive))) )
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// DATE TIME: find rows with correct date time
|
||
if(m_enable_date_filter)
|
||
{
|
||
// get date
|
||
QModelIndex index = sourceModel()->index(sourceRow, 1, sourceParent);
|
||
QString check_dt = sourceModel()->data(index).toString() + " ";
|
||
|
||
// get time
|
||
index = sourceModel()->index(sourceRow, 2, sourceParent);
|
||
check_dt += sourceModel()->data(index).toString();
|
||
|
||
if(false == check_date_in_range( QDateTime::fromString(check_dt, "dd.MM.yyyy hh:mm:ss.zzz")) )
|
||
return false;
|
||
}
|
||
|
||
// LEVEL: find rows with selected levels
|
||
QModelIndex indexLevel = sourceModel()->index(sourceRow, 0, sourceParent);
|
||
|
||
if(false == m_filter_level.isEmpty())
|
||
{
|
||
QStringList list = m_filter_level.split("|");
|
||
if(!list.isEmpty())
|
||
{
|
||
foreach(QString str, list)
|
||
{
|
||
if((sourceModel()->data(indexLevel).toString().contains(str) ) )
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
bool filter_proxy_model::check_date_in_range(QDateTime date) const
|
||
{
|
||
return ((date >= m_dt_from) &&
|
||
(date <= m_dt_to));
|
||
}
|
||
|
||
void filter_proxy_model::set_filter_level(const QString &level)
|
||
{
|
||
m_filter_level = level;
|
||
invalidateFilter();
|
||
}
|
||
|
||
void filter_proxy_model::set_search_string(const QString &str)
|
||
{
|
||
m_search_string = str;
|
||
}
|
||
|
||
void filter_proxy_model::set_enable_search_string(void)
|
||
{
|
||
m_enable_text_search = true;
|
||
invalidateFilter();
|
||
}
|
||
|
||
void filter_proxy_model::set_disable_search_string(void)
|
||
{
|
||
m_enable_text_search = false;
|
||
invalidateFilter();
|
||
}
|
||
|
||
void filter_proxy_model::set_datetime_filter(QDateTime from, QDateTime to)
|
||
{
|
||
m_dt_from = from;
|
||
m_dt_to = to;
|
||
}
|
||
|
||
void filter_proxy_model::set_enable_date_filter(void)
|
||
{
|
||
m_enable_date_filter = true;
|
||
invalidateFilter();
|
||
}
|
||
|
||
void filter_proxy_model::set_disable_date_filter(void)
|
||
{
|
||
m_enable_date_filter = false;
|
||
invalidateFilter();
|
||
}
|
||
|
||
/* * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
*
|
||
* LogViewerModel
|
||
*/
|
||
log_viewer_model::log_viewer_model( QObject* parent ) : QAbstractTableModel( parent )
|
||
{
|
||
}
|
||
|
||
int log_viewer_model::rowCount( const QModelIndex& parent ) const
|
||
{
|
||
Q_UNUSED( parent )
|
||
return m_logs.count();
|
||
}
|
||
|
||
int log_viewer_model::columnCount( const QModelIndex& parent ) const
|
||
{
|
||
Q_UNUSED( parent )
|
||
return LAST;
|
||
}
|
||
|
||
QVariant log_viewer_model::headerData( int section, Qt::Orientation orientation, int role ) const
|
||
{
|
||
if( role != Qt::DisplayRole ) {
|
||
return QVariant();
|
||
}
|
||
|
||
if( orientation == Qt::Vertical ) {
|
||
return section;
|
||
}
|
||
|
||
switch( section ) {
|
||
case LEVEL:
|
||
return "Level";
|
||
case DATE:
|
||
return "Date";
|
||
case TIME:
|
||
return "Time";
|
||
case TAG:
|
||
return "Tag";
|
||
case TEXT:
|
||
return "Text";
|
||
}
|
||
|
||
return QVariant();
|
||
}
|
||
|
||
|
||
QVariant log_viewer_model::data( const QModelIndex& index, int role ) const
|
||
{
|
||
if( !index.isValid() ||
|
||
m_logs.count() <= index.row() ||
|
||
( role != Qt::DisplayRole))
|
||
{
|
||
return QVariant();
|
||
}
|
||
|
||
return m_logs[ index.row() ][ Column( index.column() ) ];
|
||
}
|
||
|
||
void log_viewer_model::slt_append_string( const QString& level, const QString& date, const QString& time, const QString& tag, const QString& text )
|
||
{
|
||
LogViewerData log;
|
||
log[ LEVEL ] = level;
|
||
log[ DATE ] = date;
|
||
log[ TIME ] = time;
|
||
log[ TAG ] = tag;
|
||
log[ TEXT ] = text;
|
||
|
||
beginInsertRows( QModelIndex(), 0, 0 );
|
||
m_logs.insert(0, log );
|
||
endInsertRows();
|
||
|
||
emit sgnl_set_data();
|
||
}
|
||
|
||
|
||
bool log_viewer_model::setData( const QModelIndex& index, const QVariant& value, int role ) {
|
||
if( !index.isValid() || role != Qt::EditRole || m_logs.count() <= index.row() ) {
|
||
return false;
|
||
}
|
||
|
||
m_logs[ index.row() ][ Column( index.column() ) ] = value;
|
||
emit dataChanged( index, index );
|
||
|
||
return true;
|
||
}
|
||
|
||
void log_viewer_model::set_level_value(uint8_t val)
|
||
{
|
||
m_select_levels = val;
|
||
}
|
||
|
||
void log_viewer_model::clear()
|
||
{
|
||
beginResetModel();
|
||
m_logs.clear();
|
||
endResetModel();
|
||
}
|
||
}
|
||
}
|
||
|