regedit: Introduce dialog windows.
authorC. Davis <cd.rattan@gmail.com>
Fri, 27 Jul 2012 10:37:22 +0000 (03:37 -0700)
committerMichael Adam <obnox@samba.org>
Mon, 29 Apr 2013 11:05:57 +0000 (13:05 +0200)
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 <asn@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
source3/utils/regedit.c
source3/utils/regedit_dialog.c [new file with mode: 0644]
source3/utils/regedit_dialog.h [new file with mode: 0644]
source3/utils/regedit_treeview.c
source3/utils/regedit_valuelist.c
source3/wscript
source3/wscript_build

index 6f239bdc569e766f1e342c2c6c27bfe9c4882063..554c31e08916ca1c0d509a65c9fdd39c8e486990 100644 (file)
 #include "regedit.h"
 #include "regedit_treeview.h"
 #include "regedit_valuelist.h"
+#include "regedit_dialog.h"
 #include <ncurses.h>
 #include <menu.h>
+#include <panel.h>
+
+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 (file)
index 0000000..419c408
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "regedit_dialog.h"
+#include <stdarg.h>
+
+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 (file)
index 0000000..461de43
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _REGEDIT_DIALOG_H_
+#define _REGEDIT_DIALOG_H_
+
+#include <ncurses.h>
+#include <panel.h>
+#include <menu.h>
+
+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
index d24e77ac0fc58b23270cfdf3d1eea036ac501bf4..73789e6c543de60ed4a13428ab0221126f4193e8 100644 (file)
@@ -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)
index 4fc0ae8fd77a839908e35d70fdc54dde70a709da..989cbb5e8f3996b6fc0d75fc4dd6a883373b19a8 100644 (file)
@@ -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)
index 54daaa7f22158712dd8333c239097ef032bfae63..4fbc19158d8bf61b1c709036eb5ac82e3fe7b767 100644 (file)
@@ -1718,6 +1718,8 @@ main() {
         ncurses = conf.CHECK_FUNCS_IN('initscr', 'ncurses', headers='ncurses.h')
         menu = conf.CHECK_FUNCS_IN('set_menu_items item_count', 'menu',
                             headers='menu.h')
+        panel = conf.CHECK_FUNCS_IN('new_panel show_panel', 'panel',
+                            headers='panel.h')
         if ncurses and menu:
                 conf.env.build_regedit = True
 
index 82e3389bba8efb16eabb0f16264ff13edd975749..13bdbc2af1807c38e902aef57aeb1e99d4792127 100755 (executable)
@@ -1642,8 +1642,10 @@ bld.SAMBA3_PYTHON('pylibsmb',
                   )
 
 bld.SAMBA3_BINARY('regedit',
-                  source='utils/regedit.c utils/regedit_samba3.c utils/regedit_wrap.c utils/regedit_treeview.c utils/regedit_valuelist.c',
-                  deps='ncurses menu registry param popt_samba3 smbregistry',
+                  source="""utils/regedit.c utils/regedit_samba3.c
+                            utils/regedit_wrap.c utils/regedit_treeview.c
+                            utils/regedit_valuelist.c utils/regedit_dialog.c""",
+                  deps='ncurses menu panel registry param popt_samba3 smbregistry',
                   enabled=bld.env.build_regedit,
                   vars=locals())