2 * Handle console GUI selection of files
3 * Kern Sibbald, March, 2004
7 Bacula® - The Network Backup Solution
9 Copyright (C) 2004-2006 Free Software Foundation Europe e.V.
11 The main author of Bacula is Kern Sibbald, with contributions from
12 many others, a complete list can be found in the file AUTHORS.
13 This program is Free Software; you can redistribute it and/or
14 modify it under the terms of version two of the GNU General Public
15 License as published by the Free Software Foundation and included
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 Bacula® is a registered trademark of Kern Sibbald.
29 The licensor of Bacula is the Free Software Foundation Europe
30 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
31 Switzerland, email:ftf@fsfeurope.org.
37 #include "interface.h"
41 extern BSOCK *UA_sock;
42 void write_director(const gchar *msg);
43 void start_director_reader(gpointer data);
44 void stop_director_reader(gpointer data);
47 /* Forward referenced subroutines */
48 void FillDirectory(const char *path, Window *window);
50 static void click_column_cb(GtkCList *item, gint column, Window *restore);
51 static void select_row_cb(GtkCList *item, gint row, gint column,
52 GdkEventButton *event, Window *restore);
53 void row_data_destroy_cb(gpointer data);
54 void split_path_and_filename(const char *fname, POOLMEM **path, int *pnl,
55 POOLMEM **file, int *fnl);
58 static GdkPixmap *check_pixmap = NULL;
59 static GdkPixmap *check_trans = NULL;
60 static GdkPixmap *blank_pixmap = NULL;
61 static GdkPixmap *blank_trans = NULL;
64 static GtkWidget *restore_dir; /* current directory edit box */
65 static GtkWidget *scrolled; /* select files scrolled window */
66 static Window *restore;
68 const int NUM_COLUMNS = 7;
69 const int CHECK_COLUMN = 0;
70 const int FILE_COLUMN = 1;
71 const int MODES_COLUMN = 2;
72 const int DATE_COLUMN = 6;
76 * Read Director output and discard it until next prompt
78 static void discard_to_prompt()
80 while (bnet_recv(UA_sock) > 0) {
81 set_text(UA_sock->msg, UA_sock->msglen);
86 * Move up one directory
89 on_restore_up_button_clicked(GtkButton *button, gpointer user_data)
91 split_path_and_filename(restore->fname, &restore->path, &restore->pnl,
92 &restore->file, &restore->fnl);
93 FillDirectory(restore->path, restore);
96 static void mark_row(int row, bool mark)
102 gtk_clist_get_text(restore->list, row, FILE_COLUMN, &file);
104 bstrncpy(new_mark, "x", sizeof(new_mark));
105 len = Mmsg(&restore->buf, "mark %s", file);
107 bstrncpy(new_mark, " ", sizeof(new_mark));
108 len = Mmsg(&restore->buf, "unmark %s", file);
110 gtk_clist_set_text(restore->list, row, CHECK_COLUMN, new_mark);
111 /* strip trailing slash from directory name */
112 while (len > 1 && restore->buf[len-1] == '/') {
113 restore->buf[len-1] = 0;
115 write_director(restore->buf);
120 on_restore_add_button_clicked(GtkButton *button, gpointer user_data)
122 int num_selected = g_list_length(restore->list->selection);
125 for (int i=0; i < num_selected; i++) {
126 row = (int)(long int)g_list_nth_data(restore->list->selection, i);
133 on_restore_remove_button_clicked(GtkButton *button, gpointer user_data)
135 int num_selected = g_list_length(restore->list->selection);
138 for (int i=0; i < num_selected; i++) {
139 row = (int)(long int)g_list_nth_data(restore->list->selection, i);
140 mark_row(row, false);
145 * Called once at the beginning of the program for setup
147 void select_restore_setup()
149 const gchar *title[NUM_COLUMNS] = {_("Mark"), _("File"), _("Mode"), _("User"), _("Group"), _("Size"), _("Date")};
151 restore_file_selection = create_restore_file_selection();
152 if (!restore_file_selection) {
153 Dmsg0(000, "Restore_files not setup.\n");
155 restore_dir = lookup_widget(restore_file_selection, "restore_dir");
156 scrolled = lookup_widget(restore_file_selection, "scrolled");
158 Dmsg0(000, "Scrolled not setup.\n");
161 restore = new_window();
164 check_pixmap = gdk_pixmap_colormap_create_from_xpm(NULL,
165 gdk_colormap_get_system(), &check_trans, NULL,
167 blank_pixmap = gdk_pixmap_colormap_create_from_xpm(NULL,
168 gdk_colormap_get_system(), &blank_trans, NULL,
172 /* XXX: Stupid gtk_clist_set_selection_mode() has incorrect declaration of the title argument */
173 /* XXX: Workaround by typecast... peter@ifm.liu.se */
175 restore->list = (GtkCList *)gtk_clist_new_with_titles(NUM_COLUMNS, (gchar **) title);
176 gtk_clist_set_selection_mode(restore->list, GTK_SELECTION_EXTENDED);
177 gtk_clist_set_sort_column(restore->list, FILE_COLUMN);
178 gtk_clist_set_auto_sort(restore->list, true);
179 gtk_signal_connect(GTK_OBJECT(restore->list), "click_column",
180 G_CALLBACK(click_column_cb), restore);
181 gtk_signal_connect(GTK_OBJECT(restore->list), "select_row",
182 G_CALLBACK(select_row_cb), restore);
184 gtk_container_add(GTK_CONTAINER(scrolled), GTK_WIDGET(restore->list));
185 restore->buf = get_pool_memory(PM_FNAME);
186 restore->fname = get_pool_memory(PM_FNAME);
187 restore->path = get_pool_memory(PM_NAME);
188 restore->file = get_pool_memory(PM_NAME);
192 * Select files dialog called
194 void select_restore_files()
197 set_restore_dialog_defaults();
198 gtk_widget_show(GTK_WIDGET(restore->list));
199 FillDirectory("/", restore);
205 * Fill the CList box with files at path
207 void FillDirectory(const char *path, Window *restore)
209 char pathbuf[MAXSTRING];
210 char modes[20], user[20], group[20], size[20], date[30];
213 gchar *text[NUM_COLUMNS] = {marked, file, modes, user, group, size, date};
214 GtkCList *list = restore->list;
217 stop_director_reader(NULL);
218 pm_strcpy(&restore->fname, path);
219 gtk_entry_set_text(GTK_ENTRY(restore_dir), restore->fname);
220 gtk_clist_freeze(list);
221 gtk_clist_clear(list);
223 bsnprintf(pathbuf, sizeof(pathbuf), "cd %s", path);
224 Dmsg1(100, "%s\n", pathbuf);
225 write_director(pathbuf);
228 write_director("dir");
229 while (bnet_recv(UA_sock) > 0) {
230 char *p = UA_sock->msg;
232 strip_trailing_junk(UA_sock->msg);
236 Dmsg1(200, "Got: %s\n", p);
241 skip_nonspaces(&p); /* permissions */
243 bstrncpy(modes, l, sizeof(modes));
245 skip_nonspaces(&p); /* link count */
249 skip_nonspaces(&p); /* user */
252 bstrncpy(user, l, sizeof(user));
254 skip_nonspaces(&p); /* group */
256 bstrncpy(group, l, sizeof(group));
259 skip_nonspaces(&p); /* size */
261 bstrncpy(size, l, sizeof(size));
264 skip_nonspaces(&p); /* date/time */
268 bstrncpy(date, l, sizeof(date));
271 bstrncpy(marked, "x", sizeof(marked));
274 bstrncpy(marked, " ", sizeof(marked));
276 split_path_and_filename(p, &restore->path, &restore->pnl,
277 &restore->file, &restore->fnl);
279 // Dmsg1(000, "restore->fname=%s\n", restore->fname);
280 bstrncpy(file, restore->file, sizeof(file));
281 // printf("modes=%s user=%s group=%s size=%s date=%s file=%s\n",
282 // modes, user, group, size, date, file);
284 gtk_clist_append(list, text);
289 /* Fix up length of file column */
290 gtk_clist_set_column_width(list, FILE_COLUMN, gtk_clist_optimal_column_width(list, FILE_COLUMN));
291 gtk_clist_set_column_width(list, MODES_COLUMN, gtk_clist_optimal_column_width(list, MODES_COLUMN));
292 gtk_clist_thaw(list);
293 start_director_reader(NULL);
298 Window *window = (Window *)malloc(sizeof(Window));
299 memset(window, 0, sizeof(window));
305 * User clicked a column title
307 static void click_column_cb(GtkCList *item, gint column, Window *restore)
312 * User selected a row
314 static void select_row_cb(GtkCList *item, gint row, gint column,
315 GdkEventButton *event, Window *restore)
319 /* Column non-negative => double click */
321 gtk_clist_unselect_row(item, row, column);
322 /* Double click on column 0 means to mark or unmark */
324 gtk_clist_get_text(restore->list, row, CHECK_COLUMN, &marked);
325 Dmsg1(200, "Marked=%s\n", marked);
326 if (!marked || strcmp(marked, "x") != 0) {
329 mark_row(row, false);
332 /* Double clicking on directory means to move to it */
334 gtk_clist_get_text(item, row, FILE_COLUMN, &file);
336 if (len > 0 && file[len-1] == '/') {
337 /* Change to new directory */
338 pm_strcpy(restore->path, restore->fname);
340 Mmsg(restore->fname, "%s%s", restore->path, file+1);
342 Mmsg(restore->fname, "%s%s", restore->path, file);
344 FillDirectory(restore->fname, restore);
351 * CList row is being destroyed get rid of our data
353 void row_data_destroy_cb(gpointer data)
361 GdkPixmap *pixmap, *trans;
362 utf8_mark = g_locale_to_utf8(new_mark, -1, NULL, NULL, NULL);
363 gtk_clist_get_pixmap(restore->list, row, CHECK_COLUMN, &pixmap, &trans);
364 if (pixmap == blank_pixmap) {
365 bstrncpy(new_mark, "x", sizeof(new_mark));
366 // gtk_clist_set_pixmap(item, row, CHECK_COLUMN, check_pixmap, check_trans);
369 static void window_delete_cb(GtkWidget *item, GdkEvent *event, Window *restore)
371 gtk_widget_destroy(restore->window);
373 free_pool_memory(restore->buf);
374 free_pool_memory(restore->fname);
375 free_pool_memory(restore->path);
376 free_pool_memory(restore->file);
382 gtk_clist_set_pixmap(list, row, CHECK_COLUMN, check_pixmap, check_trans);
384 gtk_clist_set_pixmap(list, row, CHECK_COLUMN, blank_pixmap, blank_trans);