1
0
Fork 0

Launcher warns when setting conflicting args

Display a warning when the user tries to set arguments in additional
settings which the launcher will also set / conflict with. Blacklist
is still evolving, and we don’t actually prevent the user from running,
since maybe they are doing something special
This commit is contained in:
James Turner 2018-06-03 09:07:21 +01:00
parent 42c3a366a3
commit e3fd7f7d61
3 changed files with 107 additions and 54 deletions

View file

@ -1,5 +1,8 @@
#include "LauncherArgumentTokenizer.hxx" #include "LauncherArgumentTokenizer.hxx"
#include <algorithm>
#include <set>
#include <QVariantMap> #include <QVariantMap>
#include <QJSEngine> #include <QJSEngine>
@ -8,14 +11,17 @@ LauncherArgumentTokenizer::LauncherArgumentTokenizer()
} }
QList<ArgumentToken> LauncherArgumentTokenizer::tokenize(QString in) const void LauncherArgumentTokenizer::tokenize(QString in)
{ {
m_tokens.clear();
m_valid = false;
int index = 0; int index = 0;
const int len = in.count(); const int len = in.count();
QChar c, nc; QChar c, nc;
State state = Start; State state = Start;
QString key, value; QString key, value;
QList<ArgumentToken> result; std::vector<ArgumentToken> result;
for (; index < len; ++index) { for (; index < len; ++index) {
c = in.at(index); c = in.at(index);
@ -31,7 +37,7 @@ QList<ArgumentToken> LauncherArgumentTokenizer::tokenize(QString in) const
} else { } else {
// should we pemit single hyphen arguments? // should we pemit single hyphen arguments?
// choosing to fail for now // choosing to fail for now
return {}; return;
} }
} else if (c == QChar('#')) { } else if (c == QChar('#')) {
state = Comment; state = Comment;
@ -47,7 +53,7 @@ QList<ArgumentToken> LauncherArgumentTokenizer::tokenize(QString in) const
value.clear(); value.clear();
} else if (c.isSpace()) { } else if (c.isSpace()) {
state = Start; state = Start;
result.append(ArgumentToken{key}); result.emplace_back(key);
} else { } else {
// could check for illegal charatcers here // could check for illegal charatcers here
key.append(c); key.append(c);
@ -59,7 +65,7 @@ QList<ArgumentToken> LauncherArgumentTokenizer::tokenize(QString in) const
state = Quoted; state = Quoted;
} else if (c.isSpace()) { } else if (c.isSpace()) {
state = Start; state = Start;
result.append(ArgumentToken{key, value}); result.emplace_back(key, value);
} else { } else {
value.append(c); value.append(c);
} }
@ -93,18 +99,22 @@ QList<ArgumentToken> LauncherArgumentTokenizer::tokenize(QString in) const
// ensure last argument isn't lost // ensure last argument isn't lost
if (state == Key) { if (state == Key) {
result.append(ArgumentToken{key}); result.emplace_back(key);
} else if (state == Value) { } 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 QVariantList LauncherArgumentTokenizer::tokens() const
{ {
if (!m_valid)
return {};
QVariantList result; QVariantList result;
Q_FOREACH(auto tk, tokenize(m_argString)) { for (auto tk : m_tokens) {
QVariantMap m; QVariantMap m;
m["arg"] = tk.arg; m["arg"] = tk.arg;
m["value"] = tk.value; m["value"] = tk.value;
@ -113,11 +123,35 @@ QVariantList LauncherArgumentTokenizer::tokens() const
return result; return result;
} }
bool LauncherArgumentTokenizer::isValid() const
{
return m_valid;
}
void LauncherArgumentTokenizer::setArgString(QString argString) void LauncherArgumentTokenizer::setArgString(QString argString)
{ {
if (m_argString == argString) if (m_argString == argString)
return; return;
m_argString = argString; m_argString = argString;
tokenize(m_argString);
emit argStringChanged(m_argString); emit argStringChanged(m_argString);
} }
const std::set<std::string> 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);
}

View file

@ -21,12 +21,14 @@ class LauncherArgumentTokenizer : public QObject
Q_PROPERTY(QString argString READ argString WRITE setArgString NOTIFY argStringChanged) Q_PROPERTY(QString argString READ argString WRITE setArgString NOTIFY argStringChanged)
Q_PROPERTY(QVariantList tokens READ tokens 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: public:
LauncherArgumentTokenizer(); LauncherArgumentTokenizer();
Q_INVOKABLE QList<ArgumentToken> tokenize(QString in) const;
QString argString() const QString argString() const
{ {
return m_argString; return m_argString;
@ -34,6 +36,9 @@ public:
QVariantList tokens() const; QVariantList tokens() const;
bool isValid() const;
bool haveProtectedArgs() const;
public slots: public slots:
void setArgString(QString argString); void setArgString(QString argString);
@ -41,6 +46,8 @@ signals:
void argStringChanged(QString argString); void argStringChanged(QString argString);
private: private:
void tokenize(QString in);
enum State { enum State {
Start = 0, Start = 0,
Key, Key,
@ -49,7 +56,9 @@ private:
Comment Comment
}; };
std::vector<ArgumentToken> m_tokens;
QString m_argString; QString m_argString;
bool m_valid = false;
}; };
#endif // LAUNCHERARGUMENTTOKENIZER_HXX #endif // LAUNCHERARGUMENTTOKENIZER_HXX

View file

@ -4,56 +4,67 @@ import "."
SettingControl { SettingControl {
id: root id: root
implicitHeight: childrenRect.height implicitHeight: col.height + Style.margin * 2
readonly property string placeholder: "--option=value --prop:/sim/name=value" readonly property string placeholder: "--option=value --prop:/sim/name=value"
property alias value: edit.text property alias value: edit.text
option: "xxx" // non-empty value so apply() is called option: "xxx" // non-empty value so apply() is called
property string defaultValue: "" // needed to type save/restore logic to string property string defaultValue: "" // needed to type save/restore logic to string
SettingDescription { Column
id: description {
enabled: root.enabled id: col
anchors.top: parent.top y: Style.margin
anchors.topMargin: Style.margin
width: parent.width width: parent.width
text: qsTr("Enter additional command-line arguments if any are required. " + spacing: Style.margin
"See <a href=\"http://flightgear.sourceforge.net/getstart-en/getstart-enpa2.html#x5-450004.5\">here</a> " +
"for documentation on possible arguments.");
}
Rectangle { SettingDescription {
id: editFrame id: description
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
enabled: root.enabled enabled: root.enabled
anchors.verticalCenter: parent.verticalCenter text: qsTr("Enter additional command-line arguments if any are required. " +
anchors.left: parent.left "See <a href=\"http://flightgear.sourceforge.net/getstart-en/getstart-enpa2.html#x5-450004.5\">here</a> " +
anchors.right: parent.right "for documentation on possible arguments.");
anchors.margins: Style.margin width: parent.width
height: Math.max(Style.strutSize * 4, implicitHeight) }
textFormat: TextEdit.PlainText
font.family: "Courier"
selectByMouse: true
wrapMode: TextEdit.WordWrap
Text { SettingDescription {
id: placeholder id: warningText
visible: (edit.text.length == 0) && !edit.activeFocus enabled: root.enabled
text: root.placeholder visible: tokenizer.warnProtectedArgs
color: Style.baseTextColor width: parent.width
} text: qsTr("<b>Warning:</b> certain arguments such as the aircraft, location and time are set directly " +
} "by this launcher. Attempting to set them here will <b>not</b> 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() function apply()
@ -61,7 +72,7 @@ SettingControl {
var tokens = tokenizer.tokens; var tokens = tokenizer.tokens;
for (var i = 0; i < tokens.length; i++) { for (var i = 0; i < tokens.length; i++) {
var tk = tokens[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); _config.setProperty(tk.arg.substring(5), tk.value);
} else { } else {
_config.setArg(tk.arg, tk.value); _config.setArg(tk.arg, tk.value);
@ -73,5 +84,4 @@ SettingControl {
id: tokenizer id: tokenizer
argString: edit.text argString: edit.text
} }
} }