328 lines
8.7 KiB
C++
328 lines
8.7 KiB
C++
#include "logview.h"
|
|
#include "ui_logview.h"
|
|
#include "qad_types.h"
|
|
#include "ecombobox.h"
|
|
#include <QTextDocument>
|
|
#include <QAbstractTextDocumentLayout>
|
|
#include <QTextEdit>
|
|
#include <QTextBlock>
|
|
#include <QScrollBar>
|
|
#include <QPixmap>
|
|
#include <QEvent>
|
|
#include <QTextBlockUserData>
|
|
|
|
|
|
class TextBlockData: public QTextBlockUserData {
|
|
public:
|
|
TextBlockData(const QString & kw): keyword(kw) {}
|
|
QString keyword;
|
|
};
|
|
|
|
|
|
|
|
|
|
LogView::Category::Category() {
|
|
bold = false;
|
|
}
|
|
|
|
|
|
void LogView::Category::makeIcon(QSize size, QSize size_icon) {
|
|
icon_image = QImage();
|
|
if (!image.isNull())
|
|
icon_image = image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
|
QPixmap px = QPixmap::fromImage(image.scaled(size_icon, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
|
icon.addPixmap(px, QIcon::Active);
|
|
icon.addPixmap(px, QIcon::Disabled);
|
|
icon.addPixmap(px, QIcon::Normal);
|
|
icon.addPixmap(px, QIcon::Selected);
|
|
}
|
|
|
|
|
|
LogView::LogView(QWidget * parent): QWidget(parent) {
|
|
ui = new Ui::LogView();
|
|
ui->setupUi(this);
|
|
ui->textEdit->setContextMenuPolicy(Qt::ActionsContextMenu);
|
|
actionLogSelectAll = new QAction(QIcon(":/icons/select-all.png"), tr("Select All"), this);
|
|
actionLogCopy = new QAction(QIcon(":/icons/edit-copy.png"), tr("Copy"), this);
|
|
actionLogClear = new QAction(QIcon(":/icons/edit-clear.png"), tr("Clear"), this);
|
|
connect(actionLogSelectAll, SIGNAL(triggered(bool)), ui->textEdit, SLOT(selectAll()));
|
|
connect(actionLogCopy, SIGNAL(triggered(bool)), ui->textEdit, SLOT(copy()));
|
|
connect(actionLogClear, SIGNAL(triggered(bool)), ui->textEdit, SLOT(clear()));
|
|
ui->textEdit->addAction(actionLogSelectAll);
|
|
ui->textEdit->addAction(actionLogCopy);
|
|
ui->textEdit->addAction(actionLogClear);
|
|
ui->buttonClear->setDefaultAction(ui->actionClear);
|
|
ui->labelIconSearch->setFixedSize(preferredIconSize(1.2, this));
|
|
ui->comboCategory->addItem(tr("All"));
|
|
ui->textEdit->document()->setUndoRedoEnabled(false);
|
|
setLinesLimit(10000);
|
|
QTextCursor tc(ui->textEdit->document());
|
|
def_cf = tc.charFormat();
|
|
def_bf = tc.blockFormat();
|
|
}
|
|
|
|
|
|
LogView::~LogView() {
|
|
delete ui;
|
|
}
|
|
|
|
|
|
const QTextEdit * LogView::textEdit() const {
|
|
return ui->textEdit;
|
|
}
|
|
|
|
|
|
void LogView::setLogFont(QFont f) {
|
|
ui->textEdit->document()->setDefaultFont(f);
|
|
QTextCursor tc(ui->textEdit->document());
|
|
def_cf = tc.charFormat();
|
|
def_bf = tc.blockFormat();
|
|
}
|
|
|
|
|
|
QFont LogView::logFont() const {
|
|
return ui->textEdit->document()->defaultFont();
|
|
}
|
|
|
|
|
|
bool LogView::isFilterVisible() const {
|
|
return ui->widgetToolbar->isVisible();
|
|
}
|
|
|
|
|
|
int LogView::linesLimit() const {
|
|
int ret = ui->textEdit->document()->maximumBlockCount();
|
|
if (ret > 0) --ret;
|
|
return ret;
|
|
}
|
|
|
|
|
|
void LogView::registerCategory(const QString & label, QString keyword, const QImage & icon, QColor color, bool bold) {
|
|
QRegularExpression regexp(keyword,
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
|
QRegularExpression::PatternOptions(QRegularExpression::CaseInsensitiveOption)
|
|
#else
|
|
Qt::CaseInsensitive
|
|
#endif
|
|
);
|
|
registerCategory(label, regexp, icon, color, bold);
|
|
}
|
|
|
|
|
|
void LogView::registerCategory(const QString & label, QRegularExpression regexp, const QImage & icon, QColor color, bool bold) {
|
|
if (!regexp.isValid() || regexp.pattern().isEmpty()) return;
|
|
removeCategory(regexp);
|
|
Category c;
|
|
c.regexp = regexp;
|
|
c.label = label;
|
|
c.image = icon;
|
|
c.color = color;
|
|
c.bold = bold;
|
|
c.makeIcon(iconImageSize(), preferredIconSize(1., this));
|
|
categories.append(c);
|
|
ui->comboCategory->addItem(c.icon, label, QVariant(regexp));
|
|
}
|
|
|
|
|
|
void LogView::removeCategory(QString keyword) {
|
|
QRegularExpression regexp(keyword,
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
|
QRegularExpression::PatternOptions(QRegularExpression::CaseInsensitiveOption)
|
|
#else
|
|
Qt::CaseInsensitive
|
|
#endif
|
|
);
|
|
removeCategory(regexp);
|
|
}
|
|
|
|
|
|
void LogView::removeCategory(QRegularExpression regexp) {
|
|
Category c;
|
|
c.regexp = regexp;
|
|
categories.removeAll(c);
|
|
for (int i = 1; i < ui->comboCategory->count(); ++i) {
|
|
if (ui->comboCategory->itemData(i).
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
|
toRegularExpression()
|
|
#else
|
|
toRegExp()
|
|
#endif
|
|
.pattern() == regexp.pattern()) {
|
|
ui->comboCategory->removeItem(i);
|
|
--i;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void LogView::clearCategories() {
|
|
ui->comboCategory->blockSignals(true);
|
|
while (ui->comboCategory->count() > 1)
|
|
ui->comboCategory->removeItem(ui->comboCategory->count() - 1);
|
|
categories.clear();
|
|
ui->comboCategory->blockSignals(false);
|
|
filter();
|
|
}
|
|
|
|
|
|
void LogView::addText(const QString & text, bool insert_newline) {
|
|
addText(text, QString(), insert_newline);
|
|
}
|
|
|
|
|
|
void LogView::addText(const QString & text, const QString & keyword, bool insert_newline) {
|
|
if (text.isEmpty()) return;
|
|
QTextCursor tc(ui->textEdit->document());
|
|
QStringList sl = text.split("\n");
|
|
tc.movePosition(QTextCursor::End);
|
|
QScrollBar * bar = ui->textEdit->verticalScrollBar();
|
|
bool at_end = (bar->value() == bar->maximum()) || bar->isHidden();
|
|
for (int i = 0; i < sl.size(); ++i) {
|
|
tc.insertText(sl[i]);
|
|
if (!keyword.isEmpty())
|
|
tc.block().setUserData(new TextBlockData(keyword));
|
|
if ((i < sl.size() - 1) || insert_newline)
|
|
newLine(keyword);
|
|
}
|
|
if (at_end)
|
|
scrollToBottom();
|
|
}
|
|
|
|
|
|
void LogView::changeEvent(QEvent * e) {
|
|
QWidget::changeEvent(e);
|
|
switch (e->type()) {
|
|
case QEvent::LanguageChange:
|
|
ui->retranslateUi(this);
|
|
ui->comboCategory->setItemText(0, tr("All"));
|
|
actionLogSelectAll->setText(tr("Select All"));
|
|
actionLogCopy->setText(tr("Copy"));
|
|
actionLogClear->setText(tr("Clear"));
|
|
break;
|
|
case QEvent::Polish: {
|
|
ui->labelIconSearch->setFixedSize(preferredIconSize(1.2, this));
|
|
QSize is = iconImageSize(), is_i = preferredIconSize(1., this);
|
|
for (int i = 0; i < categories.size(); ++i)
|
|
categories[i].makeIcon(is, is_i);
|
|
} break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
|
|
void LogView::newLine(const QString & keyword) {
|
|
QTextCursor tc(ui->textEdit->document());
|
|
tc.movePosition(QTextCursor::End);
|
|
tc.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
|
|
QString line = tc.selectedText();
|
|
QImage icon;
|
|
foreach (const Category & c, categories) {
|
|
bool matched = false;
|
|
if (keyword.isEmpty()) matched = line.contains(c.regexp);
|
|
else matched = (keyword == c.regexp.pattern());
|
|
if (matched) {
|
|
QTextCharFormat cf = def_cf;
|
|
QTextBlockFormat bf = def_bf;
|
|
bf.setBackground(c.color);
|
|
if (c.bold)
|
|
cf.setFontWeight(QFont::Bold);
|
|
tc.setCharFormat(cf);
|
|
tc.setBlockFormat(bf);
|
|
icon = c.icon_image;
|
|
break;
|
|
}
|
|
}
|
|
if (!icon.isNull()) {
|
|
tc.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
|
|
tc.insertImage(icon);
|
|
}
|
|
QRegularExpression regexp =
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
|
ui->comboCategory->currentData().toRegularExpression();
|
|
#else
|
|
ui->comboCategory->itemData(ui->comboCategory->currentIndex()).toRegExp();
|
|
#endif
|
|
QString fs = ui->lineEdit->text();
|
|
if (isFilterVisible())
|
|
filterBlock(tc.block(), fs, regexp);
|
|
tc.movePosition(QTextCursor::End);
|
|
tc.insertBlock();
|
|
tc.setCharFormat(def_cf);
|
|
tc.setBlockFormat(def_bf);
|
|
}
|
|
|
|
|
|
QSize LogView::iconImageSize() {
|
|
int hei = QFontMetrics(ui->textEdit->document()->defaultFont()).height() / 1.25;
|
|
return QSize(hei, hei);
|
|
}
|
|
|
|
|
|
void LogView::filterBlock(QTextBlock block, const QString & fs, const QRegularExpression & regexp) {
|
|
bool vis = true;//, pvis = block.isVisible();
|
|
QString line = block.text();
|
|
if (!line.isEmpty()) {
|
|
if (line[0] == QChar::ObjectReplacementCharacter)
|
|
line.remove(0, 1);
|
|
}
|
|
if (regexp.isValid() && !regexp.pattern().isEmpty()) {
|
|
QString kw;
|
|
TextBlockData * bd = (TextBlockData*)block.userData();
|
|
if (bd) kw = bd->keyword;
|
|
if (!kw.isEmpty())
|
|
vis = vis && (bd->keyword == regexp.pattern());
|
|
else
|
|
vis = vis && line.contains(regexp);
|
|
}
|
|
if (!fs.isEmpty()) vis = vis && line.contains(fs, Qt::CaseInsensitive);
|
|
block.setVisible(vis);
|
|
//qDebug() << "filterBlock" << line << vis;
|
|
//if (vis != pvis)
|
|
// ;//ui->textEdit->document()->mar
|
|
}
|
|
|
|
|
|
void LogView::setFilterVisible(bool yes) {
|
|
ui->widgetToolbar->setHidden(!yes);
|
|
filter();
|
|
}
|
|
|
|
|
|
void LogView::setLinesLimit(int l) {
|
|
ui->textEdit->document()->setMaximumBlockCount(l <= 0 ? 0 : l + 1);
|
|
}
|
|
|
|
|
|
void LogView::clear() {
|
|
ui->textEdit->clear();
|
|
}
|
|
|
|
|
|
void LogView::scrollToBottom() {
|
|
QScrollBar * bar = ui->textEdit->verticalScrollBar();
|
|
bar->setValue(bar->maximum());
|
|
}
|
|
|
|
|
|
void LogView::filter() {
|
|
QTextDocument * doc = ui->textEdit->document();
|
|
int bc = doc->blockCount();
|
|
QRegularExpression regexp;
|
|
QString fs;
|
|
if (isFilterVisible()) {
|
|
regexp =
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
|
ui->comboCategory->currentData().toRegularExpression();
|
|
#else
|
|
ui->comboCategory->itemData(ui->comboCategory->currentIndex()).toRegExp();
|
|
#endif
|
|
fs = ui->lineEdit->text();
|
|
}
|
|
QTextBlock bl;
|
|
for (int i = 0; i < bc; ++i) {
|
|
bl = doc->findBlockByNumber(i);
|
|
filterBlock(bl, fs, regexp);
|
|
}
|
|
doc->markContentsDirty(0, bl.position() + bl.length());
|
|
}
|