#include "logview.h" #include "ui_logview.h" #include "qad_types.h" #include "ecombobox.h" #include #include #include #include #include #include #include #include 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, qreal ratio) { icon_image = QImage(); if (!image.isNull()) { icon_image = image.scaled(size * ratio, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) icon_image.setDevicePixelRatio(ratio); #endif } QPixmap px = QPixmap::fromImage(image.scaled(size_icon * ratio, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) px.setDevicePixelRatio(ratio); #endif 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, QBrush text_brush, QBrush background, 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, text_brush, background, bold); } void LogView::registerCategory(const QString & label, QRegularExpression regexp, const QImage & icon, QBrush text_brush, QBrush background, bool bold) { if (!regexp.isValid() || regexp.pattern().isEmpty()) return; removeCategory(regexp); Category c; c.regexp = regexp; c.label = label; c.image = icon; c.text_brush = text_brush; c.background = background; c.bold = bold; c.makeIcon(iconImageSize(), preferredIconSize(1., this) #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) , devicePixelRatioF() #endif ); 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 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) , devicePixelRatioF() #endif ); } 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; if (c.text_brush != Qt::NoBrush) cf.setForeground(c.text_brush); if (c.background != Qt::NoBrush) bf.setBackground(c.background); 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.setCharFormat(def_cf); tc.insertBlock(); 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()); }