diff --git a/src/GUI/LauncherArgumentTokenizer.cxx b/src/GUI/LauncherArgumentTokenizer.cxx index 0f8ae7e75..63a3e4ec9 100644 --- a/src/GUI/LauncherArgumentTokenizer.cxx +++ b/src/GUI/LauncherArgumentTokenizer.cxx @@ -1,5 +1,8 @@ #include "LauncherArgumentTokenizer.hxx" +#include +#include + #include #include @@ -8,14 +11,17 @@ LauncherArgumentTokenizer::LauncherArgumentTokenizer() } -QList LauncherArgumentTokenizer::tokenize(QString in) const +void LauncherArgumentTokenizer::tokenize(QString in) { + m_tokens.clear(); + m_valid = false; + int index = 0; const int len = in.count(); QChar c, nc; State state = Start; QString key, value; - QList result; + std::vector result; for (; index < len; ++index) { c = in.at(index); @@ -31,7 +37,7 @@ QList LauncherArgumentTokenizer::tokenize(QString in) const } else { // should we pemit single hyphen arguments? // choosing to fail for now - return {}; + return; } } else if (c == QChar('#')) { state = Comment; @@ -47,7 +53,7 @@ QList LauncherArgumentTokenizer::tokenize(QString in) const value.clear(); } else if (c.isSpace()) { state = Start; - result.append(ArgumentToken{key}); + result.emplace_back(key); } else { // could check for illegal charatcers here key.append(c); @@ -59,7 +65,7 @@ QList LauncherArgumentTokenizer::tokenize(QString in) const state = Quoted; } else if (c.isSpace()) { state = Start; - result.append(ArgumentToken{key, value}); + result.emplace_back(key, value); } else { value.append(c); } @@ -93,18 +99,22 @@ QList LauncherArgumentTokenizer::tokenize(QString in) const // ensure last argument isn't lost if (state == Key) { - result.append(ArgumentToken{key}); + result.emplace_back(key); } else if (state == Value) { - result.append(ArgumentToken{key, value}); + result.emplace_back(key, value); } - return result; + m_valid = true; + m_tokens = result; } QVariantList LauncherArgumentTokenizer::tokens() const { + if (!m_valid) + return {}; + QVariantList result; - Q_FOREACH(auto tk, tokenize(m_argString)) { + for (auto tk : m_tokens) { QVariantMap m; m["arg"] = tk.arg; m["value"] = tk.value; @@ -113,11 +123,35 @@ QVariantList LauncherArgumentTokenizer::tokens() const return result; } +bool LauncherArgumentTokenizer::isValid() const +{ + return m_valid; +} + void LauncherArgumentTokenizer::setArgString(QString argString) { if (m_argString == argString) return; m_argString = argString; + tokenize(m_argString); emit argStringChanged(m_argString); } + +const std::set argBlacklist({ + "lat", "lon", "aircraft", "airport", "parkpos", "season", + "runway", "vor", "time-offset", "timeofday"}); + +bool LauncherArgumentTokenizer::haveProtectedArgs() const +{ + if (!m_valid) + return false; + + auto n = std::count_if(m_tokens.begin(), m_tokens.end(), + [](const ArgumentToken& tk) + { + return (argBlacklist.find(tk.arg.toStdString()) != argBlacklist.end()); + }); + + return (n > 0); +} diff --git a/src/GUI/LauncherArgumentTokenizer.hxx b/src/GUI/LauncherArgumentTokenizer.hxx index 1eed5de01..734401bef 100644 --- a/src/GUI/LauncherArgumentTokenizer.hxx +++ b/src/GUI/LauncherArgumentTokenizer.hxx @@ -21,12 +21,14 @@ class LauncherArgumentTokenizer : public QObject Q_PROPERTY(QString argString READ argString WRITE setArgString NOTIFY argStringChanged) Q_PROPERTY(QVariantList tokens READ tokens NOTIFY argStringChanged) + + Q_PROPERTY(bool valid READ isValid NOTIFY argStringChanged) + Q_PROPERTY(bool warnProtectedArgs READ haveProtectedArgs NOTIFY argStringChanged) + public: LauncherArgumentTokenizer(); - Q_INVOKABLE QList tokenize(QString in) const; - QString argString() const { return m_argString; @@ -34,6 +36,9 @@ public: QVariantList tokens() const; + bool isValid() const; + + bool haveProtectedArgs() const; public slots: void setArgString(QString argString); @@ -41,6 +46,8 @@ signals: void argStringChanged(QString argString); private: + void tokenize(QString in); + enum State { Start = 0, Key, @@ -49,7 +56,9 @@ private: Comment }; + std::vector m_tokens; QString m_argString; + bool m_valid = false; }; #endif // LAUNCHERARGUMENTTOKENIZER_HXX diff --git a/src/GUI/qml/SettingExtraArguments.qml b/src/GUI/qml/SettingExtraArguments.qml index 77714efce..f9ad7ca21 100644 --- a/src/GUI/qml/SettingExtraArguments.qml +++ b/src/GUI/qml/SettingExtraArguments.qml @@ -4,56 +4,67 @@ import "." SettingControl { id: root - implicitHeight: childrenRect.height + implicitHeight: col.height + Style.margin * 2 readonly property string placeholder: "--option=value --prop:/sim/name=value" property alias value: edit.text option: "xxx" // non-empty value so apply() is called property string defaultValue: "" // needed to type save/restore logic to string - SettingDescription { - id: description - enabled: root.enabled - anchors.top: parent.top - anchors.topMargin: Style.margin + Column + { + id: col + y: Style.margin width: parent.width - text: qsTr("Enter additional command-line arguments if any are required. " + - "See here " + - "for documentation on possible arguments."); - } + spacing: Style.margin - Rectangle { - id: editFrame - - anchors.left: parent.left - anchors.margins: Style.margin - anchors.right: parent.right - anchors.top: description.bottom - - height: edit.height + Style.margin - - border.color: edit.activeFocus ? Style.frameColor : Style.minorFrameColor - border.width: 1 - - TextEdit { - id: edit + SettingDescription { + id: description enabled: root.enabled - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Style.margin - height: Math.max(Style.strutSize * 4, implicitHeight) - textFormat: TextEdit.PlainText - font.family: "Courier" - selectByMouse: true - wrapMode: TextEdit.WordWrap + text: qsTr("Enter additional command-line arguments if any are required. " + + "See here " + + "for documentation on possible arguments."); + width: parent.width + } - Text { - id: placeholder - visible: (edit.text.length == 0) && !edit.activeFocus - text: root.placeholder - color: Style.baseTextColor - } - } + SettingDescription { + id: warningText + enabled: root.enabled + visible: tokenizer.warnProtectedArgs + width: parent.width + text: qsTr("Warning: certain arguments such as the aircraft, location and time are set directly " + + "by this launcher. Attempting to set them here will not work as expected, " + + "since the same or conflicting arguments may be set. (For exmmple, this may cause " + + "you to start at the wrong position)"); + } + + Rectangle { + id: editFrame + height: edit.height + Style.margin + border.color: edit.activeFocus ? Style.frameColor : Style.minorFrameColor + border.width: 1 + width: parent.width + + TextEdit { + id: edit + enabled: root.enabled + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Style.margin + height: Math.max(Style.strutSize * 4, implicitHeight) + textFormat: TextEdit.PlainText + font.family: "Courier" + selectByMouse: true + wrapMode: TextEdit.WordWrap + + Text { + id: placeholder + visible: (edit.text.length == 0) && !edit.activeFocus + text: root.placeholder + color: Style.baseTextColor + } + } + } } function apply() @@ -61,7 +72,7 @@ SettingControl { var tokens = tokenizer.tokens; for (var i = 0; i < tokens.length; i++) { var tk = tokens[i]; - if (tk.arg.substring(0, 5) == "prop:") { + if (tk.arg.substring(0, 5) === "prop:") { _config.setProperty(tk.arg.substring(5), tk.value); } else { _config.setArg(tk.arg, tk.value); @@ -73,5 +84,4 @@ SettingControl { id: tokenizer argString: edit.text } - }