aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/android/androidrunconfiguration.cpp
diff options
context:
space:
mode:
authorBogDan Vatra <bogdan@kdab.com>2016-10-10 15:38:50 +0300
committerBogDan Vatra <bogdan@kdab.com>2017-04-12 13:57:34 +0000
commitd4ca232d54a9a5dabc6955139f3d3c2dcb0875f0 (patch)
treefaa9d3fe9e8e7fb9956eaf6de5d6696424dadef7 /src/plugins/android/androidrunconfiguration.cpp
parent8dc98995fa2a3eb77ab287e76dd4b4c778919eb4 (diff)
Android: Improve application output window by adding filters
- allow the user to choose the visible log levels - allow the user to choose which activities/service(s) logs are visible - wakeup the device (API 20+) - use only the most recent logs (API 21+ add "-T 0" to logcat params) - use logcat -v time format, which is the same on all Android versions In the future we can even allow the user to choose which parts of the log line are visible, e.g. time, log level, TAG, PID, Message Task-number: QTCREATORBUG-16887 Change-Id: I07ce00aff59a479660f5ac6da75eef973ba3f627 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Vikas Pachdha <vikas.pachdha@qt.io>
Diffstat (limited to 'src/plugins/android/androidrunconfiguration.cpp')
-rw-r--r--src/plugins/android/androidrunconfiguration.cpp191
1 files changed, 190 insertions, 1 deletions
diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp
index d2d7844e5c6..54f64497539 100644
--- a/src/plugins/android/androidrunconfiguration.cpp
+++ b/src/plugins/android/androidrunconfiguration.cpp
@@ -29,16 +29,205 @@
#include "androidmanager.h"
#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorersettings.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtoutputformatter.h>
#include <qtsupport/qtkitinformation.h>
+#include <QPlainTextEdit>
+#include <QRegularExpression>
+#include <QToolButton>
#include <utils/qtcassert.h>
+#include <utils/utilsicons.h>
using namespace ProjectExplorer;
namespace Android {
+static QRegularExpression logCatRegExp("([0-9\\-]*\\s+[0-9\\-:.]*)" // 1. time
+ "\\s*"
+ "([DEIVWF])" // 2. log level
+ "\\/"
+ "(.*)" // 3. TAG
+ "\\(\\s*"
+ "(\\d+)" // 4. PID
+ "\\)\\:\\s"
+ "(.*)"); // 5. Message
+
+AndroidOutputFormatter::AndroidOutputFormatter(Project *project)
+ : QtSupport::QtOutputFormatter(project)
+ , m_filtersButton(new QToolButton)
+{
+ auto filtersMenu = new QMenu(m_filtersButton.data());
+
+ m_filtersButton->setToolTip(tr("Filters"));
+ m_filtersButton->setIcon(Utils::Icons::FILTER.icon());
+ m_filtersButton->setProperty("noArrow", true);
+ m_filtersButton->setAutoRaise(true);
+ m_filtersButton->setPopupMode(QToolButton::InstantPopup);
+ m_filtersButton->setMenu(filtersMenu);
+
+ auto logsMenu = filtersMenu->addMenu(tr("Log Level"));
+ addLogAction(All, logsMenu, tr("All"));
+ addLogAction(Verbose, logsMenu, tr("Verbose"));
+ addLogAction(Info, logsMenu, tr("Info"));
+ addLogAction(Debug, logsMenu, tr("Debug"));
+ addLogAction(Warning, logsMenu, tr("Warning"));
+ addLogAction(Error, logsMenu, tr("Error"));
+ addLogAction(Fatal, logsMenu, tr("Fatal"));
+ updateLogMenu();
+ m_appsMenu = filtersMenu->addMenu(tr("Applications"));
+ appendPid(-1, tr("All"));
+}
+
+AndroidOutputFormatter::~AndroidOutputFormatter()
+{}
+
+QList<QWidget *> AndroidOutputFormatter::toolbarWidgets() const
+{
+ return QList<QWidget *>{m_filtersButton.data()};
+}
+
+void AndroidOutputFormatter::appendMessage(const QString &text, Utils::OutputFormat format)
+{
+ if (text.isEmpty())
+ return;
+
+ CachedLine line;
+ line.content = text;
+
+ if (format < Utils::StdOutFormat) {
+ line.level = SkipFiltering;
+ line.pid = -1;
+ } else {
+ QRegularExpressionMatch match = logCatRegExp.match(text);
+ if (!match.hasMatch())
+ return;
+ line.level = None;
+
+ switch (match.captured(2).toLatin1()[0]) {
+ case 'D': line.level = Debug; break;
+ case 'I': line.level = Info; break;
+ case 'V': line.level = Verbose; break;
+ case 'W': line.level = Warning; break;
+ case 'E': line.level = Error; break;
+ case 'F': line.level = Fatal; break;
+ default: return;
+ }
+ line.pid = match.captured(4).toLongLong();
+ }
+
+ m_cachedLines.append(line);
+ if (m_cachedLines.size() > ProjectExplorerPlugin::projectExplorerSettings().maxAppOutputLines)
+ m_cachedLines.pop_front();
+
+ filterMessage(line);
+}
+
+void AndroidOutputFormatter::clear()
+{
+ m_cachedLines.clear();
+}
+
+void AndroidOutputFormatter::appendPid(qint64 pid, const QString &name)
+{
+ if (m_pids.contains(pid))
+ return;
+
+ auto action = m_appsMenu->addAction(name);
+ m_pids[pid] = action;
+ action->setCheckable(true);
+ action->setChecked(pid != -1);
+ connect(action, &QAction::triggered, this, &AndroidOutputFormatter::applyFilter);
+ applyFilter();
+}
+
+void AndroidOutputFormatter::removePid(qint64 pid)
+{
+ if (pid == -1) {
+ for (auto action : m_pids)
+ m_appsMenu->removeAction(action);
+ m_pids.clear();
+ } else {
+ m_appsMenu->removeAction(m_pids[pid]);
+ m_pids.remove(pid);
+ }
+}
+
+void AndroidOutputFormatter::updateLogMenu(LogLevel set, LogLevel reset)
+{
+ m_logLevelFlags |= set;
+ m_logLevelFlags &= ~reset;
+ for (const auto & pair : m_logLevels)
+ pair.second->setChecked((m_logLevelFlags & pair.first) == pair.first);
+
+ applyFilter();
+}
+
+void AndroidOutputFormatter::filterMessage(const CachedLine &line)
+{
+ if (line.level == SkipFiltering || m_pids[-1]->isChecked()) {
+ QtOutputFormatter::appendMessage(line.content, Utils::NormalMessageFormat);
+ } else {
+ // Filter Log Level
+ if (!(m_logLevelFlags & line.level))
+ return;
+
+ // Filter PIDs
+ if (!m_pids[-1]->isChecked()) {
+ auto it = m_pids.find(line.pid);
+ if (it == m_pids.end() || !(*it)->isChecked())
+ return;
+ }
+
+ Utils::OutputFormat format = Utils::NormalMessageFormat;
+ switch (line.level) {
+ case Debug:
+ format = Utils::DebugFormat;
+ break;
+ case Info:
+ case Verbose:
+ format = Utils::StdOutFormat;
+ break;
+
+ case Warning:
+ case Error:
+ case Fatal:
+ format = Utils::StdErrFormat;
+ break;
+ default:
+ return;
+ }
+
+ Utils::OutputFormatter::appendMessage(line.content, format);
+ }
+}
+
+void AndroidOutputFormatter::applyFilter()
+{
+ if (!plainTextEdit())
+ return;
+
+ plainTextEdit()->clear();
+ if (!m_pids[-1]->isChecked()) {
+ bool allOn = true;
+ for (auto action : m_pids) {
+ if (!action->isChecked()) {
+ allOn = false;
+ break;
+ }
+ }
+ m_pids[-1]->setChecked(allOn);
+ } else {
+ for (auto action : m_pids)
+ action->setChecked(true);
+ }
+
+ for (const auto &line : m_cachedLines)
+ filterMessage(line);
+}
+
AndroidRunConfiguration::AndroidRunConfiguration(Target *parent, Core::Id id)
: RunConfiguration(parent, id)
{
@@ -56,7 +245,7 @@ QWidget *AndroidRunConfiguration::createConfigurationWidget()
Utils::OutputFormatter *AndroidRunConfiguration::createOutputFormatter() const
{
- return new QtSupport::QtOutputFormatter(target()->project());
+ return new AndroidOutputFormatter(target()->project());
}
const QString AndroidRunConfiguration::remoteChannel() const