Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement conditional actions #20

Merged
merged 1 commit into from
May 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions res/doc
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,18 @@
# cmd_output - the timeout in milliseconds (0 < t < 10000), a colon, then the command line to pass to /bin/sh -c (started in /)
#
# chain:<action>:<arg>
# chain_failure:<action>:<arg>
# chain_always:<action>:<arg>
# Adds an action to the chain that began with the preceding menu_item.
# Actions are performed in the order they are written.
# Each chain entry MUST follow the menu_item it is attached to. Another
# menu_item marks the start of the next chain.
# By default, each action only executes if the previous one was successful.
# If chain_failure is used, the action is only executed if the last one
# failed. If chain_always is used, the action is executed no matter what.
# Any error message is only displayed if the action is the last one which
# was executed in the chain (not necessarily the last one in the config
# file).
#
# For example, you might have a configuration file in KOBOeReader/.adds/nm/mystuff like:
#
Expand Down
23 changes: 19 additions & 4 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ nm_config_t *nm_config_parse(char **err_out) {
// field 1: type
char *c_typ = strtrim(strsep(&cur, ":"));
if (!strcmp(c_typ, "menu_item")) {
if (it) nm_config_push_menu_item(&cfg, it);
// type: menu_item
if (it) nm_config_push_menu_item(&cfg, it);
it = calloc(1, sizeof(nm_menu_item_t));
cur_act = NULL;
// type: menu_item - field 2: location
Expand All @@ -136,8 +136,10 @@ nm_config_t *nm_config_parse(char **err_out) {
if (!c_lbl) RETERR("file %s: line %d: field 3: expected label, got end of line", fn, line_n);
else it->lbl = strdup(c_lbl);

nm_menu_action_t *action = calloc(1, sizeof(nm_menu_action_t));
// type: menu_item - field 4: action
nm_menu_action_t *action = calloc(1, sizeof(nm_menu_action_t));
action->on_failure = true;
action->on_success = true;
char *c_act = strtrim(strsep(&cur, ":"));
if (!c_act) RETERR("file %s: line %d: field 4: expected action, got end of line", fn, line_n);
#define X(name) else if (!strcmp(c_act, #name)) action->act = NM_ACTION(name);
Expand All @@ -151,10 +153,22 @@ nm_config_t *nm_config_parse(char **err_out) {
else action->arg = strdup(c_arg);
nm_config_push_action(&cur_act, action);
it->action = cur_act;
} else if (!strcmp(c_typ, "chain")) {
} else if (!strncmp(c_typ, "chain", 5)) {
// type: chain
if (!it) RETERR("file %s: line %d: unexpected chain, no menu_item to link to", fn, line_n);
nm_menu_action_t *action = calloc(1, sizeof(nm_menu_action_t));

if (!strcmp(c_typ, "chain")) {
action->on_failure = false;
action->on_success = true;
} else if (!strcmp(c_typ, "chain_always")) {
action->on_failure = true;
action->on_success = true;
} else if (!strcmp(c_typ, "chain_failure")) {
action->on_failure = true;
action->on_success = false;
} else RETERR("file %s: line %d: field 1: unknown type '%s'", fn, line_n, c_typ);

// type: chain - field 2: action
char *c_act = strtrim(strsep(&cur, ":"));
if (!c_act) RETERR("file %s: line %d: field 2: expected action, got end of line", fn, line_n);
Expand Down Expand Up @@ -199,8 +213,9 @@ nm_config_t *nm_config_parse(char **err_out) {
size_t mm = 0, rm = 0;
for (nm_config_t *cur = cfg; cur; cur = cur->next) {
if (cur->type == NM_CONFIG_TYPE_MENU_ITEM) {
NM_LOG("cfg(NM_CONFIG_TYPE_MENU_ITEM) : %d:%s", cur->value.menu_item->loc, cur->value.menu_item->lbl);
for (nm_menu_action_t *cur_act = cur->value.menu_item->action; cur_act; cur_act = cur_act->next)
NM_LOG("cfg(NM_CONFIG_TYPE_MENU_ITEM) : %d:%s:%p:%s", cur->value.menu_item->loc, cur->value.menu_item->lbl, cur_act->act, cur_act->arg);
NM_LOG("...cfg(NM_CONFIG_TYPE_MENU_ITEM) (%s%s%s) : %p:%s", cur_act->on_success ? "on_success" : "", (cur_act->on_success && cur_act->on_failure) ? ", " : "", cur_act->on_failure ? "on_failure" : "", cur_act->act, cur_act->arg);
switch (cur->value.menu_item->loc) {
case NM_MENU_LOCATION_MAIN_MENU: mm++; break;
case NM_MENU_LOCATION_READER_MENU: rm++; break;
Expand Down
66 changes: 38 additions & 28 deletions src/menu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -143,40 +143,50 @@ extern "C" MenuTextItem* _nm_menu_hook(void* _this, QMenu* menu, QString const&

// note: we're capturing by value, i.e. the pointer to the global variable, rather then the stack variable, so this is safe
QObject::connect(action, &QAction::triggered, std::function<void(bool)>([it](bool){
NM_LOG("Item '%s' pressed...", it->lbl);
char *err;
NM_LOG("item '%s' pressed...", it->lbl);
char *err = NULL;
bool success = true;
for (nm_menu_action_t *cur = it->action; cur; cur = cur->next) {
NM_LOG("running action %p with argument %s : ", cur->act, cur->arg);
NM_LOG("action %p with argument %s : ", cur->act, cur->arg);
NM_LOG("...success=%d ; on_success=%d on_failure=%d", success, cur->on_success, cur->on_failure);
if (!((success && cur->on_success) || (!success && cur->on_failure))) {
NM_LOG("...skipping action due to condition flags");
continue;
}
free(err);
nm_action_result_t *res = cur->act(cur->arg, &err);
if (err) {
NM_LOG("Got error: '%s', displaying...", err);
ConfirmationDialogFactory_showOKDialog(QString::fromUtf8(it->lbl), QString::fromUtf8(err));
free(err);
return;
} else if (res) {
NM_LOG("Got result: type=%d msg='%s', handling...", res->type, res->msg);
MainWindowController *mwc;
switch (res->type) {
case NM_ACTION_RESULT_TYPE_SILENT:
break;
case NM_ACTION_RESULT_TYPE_MSG:
ConfirmationDialogFactory_showOKDialog(QString::fromUtf8(it->lbl), QLatin1String(res->msg));
break;
case NM_ACTION_RESULT_TYPE_TOAST:
mwc = MainWindowController_sharedInstance();
if (!mwc) {
NM_LOG("toast: could not get shared main window controller pointer");
break;
}
MainWindowController_toast(mwc, QLatin1String(res->msg), QStringLiteral(""), 1500);
if (!(success = err == NULL)) {
NM_LOG("...error: '%s'", err);
continue;
} else if (!res) {
NM_LOG("...warning: you should have returned a result with type silent, not null, upon success");
continue;
}
NM_LOG("...result: type=%d msg='%s', handling...", res->type, res->msg);
MainWindowController *mwc;
switch (res->type) {
case NM_ACTION_RESULT_TYPE_SILENT:
break;
case NM_ACTION_RESULT_TYPE_MSG:
ConfirmationDialogFactory_showOKDialog(QString::fromUtf8(it->lbl), QLatin1String(res->msg));
break;
case NM_ACTION_RESULT_TYPE_TOAST:
mwc = MainWindowController_sharedInstance();
if (!mwc) {
NM_LOG("toast: could not get shared main window controller pointer");
break;
}
nm_action_result_free(res);
} else {
NM_LOG("warning: you should have returned a result with type silent, not null, upon success");
MainWindowController_toast(mwc, QLatin1String(res->msg), QStringLiteral(""), 1500);
break;
}
nm_action_result_free(res);
}
if (err) {
NM_LOG("last action returned error %s", err);
ConfirmationDialogFactory_showOKDialog(QString::fromUtf8(it->lbl), QString::fromUtf8(err));
free(err);
}
NM_LOG("Success!");
NM_LOG("done");
}));
}

Expand Down
3 changes: 3 additions & 0 deletions src/menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
extern "C" {
#endif

#include <stdbool.h>
#include <stddef.h>

#include "action.h"
Expand All @@ -15,6 +16,8 @@ typedef enum {

typedef struct nm_menu_action_t {
char *arg;
bool on_success;
bool on_failure;
nm_action_fn_t act; // can block, must return 0 on success, nonzero with out_err set to the malloc'd error message on error
struct nm_menu_action_t *next;
} nm_menu_action_t;
Expand Down