diff --git a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp index 073d5704..c3a072b4 100644 --- a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp +++ b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp @@ -243,6 +243,15 @@ void QMLBackend::setQuestionAnswer(quint8 questionId, QString const &answer) { } +//**************************************************************************************************************************************************** +/// \param[in] questionId The id of the question. +/// \return answer for the given question. +//**************************************************************************************************************************************************** +QString QMLBackend::getQuestionAnswer(quint8 questionId) const { + return reportFlow_.getAnswer(questionId); +} + + //**************************************************************************************************************************************************** /// \param[in] categoryId The id of the question set. /// \return concatenate answers for set of questions. @@ -252,6 +261,14 @@ QString QMLBackend::collectAnswers(quint8 categoryId) const { } +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void QMLBackend::clearAnswers() { + reportFlow_.clearAnswers(); +} + + //**************************************************************************************************************************************************** /// \return The value for the 'showOnStartup' property. //**************************************************************************************************************************************************** diff --git a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h index 83f70e35..0c7af1bc 100644 --- a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h +++ b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h @@ -60,7 +60,9 @@ public: // member functions. Q_INVOKABLE bool areSameFileOrFolder(QUrl const &lhs, QUrl const &rhs) const; ///< Check if two local URL point to the same file. Q_INVOKABLE QVariantList getQuestionSet(quint8 categoryId) const; ///< Retrieve the set of question for a given bug category. Q_INVOKABLE void setQuestionAnswer(quint8 questionId, QString const &answer); ///< Feed an answer for a given question. + Q_INVOKABLE QString getQuestionAnswer(quint8 questionId) const; ///< Get the answer for a given question. Q_INVOKABLE QString collectAnswers(quint8 categoryId) const; ///< Collect answer for a given set of questions. + Q_INVOKABLE void clearAnswers(); ///< Clear all collected answers. public: // Qt/QML properties. Note that the NOTIFY-er signal is required even for read-only properties (QML warning otherwise) Q_PROPERTY(bool showOnStartup READ showOnStartup NOTIFY showOnStartupChanged) diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/BugQuestionView.qml b/internal/frontend/bridge-gui/bridge-gui/qml/BugQuestionView.qml index ffac25ae..f0a0e4e4 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/BugQuestionView.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/BugQuestionView.qml @@ -65,6 +65,13 @@ SettingsView { onAnswerChanged:{ Backend.setQuestionAnswer(modelData, answer); } + + Connections { + function onVisibleChanged() { + setDefaultValue(Backend.getQuestionAnswer(modelData)) + } + target:root + } } } // fill height so the footer label will always be attached to the bottom diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/BugReportFlow.qml b/internal/frontend/bridge-gui/bridge-gui/qml/BugReportFlow.qml index b309178f..697868a0 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/BugReportFlow.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/BugReportFlow.qml @@ -96,6 +96,7 @@ Item { root.showBugQuestion(); } onBugReportWasSent: { + Backend.clearAnswers(); root.bugReportWasSent(); } } diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/QuestionItem.qml b/internal/frontend/bridge-gui/bridge-gui/qml/QuestionItem.qml index 38d48435..59b732da 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/QuestionItem.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/QuestionItem.qml @@ -46,6 +46,12 @@ Item { return "" } + function setDefaultValue(defaultValue) { + textInput.setDefaultValue(defaultValue) + selectionRadio.setDefaultValue(defaultValue) + selectionCheckBox.setDefaultValue(defaultValue) + } + implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin ColumnLayout { @@ -75,6 +81,10 @@ Item { hint: mandatory ? textInput.text.length + "/" + _maxLength : "" placeholderText: mandatory ? qsTr("%1... (min. %2 characters)").arg(root.text).arg(_minLength) : "" + function setDefaultValue(defaultValue) { + textInput.text = root.type === QuestionItem.InputType.TextInput ? defaultValue : "" + } + validator: function (text) { if (!mandatory) return; @@ -101,6 +111,13 @@ Item { property string text: { return checkedButton ? checkedButton.text : ""; } + + function setDefaultValue(defaultValue) { + const values = root.type === QuestionItem.InputType.Radio ? defaultValue : []; + for (var i = 0; i < buttons.length; ++i) { + buttons[i].checked = values.includes(buttons[i].text); + } + } } Repeater { model: root.answerList @@ -115,14 +132,22 @@ Item { ButtonGroup { id: selectionCheckBox exclusive: false + property string delimitor: ", " property string text: { var str = ""; for (var i = 0; i < buttons.length; ++i) { if (buttons[i].checked) { - str += buttons[i].text + ", "; + str += buttons[i].text + delimitor; } } - return str.slice(0, -2); + return str.slice(0, -delimitor.length); + } + + function setDefaultValue(defaultValue) { + const values = root.type === QuestionItem.InputType.Checkbox ? defaultValue.split(delimitor) : []; + for (var i = 0; i < buttons.length; ++i) { + buttons[i].checked = values.includes(buttons[i].text); + } } } Repeater { diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/Resources/bug_report_flow.json b/internal/frontend/bridge-gui/bridge-gui/qml/Resources/bug_report_flow.json index ce9d2d8c..3054b27b 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/Resources/bug_report_flow.json +++ b/internal/frontend/bridge-gui/bridge-gui/qml/Resources/bug_report_flow.json @@ -59,9 +59,9 @@ }, { "id": 4, - "text": "Are you running any of these software?", + "text": "Can you list the software you are running?", "type": 3, - "answerList": ["VPN", "Antivirus", "Firewall", "Cache cleaner", "None of the above"] + "answerList": ["VPN", "Antivirus", "Firewall", "Cache cleaner"] } ] } diff --git a/internal/frontend/bridge-gui/bridgepp/Test/TestBugReportFlow.cpp b/internal/frontend/bridge-gui/bridgepp/Test/TestBugReportFlow.cpp index ef5116af..7d06ad7e 100644 --- a/internal/frontend/bridge-gui/bridgepp/Test/TestBugReportFlow.cpp +++ b/internal/frontend/bridge-gui/bridgepp/Test/TestBugReportFlow.cpp @@ -22,6 +22,36 @@ using namespace bridgepp; +namespace { + + + const QString goodJson = "{" + " \"metadata\": {" + " \"version\": \"1.0.0\"" + " }," + " \"data_v1.0.0\": {" + " \"categories\": [" + " {" + " \"id\": 0," + " \"name\": \"I can't receive mail\"," + " \"questions\": [0]" + " }" + " ]," + " \"questions\": [" + " {" + " \"id\": 0," + " \"text\": \"What happened?\"," + " \"tips\": \"Expected behavior\"," + " \"type\": 1" + " }" + " ]" + " }" + "}"; + + +} + + //**************************************************************************************************************************************************** // //**************************************************************************************************************************************************** @@ -84,28 +114,7 @@ TEST_F(BugReportFlowFixture, emptyFile) { // //**************************************************************************************************************************************************** TEST_F(BugReportFlowFixture, validFile) { - feedTempFile("{" - " \"metadata\": {" - " \"version\": \"1.0.0\"" - " }," - " \"data_v1.0.0\": {" - " \"categories\": [" - " {" - " \"id\": 0," - " \"name\": \"I can't receive mail\"," - " \"questions\": [0]" - " }" - " ]," - " \"questions\": [" - " {" - " \"id\": 0," - " \"text\": \"What happened?\"," - " \"tips\": \"Expected behavior\"," - " \"type\": 1" - " }" - " ]" - " }" - "}"); + feedTempFile(goodJson); EXPECT_TRUE(flow_.parse(file_.fileName())); QStringList categories = flow_.categories(); @@ -131,6 +140,8 @@ TEST_F(BugReportFlowFixture, validFile) { qDebug() << flow_.collectAnswers(0); EXPECT_EQ(flow_.collectAnswers(0), "Category: I can't receive mail\n\r - What happened?\n\rpwet\n\r"); EXPECT_EQ(flow_.collectAnswers(1), ""); + EXPECT_EQ(flow_.getAnswer(0), "pwet"); + EXPECT_EQ(flow_.getAnswer(1), ""); flow_.clearAnswers(); EXPECT_EQ(flow_.collectAnswers(0), "Category: I can't receive mail\n\r"); } diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/BugReportFlow/BugReportFlow.cpp b/internal/frontend/bridge-gui/bridgepp/bridgepp/BugReportFlow/BugReportFlow.cpp index 105b3542..f747f5b0 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/BugReportFlow/BugReportFlow.cpp +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/BugReportFlow/BugReportFlow.cpp @@ -91,6 +91,19 @@ bool BugReportFlow::setAnswer(quint8 questionId, QString const &answer) { } +//**************************************************************************************************************************************************** +/// \param[in] questionId The id of the question. +/// \return answer the given question. +//**************************************************************************************************************************************************** +QString BugReportFlow::getAnswer(quint8 questionId) const { + QString answer; + if (questionId <= questions_.count() - 1) { + answer = answers_[questionId]; + } + return answer; +} + + //**************************************************************************************************************************************************** /// \param[in] categoryId The id of the question set. /// \return concatenate answers for set of questions. @@ -103,7 +116,7 @@ QString BugReportFlow::collectAnswers(quint8 categoryId) const { answers += "Category: " + categories_[categoryId] + "\n\r"; QVariantList sets = this->questionSet(categoryId); for (QVariant const &var: sets) { - const QString& answer = answers_[var.toInt()]; + const QString& answer = getAnswer(var.toInt()); if (answer.isEmpty()) continue; answers += " - " + questions_[var.toInt()].toMap()["text"].toString() + "\n\r"; @@ -122,15 +135,12 @@ void BugReportFlow::clearAnswers() { //**************************************************************************************************************************************************** -// +/// \return true iff parsing succeed. //**************************************************************************************************************************************************** bool BugReportFlow::parseFile() { - categories_.clear(); - questions_.clear(); - questionsSet_.clear(); + reset(); QJsonObject data = getJsonDataObj(getJsonRootObj()); - QJsonArray categoriesJson = data.value("categories").toArray(); for (const QJsonValueRef &v : categoriesJson) { categories_.append(v.toObject()["name"].toString()); @@ -140,7 +150,22 @@ bool BugReportFlow::parseFile() { return true; } -QJsonObject BugReportFlow::getJsonRootObj() { + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void BugReportFlow::reset() { + categories_.clear(); + questions_.clear(); + questionsSet_.clear(); + answers_.clear(); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +QJsonObject BugReportFlow::getJsonRootObj() const { QFile file(filepath_); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return QJsonObject(); @@ -152,7 +177,10 @@ QJsonObject BugReportFlow::getJsonRootObj() { } -QJsonObject BugReportFlow::getJsonDataObj(const QJsonObject& root) { +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +QJsonObject BugReportFlow::getJsonDataObj(const QJsonObject& root) const { QString version = getJsonVersion(root); if (version.isEmpty()) return QJsonObject(); @@ -160,13 +188,15 @@ QJsonObject BugReportFlow::getJsonDataObj(const QJsonObject& root) { QJsonValue data = root.value(QString("data_v%1").arg(version)); if (data == QJsonValue::Undefined || !data.isObject()) return QJsonObject(); - QJsonObject dataObj = data.toObject(); - return migrateData(dataObj, version); + return migrateData(data.toObject(), version); } -QString BugReportFlow::getJsonVersion(const QJsonObject& root) { +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +QString BugReportFlow::getJsonVersion(const QJsonObject& root) const{ QJsonValue metadata = root.value("metadata"); if (metadata == QJsonValue::Undefined || !metadata.isObject()) { return QString(); @@ -179,9 +209,13 @@ QString BugReportFlow::getJsonVersion(const QJsonObject& root) { } -QJsonObject BugReportFlow::migrateData(const QJsonObject& data, const QString& version) { +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +QJsonObject BugReportFlow::migrateData(const QJsonObject& data, const QString& version) const{ if (version != currentFormatVersion) return QJsonObject(); + // nothing to migrate now but migration should be done here. return data; } diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/BugReportFlow/BugReportFlow.h b/internal/frontend/bridge-gui/bridgepp/bridgepp/BugReportFlow/BugReportFlow.h index 836f2217..62408e75 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/BugReportFlow/BugReportFlow.h +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/BugReportFlow/BugReportFlow.h @@ -33,23 +33,25 @@ public: // member functions. BugReportFlow(BugReportFlow &&) = delete; ///< Disabled assignment copy-constructor. ~BugReportFlow() = default; ///< Destructor. - bool parse(const QString& filepath); ///< Initialize the Bug Report Flow. + [[nodiscard]] bool parse(const QString& filepath); ///< Initialize the Bug Report Flow. - QStringList categories() const; ///< Getter for the 'bugCategories' property. - QVariantList questions() const; ///< Getter for the 'bugQuestions' property. - QVariantList questionSet(quint8 categoryId) const; ///< Retrieve the set of question for a given bug category. + [[nodiscard]] QStringList categories() const; ///< Getter for the 'bugCategories' property. + [[nodiscard]] QVariantList questions() const; ///< Getter for the 'bugQuestions' property. + [[nodiscard]] QVariantList questionSet(quint8 categoryId) const; ///< Retrieve the set of question for a given bug category. - bool setAnswer(quint8 questionId, QString const &answer); ///< Feed an answer for a given question. - QString collectAnswers(quint8 categoryId) const; ///< Collect answer for a given set of questions. + [[nodiscard]] bool setAnswer(quint8 questionId, QString const &answer); ///< Feed an answer for a given question. + [[nodiscard]] QString getAnswer(quint8 questionId) const; ///< Collect answer for a given questions. + [[nodiscard]] QString collectAnswers(quint8 categoryId) const; ///< Collect answer for a given set of questions. void clearAnswers(); ///< Clear all collected answers. private: // member functions bool parseFile(); ///< Parse the bug report flow description file. - QJsonObject getJsonRootObj(); ///< Extract the JSON root object. - QJsonObject getJsonDataObj(const QJsonObject& root); ///< Extract the JSON data object. - QString getJsonVersion(const QJsonObject& root); ///< Extract the JSON version of the file. - QJsonObject migrateData(const QJsonObject& data, const QString& version); ///< Migrate data if needed/possible. + void reset(); ///< Reset all data. + [[nodiscard]] QJsonObject getJsonRootObj() const; ///< Extract the JSON root object. + [[nodiscard]] QJsonObject getJsonDataObj(const QJsonObject& root) const; ///< Extract the JSON data object. + [[nodiscard]] QString getJsonVersion(const QJsonObject& root) const; ///< Extract the JSON version of the file. + [[nodiscard]] QJsonObject migrateData(const QJsonObject& data, const QString& version) const; ///< Migrate data if needed/possible. private: // data members QString filepath_; ///< The file path of the BugReportFlow description file.