From 6155abcf82f0bb03e62f7fc4b1df3f7260337bc3 Mon Sep 17 00:00:00 2001 From: "C. Davis" Date: Fri, 27 Jul 2012 03:37:22 -0700 Subject: regedit: Introduce dialog windows. Link to ncurses "panels" library to support popup dialog windows, and begin working on a small dialog library. Right now, it is useful for "yes/no" confirmation popups, but later it'll be used for more complex forms for editing values. Reviewed-by: Andreas Schneider Reviewed-by: Michael Adam --- source3/utils/regedit.c | 245 ++++++++++++++++++++++++++------------ source3/utils/regedit_dialog.c | 233 ++++++++++++++++++++++++++++++++++++ source3/utils/regedit_dialog.h | 74 ++++++++++++ source3/utils/regedit_treeview.c | 2 +- source3/utils/regedit_valuelist.c | 2 +- 5 files changed, 481 insertions(+), 75 deletions(-) create mode 100644 source3/utils/regedit_dialog.c create mode 100644 source3/utils/regedit_dialog.h (limited to 'source3/utils') diff --git a/source3/utils/regedit.c b/source3/utils/regedit.c index 6f239bdc56..554c31e089 100644 --- a/source3/utils/regedit.c +++ b/source3/utils/regedit.c @@ -24,8 +24,22 @@ #include "regedit.h" #include "regedit_treeview.h" #include "regedit_valuelist.h" +#include "regedit_dialog.h" #include #include +#include + +struct regedit { + WINDOW *main_window; + PANEL *main_panel; + WINDOW *path_label; + WINDOW *key_label; + WINDOW *value_label; + struct value_list *vl; + struct tree_view *keys; + bool tree_input; + struct dialog *dia; +}; /* load all available hives */ static struct tree_node *load_hives(TALLOC_CTX *mem_ctx, @@ -74,83 +88,167 @@ static struct tree_node *load_hives(TALLOC_CTX *mem_ctx, return root; } -static void handle_tree_input(struct tree_view *view, struct value_list *vl, - WINDOW *path, int c) +static void print_heading(WINDOW *win, bool selected, const char *str) +{ + if (selected) { + wattron(win, A_REVERSE); + } else { + wattroff(win, A_REVERSE); + } + wmove(win, 0, 0); + wclrtoeol(win); + waddstr(win, str); + wnoutrefresh(win); + wrefresh(win); +} + +static void delete_key_callback(struct dialog *dia, int selection, void *arg) +{ + struct regedit *regedit = arg; + + //mvwprintw(regedit->main_window, 1, 0, "Selection: %d", selection); + + if (selection == DIALOG_OK) { + /* TODO */ + } + + talloc_free(regedit->dia); + regedit->dia = NULL; +} + +static void delete_value_callback(struct dialog *dia, int selection, void *arg) +{ + struct regedit *regedit = arg; + + if (selection == DIALOG_OK) { + /* TODO */ + } + + talloc_free(regedit->dia); + regedit->dia = NULL; +} + +static void handle_tree_input(struct regedit *regedit, int c) { struct tree_node *node; switch (c) { case KEY_DOWN: - menu_driver(view->menu, REQ_DOWN_ITEM); - node = item_userptr(current_item(view->menu)); - value_list_load(vl, node->key); + menu_driver(regedit->keys->menu, REQ_DOWN_ITEM); + node = item_userptr(current_item(regedit->keys->menu)); + value_list_load(regedit->vl, node->key); break; case KEY_UP: - menu_driver(view->menu, REQ_UP_ITEM); - node = item_userptr(current_item(view->menu)); - value_list_load(vl, node->key); + menu_driver(regedit->keys->menu, REQ_UP_ITEM); + node = item_userptr(current_item(regedit->keys->menu)); + value_list_load(regedit->vl, node->key); break; case '\n': case KEY_ENTER: case KEY_RIGHT: - node = item_userptr(current_item(view->menu)); + node = item_userptr(current_item(regedit->keys->menu)); if (node && tree_node_has_children(node)) { tree_node_load_children(node); - tree_node_print_path(path, node->child_head); - tree_view_update(view, node->child_head); - value_list_load(vl, node->child_head->key); + tree_node_print_path(regedit->path_label, + node->child_head); + tree_view_update(regedit->keys, node->child_head); + value_list_load(regedit->vl, node->child_head->key); } break; case KEY_LEFT: - node = item_userptr(current_item(view->menu)); + node = item_userptr(current_item(regedit->keys->menu)); if (node && node->parent) { - tree_node_print_path(path, node->parent); + tree_node_print_path(regedit->path_label, node->parent); node = tree_node_first(node->parent); - tree_view_update(view, node); - value_list_load(vl, node->key); + tree_view_update(regedit->keys, node); + value_list_load(regedit->vl, node->key); } break; + case 'd': + case 'D': + node = item_userptr(current_item(regedit->keys->menu)); + regedit->dia = dialog_confirm_new(regedit, "Delete Key", + regedit->main_window, + "Really delete key \"%s\"?", + node->name); + dialog_set_cb(regedit->dia, delete_key_callback, regedit); + break; } + + tree_view_show(regedit->keys); + value_list_show(regedit->vl); } -static void handle_value_input(struct value_list *vl, int c) +static void handle_value_input(struct regedit *regedit, int c) { + struct value_item *vitem; + switch (c) { case KEY_DOWN: - menu_driver(vl->menu, REQ_DOWN_ITEM); + menu_driver(regedit->vl->menu, REQ_DOWN_ITEM); break; case KEY_UP: - menu_driver(vl->menu, REQ_UP_ITEM); + menu_driver(regedit->vl->menu, REQ_UP_ITEM); break; case KEY_ENTER: break; + case 'd': + case 'D': + vitem = item_userptr(current_item(regedit->vl->menu)); + if (vitem) { + regedit->dia = dialog_confirm_new(regedit, "Delete Value", + regedit->main_window, + "Really delete value \"%s\"?", + vitem->value_name); + dialog_set_cb(regedit->dia, delete_value_callback, regedit); + } + break; } + + value_list_show(regedit->vl); } -static void print_heading(WINDOW *win, bool selected, const char *str) +static void handle_dialog_input(struct regedit *regedit, int c) { - if (selected) { - wattron(win, A_REVERSE); - } else { - wattroff(win, A_REVERSE); + switch (c) { + case KEY_LEFT: + dialog_driver(regedit->dia, DIALOG_LEFT); + break; + case KEY_RIGHT: + dialog_driver(regedit->dia, DIALOG_RIGHT); + break; + case '\n': + case KEY_ENTER: + dialog_driver(regedit->dia, DIALOG_ENTER); + break; + } +} + +static void handle_main_input(struct regedit *regedit, int c) +{ + switch (c) { + case '\t': + regedit->tree_input = !regedit->tree_input; + print_heading(regedit->key_label, regedit->tree_input == true, + "Keys"); + print_heading(regedit->value_label, regedit->tree_input == false, + "Values"); + break; + default: + if (regedit->tree_input) { + handle_tree_input(regedit, c); + } else { + handle_value_input(regedit, c); + } } - wmove(win, 0, 0); - wclrtoeol(win); - waddstr(win, str); - wnoutrefresh(win); - wrefresh(win); } /* test navigating available hives */ static void display_test_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) { - WINDOW *main_window, *path_label; - WINDOW *key_label, *value_label; - struct value_list *vl; - struct tree_view *view; + struct regedit *regedit; struct tree_node *root; - bool tree_view_input = true; int c; initscr(); @@ -159,52 +257,53 @@ static void display_test_window(TALLOC_CTX *mem_ctx, noecho(); keypad(stdscr, TRUE); - main_window = newwin(25, 80, 0, 0); - SMB_ASSERT(main_window != NULL); + regedit = talloc_zero(mem_ctx, struct regedit); + SMB_ASSERT(regedit != NULL); + + regedit->main_window = newwin(25, 80, 0, 0); + SMB_ASSERT(regedit->main_window != NULL); - keypad(main_window, TRUE); + keypad(regedit->main_window, TRUE); - mvwprintw(main_window, 0, 0, "Path: "); - path_label = derwin(main_window, 1, 65, 0, 6); - wprintw(path_label, "/"); + mvwprintw(regedit->main_window, 0, 0, "Path: "); + regedit->path_label = derwin(regedit->main_window, 1, 65, 0, 6); + wprintw(regedit->path_label, "/"); - root = load_hives(mem_ctx, ctx); + root = load_hives(regedit, ctx); SMB_ASSERT(root != NULL); - key_label = derwin(main_window, 1, 10, 2, 0); - value_label = derwin(main_window, 1, 10, 2, 25); - - print_heading(key_label, true, "Keys"); - view = tree_view_new(mem_ctx, root, main_window, 15, 24, 3, 0); - SMB_ASSERT(view != NULL); - - print_heading(value_label, false, "Values"); - vl = value_list_new(mem_ctx, main_window, 15, 40, 3, 25); - SMB_ASSERT(vl != NULL); - - refresh(); - tree_view_show(view); - value_list_show(vl); - - while ((c = wgetch(main_window)) != 'q') { - switch (c) { - case '\t': - tree_view_input = !tree_view_input; - print_heading(key_label, tree_view_input == true, - "Keys"); - print_heading(value_label, tree_view_input == false, - "Values"); - break; - default: - if (tree_view_input) { - handle_tree_input(view, vl, path_label, c); - } else { - handle_value_input(vl, c); - } + regedit->key_label = derwin(regedit->main_window, 1, 10, 2, 0); + regedit->value_label = derwin(regedit->main_window, 1, 10, 2, 25); + + print_heading(regedit->key_label, true, "Keys"); + regedit->keys = tree_view_new(regedit, root, regedit->main_window, + 15, 24, 3, 0); + SMB_ASSERT(regedit->keys != NULL); + + print_heading(regedit->value_label, false, "Values"); + regedit->vl = value_list_new(regedit, regedit->main_window, + 15, 40, 3, 25); + SMB_ASSERT(regedit->vl != NULL); + + regedit->tree_input = true; + + tree_view_show(regedit->keys); + value_list_show(regedit->vl); + + regedit->main_panel = new_panel(regedit->main_window); + SMB_ASSERT(regedit->main_panel != NULL); + + update_panels(); + doupdate(); + while ((c = wgetch(regedit->main_window)) != 'q') { + if (regedit->dia) { + handle_dialog_input(regedit, c); + } else { + handle_main_input(regedit, c); } - tree_view_show(view); - value_list_show(vl); + update_panels(); + doupdate(); } endwin(); diff --git a/source3/utils/regedit_dialog.c b/source3/utils/regedit_dialog.c new file mode 100644 index 0000000000..419c4081e0 --- /dev/null +++ b/source3/utils/regedit_dialog.c @@ -0,0 +1,233 @@ +/* + * Samba Unix/Linux SMB client library + * Registry Editor + * Copyright (C) Christopher Davis 2012 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "includes.h" +#include "regedit_dialog.h" +#include + +static int dialog_free(struct dialog *dia) +{ + if (dia->window) { + delwin(dia->window); + } + if (dia->sub_window) { + delwin(dia->sub_window); + } + if (dia->panel) { + del_panel(dia->panel); + } + if (dia->choices) { + unpost_menu(dia->choices); + free_menu(dia->choices); + } + if (dia->choice_items) { + ITEM **it; + for (it = dia->choice_items; *it != NULL; ++it) { + free_item(*it); + } + } + + return 0; +} + +struct dialog *dialog_new(TALLOC_CTX *ctx, const char *title, int nlines, + int ncols, int y, int x) +{ + struct dialog *dia; + + dia = talloc_zero(ctx, struct dialog); + if (dia == NULL) { + return NULL; + } + + talloc_set_destructor(dia, dialog_free); + + dia->window = newwin(nlines, ncols, y, x); + if (dia->window == NULL) { + goto fail; + } + + box(dia->window, 0, 0); + mvwaddstr(dia->window, 0, 1, title); + + /* body of the dialog within the box outline */ + dia->sub_window = derwin(dia->window, nlines - 2, ncols - 2, 1, 1); + if (dia->sub_window == NULL) { + goto fail; + } + + dia->panel = new_panel(dia->window); + if (dia->panel == NULL) { + goto fail; + } + + return dia; + +fail: + talloc_free(dia); + + return NULL; + +} + +struct dialog *dialog_center_new(TALLOC_CTX *ctx, const char *title, int nlines, + int ncols, WINDOW *below) +{ + int y, x, maxy, maxx; + + getmaxyx(below, maxy, maxx); + + y = maxy / 2 - nlines; + x = maxx / 2 - ncols; + + return dialog_new(ctx, title, nlines, ncols, y, x); +} + +struct dialog *dialog_choice_new(TALLOC_CTX *ctx, const char *title, + const char **choices, int nlines, + int ncols, int y, int x) +{ + size_t nchoices, i; + struct dialog *dia; + + dia = dialog_new(ctx, title, nlines, ncols, y, x); + if (dia == NULL) { + return NULL; + } + + dia->menu_window = derwin(dia->sub_window, 1, ncols - 3, + nlines - 3, 0); + if (dia->menu_window == NULL) { + goto fail; + } + + for (nchoices = 0; choices[nchoices] != NULL; ++nchoices) + ; + dia->choice_items = talloc_zero_array(dia, ITEM *, nchoices + 1); + if (dia->choice_items == NULL) { + goto fail; + } + for (i = 0; i < nchoices; ++i) { + char *desc = talloc_strdup(dia, choices[i]); + if (desc == NULL) { + goto fail; + } + dia->choice_items[i] = new_item(desc, desc); + if (dia->choice_items[i] == NULL) { + goto fail; + } + /* store choice index */ + set_item_userptr(dia->choice_items[i], (void*)(uintptr_t)i); + } + + dia->choices = new_menu(dia->choice_items); + if (dia->choices == NULL) { + goto fail; + } + + set_menu_format(dia->choices, 1, ncols); + set_menu_win(dia->choices, dia->sub_window); + set_menu_sub(dia->choices, dia->menu_window); + menu_opts_off(dia->choices, O_SHOWDESC); + set_menu_mark(dia->choices, "* "); + post_menu(dia->choices); + wmove(dia->sub_window, 0, 0); + + return dia; + +fail: + talloc_free(dia); + + return NULL; +} + +struct dialog *dialog_choice_center_new(TALLOC_CTX *ctx, const char *title, + const char **choices, int nlines, + int ncols, WINDOW *below) +{ + int y, x, maxy, maxx; + + getmaxyx(below, maxy, maxx); + + y = maxy / 2 - nlines; + x = maxx / 2 - ncols; + + return dialog_choice_new(ctx, title, choices, nlines, ncols, y, x); +} + +struct dialog *dialog_confirm_new(TALLOC_CTX *ctx, const char *title, + WINDOW *below, const char *msg, ...) +{ + va_list ap; + struct dialog *dia; + char *str; + const char *choices[] = { + "Ok", + "Cancel", + NULL + }; + int width; + + va_start(ap, msg); + str = talloc_vasprintf(ctx, msg, ap); + va_end(ap); + if (str == NULL) { + return NULL; + } + + width = strlen(str) + 2; + + dia = dialog_choice_center_new(ctx, title, choices, 5, width, below); + if (dia == NULL) { + return NULL; + } + + waddstr(dia->sub_window, str); + talloc_free(str); + + return dia; +} + +void dialog_set_cb(struct dialog *dia, dialogfn fn, void *arg) +{ + dia->dialogcb = fn; + dia->dialogarg = arg; +} + +void dialog_driver(struct dialog *dia, enum dialog_op op) +{ + switch (op) { + case DIALOG_LEFT: + menu_driver(dia->choices, REQ_LEFT_ITEM); + break; + case DIALOG_RIGHT: + menu_driver(dia->choices, REQ_RIGHT_ITEM); + break; + case DIALOG_ENTER: + if (dia->dialogcb) { + ITEM *item; + int selection; + + item = current_item(dia->choices); + selection = (int)(uintptr_t)item_userptr(item); + dia->dialogcb(dia, selection, dia->dialogarg); + } + break; + } +} diff --git a/source3/utils/regedit_dialog.h b/source3/utils/regedit_dialog.h new file mode 100644 index 0000000000..461de43b82 --- /dev/null +++ b/source3/utils/regedit_dialog.h @@ -0,0 +1,74 @@ +/* + * Samba Unix/Linux SMB client library + * Registry Editor + * Copyright (C) Christopher Davis 2012 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _REGEDIT_DIALOG_H_ +#define _REGEDIT_DIALOG_H_ + +#include +#include +#include + +struct dialog; + +typedef void (*dialogfn)(struct dialog *, int, void *); + +struct dialog { + WINDOW *window; + WINDOW *sub_window; + WINDOW *menu_window; + PANEL *panel; + MENU *choices; + ITEM **choice_items; + dialogfn dialogcb; + void *dialogarg; +}; + +struct dialog *dialog_new(TALLOC_CTX *ctx, const char *title, int nlines, + int ncols, int y, int x); + +struct dialog *dialog_center_new(TALLOC_CTX *ctx, const char *title, int nlines, + int ncols, WINDOW *below); + +struct dialog *dialog_choice_new(TALLOC_CTX *ctx, const char *title, + const char **choices, int nlines, int ncols, + int y, int x); + +struct dialog *dialog_choice_center_new(TALLOC_CTX *ctx, const char *title, + const char **choices, int nlines, + int ncols, WINDOW *below); + +struct dialog *dialog_confirm_new(TALLOC_CTX *ctx, const char *title, + WINDOW *below, const char *msg, ...); + +void dialog_set_cb(struct dialog *dia, dialogfn fn, void *arg); + +enum dialog_op { + DIALOG_LEFT, + DIALOG_RIGHT, + DIALOG_ENTER +}; + +enum dialog_selection { + DIALOG_OK = 0, + DIALOG_CANCEL = 1 +}; + +void dialog_driver(struct dialog *dia, enum dialog_op op); + +#endif diff --git a/source3/utils/regedit_treeview.c b/source3/utils/regedit_treeview.c index d24e77ac0f..73789e6c54 100644 --- a/source3/utils/regedit_treeview.c +++ b/source3/utils/regedit_treeview.c @@ -262,7 +262,7 @@ fail: void tree_view_show(struct tree_view *view) { post_menu(view->menu); - wrefresh(view->window); + //wrefresh(view->window); } static int tree_view_free(struct tree_view *view) diff --git a/source3/utils/regedit_valuelist.c b/source3/utils/regedit_valuelist.c index 4fc0ae8fd7..989cbb5e8f 100644 --- a/source3/utils/regedit_valuelist.c +++ b/source3/utils/regedit_valuelist.c @@ -125,7 +125,7 @@ static uint32_t get_num_values(TALLOC_CTX *ctx, const struct registry_key *key) void value_list_show(struct value_list *vl) { post_menu(vl->menu); - wrefresh(vl->window); + //wrefresh(vl->window); } static WERROR append_data_summary(struct value_item *vitem) -- cgit