File indexing completed on 2024-05-12 05:12:46

0001 /*
0002     SPDX-FileCopyrightText: 2018 Daniel Vrátil <dvratil@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "logging.h"
0008 #include "loggeradaptor.h"
0009 #include "loggingfiltermodel.h"
0010 #include "loggingmodel.h"
0011 
0012 #include <KLocalizedString>
0013 
0014 #include <QCheckBox>
0015 #include <QDBusConnection>
0016 #include <QFileDialog>
0017 #include <QHBoxLayout>
0018 #include <QHeaderView>
0019 #include <QLabel>
0020 #include <QMessageBox>
0021 #include <QPushButton>
0022 #include <QStandardItemModel>
0023 #include <QTreeView>
0024 
0025 #include <Libkdepim/KCheckComboBox>
0026 
0027 #include <KConfigGroup>
0028 #include <KSharedConfig>
0029 
0030 #ifndef COMPILE_WITH_UNITY_CMAKE_SUPPORT
0031 Q_DECLARE_METATYPE(LoggingModel::Message)
0032 #endif
0033 #define DBUS_PATH QStringLiteral("/logger")
0034 #define DBUS_INTERFACE QStringLiteral("org.kde.akonadiconsole.logger")
0035 
0036 using namespace KPIM;
0037 
0038 Logging::Logging(QWidget *parent)
0039     : QWidget(parent)
0040 {
0041     auto l = new QVBoxLayout(this);
0042     setLayout(l);
0043 
0044     mEnabledCheckbox = new QCheckBox(i18n("Enable"), this);
0045     connect(mEnabledCheckbox, &QCheckBox::toggled, this, [this](bool toggled) {
0046         Q_EMIT enabledChanged(toggled);
0047     });
0048     l->addWidget(mEnabledCheckbox);
0049 
0050     auto h = new QHBoxLayout;
0051     l->addLayout(h);
0052 
0053     h->addWidget(new QLabel(i18n("Programs:"), this));
0054     h->addWidget(mAppFilter = new KCheckComboBox());
0055     h->setStretchFactor(mAppFilter, 2);
0056     h->addWidget(new QLabel(i18n("Types:"), this));
0057     h->addWidget(mTypeFilter = new KCheckComboBox());
0058     h->setStretchFactor(mTypeFilter, 2);
0059     mTypeFilter->addItem(i18n("Debug"), QtDebugMsg);
0060     mTypeFilter->addItem(i18n("Info"), QtInfoMsg);
0061     mTypeFilter->addItem(i18n("Warning"), QtWarningMsg);
0062     mTypeFilter->addItem(i18n("Critical"), QtCriticalMsg);
0063     mTypeFilter->addItem(i18n("Fatal"), QtFatalMsg);
0064     h->addWidget(new QLabel(i18n("Categories:")));
0065     h->addWidget(mCategoryFilter = new KCheckComboBox());
0066     h->setStretchFactor(mCategoryFilter, 2);
0067 
0068     mModel = new LoggingModel(this);
0069 
0070     auto filterModel = new LoggingFilterModel(this);
0071     filterModel->setAppFilter(mAppFilter);
0072     filterModel->setCategoryFilter(mCategoryFilter);
0073     filterModel->setTypeFilter(mTypeFilter);
0074     filterModel->setSourceModel(mModel);
0075 
0076     for (int i = 0; i < mTypeFilter->count(); ++i) {
0077         mTypeFilter->setItemCheckState(i, Qt::Checked);
0078     }
0079 
0080     mView = new QTreeView;
0081     mView->setRootIsDecorated(false);
0082     l->addWidget(mView);
0083     mView->setModel(filterModel);
0084     mModel->setAppFilterModel(qobject_cast<QStandardItemModel *>(mAppFilter->model()));
0085     mModel->setCategoryFilterModel(qobject_cast<QStandardItemModel *>(mCategoryFilter->model()));
0086 
0087     h = new QHBoxLayout;
0088     l->addLayout(h);
0089 
0090     auto btn = new QPushButton(i18n("Save to File..."), this);
0091     connect(btn, &QPushButton::clicked, this, &Logging::saveToFile);
0092     h->addWidget(btn);
0093     h->addStretch(1);
0094 
0095     new LoggerAdaptor(this);
0096     QDBusConnection::sessionBus().registerObject(DBUS_PATH, this, QDBusConnection::ExportAdaptors);
0097 
0098     KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Logging"));
0099     mView->header()->restoreState(config.readEntry<QByteArray>("view", QByteArray()));
0100 }
0101 
0102 Logging::~Logging()
0103 {
0104     KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Logging"));
0105     config.writeEntry("view", mView->header()->saveState());
0106 }
0107 
0108 bool Logging::enabled() const
0109 {
0110     return mEnabledCheckbox->isChecked();
0111 }
0112 
0113 void Logging::message(qint64 timestamp,
0114                       const QString &app,
0115                       qint64 pid,
0116                       int type,
0117                       const QString &category,
0118                       const QString &file,
0119                       const QString &function,
0120                       int line,
0121                       int /*version*/,
0122                       const QString &msg)
0123 {
0124     mModel->addMessage(timestamp, app, pid, static_cast<QtMsgType>(type), category, file, function, line, msg);
0125 }
0126 
0127 void Logging::saveToFile()
0128 {
0129     const auto filename = QFileDialog::getSaveFileName(this, i18n("Save to File..."));
0130     if (filename.isEmpty()) {
0131         return;
0132     }
0133 
0134     QFile file(filename);
0135     if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
0136         QMessageBox::warning(this, i18n("Error"), i18n("Failed to open file: %1", file.errorString()));
0137         return;
0138     }
0139 
0140     QTextStream stream(&file);
0141     for (int row = 0, cnt = mModel->rowCount(); row < cnt; ++row) {
0142         const auto msg = mModel->data(mModel->index(row, 0), LoggingModel::MessageRole).value<LoggingModel::Message>();
0143         stream << "[" << QDateTime::fromMSecsSinceEpoch(msg.timestamp, Qt::UTC).toString(Qt::ISODateWithMs) << "] " << msg.app << " ";
0144         if (!msg.category.isEmpty()) {
0145             stream << msg.category << " ";
0146         }
0147         if (!msg.function.isEmpty()) {
0148             stream << msg.function << ": ";
0149         }
0150         stream << msg.message << "\n";
0151     }
0152 }
0153 
0154 #include "moc_logging.cpp"