diff --git a/libnymea-app-core/connection/nymeaconnection.cpp b/libnymea-app-core/connection/nymeaconnection.cpp index 8142ec09..7a9e9206 100644 --- a/libnymea-app-core/connection/nymeaconnection.cpp +++ b/libnymea-app-core/connection/nymeaconnection.cpp @@ -393,10 +393,11 @@ void NymeaConnection::updateActiveBearers() } // qDebug() << "Available bearers:" << availableBearerTypes; if (m_availableBearerTypes != availableBearerTypes) { - qDebug() << "Available Bearer Types changed:" << availableBearerTypes; m_availableBearerTypes = availableBearerTypes; emit availableBearerTypesChanged(); + } else { + qDebug() << "Available Bearer Types:" << availableBearerTypes; } if (!m_currentHost) { @@ -419,7 +420,6 @@ void NymeaConnection::updateActiveBearers() qDebug() << "There's a host but no connection. Trying to connect now..."; connectInternal(m_currentHost); } - } diff --git a/libnymea-app-core/connection/nymeahost.cpp b/libnymea-app-core/connection/nymeahost.cpp index 66015823..abb86e00 100644 --- a/libnymea-app-core/connection/nymeahost.cpp +++ b/libnymea-app-core/connection/nymeahost.cpp @@ -182,7 +182,7 @@ Connection *Connections::bestMatch(Connection::BearerTypes bearerTypes) const { Connection *best = nullptr; foreach (Connection *c, m_connections) { - qDebug() << "have connection:" << bearerTypes << c->url() << c->bearerType() << bearerTypes.testFlag(c->bearerType()); +// qDebug() << "have connection:" << bearerTypes << c->url() << c->bearerType() << bearerTypes.testFlag(c->bearerType()); if ((bearerTypes & c->bearerType()) == Connection::BearerTypeNone) { continue; } diff --git a/nymea-app/applogcontroller.cpp b/nymea-app/applogcontroller.cpp index 34acbd13..f3c8a220 100644 --- a/nymea-app/applogcontroller.cpp +++ b/nymea-app/applogcontroller.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include QtMessageHandler AppLogController::s_oldLogMessageHandler = nullptr; @@ -23,14 +25,21 @@ AppLogController *AppLogController::instance() return thiz; } -AppLogController::AppLogController(QObject *parent) : QObject(parent) +AppLogController::AppLogController(QObject *parent) : QAbstractListModel(parent) { QString fileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/nymea-app.log"; m_logFile.setFileName(fileName); qDebug() << "App log file:" << fileName; - if (!m_logFile.open(QFile::ReadWrite)) { + if (QFile::exists(fileName)) { + if (QFile::exists(fileName + ".old")) { + QFile::remove(fileName + ".old"); + } + QFile::rename(fileName, fileName + ".old"); + } + + if (!m_logFile.open(QFile::ReadWrite | QFile::Truncate)) { qDebug() << "Cannot open logfile for writing"; return; } @@ -74,26 +83,62 @@ void AppLogController::setEnabled(bool enabled) } -QByteArray AppLogController::content() +int AppLogController::rowCount(const QModelIndex &parent) const { - return m_buffer; + Q_UNUSED(parent) + return m_buffer.count(); +} + +QVariant AppLogController::data(const QModelIndex &index, int role) const +{ + switch (role) { + case RoleText: + return m_buffer.at(index.row()); + case RoleType: + return m_types.at(index.row()); + } + return QVariant(); +} + +QHash AppLogController::roleNames() const +{ + QHash roles; + roles.insert(RoleText, "text"); + roles.insert(RoleType, "type"); + return roles; +} + +void AppLogController::toClipboard() +{ + m_logFile.seek(0); + QByteArray completeLog = m_logFile.readAll(); + QGuiApplication::clipboard()->setText(completeLog); } void AppLogController::logMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message) { s_oldLogMessageHandler(type, context, message); + instance()->append(message, type == QtWarningMsg ? TypeWarning : TypeInfo); +} +void AppLogController::append(const QString &message, AppLogController::Type type) +{ QString finalMessage = message + "\n"; - instance()->m_logFile.write(finalMessage.toUtf8()); - instance()->m_logFile.flush(); - instance()->m_buffer.append(finalMessage); + m_logFile.write(finalMessage.toUtf8()); + m_logFile.flush(); - int maxBuffer = 1024 * 1024; - if (instance()->m_buffer.size() > maxBuffer) { - instance()->m_buffer.remove(0, instance()->m_buffer.size() - maxBuffer); + beginInsertRows(QModelIndex(), m_buffer.count(), m_buffer.count()); + m_buffer.append(message); + m_types.append(type); + endInsertRows(); + + int maxEntries = 1024; + if (m_buffer.size() > maxEntries) { + beginRemoveRows(QModelIndex(), 0, 0); + m_buffer.removeFirst(); + m_types.removeFirst(); + endRemoveRows(); } - emit instance()->contentChanged(); - emit instance()->contentAdded(finalMessage.toUtf8()); } void AppLogController::activate() diff --git a/nymea-app/applogcontroller.h b/nymea-app/applogcontroller.h index e998a697..525c458c 100644 --- a/nymea-app/applogcontroller.h +++ b/nymea-app/applogcontroller.h @@ -4,15 +4,27 @@ #include #include #include +#include -class AppLogController : public QObject +class AppLogController : public QAbstractListModel { Q_OBJECT Q_PROPERTY(bool canWriteLogs READ canWriteLogs CONSTANT) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) - Q_PROPERTY(QByteArray content READ content NOTIFY contentChanged) public: + enum Type { + TypeInfo, + TypeWarning + }; + Q_ENUM(Type) + + enum Roles { + RoleText, + RoleType + }; + Q_ENUM(Roles) + static QObject* appLogControllerProvider(QQmlEngine *engine, QJSEngine *scriptEngine); static AppLogController* instance(); @@ -21,23 +33,29 @@ public: bool enabled() const; void setEnabled(bool enabled); - QByteArray content(); + int rowCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &parent, int role) const override; + QHash roleNames() const override; + + + Q_INVOKABLE void toClipboard(); signals: void enabledChanged(); - void contentChanged(); - void contentAdded(const QByteArray &newContent); private: explicit AppLogController(QObject *parent = nullptr); static QtMessageHandler s_oldLogMessageHandler; static void logMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message); + void append(const QString &message, Type type = TypeInfo); + void activate(); void deactivate(); QFile m_logFile; - QByteArray m_buffer; + QStringList m_buffer; + QList m_types; }; #endif // APPLOGCONTROLLER_H diff --git a/nymea-app/images.qrc b/nymea-app/images.qrc index effa074f..e5e9efc1 100644 --- a/nymea-app/images.qrc +++ b/nymea-app/images.qrc @@ -171,5 +171,6 @@ ui/images/powersocket.svg ui/images/dial.svg ui/images/ventilation.svg + ui/images/edit-copy.svg diff --git a/nymea-app/ui/appsettings/DeveloperOptionsPage.qml b/nymea-app/ui/appsettings/DeveloperOptionsPage.qml index a4d5bb2b..92bc2620 100644 --- a/nymea-app/ui/appsettings/DeveloperOptionsPage.qml +++ b/nymea-app/ui/appsettings/DeveloperOptionsPage.qml @@ -72,26 +72,25 @@ Page { text: qsTr("App log") backButtonVisible: true onBackPressed: pageStack.pop() + HeaderButton { + imageSource: "../images/edit-copy.svg" + onClicked: AppLogController.toClipboard() + } } - ScrollView { + ListView { anchors.fill: parent - TextArea { - id: logArea - wrapMode: Text.WordWrap - readOnly: true - font.pixelSize: app.smallFont + ScrollBar.vertical: ScrollBar {} - Component.onCompleted: { - text = AppLogController.content - } - Connections { - target: AppLogController - onContentAdded: { - logArea.append(newContent) - } - } + model: AppLogController + delegate: Text { + width: parent.width + maximumLineCount: 2 + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + text: model.text + color: model.type === AppLogController.TypeWarning ? "red" : app.foregroundColor + font.pixelSize: app.smallFont } } } diff --git a/nymea-app/ui/images/edit-copy.svg b/nymea-app/ui/images/edit-copy.svg new file mode 100644 index 00000000..159b5865 --- /dev/null +++ b/nymea-app/ui/images/edit-copy.svg @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + +