new features implemented, switch to Version 3.0; done: find, replace, goto line

master
Marc Wäckerlin 6 years ago
parent b513f940df
commit 2133615a4c
  1. 5
      configure.ac
  2. 172
      src/commands.hxx
  3. 12
      src/editor.hxx
  4. 54
      src/help.hxx
  5. 36
      src/help.ui
  6. 5
      src/makefile.am
  7. 84
      src/scriptfile.hxx
  8. 73
      src/scriptfile.ui
  9. 72
      src/testgui.hxx
  10. 129
      src/testgui.ui

@ -8,8 +8,9 @@
# change this: # change this:
m4_define(x_package_name, webtester) # project's name m4_define(x_package_name, webtester) # project's name
m4_define(x_major, 2) # project's major version m4_define(x_major, 3) # project's major version
m4_define(x_minor, 2) # project's minor version m4_define(x_minor, 0) # project's minor version
m4_define(x_least_diff, 123)
# never edit this block: # never edit this block:
m4_include(ax_init_standard_project.m4) m4_include(ax_init_standard_project.m4)

@ -278,7 +278,7 @@ class Empty: public Command {
QString description() const { QString description() const {
return return
"" ""
"\n\n" "\n\n--\n\n"
"Empty lines are allowed"; "Empty lines are allowed";
} }
QString command() const { QString command() const {
@ -306,7 +306,7 @@ class Comment: public Command {
QString description() const { QString description() const {
return return
"# comment" "# comment"
"\n\n" "\n\n--\n\n"
"Comments are lines that start with #"; "Comments are lines that start with #";
} }
QString command() const { QString command() const {
@ -383,7 +383,7 @@ class Screenshot: public Command {
QString description() const { QString description() const {
return return
tag()+" <filename-base>" tag()+" <filename-base>"
"\n\n" "\n\n--\n\n"
"Create a PNG screenshot of the actual web page and store it in the " "Create a PNG screenshot of the actual web page and store it in the "
"file <filename-base>.png. If not already opened, a browser window " "file <filename-base>.png. If not already opened, a browser window "
"will pop up to take the screenshot."; "will pop up to take the screenshot.";
@ -450,6 +450,7 @@ class Script: public QObject {
void logging(QString); void logging(QString);
void progress(QString, int, int, int); void progress(QString, int, int, int);
public: public:
typedef std::map<QString, std::shared_ptr<Command>> Prototypes;
typedef std::pair<QString, QStringList> Signal; typedef std::pair<QString, QStringList> Signal;
enum ClickType { enum ClickType {
REAL_MOUSE_CLICK, REAL_MOUSE_CLICK,
@ -500,57 +501,79 @@ class Script: public QObject {
} }
QString syntax() const { QString syntax() const {
return return
"Script syntax is a text file that consists of list of commands. Each " "Script syntax is a text file that consists of a list of commands. Each "
"command starts at the begin of a new line. Empty lines are allowed. " "command starts at the begin of a new line. Empty lines are allowed. "
"Lines that start with \"#\" are treated as comments." "Lines that start with \"#\" are treated as comments."
"\n\n" "\n\n"
"Subcommands are indented. The first indented line defines the level of " "Subcommands are indented. The first indented line defines the level of "
"indentation. All following lines must be indented by the same level." "indentation. All following lines must be indented at least by the same level."
"\n\n" "\n\n"
"Note: When a selector is required as parameter, then the selector " "Note: When a selector is required as parameter, then the selector "
"is a CSS selector." "is a CSS selector."
"\n\n" "\n\n"
"Thanks to the filter script doxygen-webtester.sed, you cab use the " "Thanks to the filter script doxygen-webtester.sed, you can use the "
"comments for producing doxygen documenation. Just start comments with " "comments for producing doxygen documenation. Just start comments with "
"\"##\" to import them to doxygen. This script is automatically configured, " "\"##\" to import them to doxygen. This script is automatically configured, "
"when you use the autotools bootstrap from:\n" "when you use the autotools bootstrap from:\n"
"https://dev.marc.waeckerlin.org/redmine/projects/bootstrap-build-environment"; "https://mrw.sh/development/bootstrap-build-environment";
} }
/// set workdir /// set workdir
void path(QString path) { void path(QString path) {
_path = (path.size()?path:".")+QDir::separator(); _path = (path.size()?path:".")+QDir::separator();
} }
/// get workdir /// get workdir
QString path() { QString path() const {
return _path; return _path;
} }
/// get all command prototypes
const Prototypes& prototypes() const {
return _prototypes;
}
QString commands(Formatting f = PLAIN) const { QString commands(Formatting f = PLAIN) const {
QString cmds; QString cmds;
for (auto it(_prototypes.begin()); it!=_prototypes.end(); ++it) switch (f) {
switch (f) { case PLAIN: {
case PLAIN: { for (auto it(_prototypes.begin()); it!=_prototypes.end(); ++it)
cmds+="\n\n\nCOMMAND: "+it->first+"\n\n"+it->second->description(); cmds+="\n\n\nCOMMAND: "+it->first+"\n\n"+it->second->description();
} break; } break;
case HTML: { case HTML: {
cmds+="<h1>"+it->first+"</h1><p>" auto format = [](QString s) {
+it->second->description() return s
.replace("&", "&amp;") .replace("&", "&amp;")
.replace("<", "&lt;") .replace("<", "&lt;")
.replace(">", "&gt;") .replace(">", "&gt;")
.replace(QRegularExpression("&lt;([^ ]+)&gt;"), .replace(QRegularExpression("&lt;([-_A-Za-z0-9]+)&gt;"), "<i>\\1</i>")
"<i>\\1</i>") .replace(QRegularExpression("(\n[^ ][^\n]*)(\n +-)"), "\\1<ul>\\2")
.replace(QRegularExpression("(\n[^ ][^\n]*)(\n +-)"), .replace(QRegularExpression("(\n +-[^\n]*\n)([^ ])"), "\\1</ul>\\2")
"\\1<ul>\\2") .replace(QRegularExpression("\n +- ([^\n]*)(</ul>)?"), "<li>\\1</li>\\2")
.replace(QRegularExpression("(\n +-[^\n]*\n)([^ ])"), .replace("</li>\n", "</li>")
"\\1</ul>\\2") .replace("\n ", "\n&nbsp;&nbsp;")
.replace(QRegularExpression("\n +- ([^\n]*)(</ul>)?"), .replace("\n\n", "</p><p>")
"<li>\\1</li>\\2") .replace("\n", "<br/>")
.replace("</li>\n", "</li>") .replace(QRegularExpression("(http(s)?://[-/^a-z0-9.]+)"), "<a href=\"\\1\">\\1</a>");
.replace("\n ", "\n&nbsp;&nbsp;") };
.replace("\n\n", "</p><p>") cmds = "<style>div#table-of-contents {border: 2px solid black; background-color: red; width: 100%; column-width: 5em;}</style>"
.replace("\n", "<br/>") "<h1>Contents</h1><ul>"
+"</p>"; "<li id=\"top-syntax-description\"><a href=\"#syntax-description\">Syntax</a></li>"
} break; "<li id=\"top-command-list\"><a href=\"#command-list\">Commands</a><ul>";
for (auto[name,command]: _prototypes)
cmds += "<li id=\"top-"+name+"\"><a href=\"#"+name+"\">"+name+"</a></li>";
cmds += "</ul></li></ul>"
"<h1 id=\"syntax-description\"><a href=\"#top-syntax-description\">Syntax</a></h1>"
+format(syntax())+
"<h1 id=\"command-list\"><a href=\"#top-command-list\">Commands</a></h1>";
for (auto[name,command]: _prototypes) {
QStringList doc(command->description().split("\n\n--\n\n"));
assert(doc.size()==2); // description does not match expected format
QString usage(doc.takeFirst());
QString description(doc.takeFirst());
cmds += "<h2 id=\""+name+"\"><a href=\"#top-"+name+"\">"+name+"</a></h2><h3>Usage</h3><p>"
+ format(usage)
+ "</p><h3>Description</h3><p>"
+ format(description)
+ "</p>";
}
} break;
} }
return cmds.trimmed(); return cmds.trimmed();
} }
@ -1155,7 +1178,6 @@ class Script: public QObject {
QString username; QString username;
QString password; QString password;
}; };
typedef std::map<QString, std::shared_ptr<Command>> Prototypes;
typedef std::vector<std::shared_ptr<Command>> Commands; typedef std::vector<std::shared_ptr<Command>> Commands;
Prototypes _prototypes; Prototypes _prototypes;
Commands _script; Commands _script;
@ -1205,7 +1227,7 @@ class Do: public Command {
QString description() const { QString description() const {
return return
tag()+" [<selector>]\n <javascript-line1>\n <javascript-line2>" tag()+" [<selector>]\n <javascript-line1>\n <javascript-line2>"
"\n\n" "\n\n--\n\n"
"Execute JavaScript on a CSS selected object. The object is the first " "Execute JavaScript on a CSS selected object. The object is the first "
"object in the DOM tree that matches the given CSS selector. You can " "object in the DOM tree that matches the given CSS selector. You can "
"refere to the selected object within the scripy by \"this\". The " "refere to the selected object within the scripy by \"this\". The "
@ -1248,7 +1270,7 @@ class Load: public Command {
QString description() const { QString description() const {
return return
tag()+" <url>" tag()+" <url>"
"\n\n" "\n\n--\n\n"
"Load an URL, the URL is given as parameter in full syntax."; "Load an URL, the URL is given as parameter in full syntax.";
} }
QString command() const { QString command() const {
@ -1277,7 +1299,7 @@ class Expect: public Command {
QString description() const { QString description() const {
return return
tag()+" <signal> [<parameter>]" tag()+" <signal> [<parameter>]"
"\n\n" "\n\n--\n\n"
"Expect a signal. Signals are emitted by webkit and may contain " "Expect a signal. Signals are emitted by webkit and may contain "
"parameter. If a parameter is given in the script, then the parameter " "parameter. If a parameter is given in the script, then the parameter "
"must match exactly. If no parameter is given, then the signal must " "must match exactly. If no parameter is given, then the signal must "
@ -1346,7 +1368,7 @@ class Open: public Command {
QString description() const { QString description() const {
return return
tag()+ tag()+
"\n\n" "\n\n--\n\n"
"Open the browser window, so you can follow the test steps visually."; "Open the browser window, so you can follow the test steps visually.";
} }
QString command() const { QString command() const {
@ -1372,7 +1394,7 @@ class Sleep: public Command {
QString description() const { QString description() const {
return return
tag()+" <seconds>" tag()+" <seconds>"
"\n\n" "\n\n--\n\n"
"Sleep for a certain amount of seconds. This helps, if you must wait " "Sleep for a certain amount of seconds. This helps, if you must wait "
"for some javascript actions, i.e. AJAX or slow pages, and the " "for some javascript actions, i.e. AJAX or slow pages, and the "
"excpeted signals are not sufficient."; "excpeted signals are not sufficient.";
@ -1410,7 +1432,7 @@ class Exit: public Command {
QString description() const { QString description() const {
return return
tag()+ tag()+
"\n\n" "\n\n--\n\n"
"Successfully terminate script immediately. The following commands " "Successfully terminate script immediately. The following commands "
"are not executed. This helps when you debug your scripts and you " "are not executed. This helps when you debug your scripts and you "
"want the script stop at a certain point for investigations."; "want the script stop at a certain point for investigations.";
@ -1437,7 +1459,7 @@ class IgnoreTo: public Command {
QString description() const { QString description() const {
return return
tag()+" <label>" tag()+" <label>"
"\n\n" "\n\n--\n\n"
"Ignore all following commands up to a given label. The following " "Ignore all following commands up to a given label. The following "
"commands are not executed until the given label appears in the " "commands are not executed until the given label appears in the "
"script. This helps when you debug your scripts and you " "script. This helps when you debug your scripts and you "
@ -1470,7 +1492,7 @@ class Label: public Command {
QString description() const { QString description() const {
return return
tag()+" <label>" tag()+" <label>"
"\n\n" "\n\n--\n\n"
"This marks the label refered by command \"ignoreto\"."; "This marks the label refered by command \"ignoreto\".";
} }
QString command() const { QString command() const {
@ -1500,7 +1522,7 @@ class Upload: public Command {
QString description() const { QString description() const {
return return
tag()+" <selector> -> <filename>" tag()+" <selector> -> <filename>"
"\n\n" "\n\n--\n\n"
"Presses the specified file upload button and passes a given file " "Presses the specified file upload button and passes a given file "
"name. The command requires a CSS selector followed by a filename. " "name. The command requires a CSS selector followed by a filename. "
"The first object that matches the selector is used."; "The first object that matches the selector is used.";
@ -1554,7 +1576,7 @@ class Exists: public Command {
QString description() const { QString description() const {
return return
tag()+" <selector> -> <text>" tag()+" <selector> -> <text>"
"\n\n" "\n\n--\n\n"
"Assert that a certain text exists in the selected object, or if no " "Assert that a certain text exists in the selected object, or if no "
"text is given, assert that the specified object exists. The object " "text is given, assert that the specified object exists. The object "
"is given by a CSS selector. All matching objects are search for the " "is given by a CSS selector. All matching objects are search for the "
@ -1610,7 +1632,7 @@ class Not: public Command {
QString description() const { QString description() const {
return return
tag()+" <selector> -> <text>" tag()+" <selector> -> <text>"
"\n\n" "\n\n--\n\n"
"Assert that a certain text does not exists in the selected object, " "Assert that a certain text does not exists in the selected object, "
"or if no text is given, assert that the specified object does not " "or if no text is given, assert that the specified object does not "
"exists. The object is given by a CSS selector. All matching objects " "exists. The object is given by a CSS selector. All matching objects "
@ -1659,7 +1681,7 @@ class Execute: public Command {
QString description() const { QString description() const {
return return
tag()+" <command>\n <line1>\n <line2>\n <...>" tag()+" <command>\n <line1>\n <line2>\n <...>"
"\n\n" "\n\n--\n\n"
"Execute <command>. The command can have space separated arguments. " "Execute <command>. The command can have space separated arguments. "
"Following lines that are intended by at least " "Following lines that are intended by at least "
"one space are streamed into the command. This way, you can e.g. " "one space are streamed into the command. This way, you can e.g. "
@ -1726,7 +1748,7 @@ class Download: public Command {
return return
tag()+" <filename>\n" tag()+" <filename>\n"
" <command-to-start-download>" " <command-to-start-download>"
"\n\n" "\n\n--\n\n"
"Set download file before loading a download link or clicking on a " "Set download file before loading a download link or clicking on a "
"download button. The next line must be exactly one command that " "download button. The next line must be exactly one command that "
"initiates the download.\n\n" "initiates the download.\n\n"
@ -1807,7 +1829,7 @@ class Click: public Command {
QString description() const { QString description() const {
return return
tag()+" [<clicktype>] <selector>" tag()+" [<clicktype>] <selector>"
"\n\n" "\n\n--\n\n"
"Click on the specified element. Either you explicitely specify a click" "Click on the specified element. Either you explicitely specify a click"
" type, such as <realmouse> or <javascript>, or the previously set or" " type, such as <realmouse> or <javascript>, or the previously set or"
" the default clicktype is used."; " the default clicktype is used.";
@ -1861,10 +1883,10 @@ class Set: public Command {
} }
QString description() const { QString description() const {
return return
tag()+" <variable>=<value>\n"+ tag()+" <variable>=<value>\n\n"+
tag()+" <variable>\n" tag()+" <variable>\n"
" <command>" " <command>"
"\n\n" "\n\n--\n\n"
"Sets the value of a variable either to a constant, or to the output" "Sets the value of a variable either to a constant, or to the output"
" of a command. A command should be a command that produces an" " of a command. A command should be a command that produces an"
" output, such as <do>, which returns the result of JavaScript or" " output, such as <do>, which returns the result of JavaScript or"
@ -1920,7 +1942,7 @@ class UnSet: public Command {
QString description() const { QString description() const {
return return
tag()+" <variable>" tag()+" <variable>"
"\n\n" "\n\n--\n\n"
"Undo the setting of a variable. The opposite of «set»."; "Undo the setting of a variable. The opposite of «set».";
} }
QString command() const { QString command() const {
@ -1949,7 +1971,7 @@ class Timeout: public Command {
QString description() const { QString description() const {
return return
tag()+" <seconds>" tag()+" <seconds>"
"\n\n" "\n\n--\n\n"
"Set the timeout in seconds (defaults to 10)."; "Set the timeout in seconds (defaults to 10).";
} }
QString command() const { QString command() const {
@ -1982,7 +2004,7 @@ class CaCertificate: public Command {
QString description() const { QString description() const {
return return
tag()+" <filename.pem>" tag()+" <filename.pem>"
"\n\n" "\n\n--\n\n"
"Load a CA certificate that will be accepted on SSL connections."; "Load a CA certificate that will be accepted on SSL connections.";
} }
QString command() const { QString command() const {
@ -2018,7 +2040,7 @@ class ClientCertificate: public Command {
QString description() const { QString description() const {
return return
tag()+" <certfile.pem> <keyfile.pem> <keypassword>" tag()+" <certfile.pem> <keyfile.pem> <keypassword>"
"\n\n" "\n\n--\n\n"
"Load a client certificate to authenticate on SSL connections. " "Load a client certificate to authenticate on SSL connections. "
"The password for the keyfile should not contain spaces. " "The password for the keyfile should not contain spaces. "
"Create the two files from a PKCS#12 file using OpenSSL:\n" "Create the two files from a PKCS#12 file using OpenSSL:\n"
@ -2078,7 +2100,7 @@ class ClickType: public Command {
QString description() const { QString description() const {
return return
tag()+" <type>" tag()+" <type>"
"\n\n" "\n\n--\n\n"
"Set how mouseclicks should be mapped. The best solution depends on" "Set how mouseclicks should be mapped. The best solution depends on"
" your problem. Normally it is good to call \"click()\" on the element" " your problem. Normally it is good to call \"click()\" on the element"
" using javascript. But with complex javascript infected websites, it" " using javascript. But with complex javascript infected websites, it"
@ -2122,9 +2144,9 @@ class SetValue: public Command {
} }
QString description() const { QString description() const {
return return
tag()+" <selector> -> '<value>'\n"+ tag()+" <selector> -> '<value>'\n\n"+
tag()+" <selector> -> '<value1>', '<value2>', <...>" tag()+" <selector> -> '<value1>', '<value2>', <...>"
"\n\n" "\n\n--\n\n"
"Set the selected element to a given value. It is mostly the same as" "Set the selected element to a given value. It is mostly the same as"
" the following constuct, except that options in a select are evaluated" " the following constuct, except that options in a select are evaluated"
" correctly:\n\n" " correctly:\n\n"
@ -2191,7 +2213,7 @@ class Function: public CommandContainer {
" <command1>\n" " <command1>\n"
" <command2>\n" " <command2>\n"
" <...>" " <...>"
"\n\n" "\n\n--\n\n"
"Define a function with arguments. The arguments are treated like" "Define a function with arguments. The arguments are treated like"
" local variables. In a sequence of scripts within the same testrun," " local variables. In a sequence of scripts within the same testrun,"
" functions are inherited from all followin scripts, so you can first" " functions are inherited from all followin scripts, so you can first"
@ -2241,7 +2263,7 @@ class Call: public Command {
QString description() const { QString description() const {
return return
tag()+" <name> ['<arg1>', '<arg2>', ...]" tag()+" <name> ['<arg1>', '<arg2>', ...]"
"\n\n" "\n\n--\n\n"
"Calls a function. The number of arguments must be exactly the same" "Calls a function. The number of arguments must be exactly the same"
" as in the function definition.\n\n" " as in the function definition.\n\n"
"If you quote the values, then quote all values with the same" "If you quote the values, then quote all values with the same"
@ -2296,7 +2318,7 @@ class If: public CommandContainer {
" <command3>\n" " <command3>\n"
" <command4>\n" " <command4>\n"
" <...>\n" " <...>\n"
"\n\n" "\n\n--\n\n"
"Execute commands conditionally. " "Execute commands conditionally. "
"The first variant compares a variable to a value. " "The first variant compares a variable to a value. "
"The comparision <cmp> can be = ! . ^ ~ < >, " "The comparision <cmp> can be = ! . ^ ~ < >, "
@ -2408,7 +2430,7 @@ class While: public CommandContainer {
" <command1>\n" " <command1>\n"
" <command2>\n" " <command2>\n"
" <...>\n" " <...>\n"
"\n\n" "\n\n--\n\n"
"Repeats commands conditionally. " "Repeats commands conditionally. "
"The first variant compares a variable to a value. " "The first variant compares a variable to a value. "
"The comparision <cmp> can be = ! . ^ ~ < >, " "The comparision <cmp> can be = ! . ^ ~ < >, "
@ -2501,7 +2523,7 @@ class TestSuite: public Command {
QString description() const { QString description() const {
return return
tag()+" <name>" tag()+" <name>"
"\n\n" "\n\n--\n\n"
"Start a testsuite and give it a name."; "Start a testsuite and give it a name.";
} }
QString command() const { QString command() const {
@ -2530,7 +2552,7 @@ class TestCase: public Command {
QString description() const { QString description() const {
return return
tag()+" <name>" tag()+" <name>"
"\n\n" "\n\n--\n\n"
"Start a testcase and give it a name."; "Start a testcase and give it a name.";
} }
QString command() const { QString command() const {
@ -2558,10 +2580,10 @@ class Check: public Command {
} }
QString description() const { QString description() const {
return return
tag()+" <value1> <cmp> <value2>\n"+ tag()+" <value1> <cmp> <value2>\n\n"+
tag()+" <value1> <cmp>\n" tag()+" <value1> <cmp>\n"
" <command>" " <command>"
"\n\n" "\n\n--\n\n"
"Compares two values (you can use variables) or compares a value to the" "Compares two values (you can use variables) or compares a value to the"
" result of a command. The command should be a command that produces an" " result of a command. The command should be a command that produces an"
" output, such as <do>, which returns the result of JavaScript or" " output, such as <do>, which returns the result of JavaScript or"
@ -2644,7 +2666,7 @@ class For: public CommandContainer {
" <command1>\n" " <command1>\n"
" <command2>\n" " <command2>\n"
" <...>" " <...>"
"\n\n" "\n\n--\n\n"
"Executes the given commands with the variable set to the specifier values," "Executes the given commands with the variable set to the specifier values,"
"repeated once per given value. The variable is treated like a local variale" "repeated once per given value. The variable is treated like a local variale"
" in the loop.\n\n" " in the loop.\n\n"
@ -2696,7 +2718,7 @@ class Echo: public Command {
QString description() const { QString description() const {
return return
tag()+" <text>" tag()+" <text>"
"\n\n" "\n\n--\n\n"
"Echoes a text to the log."; "Echoes a text to the log.";
} }
QString command() const { QString command() const {
@ -2725,7 +2747,7 @@ class OfflineStoragePath: public Command {
QString description() const { QString description() const {
return return
tag()+" <path>" tag()+" <path>"
"\n\n" "\n\n--\n\n"
"Set offline storage path. Defaults to /tmp."; "Set offline storage path. Defaults to /tmp.";
} }
QString command() const { QString command() const {
@ -2758,7 +2780,7 @@ class ClearCookies: public Command {
QString description() const { QString description() const {
return return
tag()+" <url>" tag()+" <url>"
"\n\n" "\n\n--\n\n"
"Clear all cookies of given URL <url>, or of the current URL if no" "Clear all cookies of given URL <url>, or of the current URL if no"
" <url> is specified."; " <url> is specified.";
} }
@ -2794,7 +2816,7 @@ class Include: public CommandContainer {
QString description() const { QString description() const {
return return
tag()+" <filename>" tag()+" <filename>"
"\n\n" "\n\n--\n\n"
"Include a test script."; "Include a test script.";
} }
QString command() const { QString command() const {
@ -2861,7 +2883,7 @@ class Case: public Command {
" <command>\n" " <command>\n"
" <command>\n" " <command>\n"
" <...>\n" " <...>\n"
"\n\n" "\n\n--\n\n"
"Execute commands conditionally depending on a variable. " "Execute commands conditionally depending on a variable. "
"It is equivalent to neested if-else-if commands." "It is equivalent to neested if-else-if commands."
"The first variant compares a variable to a value. " "The first variant compares a variable to a value. "
@ -2981,7 +3003,7 @@ class Fail: public Command {
QString description() const { QString description() const {
return return
tag()+" <text>" tag()+" <text>"
"\n\n" "\n\n--\n\n"
"Fail with error text."; "Fail with error text.";
} }
QString command() const { QString command() const {
@ -3012,7 +3034,7 @@ class Auth: public Command {
tag()+" <realm> <username> <password>" tag()+" <realm> <username> <password>"
"\n\n"+ "\n\n"+
tag()+" <realm>" tag()+" <realm>"
"\n\n" "\n\n--\n\n"
"Set basic authentication credentials for <realm> to" "Set basic authentication credentials for <realm> to"
" <username> and <password>. If no realm is given," " <username> and <password>. If no realm is given,"
" the credentials for the given realm are removed."; " the credentials for the given realm are removed.";
@ -3054,7 +3076,7 @@ class Ignore: public Command {
QString description() const { QString description() const {
return return
tag()+" <signal1> <signal2> <...>" tag()+" <signal1> <signal2> <...>"
"\n\n" "\n\n--\n\n"
"Ignores a specific signal. It will not be placed in the queue " "Ignores a specific signal. It will not be placed in the queue "
"and any expect for this signal is always true. You can call " "and any expect for this signal is always true. You can call "
"ignore with a space separated list of signal names. You cannot " "ignore with a space separated list of signal names. You cannot "
@ -3086,7 +3108,7 @@ class UnIgnore: public Command {
QString description() const { QString description() const {
return return
tag()+" <signal1> <signal2> <...>" tag()+" <signal1> <signal2> <...>"
"\n\n" "\n\n--\n\n"
"Undo ignoring a specific signal. It will be placed in the queue " "Undo ignoring a specific signal. It will be placed in the queue "
"and any expect this signal checks the queue. You can call " "and any expect this signal checks the queue. You can call "
"unignore with a space separated list of signal names. You cannot " "unignore with a space separated list of signal names. You cannot "
@ -3119,7 +3141,7 @@ class : public Command {
QString description() const { QString description() const {
return return
tag()+ tag()+
"\n\n" "\n\n--\n\n"
""; "";
} }
QString command() const { QString command() const {

@ -76,6 +76,13 @@ class CodeEditor: public QPlainTextEdit {
Q_SIGNALS: Q_SIGNALS:
void include(QString); void include(QString);
void link(QString); void link(QString);
public Q_SLOTS:
void gotoLine(int line) {
if (textCursor().blockNumber()==line-1) return;
QTextCursor cursor(document()->findBlockByNumber(line-1));
setTextCursor(cursor);
highlightCurrentLine();
}
public: public:
CodeEditor(QWidget *parent = 0): QPlainTextEdit(parent) { CodeEditor(QWidget *parent = 0): QPlainTextEdit(parent) {
Highlighter *highlighter(new Highlighter(document())); Highlighter *highlighter(new Highlighter(document()));
@ -87,11 +94,6 @@ class CodeEditor: public QPlainTextEdit {
updateLineNumberAreaWidth(0); updateLineNumberAreaWidth(0);
highlightCurrentLine(); highlightCurrentLine();
} }
void gotoLine(int line) {
QTextCursor cursor(document()->findBlockByNumber(line-1));
setTextCursor(cursor);
highlightCurrentLine();
}
void lineNumberAreaPaintEvent(QPaintEvent *event) { void lineNumberAreaPaintEvent(QPaintEvent *event) {
QPainter painter(lineNumberArea); QPainter painter(lineNumberArea);
painter.fillRect(event->rect(), Qt::lightGray); painter.fillRect(event->rect(), Qt::lightGray);

@ -0,0 +1,54 @@
#ifndef __HELP__HXX
#define __HELP__HXX
#include <ui_help.hxx>
#include <commands.hxx>
#include <cassert>
class Help: public QDockWidget, protected Ui::Help {
Q_OBJECT
public:
Help(QWidget* p = nullptr): QDockWidget(p) {
setupUi(this);
_search->hide();
_help->setText(script.commands(Script::HTML));
}
public Q_SLOTS:
void on__search_textEdited(const QString& txt) {
_help->moveCursor(QTextCursor::Start);
if (script.prototypes().count(txt))
_help->scrollToAnchor(txt);
else
_help->find(txt);
}
void on__search_returnPressed() {
next();
}
void next() {
_help->find(_search->text());
}
void previous() {
_help->find(_search->text(), QTextDocument::FindBackward);
}
void startSearch() {
_search->show();
_search->setFocus();
_search->selectAll();
}
protected:
void keyPressEvent(QKeyEvent *e) {
if (e->matches(QKeySequence::Find))
startSearch();
if (e->matches(QKeySequence::FindNext))
next();
if (e->matches(QKeySequence::FindPrevious))
previous();
if (e->matches(QKeySequence::Cancel))
_search->hide();
return QDockWidget::keyPressEvent(e);
}
private:
const Script script;
};
#endif

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Help</class>
<widget class="QDockWidget" name="Help">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Help?!?</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextBrowser" name="_help">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="_search"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

@ -8,9 +8,10 @@
bin_PROGRAMS = webtester webrunner bin_PROGRAMS = webtester webrunner
webtester_MOCFILES = moc_testgui.cxx moc_scriptfile.cxx moc_commands.cxx moc_webpage.cxx \ webtester_MOCFILES = moc_testgui.cxx moc_scriptfile.cxx moc_help.cxx \
moc_commands.cxx moc_webpage.cxx \
moc_networkaccessmanager.cxx moc_editor.cxx moc_networkaccessmanager.cxx moc_editor.cxx
webtester_UIFILES = ui_testgui.hxx ui_scriptfile.hxx webtester_UIFILES = ui_testgui.hxx ui_scriptfile.hxx ui_help.hxx
webtester_SOURCES = version.cxx webtester.cxx exceptions.hxx version.hxx \ webtester_SOURCES = version.cxx webtester.cxx exceptions.hxx version.hxx \
${webtester_MOCFILES} ${webtester_UIFILES} ${webtester_MOCFILES} ${webtester_UIFILES}

@ -5,6 +5,7 @@
#include <ui_scriptfile.hxx> #include <ui_scriptfile.hxx>
#include <QMessageBox> #include <QMessageBox>
#include <QScrollBar> #include <QScrollBar>
#include <QShortcut>
#include <QTextDocumentFragment> #include <QTextDocumentFragment>
#include <cassert> #include <cassert>
@ -16,17 +17,18 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
void include(QString); void include(QString);
void close(ScriptFile*); void close(ScriptFile*);
void run(const QString&, const QString&, bool, Script&); void run(const QString&, const QString&, bool, Script&);
void running(QString file, int line); void progress(QString, int, int, int);
public: public:
ScriptFile(QWidget* p = nullptr): QDockWidget(p) { ScriptFile(QWidget* p = nullptr, QString name = QString()): QDockWidget(p), _name(name) {
setupUi(this); setupUi(this);
setWindowTitle(_name+"[*]");
assert(connect(_editor, SIGNAL(textChanged()), SLOT(modified()))); assert(connect(_editor, SIGNAL(textChanged()), SLOT(modified())));
assert(connect(_editor, SIGNAL(include(QString)), SIGNAL(include(QString)))); assert(connect(_editor, SIGNAL(include(QString)), SIGNAL(include(QString))));
assert(connect(_editor, SIGNAL(link(QString)), SIGNAL(link(QString)))); assert(connect(_editor, SIGNAL(link(QString)), SIGNAL(link(QString))));
assert(connect(_editor, SIGNAL(cursorPositionChanged()), SLOT(setLine())));
assert(connect(_line, SIGNAL(valueChanged(int)), SLOT(gotoLine(int))));
_searchBar->hide(); _searchBar->hide();
_replaceBar->hide(); _replaceBar->hide();
_lineBar->hide();
_progress->hide();
_status->setCurrentIndex(STATUS_NONE); _status->setCurrentIndex(STATUS_NONE);
} }
CodeEditor* editor() { CodeEditor* editor() {
@ -40,10 +42,14 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
setWindowTitle(name+"[*]"); setWindowTitle(name+"[*]");
setWindowModified(false); setWindowModified(false);
} }
public Q_SLOTS:
void setLine() {
int pos(_editor->textCursor().blockNumber()+1);
if (pos) _line->setValue(pos);
}
void gotoLine(int line) { void gotoLine(int line) {
_editor->gotoLine(line); _editor->gotoLine(line);
} }
public Q_SLOTS:
void load(QString name = QString()) { void load(QString name = QString()) {
if (isWindowModified() && if (isWindowModified() &&
QMessageBox::question(this, tr("Changes Not Saved"), QMessageBox::question(this, tr("Changes Not Saved"),
@ -108,8 +114,6 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
modified(this); modified(this);
} }
void run() { void run() {
_progress->reset();
_progress->show();
_status->setCurrentIndex(STATUS_RUNNING); _status->setCurrentIndex(STATUS_RUNNING);
bool oldRecordState(_record->isChecked()); bool oldRecordState(_record->isChecked());
_record->setChecked(false); _record->setChecked(false);
@ -118,9 +122,7 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
Script script; Script script;
try { try {
assert(connect(&script, SIGNAL(progress(QString, int, int, int)), assert(connect(&script, SIGNAL(progress(QString, int, int, int)),
SLOT(progress(QString, int, int, int)))); SIGNAL(progress(QString, int, int, int))));
assert(connect(&script, SIGNAL(progress(QString, int, int, int)),
SIGNAL(running(QString, int))));
QString text(_editor->textCursor().selection().toPlainText()); QString text(_editor->textCursor().selection().toPlainText());
if (text.isEmpty()) text = _editor->toPlainText(); if (text.isEmpty()) text = _editor->toPlainText();
run(_name, text, _screenshots->isChecked(), script); run(_name, text, _screenshots->isChecked(), script);
@ -158,7 +160,6 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
_run->setEnabled(true); _run->setEnabled(true);
_record->setEnabled(true); _record->setEnabled(true);
_record->setChecked(oldRecordState); _record->setChecked(oldRecordState);
_progress->hide();
} }
void appendCommand(const QString& txt) { void appendCommand(const QString& txt) {
if (!_record->isChecked()) return; if (!_record->isChecked()) return;
@ -225,22 +226,69 @@ class ScriptFile: public QDockWidget, protected Ui::ScriptFile {
_editor->moveCursor(QTextCursor::End); _editor->moveCursor(QTextCursor::End);
_editor->ensureCursorVisible(); _editor->ensureCursorVisible();
} }
void progress(const QString& file, int line, int pos, int max) {
_progress->setFormat(QString("%1:%2 — %p%").arg(file).arg(line));
_progress->setMinimum(0);
_progress->setMaximum(max);
_progress->setValue(pos);
}
void runEnabled(bool f = true) { void runEnabled(bool f = true) {
_run->setEnabled(false); _run->setEnabled(f);
} }
void on__run_clicked() { void on__run_clicked() {
run(); run();
} }
void on__from_textEdited(const QString& txt) {
on__next_clicked();
}
void on__next_clicked() {
if (_regex->isChecked())
_editor->find(QRegExp(_from->text()));
else
_editor->find(_from->text());
}
void on__previous_clicked() {
if (_regex->isChecked())
_editor->find(QRegExp(_from->text()), QTextDocument::FindBackward);
else
_editor->find(_from->text(), QTextDocument::FindBackward);
}
void on__replace_clicked() {
QTextCursor tc(_editor->textCursor());
if (tc.hasSelection()) tc.insertText(_to->text());
}
void on__replaceAll_clicked() {
QTextCursor cursor(_editor->textCursor());
if (_regex->isChecked())
_editor->setPlainText(_editor->toPlainText().replace(QRegExp(_from->text()), _to->text()));
else
_editor->setPlainText(_editor->toPlainText().replace(_from->text(), _to->text()));
_editor->setTextCursor(cursor);
}
void startSearch() {
_searchBar->show();
_from->setFocus();
_from->selectAll();
}
void startReplace() {
_searchBar->show();
_replaceBar->show();
_to->setFocus();
_to->selectAll();
}
protected: protected:
void closeEvent(QCloseEvent*) { void closeEvent(QCloseEvent*) {
close(this); close(this);
} }
void keyPressEvent(QKeyEvent *e) {
if (e->matches(QKeySequence::Find))
startSearch();
if (e->matches(QKeySequence::Replace))
startReplace();
if (e->matches(QKeySequence::FindNext))
on__next_clicked();
if (e->matches(QKeySequence::FindPrevious))
on__previous_clicked();
if (e->matches(QKeySequence::Cancel)) {
_searchBar->hide();
_replaceBar->hide();
}
return QDockWidget::keyPressEvent(e);
}
private: private:
enum RunStatus { enum RunStatus {
STATUS_NONE = 0, STATUS_NONE = 0,

@ -133,6 +133,13 @@
</widget> </widget>
</widget> </widget>
</item> </item>
<item>
<widget class="QSpinBox" name="_line">
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@ -158,9 +165,9 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="_all"> <widget class="QCheckBox" name="_regex">
<property name="text"> <property name="text">
<string>all</string> <string>RegularExpression</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -181,38 +188,15 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="_regex"> <widget class="QPushButton" name="_replaceAll">
<property name="text">
<string>RegularExpression</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="_lineBar" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSpinBox" name="_line"/>
</item>
<item>
<widget class="QPushButton" name="_goLine">
<property name="text"> <property name="text">
<string>line</string> <string>replace all</string>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QProgressBar" name="_progress">
<property name="value">
<number>24</number>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
@ -224,5 +208,38 @@
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections/> <connections>
<connection>
<sender>_from</sender>
<signal>returnPressed()</signal>
<receiver>_next</receiver>
<slot>click()</slot>
<hints>
<hint type="sourcelabel">
<x>259</x>
<y>496</y>
</hint>
<hint type="destinationlabel">
<x>303</x>
<y>505</y>
</hint>
</hints>
</connection>
<connection>
<sender>_to</sender>
<signal>returnPressed()</signal>
<receiver>_replace</receiver>
<slot>click()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>564</y>
</hint>
<hint type="destinationlabel">
<x>562</x>
<y>558</y>
</hint>
</hints>
</connection>
</connections>
</ui> </ui>

@ -19,6 +19,7 @@
#include <QScrollBar> #include <QScrollBar>
#include <QFile> #include <QFile>
#include <QMessageBox> #include <QMessageBox>
#include <QShortcut>
#include <QCompleter> #include <QCompleter>
#include <ui_testgui.hxx> #include <ui_testgui.hxx>
#include <stdexcept> #include <stdexcept>
@ -42,14 +43,16 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
setDockOptions(dockOptions()|QMainWindow::GroupedDragging); setDockOptions(dockOptions()|QMainWindow::GroupedDragging);
#endif #endif
menuViews->addAction(_setupScriptDock->toggleViewAction()); menuViews->addAction(_setupScriptDock->toggleViewAction());
menuViews->addAction(_scriptCommandsDock->toggleViewAction()); menuViews->addAction(_helpDock->toggleViewAction());
menuViews->addAction(_domDock->toggleViewAction()); menuViews->addAction(_domDock->toggleViewAction());
menuViews->addAction(_linksDock->toggleViewAction()); menuViews->addAction(_linksDock->toggleViewAction());
menuViews->addAction(_formsDock->toggleViewAction()); menuViews->addAction(_formsDock->toggleViewAction());
menuViews->addAction(_logDock->toggleViewAction()); menuViews->addAction(_logDock->toggleViewAction());
menuViews->addAction(_sourceDock->toggleViewAction()); menuViews->addAction(_sourceDock->toggleViewAction());
menuViews->addAction(_executeDock->toggleViewAction()); menuViews->addAction(_executeDock->toggleViewAction());
menuHelp->addAction(_helpDock->toggleViewAction());
statusbar->addPermanentWidget(_progress = new QProgressBar(), 1);
_progress->hide();
QSettings settings("mrw", "webtester"); QSettings settings("mrw", "webtester");
restoreGeometry(settings.value("geometry").toByteArray()); restoreGeometry(settings.value("geometry").toByteArray());
restoreState(settings.value("windowstate").toByteArray()); restoreState(settings.value("windowstate").toByteArray());
@ -64,7 +67,6 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
_web->setPage(pg); _web->setPage(pg);
_web->installEventFilter(this); // track mouse and keyboard _web->installEventFilter(this); // track mouse and keyboard
pg->setForwardUnsupportedContent(true); pg->setForwardUnsupportedContent(true);
_commands->setText(Script().commands(Script::HTML));
assert(connect(menuFile, SIGNAL(aboutToShow()), SLOT(fileMenuOpened()))); assert(connect(menuFile, SIGNAL(aboutToShow()), SLOT(fileMenuOpened())));
assert(connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*, QWidget*)), assert(connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*, QWidget*)),
SLOT(focusChanged(QWidget*, QWidget*)))); SLOT(focusChanged(QWidget*, QWidget*))));
@ -89,6 +91,26 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
enterText(true); enterText(true);
_web->stop(); _web->stop();
} }
void on__actionAbout_triggered() {
QMessageBox::about(this, tr("About"),
tr("Webtester\n"
"Version: %1\n"
"Builddate: %2\n"
"Release: %3\n"
"Libraries:\n"
"qt-%4 (%5)\n")
.arg(VERSION)
.arg(BUILD_DATE)
.arg(PACKAGE_VERSION)
.arg(qVersion())
.arg(QT_VERSION_STR));
}
void on__actionNew_triggered() {
QString name(QFileDialog::getSaveFileName(this, tr("Filename for new Test Script")));
QFileInfo info(name);
if (info.absoluteDir()==QDir::current()) name = info.fileName();
if (!name.isEmpty()) newScript(name);
}
void on__actionOpen_triggered() { void on__actionOpen_triggered() {
QString name(QFileDialog::getOpenFileName(this, tr("Open Test Script"))); QString name(QFileDialog::getOpenFileName(this, tr("Open Test Script")));
if (name.isEmpty()) return; if (name.isEmpty()) return;
@ -117,10 +139,6 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
ScriptFile* active(activeScriptFile()); ScriptFile* active(activeScriptFile());
if (active) active->clear(); if (active) active->clear();
} }
void on__actionRun_triggered() {
ScriptFile* active(activeScriptFile());
if (active) active->run();
}
void on__focused_clicked() { void on__focused_clicked() {
enterText(true); enterText(true);
QWebElement element(focused()); QWebElement element(focused());
@ -239,7 +257,6 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
_actionSaveAs->setEnabled(active); _actionSaveAs->setEnabled(active);
_actionSave->setEnabled(active&&active->isWindowModified()); _actionSave->setEnabled(active&&active->isWindowModified());
_actionClear->setEnabled(active); _actionClear->setEnabled(active);
_actionRun->setEnabled(active);
} }
QString activate(QString name) { QString activate(QString name) {
QFileInfo info(name); QFileInfo info(name);
@ -247,7 +264,6 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
if (!_testscripts.contains(name)) return load(name); if (!_testscripts.contains(name)) return load(name);
_testscripts[name]->show(); _testscripts[name]->show();
_testscripts[name]->raise(); _testscripts[name]->raise();
_testscripts[name]->activateWindow();
return name; return name;
} }
QString load(QString name) { QString load(QString name) {
@ -259,24 +275,29 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
} catch(const std::exception& x) { } catch(const std::exception& x) {
remove(_testscripts[name]); remove(_testscripts[name]);
} }
QDockWidget* first(_testscripts.isEmpty()?_setupScriptDock:_testscripts.last()); newScript(name);
_testscripts[name] = new ScriptFile(this);
assert(connect(_testscripts[name], SIGNAL(modified(ScriptFile*)), SLOT(modified(ScriptFile*))));
assert(connect(_testscripts[name], SIGNAL(link(QString)), SLOT(activate(QString))));
assert(connect(_testscripts[name], SIGNAL(close(ScriptFile*)), SLOT(remove(ScriptFile*))));
assert(connect(_testscripts[name], SIGNAL(run(const QString&, const QString&, bool, Script&)),
SLOT(run(const QString&, const QString&, bool, Script&))));
assert(connect(_testscripts[name], SIGNAL(running(QString, int)),
SLOT(showFileLine(QString, int))));
try { try {
_testscripts[name]->load(name); _testscripts[name]->load(name);
tabifyDockWidget(first, _testscripts[name]);
return activate(name); return activate(name);
} catch(const std::exception& x) { } catch(const std::exception& x) {
remove(_testscripts[name]); remove(_testscripts[name]);
return QString(); return QString();
} }
} }
QString newScript(QString name) {
if (_testscripts.contains(name)) return activate(name);
QDockWidget* first(_testscripts.isEmpty()?_setupScriptDock:_testscripts.last());
_testscripts[name] = new ScriptFile(this, name);
assert(connect(_testscripts[name], SIGNAL(modified(ScriptFile*)), SLOT(modified(ScriptFile*))));
assert(connect(_testscripts[name], SIGNAL(link(QString)), SLOT(activate(QString))));
assert(connect(_testscripts[name], SIGNAL(close(ScriptFile*)), SLOT(remove(ScriptFile*))));
assert(connect(_testscripts[name], SIGNAL(run(const QString&, const QString&, bool, Script&)),
SLOT(run(const QString&, const QString&, bool, Script&))));
assert(connect(_testscripts[name], SIGNAL(progress(QString, int, int, int)),
SLOT(progress(QString, int, int, int))));
tabifyDockWidget(first, _testscripts[name]);
return name;
}
void remove(ScriptFile* scriptfile) { void remove(ScriptFile* scriptfile) {
/// @todo check if modified /// @todo check if modified
_testscripts.remove(scriptfile->name()); _testscripts.remove(scriptfile->name());
@ -294,7 +315,12 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
script.parse(text.split('\n'), name); script.parse(text.split('\n'), name);
script.run(_web->page()->mainFrame(), testsuites, QString(), screenshots); script.run(_web->page()->mainFrame(), testsuites, QString(), screenshots);
} }
void showFileLine(QString file, int line) { void progress(QString file, int line, int pos, int max) {
_progress->setVisible(max>0&&pos!=max);
_progress->setFormat(QString("%1:%2 — %p%").arg(file).arg(line));
_progress->setMinimum(0);
_progress->setMaximum(max);
_progress->setValue(pos);
if (!_actionCursorFollowsFiles->isChecked() || file.isEmpty() || file=="setup") return; if (!_actionCursorFollowsFiles->isChecked() || file.isEmpty() || file=="setup") return;
try { try {
QString name(activate(file)); QString name(activate(file));
@ -304,10 +330,9 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
} }
protected: protected:
ScriptFile* activeScriptFile(QWidget* focus=nullptr) { ScriptFile* activeScriptFile(QWidget* focus=nullptr) {
//for (auto win: _testscripts) if (win->isActiveWindow()) return win;
ScriptFile* active(nullptr); ScriptFile* active(nullptr);
for (QObject* wid(focus?focus:QApplication::focusWidget()); !active && wid; wid = wid->parent()) for (QObject* wid(focus?focus:QApplication::focusWidget()); !active && wid; wid = wid->parent())
active = dynamic_cast<ScriptFile*>(wid); active = qobject_cast<ScriptFile*>(wid);
return active; return active;
} }
void closeEvent(QCloseEvent* event) { void closeEvent(QCloseEvent* event) {
@ -324,7 +349,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
} }
QMainWindow::closeEvent(event); QMainWindow::closeEvent(event);
} }
bool eventFilter(QObject*, QEvent* event) { bool eventFilter(QObject* target, QEvent* event) {
if (_inEventFilter) return false; if (_inEventFilter) return false;
_inEventFilter = true; _inEventFilter = true;
enterText(); enterText();
@ -829,6 +854,7 @@ class TestGUI: public QMainWindow, protected Ui::TestGUI {
bool _inEventFilter; // actually handling event filter bool _inEventFilter; // actually handling event filter
Script _setupScript; Script _setupScript;
QMap<QString, ScriptFile*> _testscripts; QMap<QString, ScriptFile*> _testscripts;
QProgressBar* _progress = nullptr;
}; };
#endif // TESTGUI_HXX #endif // TESTGUI_HXX

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>888</width> <width>852</width>
<height>1180</height> <height>759</height>
</rect> </rect>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
@ -103,7 +103,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>888</width> <width>852</width>
<height>34</height> <height>34</height>
</rect> </rect>
</property> </property>
@ -116,6 +116,7 @@
<property name="title"> <property name="title">
<string>F&amp;ile</string> <string>F&amp;ile</string>
</property> </property>
<addaction name="_actionNew"/>
<addaction name="_actionOpen"/> <addaction name="_actionOpen"/>
<addaction name="_actionOpenSetupScript"/> <addaction name="_actionOpenSetupScript"/>
<addaction name="separator"/> <addaction name="separator"/>
@ -123,15 +124,14 @@
<addaction name="_actionSaveAs"/> <addaction name="_actionSaveAs"/>
<addaction name="_actionRevertToSaved"/> <addaction name="_actionRevertToSaved"/>
<addaction name="_actionClear"/> <addaction name="_actionClear"/>
<addaction name="_actionRun"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="_actionQuit"/> <addaction name="_actionQuit"/>
</widget> </widget>
<widget class="QMenu" name="menuHelp"> <widget class="QMenu" name="menuHelp">
<property name="title"> <property name="title">
<string>Help</string> <string>&amp;Help</string>
</property> </property>
<addaction name="_actionCommands"/> <addaction name="_actionAbout"/>
</widget> </widget>
<widget class="QMenu" name="menuOptions"> <widget class="QMenu" name="menuOptions">
<property name="title"> <property name="title">
@ -254,7 +254,7 @@
<string>Execute &amp;JavaScript on First Selected Item</string> <string>Execute &amp;JavaScript on First Selected Item</string>
</property> </property>
<attribute name="dockWidgetArea"> <attribute name="dockWidgetArea">
<number>8</number> <number>1</number>
</attribute> </attribute>
<widget class="QWidget" name="dockWidgetContents_10"> <widget class="QWidget" name="dockWidgetContents_10">
<layout class="QVBoxLayout" name="verticalLayout_5"> <layout class="QVBoxLayout" name="verticalLayout_5">
@ -476,24 +476,13 @@ this.dispatchEvent(evObj);</string>
</layout> </layout>
</widget> </widget>
</widget> </widget>
<widget class="QDockWidget" name="_scriptCommandsDock"> <widget class="Help" name="_helpDock">
<property name="windowTitle"> <property name="windowTitle">
<string>Script &amp;Commands</string> <string>&amp;Help</string>
</property> </property>
<attribute name="dockWidgetArea"> <attribute name="dockWidgetArea">
<number>4</number> <number>4</number>
</attribute> </attribute>
<widget class="QWidget" name="dockWidgetContents_3">
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<widget class="QTextBrowser" name="_commands">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget> </widget>
<action name="_actionDOMTree"> <action name="_actionDOMTree">
<property name="checkable"> <property name="checkable">
@ -588,17 +577,6 @@ this.dispatchEvent(evObj);</string>
<string>Ctrl+Q</string> <string>Ctrl+Q</string>
</property> </property>
</action> </action>
<action name="_actionRun">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Run</string>
</property>
<property name="shortcut">
<string>Ctrl+R</string>
</property>
</action>
<action name="_actionRunLine"> <action name="_actionRunLine">
<property name="text"> <property name="text">
<string>Run &amp;Line</string> <string>Run &amp;Line</string>
@ -650,9 +628,9 @@ this.dispatchEvent(evObj);</string>
<string>O&amp;pen Setup Script ...</string> <string>O&amp;pen Setup Script ...</string>
</property> </property>
</action> </action>
<action name="_actionCommands"> <action name="_actionAbout">
<property name="text"> <property name="text">
<string>&amp;Commands ...</string> <string>&amp;About</string>
</property> </property>
</action> </action>
<action name="_actionCursorFollowsFiles"> <action name="_actionCursorFollowsFiles">
@ -663,12 +641,17 @@ this.dispatchEvent(evObj);</string>
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Cursor Follows Files</string> <string>&amp;Cursor Follows Files</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When running a script, the currently running file and line is highlighted. So the cursor follows the current file and line when running a script.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When running a script, the currently running file and line is highlighted. So the cursor follows the current file and line when running a script.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</action> </action>
<action name="_actionNew">
<property name="text">
<string>&amp;New ...</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
@ -681,12 +664,20 @@ this.dispatchEvent(evObj);</string>
<extends>QPlainTextEdit</extends> <extends>QPlainTextEdit</extends>
<header>editor.hxx</header> <header>editor.hxx</header>
</customwidget> </customwidget>
<customwidget>
<class>Help</class>
<extends>QDockWidget</extends>
<header>help.hxx</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>_load</tabstop> <tabstop>_load</tabstop>
<tabstop>_web</tabstop> <tabstop>_web</tabstop>
</tabstops> </tabstops>
<resources/> <resources>
<include location="ressourcen.qrc"/>
</resources>
<connections> <connections>
<connection> <connection>
<sender>_selector</sender> <sender>_selector</sender>
@ -695,12 +686,12 @@ this.dispatchEvent(evObj);</string>
<slot>click()</slot> <slot>click()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>785</x> <x>267</x>
<y>1144</y> <y>589</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>875</x> <x>360</x>
<y>1075</y> <y>496</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
@ -711,12 +702,12 @@ this.dispatchEvent(evObj);</string>
<slot>click()</slot> <slot>click()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>785</x> <x>267</x>
<y>1144</y> <y>589</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>874</x> <x>359</x>
<y>1144</y> <y>589</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
@ -731,8 +722,8 @@ this.dispatchEvent(evObj);</string>
<y>-1</y> <y>-1</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>630</x> <x>369</x>
<y>971</y> <y>599</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
@ -743,8 +734,8 @@ this.dispatchEvent(evObj);</string>
<slot>setChecked(bool)</slot> <slot>setChecked(bool)</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>630</x> <x>369</x>
<y>971</y> <y>599</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>-1</x> <x>-1</x>
@ -763,8 +754,8 @@ this.dispatchEvent(evObj);</string>
<y>-1</y> <y>-1</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>748</x> <x>851</x>
<y>374</y> <y>337</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
@ -775,8 +766,8 @@ this.dispatchEvent(evObj);</string>
<slot>setChecked(bool)</slot> <slot>setChecked(bool)</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>748</x> <x>851</x>
<y>374</y> <y>337</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>-1</x> <x>-1</x>
@ -795,8 +786,8 @@ this.dispatchEvent(evObj);</string>
<y>-1</y> <y>-1</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>748</x> <x>851</x>
<y>537</y> <y>468</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
@ -807,8 +798,8 @@ this.dispatchEvent(evObj);</string>
<slot>setChecked(bool)</slot> <slot>setChecked(bool)</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>748</x> <x>851</x>
<y>537</y> <y>468</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>-1</x> <x>-1</x>
@ -827,8 +818,8 @@ this.dispatchEvent(evObj);</string>
<y>-1</y> <y>-1</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>748</x> <x>851</x>
<y>699</y> <y>599</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
@ -839,8 +830,8 @@ this.dispatchEvent(evObj);</string>
<slot>setChecked(bool)</slot> <slot>setChecked(bool)</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>748</x> <x>851</x>
<y>699</y> <y>599</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>-1</x> <x>-1</x>
@ -860,7 +851,7 @@ this.dispatchEvent(evObj);</string>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>182</x> <x>182</x>
<y>971</y> <y>730</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
@ -872,7 +863,7 @@ this.dispatchEvent(evObj);</string>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>182</x> <x>182</x>
<y>971</y> <y>730</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>-1</x> <x>-1</x>
@ -891,8 +882,8 @@ this.dispatchEvent(evObj);</string>
<y>-1</y> <y>-1</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>842</x> <x>851</x>
<y>1004</y> <y>730</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
@ -903,8 +894,8 @@ this.dispatchEvent(evObj);</string>
<slot>setChecked(bool)</slot> <slot>setChecked(bool)</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>842</x> <x>851</x>
<y>1004</y> <y>730</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>-1</x> <x>-1</x>
@ -935,12 +926,12 @@ this.dispatchEvent(evObj);</string>
<slot>click()</slot> <slot>click()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>277</x> <x>513</x>
<y>315</y> <y>257</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>549</x> <x>603</x>
<y>315</y> <y>258</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>

Loading…
Cancel
Save