Hello community,
here is the log from the commit of package libyui-rest-api for openSUSE:Factory
checked in at 2019-12-25 10:54:14
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libyui-rest-api (Old)
and /work/SRC/openSUSE:Factory/.libyui-rest-api.new.6675 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libyui-rest-api"
Wed Dec 25 10:54:14 2019 rev:3 rq:755632 version:0.3.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/libyui-rest-api/libyui-rest-api.changes
2019-07-11 13:14:24.114848721 +0200
+++
/work/SRC/openSUSE:Factory/.libyui-rest-api.new.6675/libyui-rest-api.changes
2019-12-25 10:54:19.705620406 +0100
@@ -1,0 +2,9 @@
+Fri Nov 29 14:44:10 UTC 2019 - Rodion Iafarov <[email protected]>
+
+- Add support to operate on many widgets with rest-api (bsc#1132247)
+- Support column index when selecting a row
+- Update documentation
+- Increase SO version to 11
+- 0.3.0
+
+-------------------------------------------------------------------
Old:
----
libyui-rest-api-0.2.0.tar.bz2
New:
----
libyui-rest-api-0.3.0.tar.bz2
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ libyui-rest-api.spec ++++++
--- /var/tmp/diff_new_pack.sJT0Me/_old 2019-12-25 10:54:20.205620563 +0100
+++ /var/tmp/diff_new_pack.sJT0Me/_new 2019-12-25 10:54:20.205620563 +0100
@@ -16,12 +16,12 @@
#
-%define so_version 10
+%define so_version 11
%define bin_name %{name}%{so_version}
-%define libyui_devel_version libyui-devel >= 3.6.0
+%define libyui_devel_version libyui-devel >= 3.8.0
Name: libyui-rest-api
-Version: 0.2.0
+Version: 0.3.0
Release: 0
Summary: Libyui - REST API plugin, the shared part
License: LGPL-2.1-only OR LGPL-3.0-only
++++++ libyui-rest-api-0.2.0.tar.bz2 -> libyui-rest-api-0.3.0.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/libyui-rest-api-0.2.0/README.md
new/libyui-rest-api-0.3.0/README.md
--- old/libyui-rest-api-0.2.0/README.md 2019-07-03 08:16:11.000000000 +0200
+++ new/libyui-rest-api-0.3.0/README.md 2019-12-10 17:02:47.000000000 +0100
@@ -38,7 +38,7 @@
- [ ] Allow sending more user actions
- [ ] Some widgets do not send notify events when changed via the API
- [ ] SSL encryption/peer verification (needed for secure transferring of
sensitive data
- like passwords)
+ like passwords)
- [ ] Allow connection via Unix domain sockets
### Usage
@@ -50,6 +50,10 @@
After that, you can get the documentation how to interact with the UI by
accessing
http://localhost:9999 (or http://ipv6-localhost:9999 via IPv6).
+NOTE: For MultiItemSelector and CustomItemSelector, rest-api doesn't work as
expected
+in ncurses with `notify` set to true, when using pure C++ code. This
limitation is
+due to widget implementation. With ruby wrapper, there is no issue.
+
### Remote Access
By setting `YUI_HTTP_REMOTE=1` environmental variable, one can allow
connections
@@ -76,53 +80,49 @@
---
<h1>LibYUI Embedded Webserver</h1>
+<p>This webserver provides a REST API for the LibYUI application.</p>
+<p>It can be used for testing and controlling the application in automated
tests.</p> <br>
<h2>Short Documentation</h2>
<h3>Application</h3>
-<p>Request: <pre>GET /application</pre>
-</p>
+<p>Request: <pre>GET /application</pre></p>
<h4>Description</h4>
<p>Get the application and UI generic properties like text or graphical mode,
dialog size, screen size and supported UI featues.</p>
<h4>Response</h4>
<p>JSON format</p>
<h4>Examples</h4>
<p>
- <pre>curl http://localhost:9999/application</pre>
+ <pre>curl http://localhost:9999/application</pre>
</p>
<hr>
<h3>Dump Whole Dialog</h3>
-<p>Request: <pre>GET /dialog</pre>
-</p>
+ <p>Request: <pre>GET /dialog</pre></p>
<h4>Description</h4>
<p>Get the complete dialog structure in the JSON format. The result contains a
nested structure exactly following the structure of the current dialog.</p>
<h4>Response</h4>
<p>JSON format</p>
<h4>Examples</h4>
<p>
- <pre>curl http://localhost:9999/dialog</pre>
+ <pre>curl http://localhost:9999/dialog</pre>
</p>
<hr>
<h3>Read Specific Widgets</h3>
-<p>Request: <pre>GET /widgets</pre>
-</p>
+<p>Request: <pre>GET /widgets</pre></p>
<h4>Description</h4>
<p>Return only the selected widgets (in JSON format). The result is a flat
list (no nested structures).</p>
<h4>Parameters</h4>
<p>Filter widgets: <ul>
- <li>
- <b>id</b> - widget ID serialized as string, might
include special characters like backtick (\`)</li>
- <li>
- <b>label</b> - widget label as currently displayed
(i.e. translated!) </li>
- <li>
- <b>type</b> - widget type</li>
- </ul>
+ <li><b>id</b> - widget ID serialized as string, might include special
characters like backtick (\`)</li>
+ <li><b>label</b> - widget label as currently displayed (i.e.
translated!) </li>
+ <li><b>type</b> - widget type</li>
+ </ul>
</p>
<h4>Response</h4>
<p>JSON format</p>
<h4>Examples</h4>
<p>
- <pre>curl 'http://localhost:9999/widgets?id=next'</pre>
- <pre>curl 'http://localhost:9999/widgets?label=Next'</pre>
- <pre>curl 'http://localhost:9999/widgets?type=YCheckBox'</pre>
+ <pre>curl 'http://localhost:9999/widgets?id=next'</pre>
+ <pre>curl 'http://localhost:9999/widgets?label=Next'</pre>
+ <pre>curl 'http://localhost:9999/widgets?type=YCheckBox'</pre>
</p>
<hr>
<h3>Change Widgets, Do an Action</h3>
@@ -131,25 +131,35 @@
<p>Do an action with specified widgets.</p>
<h4>Parameters</h4>
<p>Filter the widgets, one of: <ul>
- <li>
- <b>id</b> - widget ID serialized as string, might
include special characters like backtick (\`)</li>
- <li>
- <b>label</b> - widget label as currently displayed
(i.e. translated!) </li>
- <li>
- <b>type</b> - widget type</li>
- </ul> Then specify the action: <ul>
- <li>
- <b>action</b> - action to do</li>
- <li>
- <b>value</b> (optional) - new value or a parameter of
the action</li>
- </ul>
+ <li><b>id</b> - widget ID serialized as string, might include special
characters like backtick (\`)</li>
+ <li><b>label</b> - widget label as currently displayed (i.e.
translated!) </li>
+ <li><b>type</b> - widget type</li>
+ </ul> Then specify the action: <ul>
+ <li><b>action</b> - action to do</li>
+ <li><b>value</b> (optional) - new value or a parameter of the
action</li>
+ <li><b>column</b> (optional) - column id when selecting item in the
table</li>
+ </ul>
+</p> Supported actions: <ul>
+ <li><b>press</b> - to press the button</li>
+ <li><b>check</b>|<b>uncheck</b>|<b>toggle</b> - check, uncheck or toggle
checkbox</li>
+ <li><b>enter_text</b> - set text in the field, requires <b>value</b>
parameter</li>
+ <li><b>switch_radio</b> - activate radio button</li>
+ <li><b>select</b> - select value in the combobox, row in the table or node
in the tree, requires <b>value</b> parameter<br />
+ In case of table: select row in the table with given value. If
<b>column</b> parameters is not provided, first column will be used. <br />
+ In case of tree: select node in the tree. Use <b>'|'</b> as delimiter
for child nodes.</li>
+
+</ul>
</p>
<h4>Response</h4>
<p>JSON format</p>
<h4>Examples</h4>
<p>
- Press the "next" button:
- <pre>curl -X POST
'http://localhost:9999/widgets?id=next&action=press'</pre>
- Set value "test" for the InputField with label "Description":
- <pre>curl -X POST
'http://localhost:9999/widgets?label=Description&action=enter&value=test'</pre>
+ <pre> # press the "next" button
+curl -X POST 'http://localhost:9999/widgets?id=next&action=press'</pre>
+ <pre> # set value "test" for the InputField with label "Description"
+curl -X POST
'http://localhost:9999/widgets?label=Description&action=enter_text&value=test'</pre>
+ <pre> # select row with "test" cell value in the 2-nd column (counting
from zero) in table with id "names"
+curl -X POST
'http://localhost:9999/widgets?id=names&action=select&value=test&column=2'</pre>
+ <pre> # select tree item with in tree with id "files"
+curl -X POST
'http://localhost:9999/widgets?id=files&action=select&value=root|subnode|subnode'</pre>
</p>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/libyui-rest-api-0.2.0/VERSION.cmake
new/libyui-rest-api-0.3.0/VERSION.cmake
--- old/libyui-rest-api-0.2.0/VERSION.cmake 2019-07-03 08:16:11.000000000
+0200
+++ new/libyui-rest-api-0.3.0/VERSION.cmake 2019-12-10 17:02:47.000000000
+0100
@@ -1,5 +1,5 @@
SET( VERSION_MAJOR "0")
-SET( VERSION_MINOR "2" )
+SET( VERSION_MINOR "3" )
SET( VERSION_PATCH "0" )
SET( VERSION
"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${GIT_SHA1_VERSION}" )
@@ -8,7 +8,7 @@
# Currently you must also change so_version in libyui.spec
# *and also in **all** other* libyui-*.spec files in the other repositories.
# Yes, such a design is suboptimal.
-SET( SONAME_MAJOR "10" )
+SET( SONAME_MAJOR "11" )
SET( SONAME_MINOR "0" )
SET( SONAME_PATCH "0" )
SET( SONAME "${SONAME_MAJOR}.${SONAME_MINOR}.${SONAME_PATCH}" )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/libyui-rest-api-0.2.0/package/libyui-rest-api.changes
new/libyui-rest-api-0.3.0/package/libyui-rest-api.changes
--- old/libyui-rest-api-0.2.0/package/libyui-rest-api.changes 2019-07-03
08:16:11.000000000 +0200
+++ new/libyui-rest-api-0.3.0/package/libyui-rest-api.changes 2019-12-10
17:02:47.000000000 +0100
@@ -1,4 +1,13 @@
-------------------------------------------------------------------
+Fri Nov 29 14:44:10 UTC 2019 - Rodion Iafarov <[email protected]>
+
+- Add support to operate on many widgets with rest-api (bsc#1132247)
+- Support column index when selecting a row
+- Update documentation
+- Increase SO version to 11
+- 0.3.0
+
+-------------------------------------------------------------------
Fri Jun 28 19:35:51 UTC 2019 - Ladislav Slezák <[email protected]>
- Split the libyui-rest-api plugin to separate Qt and Ncurses parts
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/libyui-rest-api-0.2.0/package/libyui-rest-api.spec
new/libyui-rest-api-0.3.0/package/libyui-rest-api.spec
--- old/libyui-rest-api-0.2.0/package/libyui-rest-api.spec 2019-07-03
08:16:11.000000000 +0200
+++ new/libyui-rest-api-0.3.0/package/libyui-rest-api.spec 2019-12-10
17:02:47.000000000 +0100
@@ -16,12 +16,12 @@
#
-%define so_version 10
+%define so_version 11
%define bin_name %{name}%{so_version}
-%define libyui_devel_version libyui-devel >= 3.6.0
+%define libyui_devel_version libyui-devel >= 3.8.0
Name: libyui-rest-api
-Version: 0.2.0
+Version: 0.3.0
Release: 0
Summary: Libyui - REST API plugin, the shared part
License: LGPL-2.1-only OR LGPL-3.0-only
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/libyui-rest-api-0.2.0/src/YHttpRootHandler.cc
new/libyui-rest-api-0.3.0/src/YHttpRootHandler.cc
--- old/libyui-rest-api-0.2.0/src/YHttpRootHandler.cc 2019-07-03
08:16:11.000000000 +0200
+++ new/libyui-rest-api-0.3.0/src/YHttpRootHandler.cc 2019-12-10
17:02:47.000000000 +0100
@@ -100,6 +100,18 @@
" <ul>"
" <li><b>action</b> - action to do</li>"
" <li><b>value</b> (optional) - new value or a parameter of the
action</li>"
+" <li><b>column</b> (optional) - column id when selecting item in the
table</li>"
+" </ul>"
+" </p>"
+" Supported actions:"
+" <ul>"
+" <li><b>press</b> - to press the button</li>"
+" <li><b>check</b>|<b>uncheck</b>|<b>toggle</b> - check, uncheck or
toggle checkbox</li>"
+" <li><b>enter_text</b> - set text in the field, requires
<b>value</b> parameter</li>"
+" <li><b>switch_radio</b> - activate radio button</li>"
+" <li><b>select</b> - select value in the combobox, row in the table
or node in the tree, requires <b>value</b> parameter<br />"
+" In case of table: select row in the table with given value.
If <b>column</b> parameters is not provided, first column will be used. <br />"
+" In case of tree: select node in the tree. Use <b>'|'</b> as
delimiter for child nodes.</li>"
" </ul>"
" </p>"
" <h4>Response</h4>"
@@ -109,7 +121,11 @@
" <pre> # press the `next button\n"
" curl -X POST 'http://localhost:@port@/widgets?id=`next&action=press'</pre>"
" <pre> # set value \"test\" for the InputField with label
\"Description\"\n"
-" curl -X POST
'http://localhost:@port@/widgets?label=Description&action=enter&value=test'</pre>"
+" curl -X POST
'http://localhost:@port@/widgets?label=Description&action=enter_text&value=test'</pre>"
+" <pre> # select row with \"test\" cell value in the 2-nd column
(counting from zero) in table with id \"names\"\n"
+" curl -X POST
'http://localhost:@port@/widgets?id=names&action=select&value=test&column=2'</pre>"
+" <pre> # select tree item with in tree with id \"files\"\n"
+" curl -X POST
'http://localhost:@port@/widgets?id=files&action=select&value=root|subnode|subnode'</pre>"
" </p>"
" </body>"
"</html>";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/libyui-rest-api-0.2.0/src/YHttpWidgetsActionHandler.cc
new/libyui-rest-api-0.3.0/src/YHttpWidgetsActionHandler.cc
--- old/libyui-rest-api-0.2.0/src/YHttpWidgetsActionHandler.cc 2019-07-03
08:16:11.000000000 +0200
+++ new/libyui-rest-api-0.3.0/src/YHttpWidgetsActionHandler.cc 2019-12-10
17:02:47.000000000 +0100
@@ -14,13 +14,29 @@
Floor, Boston, MA 02110-1301 USA
*/
+#include "YCheckBox.h"
#include "YComboBox.h"
#include "YDialog.h"
-#include "YCheckBox.h"
+#include "YDumbTab.h"
#include "YInputField.h"
+#include "YIntField.h"
+#include "YItemSelector.h"
+#include "YMenuButton.h"
+#include "YMultiLineEdit.h"
#include "YPushButton.h"
#include "YRadioButton.h"
+#include "YRichText.h"
#include "YTable.h"
+#include "YTree.h"
+#include "YTreeItem.h"
+#include "YSelectionBox.h"
+
+#include <codecvt>
+#include <vector>
+#include <sstream>
+#include <cstdlib>
+#include <string>
+#include <boost/algorithm/string.hpp>
#include "YHttpWidgetsActionHandler.h"
@@ -28,36 +44,43 @@
const char* url, const char* method, const char* upload_data,
size_t* upload_data_size, std::ostream& body, bool *redraw)
{
- if (YDialog::topmostDialog(false)) {
+ if ( YDialog::topmostDialog(false) )
+ {
WidgetArray widgets;
- if (const char* label = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "label"))
- widgets = YWidgetFinder::by_label(label);
- else if (const char* id = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "id"))
- widgets = YWidgetFinder::by_id(id);
- else if (const char* type = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "type"))
- widgets = YWidgetFinder::by_type(type);
- else {
+ const char* label = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "label");
+ const char* id = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "id");
+ const char* type = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "type");
+
+ if ( label || id || type )
+ {
+ widgets = YWidgetFinder::find(label, id, type);
+ }
+ else
+ {
widgets = YWidgetFinder::all();
}
- if (widgets.empty()) {
+ if ( widgets.empty() )
+ {
body << "{ \"error\" : \"Widget not found\" }" << std::endl;
_error_code = MHD_HTTP_NOT_FOUND;
}
- else if (const char* action = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "action"))
+ else if ( const char* action = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "action") )
{
- std::string value;
- if (const char* val = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "value"))
- value = val;
-
- _error_code = do_action(widgets, action, value, body);
+ if( widgets.size() != 1 )
+ {
+ body << "{ \"error\" : \"Multiple widgets found to act on, try
using multicriteria search (label+id+type)\" }" << std::endl;
+ _error_code = MHD_HTTP_NOT_FOUND;
+ }
+ _error_code = do_action(widgets[0], action, connection, body);
// the action possibly changed something in the UI, signalize
redraw needed
- if (redraw && _error_code == MHD_HTTP_OK)
+ if ( redraw && _error_code == MHD_HTTP_OK )
*redraw = true;
}
- else {
+ else
+ {
body << "{ \"error\" : \"Missing action parameter\" }" <<
std::endl;
_error_code = MHD_HTTP_NOT_FOUND;
}
@@ -73,87 +96,325 @@
return "application/json";
}
-int YHttpWidgetsActionHandler::do_action(WidgetArray widgets, const
std::string &action, const std::string &value, std::ostream& body) {
+int YHttpWidgetsActionHandler::do_action(YWidget *widget, const std::string
&action, struct MHD_Connection *connection, std::ostream& body) {
+
yuiMilestone() << "Starting action: " << action << std::endl;
// TODO improve this, maybe use better names for the actions...
// press a button
- if (action == "press") {
- return action_handler<YPushButton>(widgets, [] (YPushButton *button) {
- yuiMilestone() << "Pressing button \"" << button->label() << '"'
<< std::endl;
- button->setKeyboardFocus();
- button->activate();
- } );
+ if ( action == "press" )
+ {
+ yuiMilestone() << "Received action: press" << std::endl;
+ if (dynamic_cast<YPushButton*>(widget))
+ {
+ return action_handler<YPushButton>(widget, [] (YPushButton *button)
+ {
+ yuiMilestone() << "Pressing button \"" << button->label() <<
'"' << std::endl;
+ button->setKeyboardFocus();
+ button->activate();
+ } );
+ }
+ else if ( dynamic_cast<YRichText*>(widget) )
+ {
+ std::string value;
+ if ( const char* val = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "value") )
+ value = val;
+ return action_handler<YRichText>(widget, [&] (YRichText *rt) {
+ yuiMilestone() << "Activating hyperlink on richtext: \"" <<
value << '"' << std::endl;
+ rt->setKeyboardFocus();
+ rt->activateLink(value);
+ } );
+ }
+ else if( dynamic_cast<YMenuButton*>(widget) )
+ {
+ std::string value;
+ if ( const char* val = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "value") )
+ value = val;
+ return action_handler<YMenuButton>(widget, [&] (YMenuButton *mb) {
+ // Vector of string to store path to the tree item
+ std::vector<std::string> path;
+ boost::split( path, value, boost::is_any_of( TreePathDelimiter
) );
+ YMenuItem * item = mb->findItem( path );
+ if ( item )
+ {
+ yuiMilestone() << "Activating Item by path :" << value <<
" in \"" << mb->label() << "\" MenuButton" << std::endl;
+ mb->setKeyboardFocus();
+ mb->activateItem( item );
+ }
+ else
+ {
+ body << "Item with path: \"" << value << "\" cannot be
found in the MenuButton widget" << std::endl;
+ throw YUIException("Item cannot be found in the MenuButton
widget");
+ }
+ } );
+ }
+ else
+ {
+ body << "Action is not supported for the selected widget: " <<
widget->widgetClass() << std::endl;
+ return MHD_HTTP_NOT_FOUND;
+ }
}
// check a checkbox
- else if (action == "check") {
- return action_handler<YCheckBox>(widgets, [] (YCheckBox *checkbox) {
- if (checkbox->isChecked()) return;
- yuiMilestone() << "Checking \"" << checkbox->label() << '"' <<
std::endl;
- checkbox->setKeyboardFocus();
- checkbox->setChecked(true);
- } );
+ else if ( action == "check" )
+ {
+ if ( dynamic_cast<YCheckBox*>(widget) )
+ {
+ return action_handler<YCheckBox>(widget, [] (YCheckBox *checkbox) {
+ if (checkbox->isChecked()) return;
+ yuiMilestone() << "Checking \"" << checkbox->label() << '"' <<
std::endl;
+ checkbox->setKeyboardFocus();
+ checkbox->setChecked(true);
+ } );
+ }
+ else if( dynamic_cast<YItemSelector*>(widget) )
+ {
+ std::string value;
+ if (const char* val = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "value"))
+ value = val;
+
+ return get_item_selector_handler(widget, value, body, 1);
+ }
+ else
+ {
+ body << "Action is not supported for the selected widget" <<
widget->widgetClass() << std::endl;
+ return MHD_HTTP_NOT_FOUND;
+ }
}
// uncheck a checkbox
- else if (action == "uncheck") {
- return action_handler<YCheckBox>(widgets, [] (YCheckBox *checkbox) {
- if (!checkbox->isChecked()) return;
- yuiMilestone() << "Unchecking \"" << checkbox->label() << '"' <<
std::endl;
- checkbox->setKeyboardFocus();
- checkbox->setChecked(false);
- } );
+ else if ( action == "uncheck" )
+ {
+ if ( dynamic_cast<YCheckBox*>(widget) )
+ {
+ return action_handler<YCheckBox>(widget, [] (YCheckBox *checkbox) {
+ if (!checkbox->isChecked()) return;
+ yuiMilestone() << "Unchecking \"" << checkbox->label() << '"'
<< std::endl;
+ checkbox->setKeyboardFocus();
+ checkbox->setChecked(false);
+ } );
+ }
+ else if( dynamic_cast<YItemSelector*>(widget) )
+ {
+ std::string value;
+ if ( const char* val = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "value") )
+ value = val;
+
+ return get_item_selector_handler(widget, value, body, 0);
+ }
+ else
+ {
+ body << "Action is not supported for the selected widget" <<
widget->widgetClass() << std::endl;
+ return MHD_HTTP_NOT_FOUND;
+ }
}
// toggle a checkbox (reverse the state)
- else if (action == "toggle") {
- return action_handler<YCheckBox>(widgets, [] (YCheckBox *checkbox) {
- yuiMilestone() << "Toggling \"" << checkbox->label() << '"' <<
std::endl;
- checkbox->setKeyboardFocus();
- checkbox->setChecked(!checkbox->isChecked());
- } );
+ else if ( action == "toggle" ) {
+ if ( dynamic_cast<YCheckBox*>(widget) )
+ {
+ return action_handler<YCheckBox>(widget, [] (YCheckBox *checkbox) {
+ yuiMilestone() << "Toggling \"" << checkbox->label() << '"' <<
std::endl;
+ checkbox->setKeyboardFocus();
+ checkbox->setChecked(!checkbox->isChecked());
+ } );
+ }
+ else if( dynamic_cast<YItemSelector*>(widget) )
+ {
+ std::string value;
+ if ( const char* val = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "value") )
+ value = val;
+
+ return get_item_selector_handler(widget, value, body);
+ }
+ else
+ {
+ body << "Action is not supported for the selected widget" <<
widget->widgetClass() << std::endl;
+ return MHD_HTTP_NOT_FOUND;
+ }
}
// enter input field text
- else if (action == "enter_text") {
- return action_handler<YInputField>(widgets, [&] (YInputField *input) {
- yuiMilestone() << "Setting value for InputField \"" <<
input->label() << '"' << std::endl;
- input->setKeyboardFocus();
- input->setValue(value);
- } );
- }
- else if (action == "switch_radio") {
- return action_handler<YRadioButton>(widgets, [&] (YRadioButton *rb) {
- yuiMilestone() << "Activating RadioButton \"" << rb->label() <<
'"' << std::endl;
- rb->setKeyboardFocus();
- rb->setValue(true);
- } );
- }
- else if (action == "select_combo") {
- return action_handler<YComboBox>(widgets, [&] (YComboBox *cb) {
- yuiMilestone() << "Activating ComboBox \"" << cb->label() << '"'
<< std::endl;
- cb->setKeyboardFocus();
- cb->setValue(value);
- } );
- }
- else if (action == "select_table") {
- return action_handler<YTable>(widgets, [&] (YTable *tb) {
- YItem * item = tb->findItem(value, 0);
- if (item) {
- yuiMilestone() << "Activating Table \"" << tb->label() << '"'
<< std::endl;
- tb->setKeyboardFocus();
- tb->selectItem(item);
- }
- else {
- yuiWarning() << '"' << value << "\" is not a valid item" <<
std::endl;
- }
- } );
+ else if ( action == "enter_text" )
+ {
+ std::string value;
+ if ( const char* val = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "value") )
+ value = val;
+
+ if ( dynamic_cast<YInputField*>(widget) )
+ {
+ return action_handler<YInputField>(widget, [&] (YInputField
*input) {
+ yuiMilestone() << "Setting value for InputField \"" <<
input->label() << '"' << std::endl;
+ input->setKeyboardFocus();
+ input->setValue(value);
+ } );
+ }
+ else if ( dynamic_cast<YIntField*>(widget) )
+ {
+ return action_handler<YIntField>(widget, [&] (YIntField *input) {
+ yuiMilestone() << "Setting value for YIntField \"" <<
input->label() << '"' << std::endl;
+ input->setKeyboardFocus();
+ input->setValue(atoi(value.c_str()));
+ } );
+ }
+ else if ( dynamic_cast<YMultiLineEdit*>(widget) )
+ {
+ return action_handler<YMultiLineEdit>(widget, [&] (YMultiLineEdit
*input) {
+ yuiMilestone() << "Setting value for YMultiLineEdit \"" <<
input->label() << '"' << std::endl;
+ input->setKeyboardFocus();
+ input->setValue(value);
+ } );
+ }
+ else
+ {
+ body << "Action is not supported for the selected widget: " <<
widget->widgetClass() << std::endl;
+ return MHD_HTTP_NOT_FOUND;
+ }
+ }
+ else if ( action == "select" )
+ {
+ std::string value;
+ if (const char* val = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "value"))
+ value = val;
+
+ if ( dynamic_cast<YComboBox*>(widget) )
+ {
+ return action_handler<YComboBox>(widget, [&] (YComboBox *cb) {
+ yuiMilestone() << "Activating ComboBox \"" << cb->label() <<
'"' << std::endl;
+ cb->setKeyboardFocus();
+ cb->setValue(value);
+ } );
+ }
+ else if( dynamic_cast<YTable*>(widget) )
+ {
+ int column_id = 0;
+ if ( const char* val = MHD_lookup_connection_value(connection,
MHD_GET_ARGUMENT_KIND, "column") )
+ column_id = atoi(val);
+ return action_handler<YTable>(widget, [&] (YTable *tb) {
+ YItem * item = tb->findItem(value, column_id);
+ if ( item )
+ {
+ yuiMilestone() << "Activating Table \"" << tb->label()
<< '"' << std::endl;
+ tb->setKeyboardFocus();
+ tb->selectItem(item);
+ }
+ else
+ {
+ body << '"' << value << "\" item cannot be found in the
table" << std::endl;
+ throw YUIException("Item cannot be found in the table");
+ }
+ } );
+ }
+ else if( dynamic_cast<YTree*>(widget) )
+ {
+ return action_handler<YTree>(widget, [&] (YTree *tree) {
+ // Vector of string to store path to the tree item
+ std::vector<std::string> path;
+ boost::split( path, value, boost::is_any_of( TreePathDelimiter
) );
+ YItem * item = tree->findItem( path );
+ if (item)
+ {
+ yuiMilestone() << "Activating Tree Item \"" <<
item->label() << '"' << std::endl;
+ tree->setKeyboardFocus();
+ tree->selectItem(item);
+ tree->activate();
+ }
+ else
+ {
+ body << '"' << value << "\" item cannot be found in the
tree" << std::endl;
+ throw YUIException("Item cannot be found in the tree");
+ }
+ } );
+ }
+ else if ( dynamic_cast<YDumbTab*>(widget) )
+ {
+ return action_handler<YDumbTab>(widget, [&] (YDumbTab *tab) {
+ YItem * item = tab->findItem( value );
+ if ( item )
+ {
+ yuiMilestone() << "Activating Tree Item \"" <<
item->label() << '"' << std::endl;
+ tab->setKeyboardFocus();
+ tab->selectItem(item);
+ tab->activate();
+ }
+ else
+ {
+ body << '"' << value << "\" item cannot be found in the
tree" << std::endl;
+ throw YUIException("Item cannot be found in the tree");
+ }
+ } );
+ }
+ else if( dynamic_cast<YRadioButton*>(widget) )
+ {
+ return action_handler<YRadioButton>(widget, [&] (YRadioButton *rb)
{
+ yuiMilestone() << "Activating RadioButton \"" << rb->label()
<< '"' << std::endl;
+ rb->setKeyboardFocus();
+ rb->setValue(true);
+ } );
+ }
+ else if( dynamic_cast<YSelectionBox*>(widget) )
+ {
+ return action_handler<YSelectionBox>(widget, [&] (YSelectionBox
*sb) {
+ YItem * item = sb->findItem( value );
+ if ( item )
+ {
+ yuiMilestone() << "Activating selection box \"" <<
sb->label() << '"' << std::endl;
+ sb->setKeyboardFocus();
+ sb->selectItem(item);
+ }
+ else
+ {
+ body << '"' << value << "\" item cannot be found in the
selection box" << std::endl;
+ throw YUIException("Item cannot be found in the selection
box");
+ }
+ } );
+ }
+ else if( dynamic_cast<YItemSelector*>(widget) )
+ {
+ return get_item_selector_handler(widget, value, body, 1);
+ }
+ else
+ {
+ body << "Action is not supported for the selected widget" <<
widget->widgetClass() << std::endl;
+ return MHD_HTTP_NOT_FOUND;
+ }
}
// TODO: more actions
// else if (action == "enter") {
// }
- else {
+ else
+ {
body << "{ \"error\" : \"Unknown action\" }" << std::endl;
return MHD_HTTP_NOT_FOUND;
}
return MHD_HTTP_OK;
}
+
+int YHttpWidgetsActionHandler::get_item_selector_handler(YWidget *widget,
const std::string &value, std::ostream& body, const int state) {
+ return action_handler<YItemSelector>(widget, [&] (YItemSelector *is) {
+ YItem * item = is->findItem( value );
+ if ( item )
+ {
+ yuiMilestone() << "Activating item selector with item \"" << value
<< '"' << std::endl;
+ is->setKeyboardFocus();
+ // Toggle in case state is undefined
+ bool select = state < 0 ? !item->selected() :
+ state == 0 ? false :
+ true;
+ if( state < 0 )
+ {
+ select = !item->selected();
+ }
+ else
+ {
+ select = state == 0 ? false : true;
+ }
+ item->setSelected( select );
+ is->selectItem( item, select );
+ is->activateItem( item );
+ }
+ else
+ {
+ body << '"' << value << "\" item cannot be found in the item
selector" << std::endl;
+ throw YUIException("Item cannot be found in the item selector");
+ }
+ } );
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/libyui-rest-api-0.2.0/src/YHttpWidgetsActionHandler.h
new/libyui-rest-api-0.3.0/src/YHttpWidgetsActionHandler.h
--- old/libyui-rest-api-0.2.0/src/YHttpWidgetsActionHandler.h 2019-07-03
08:16:11.000000000 +0200
+++ new/libyui-rest-api-0.3.0/src/YHttpWidgetsActionHandler.h 2019-12-10
17:02:47.000000000 +0100
@@ -25,7 +25,9 @@
#include <functional>
#include <microhttpd.h>
-#define YUILogComponent "rest-api"
+#define YUILogComponent "rest-api"
+#define TreePathDelimiter "|"
+
#include "YUILog.h"
class YHttpWidgetsActionHandler : public YHttpHandler
@@ -50,39 +52,40 @@
int _error_code;
-
// TODO: move this somewhere else...
- int do_action(WidgetArray widgets, const std::string &action, const
std::string &value, std::ostream& body);
+ int do_action(YWidget *widget, const std::string &action, struct
MHD_Connection *connection, std::ostream& body);
template<typename T>
- int action_handler(WidgetArray widgets, std::function<void (T*)>
handler_func) {
- for(YWidget *widget: widgets) {
- if (auto w = dynamic_cast<T*>(widget)) {
- try
- {
- // allow changing only the enabled widgets, disabled ones
- // cannot be changed by user from the UI, do not be more
powerfull
- if (handler_func && widget->isEnabled()) handler_func(w);
- }
- // some widgets may throw an exception when setting invalid
values
- catch (const YUIException &e)
- {
- return MHD_HTTP_UNPROCESSABLE_ENTITY;
- }
+ int action_handler(YWidget *widget, std::function<void (T*)> handler_func)
{
+ if (auto w = dynamic_cast<T*>(widget)) {
+ try
+ {
+ // allow changing only the enabled widgets, disabled ones
+ // cannot be changed by user from the UI, do not be more
powerfull
+ if (handler_func && widget->isEnabled()) handler_func(w);
}
- else {
- // TODO: demangle the C++ names here ?
- //
https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html
- yuiError() << "Expected " << typeid(T).name() << " widget,
found " << widget->widgetClass()
- << " (" << typeid(*widget).name() << ')' << std::endl;
- return MHD_HTTP_NOT_FOUND;
+ // some widgets may throw an exception when setting invalid values
+ catch (const YUIException &e)
+ {
+ yuiError() << "Error while processing action on widget "
+ << typeid(*widget).name() << " " << e.what() << std::endl;
+ return MHD_HTTP_UNPROCESSABLE_ENTITY;
}
}
+ else {
+ // TODO: demangle the C++ names here ?
+ //
https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html
+ yuiError() << "Expected " << typeid(T).name() << " widget, found "
<< widget->widgetClass()
+ << " (" << typeid(*widget).name() << ')' << std::endl;
+ return MHD_HTTP_NOT_FOUND;
+ }
return MHD_HTTP_OK;
}
+ int get_item_selector_handler(YWidget *widget, const std::string &value,
std::ostream& body, const int state = -1);
+
};
#endif // YHttpWidgetsActionHandler_h
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/libyui-rest-api-0.2.0/src/YJsonSerializer.cc
new/libyui-rest-api-0.3.0/src/YJsonSerializer.cc
--- old/libyui-rest-api-0.2.0/src/YJsonSerializer.cc 2019-07-03
08:16:11.000000000 +0200
+++ new/libyui-rest-api-0.3.0/src/YJsonSerializer.cc 2019-12-10
17:02:47.000000000 +0100
@@ -267,6 +267,16 @@
json["password_mode"] = inp->passwordMode();
}
+ if (auto inp = dynamic_cast<YMultiLineEdit*>(widget))
+ {
+ json["value"] = inp->value();
+ }
+
+ if (auto inp = dynamic_cast<YProgressBar*>(widget))
+ {
+ json["value"] = inp->value();
+ }
+
if (auto intf = dynamic_cast<YIntField*>(widget))
{
json["value"] = intf->value();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/libyui-rest-api-0.2.0/src/YWidgetFinder.cc
new/libyui-rest-api-0.3.0/src/YWidgetFinder.cc
--- old/libyui-rest-api-0.2.0/src/YWidgetFinder.cc 2019-07-03
08:16:11.000000000 +0200
+++ new/libyui-rest-api-0.3.0/src/YWidgetFinder.cc 2019-12-10
17:02:47.000000000 +0100
@@ -16,6 +16,7 @@
// boost::erase_all
#include <boost/algorithm/string.hpp>
+#include <functional>
#include "YDialog.h"
#include "YWidget.h"
@@ -24,105 +25,101 @@
#include "YWidgetFinder.h"
// internal helper methods
-static void find_widgets_by_label_rec(YWidget *w, const std::string &label,
WidgetArray &array);
-static void find_widgets_by_id_rec(YWidget *w, const std::string &id,
WidgetArray &array);
-static void find_widgets_by_type_rec(YWidget *w, const std::string &type,
WidgetArray &array);
-static void find_all_widgets_rec(YWidget *w, WidgetArray &array);
+static bool filter_by_label_rec(YWidget *w, const std::string &label);
+static bool filter_by_id_rec(YWidget *w, const std::string &id);
+static bool filter_by_type_rec(YWidget *w, const std::string &type);
+static void find_widgets(YWidget *w, WidgetArray &array, std::function<bool
(YWidget*)> filter_func);
+
+// WidgetArray YWidgetFinder::find(const std::string &label, const std::string
&id, const std::string &type)
+WidgetArray YWidgetFinder::find( const char* label, const char* id, const
char* type )
+{
+ WidgetArray ret;
+ find_widgets(YDialog::topmostDialog(), ret, [& label, & id, & type]
(YWidget *w) {
+ return (!label || filter_by_label_rec(w, label)) &&
+ (!id || filter_by_id_rec(w, id)) &&
+ (!type || filter_by_type_rec(w, type));
+ } );
+ return ret;
+}
WidgetArray YWidgetFinder::by_label(const std::string &label)
{
WidgetArray ret;
- find_widgets_by_label_rec(YDialog::topmostDialog(), label, ret);
+ find_widgets(YDialog::topmostDialog(), ret, [& label] (YWidget *w) {
+ return filter_by_label_rec(w, label);
+ } );
return ret;
}
WidgetArray YWidgetFinder::by_id(const std::string &id)
{
WidgetArray ret;
- find_widgets_by_id_rec(YDialog::topmostDialog(), id, ret);
+ find_widgets(YDialog::topmostDialog(), ret, [& id] (YWidget *w) {
+ return filter_by_id_rec(w, id);
+ } );
return ret;
}
WidgetArray YWidgetFinder::by_type(const std::string &type)
{
WidgetArray ret;
- find_widgets_by_type_rec(YDialog::topmostDialog(), type, ret);
+ find_widgets(YDialog::topmostDialog(), ret, [& type] (YWidget *w) {
+ return filter_by_type_rec(w, type);
+ } );
return ret;
}
WidgetArray YWidgetFinder::all()
{
WidgetArray ret;
- find_all_widgets_rec(YDialog::topmostDialog(), ret);
+ find_widgets(YDialog::topmostDialog(), ret, [] (YWidget *w) {
+ return true;
+ } );
return ret;
}
+void find_widgets(YWidget *w, WidgetArray &array, std::function<bool
(YWidget*)> filter_func) {
+ if ( !w )
+ return;
-void find_all_widgets_rec(YWidget *w, WidgetArray &array)
-{
- if (!w) return;
- array.push_back(w);
+ if( filter_func(w) )
+ array.push_back(w);
- // search also in the children widgets
- // YWidget provides begin() and end() so we can iterate it just like any
container
for(YWidget *child: *w)
{
- find_all_widgets_rec(child, array);
+ find_widgets(child, array, filter_func);
};
}
-void find_widgets_by_label_rec(YWidget *w, const std::string &label,
WidgetArray &array)
+static bool filter_by_label_rec(YWidget *w, const std::string &label)
{
- if (!w) return;
// check the widget label if it is defined
- if (w->propertySet().contains("Label"))
+ if ( w->propertySet().contains("Label") )
{
std::string widget_label = w->getProperty("Label").stringVal();
boost::erase_all(widget_label, "&");
- if (widget_label == label)
- {
- array.push_back(w);
- }
+ if ( widget_label == label )
+ return true;
}
-
- // search also in the children widgets
- // YWidget provides begin() and end() so we can iterate it just like any
container
- for(YWidget *child: *w)
- {
- find_widgets_by_label_rec(child, label, array);
- };
+ return false;
}
-void find_widgets_by_id_rec(YWidget *w, const std::string &id, WidgetArray
&array)
+static bool filter_by_id_rec(YWidget *w, const std::string &id)
{
- if (!w) return;
- // check the widget ID if it is defined
- if (w->hasId() && w->id()->toString() == id) {
- array.push_back(w);
- }
+ if ( w->hasId() && w->id()->toString() == id )
+ return true;
- // search also in the children widgets
- // YWidget provides begin() and end() so we can iterate it just like any
container
- for(YWidget *child: *w)
- {
- find_widgets_by_id_rec(child, id, array);
- };
+ return false;
}
-void find_widgets_by_type_rec(YWidget *w, const std::string &type, WidgetArray
&array)
+
+static bool filter_by_type_rec(YWidget *w, const std::string &type)
{
- if (!w) return;
auto propSet = w->propertySet();
- if (propSet.contains("WidgetClass") &&
w->getProperty("WidgetClass").stringVal() == type)
- array.push_back(w);
+ if ( propSet.contains("WidgetClass") &&
w->getProperty("WidgetClass").stringVal() == type )
+ return true;
- // search also in the children widgets
- // YWidget provides begin() and end() so we can iterate it just like any
container
- for(YWidget *child: *w)
- {
- find_widgets_by_type_rec(child, type, array);
- };
+ return false;
}
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/libyui-rest-api-0.2.0/src/YWidgetFinder.h
new/libyui-rest-api-0.3.0/src/YWidgetFinder.h
--- old/libyui-rest-api-0.2.0/src/YWidgetFinder.h 2019-07-03
08:16:11.000000000 +0200
+++ new/libyui-rest-api-0.3.0/src/YWidgetFinder.h 2019-12-10
17:02:47.000000000 +0100
@@ -29,6 +29,9 @@
public:
+ // static WidgetArray find(const std::string &label, const std::string
&id, const std::string &type);
+ static WidgetArray find( const char* label, const char* id, const char*
type );
+
static WidgetArray by_label(const std::string &label);
static WidgetArray by_id(const std::string &id);