regedit: Cut off the front of the path when screen width is too small.
[Samba/bjacke.git] / source3 / utils / regedit_treeview.c
blobf0c3bd81f827158c99f2250b3c50d22b2199970d
1 /*
2 * Samba Unix/Linux SMB client library
3 * Registry Editor
4 * Copyright (C) Christopher Davis 2012
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "regedit_treeview.h"
21 #include "lib/registry/registry.h"
23 struct tree_node *tree_node_new(TALLOC_CTX *ctx, struct tree_node *parent,
24 const char *name, struct registry_key *key)
26 struct tree_node *node;
28 node = talloc_zero(ctx, struct tree_node);
29 if (!node) {
30 return NULL;
33 node->name = talloc_strdup(node, name);
34 if (!node->name) {
35 talloc_free(node);
36 return NULL;
39 node->key = talloc_steal(node, key);
41 if (parent) {
42 /* Check if this node is the first descendant of parent. */
43 if (!parent->child_head) {
44 parent->child_head = node;
46 node->parent = parent;
49 return node;
52 void tree_node_append(struct tree_node *left, struct tree_node *right)
54 if (left->next) {
55 right->next = left->next;
56 left->next->previous = right;
58 left->next = right;
59 right->previous = left;
62 void tree_node_append_last(struct tree_node *list, struct tree_node *node)
64 tree_node_append(tree_node_last(list), node);
67 struct tree_node *tree_node_pop(struct tree_node **plist)
69 struct tree_node *node;
71 node = *plist;
73 if (node == NULL)
74 return NULL;
76 *plist = node->previous;
77 if (*plist == NULL) {
78 *plist = node->next;
80 if (node->previous) {
81 node->previous->next = node->next;
83 if (node->next) {
84 node->next->previous = node->previous;
86 if (node->parent && node->parent->child_head == node) {
87 node->parent->child_head = node->next;
89 node->next = NULL;
90 node->previous = NULL;
92 return node;
95 struct tree_node *tree_node_first(struct tree_node *list)
97 /* Grab the first node in this list from the parent if available. */
98 if (list->parent) {
99 return list->parent->child_head;
102 while (list && list->previous) {
103 list = list->previous;
106 return list;
109 struct tree_node *tree_node_last(struct tree_node *list)
111 while (list && list->next) {
112 list = list->next;
115 return list;
118 bool tree_node_has_children(struct tree_node *node)
120 const char *classname;
121 uint32_t num_subkeys;
122 uint32_t num_values;
123 NTTIME last_change_time;
124 uint32_t max_subkeynamelen;
125 uint32_t max_valnamelen;
126 uint32_t max_valbufsize;
127 WERROR rv;
129 if (node->child_head) {
130 return true;
133 rv = reg_key_get_info(node, node->key, &classname, &num_subkeys,
134 &num_values, &last_change_time,
135 &max_subkeynamelen, &max_valnamelen,
136 &max_valbufsize);
138 if (W_ERROR_IS_OK(rv)) {
139 return num_subkeys != 0;
142 return false;
145 WERROR tree_node_load_children(struct tree_node *node)
147 struct registry_key *key;
148 const char *key_name, *klass;
149 NTTIME modified;
150 uint32_t i;
151 WERROR rv;
152 struct tree_node *new_node, *prev;
154 /* does this node already have it's children loaded? */
155 if (node->child_head)
156 return WERR_OK;
158 for (prev = NULL, i = 0; ; ++i) {
159 rv = reg_key_get_subkey_by_index(node, node->key, i,
160 &key_name, &klass,
161 &modified);
162 if (!W_ERROR_IS_OK(rv)) {
163 if (W_ERROR_EQUAL(rv, WERR_NO_MORE_ITEMS)) {
164 break;
167 return rv;
170 rv = reg_open_key(node, node->key, key_name, &key);
171 if (!W_ERROR_IS_OK(rv)) {
172 return rv;
175 new_node = tree_node_new(node, node, key_name, key);
176 if (new_node == NULL) {
177 return WERR_NOMEM;
180 if (prev) {
181 tree_node_append(prev, new_node);
183 prev = new_node;
186 return WERR_OK;
189 void tree_node_free_recursive(struct tree_node *list)
191 struct tree_node *node;
193 if (list == NULL) {
194 return;
197 while ((node = tree_node_pop(&list)) != NULL) {
198 if (node->child_head) {
199 tree_node_free_recursive(node->child_head);
201 node->child_head = NULL;
202 talloc_free(node);
206 static void tree_view_free_current_items(ITEM **items)
208 size_t i;
209 struct tree_node *node;
210 ITEM *item;
212 if (items == NULL) {
213 return;
216 for (i = 0; items[i] != NULL; ++i) {
217 item = items[i];
218 node = item_userptr(item);
219 if (node && node->label) {
220 talloc_free(node->label);
221 node->label = NULL;
223 free_item(item);
226 talloc_free(items);
229 void tree_view_clear(struct tree_view *view)
231 unpost_menu(view->menu);
232 set_menu_items(view->menu, view->empty);
233 tree_view_free_current_items(view->current_items);
234 view->current_items = NULL;
237 WERROR tree_view_update(struct tree_view *view, struct tree_node *list)
239 ITEM **items;
240 struct tree_node *node;
241 size_t i, n_items;
243 if (list == NULL) {
244 list = view->root;
246 for (n_items = 0, node = list; node != NULL; node = node->next) {
247 n_items++;
250 items = talloc_zero_array(view, ITEM *, n_items + 1);
251 if (items == NULL) {
252 return WERR_NOMEM;
255 for (i = 0, node = list; node != NULL; ++i, node = node->next) {
256 const char *label = node->name;
258 /* Add a '+' marker to indicate that the item has
259 descendants. */
260 if (tree_node_has_children(node)) {
261 SMB_ASSERT(node->label == NULL);
262 node->label = talloc_asprintf(node, "+%s", node->name);
263 if (node->label == NULL) {
264 goto fail;
266 label = node->label;
269 items[i] = new_item(label, node->name);
270 set_item_userptr(items[i], node);
273 unpost_menu(view->menu);
274 set_menu_items(view->menu, items);
275 tree_view_free_current_items(view->current_items);
276 view->current_items = items;
278 return WERR_OK;
280 fail:
281 tree_view_free_current_items(items);
283 return WERR_NOMEM;
286 void tree_view_show(struct tree_view *view)
288 post_menu(view->menu);
291 static int tree_view_free(struct tree_view *view)
293 if (view->menu) {
294 unpost_menu(view->menu);
295 free_menu(view->menu);
297 if (view->empty[0]) {
298 free_item(view->empty[0]);
300 if (view->panel) {
301 del_panel(view->panel);
303 if (view->window) {
304 delwin(view->window);
306 tree_view_free_current_items(view->current_items);
307 tree_node_free_recursive(view->root);
309 return 0;
312 struct tree_view *tree_view_new(TALLOC_CTX *ctx, struct tree_node *root,
313 int nlines, int ncols, int begin_y,
314 int begin_x)
316 struct tree_view *view;
317 static const char *dummy = "(empty)";
319 view = talloc_zero(ctx, struct tree_view);
320 if (view == NULL) {
321 return NULL;
324 talloc_set_destructor(view, tree_view_free);
326 view->empty[0] = new_item(dummy, dummy);
327 if (view->empty[0] == NULL) {
328 goto fail;
330 view->window = newwin(nlines, ncols, begin_y, begin_x);
331 if (view->window == NULL) {
332 goto fail;
334 view->panel = new_panel(view->window);
335 if (view->panel == NULL) {
336 goto fail;
338 view->root = root;
340 view->menu = new_menu(view->empty);
341 if (view->menu == NULL) {
342 goto fail;
344 set_menu_format(view->menu, nlines, 1);
345 set_menu_win(view->menu, view->window);
346 menu_opts_off(view->menu, O_SHOWDESC);
347 set_menu_mark(view->menu, "* ");
349 tree_view_update(view, root);
351 return view;
353 fail:
354 talloc_free(view);
356 return NULL;
359 void tree_view_resize(struct tree_view *view, int nlines, int ncols,
360 int begin_y, int begin_x)
362 WINDOW *nwin;
364 unpost_menu(view->menu);
365 nwin = newwin(nlines, ncols, begin_y, begin_x);
366 replace_panel(view->panel, nwin);
367 delwin(view->window);
368 view->window = nwin;
369 set_menu_format(view->menu, nlines, 1);
370 set_menu_win(view->menu, view->window);
371 post_menu(view->menu);
374 static void print_path_recursive(WINDOW *label, struct tree_node *node, size_t *len)
376 if (node->parent)
377 print_path_recursive(label, node->parent, len);
379 wprintw(label, "%s/", node->name);
380 *len += 1 + strlen(node->name);
383 /* print the path of node to label */
384 size_t tree_node_print_path(WINDOW *label, struct tree_node *node)
386 size_t len = 1;
388 if (node == NULL)
389 return 0;
391 werase(label);
392 wprintw(label, "/");
394 if (node->parent)
395 print_path_recursive(label, node->parent, &len);
397 return len;