4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2002, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* abox.c - the dialog box widget used for filer operations.
24 * The actual code for specific operations is in action.c.
35 #include "gui_support.h"
39 #define RESPONSE_QUIET 1
41 /* Static prototypes */
42 static void abox_class_init(GObjectClass
*gclass
, gpointer data
);
43 static void abox_init(GTypeInstance
*object
, gpointer gclass
);
44 static void response(GtkDialog
*dialog
, gint response_id
);
45 static void abox_finalise(GObject
*object
);
46 static void shade(ABox
*abox
);
48 GType
abox_get_type(void)
50 static GType type
= 0;
54 static const GTypeInfo info
=
58 NULL
, /* base_finalise */
59 (GClassInitFunc
) abox_class_init
,
60 NULL
, /* class_finalise */
61 NULL
, /* class_data */
64 (GInstanceInitFunc
) abox_init
67 type
= g_type_register_static(GTK_TYPE_DIALOG
,
74 GtkWidget
* abox_new(const gchar
*title
, gboolean quiet
)
79 widget
= GTK_WIDGET(gtk_widget_new(abox_get_type(), NULL
));
80 abox
= (ABox
*) widget
;
82 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(abox
->quiet
), quiet
);
84 gtk_window_set_title(GTK_WINDOW(widget
), title
);
85 gtk_dialog_set_has_separator(GTK_DIALOG(widget
), FALSE
);
90 static void abox_class_init(GObjectClass
*gclass
, gpointer data
)
92 GtkDialogClass
*dialog
= (GtkDialogClass
*) gclass
;
94 dialog
->response
= response
;
96 g_signal_new("flag_toggled", G_TYPE_FROM_CLASS(gclass
),
97 G_SIGNAL_RUN_LAST
, G_STRUCT_OFFSET(ABoxClass
, flag_toggled
),
98 NULL
, NULL
, g_cclosure_marshal_VOID__INT
,
99 G_TYPE_NONE
, 1, G_TYPE_INT
);
101 gclass
->finalize
= abox_finalise
;
104 static void abox_init(GTypeInstance
*object
, gpointer gclass
)
106 GtkWidget
*frame
, *text
, *scrollbar
, *button
;
107 ABox
*abox
= ABOX(object
);
108 GtkDialog
*dialog
= GTK_DIALOG(object
);
110 gtk_window_set_position(GTK_WINDOW(dialog
), GTK_WIN_POS_MOUSE
);
112 abox
->dir_label
= gtk_label_new(_("<dir>"));
113 gtk_widget_set_size_request(abox
->dir_label
, 8, -1);
114 abox
->results
= NULL
;
116 abox
->next_dir
= NULL
;
117 abox
->next_timer
= 0;
118 abox
->question
= FALSE
;
119 gtk_misc_set_alignment(GTK_MISC(abox
->dir_label
), 0.5, 0.5);
120 gtk_box_pack_start(GTK_BOX(dialog
->vbox
),
121 abox
->dir_label
, FALSE
, TRUE
, 0);
123 abox
->log_hbox
= gtk_hbox_new(FALSE
, 0);
124 gtk_box_pack_start(GTK_BOX(dialog
->vbox
),
125 abox
->log_hbox
, TRUE
, TRUE
, 4);
127 frame
= gtk_frame_new(NULL
);
128 gtk_box_pack_start(GTK_BOX(abox
->log_hbox
), frame
, TRUE
, TRUE
, 0);
130 text
= gtk_text_view_new();
131 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_IN
);
132 gtk_container_add(GTK_CONTAINER(frame
), text
);
134 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text
), GTK_WRAP_WORD
);
137 scrollbar
= gtk_vscrollbar_new(NULL
);
138 gtk_widget_set_scroll_adjustments(text
, NULL
,
139 gtk_range_get_adjustment(GTK_RANGE(scrollbar
)));
140 gtk_text_buffer_create_tag(
141 gtk_text_view_get_buffer(GTK_TEXT_VIEW(abox
->log
)),
142 "error", "foreground", "red",
144 gtk_text_buffer_create_tag(
145 gtk_text_view_get_buffer(GTK_TEXT_VIEW(abox
->log
)),
146 "question", "weight", "bold",
148 gtk_text_view_set_editable(GTK_TEXT_VIEW(text
), FALSE
);
149 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text
), FALSE
);
150 gtk_widget_set_size_request(text
, 400, 100);
152 gtk_box_pack_start(GTK_BOX(abox
->log_hbox
), scrollbar
, FALSE
, TRUE
, 0);
154 gtk_dialog_add_buttons(dialog
,
155 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
156 GTK_STOCK_NO
, GTK_RESPONSE_NO
,
157 GTK_STOCK_YES
, GTK_RESPONSE_YES
,
160 abox
->flag_box
= gtk_hbox_new(FALSE
, 16);
161 gtk_box_pack_end(GTK_BOX(dialog
->vbox
),
162 abox
->flag_box
, FALSE
, TRUE
, 2);
164 button
= button_new_mixed(GTK_STOCK_GOTO_LAST
, _("_Quiet"));
165 GTK_WIDGET_SET_FLAGS(button
, GTK_CAN_DEFAULT
);
166 gtk_dialog_add_action_widget(dialog
, button
, RESPONSE_QUIET
);
167 gtk_dialog_set_default_response(dialog
, RESPONSE_QUIET
);
169 gtk_widget_show_all(dialog
->vbox
);
171 abox
->quiet
= abox_add_flag(abox
,
172 _("Quiet"), _("Don't confirm every operation"),
178 static void flag_toggled(GtkToggleButton
*toggle
, ABox
*abox
)
182 code
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toggle
),
187 g_signal_emit_by_name(abox
, "flag_toggled", code
);
191 GtkWidget
*abox_add_flag(ABox
*abox
, const gchar
*label
, const gchar
*tip
,
192 gint response
, gboolean default_value
)
196 check
= gtk_check_button_new_with_label(label
);
197 gtk_tooltips_set_tip(tooltips
, check
, tip
, NULL
);
198 g_object_set_data(G_OBJECT(check
), "abox-response",
199 GINT_TO_POINTER(response
));
200 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check
), default_value
);
201 g_signal_connect(check
, "toggled", G_CALLBACK(flag_toggled
), abox
);
202 gtk_box_pack_end(GTK_BOX(abox
->flag_box
), check
, FALSE
, TRUE
, 0);
203 gtk_widget_show(check
);
208 static void response(GtkDialog
*dialog
, gint response_id
)
210 ABox
*abox
= ABOX(dialog
);
212 if (response_id
== GTK_RESPONSE_CANCEL
)
213 gtk_widget_destroy(GTK_WIDGET(dialog
));
214 else if (response_id
== RESPONSE_QUIET
)
216 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(abox
->quiet
),
218 gtk_dialog_response(dialog
, GTK_RESPONSE_YES
);
220 else if (response_id
== GTK_RESPONSE_YES
||
221 response_id
== GTK_RESPONSE_NO
)
223 abox
->question
= FALSE
;
228 /* Display the question. Unshade the Yes, No and entry box (if any).
229 * Will send a response signal when the user makes a choice.
231 void abox_ask(ABox
*abox
, const gchar
*question
)
233 g_return_if_fail(abox
!= NULL
);
234 g_return_if_fail(question
!= NULL
);
235 g_return_if_fail(IS_ABOX(abox
));
237 abox_log(abox
, question
, "question");
239 abox
->question
= TRUE
;
243 void abox_cancel_ask(ABox
*abox
)
245 g_return_if_fail(abox
!= NULL
);
246 g_return_if_fail(IS_ABOX(abox
));
248 abox
->question
= FALSE
;
252 void abox_log(ABox
*abox
, const gchar
*message
, const gchar
*style
)
255 GtkTextBuffer
*text_buffer
;
257 text_buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(abox
->log
));
259 gtk_text_buffer_get_end_iter(text_buffer
, &end
);
260 gtk_text_buffer_insert_with_tags_by_name(text_buffer
,
261 &end
, message
, -1, style
, NULL
);
262 gtk_text_view_scroll_to_mark(
263 GTK_TEXT_VIEW(abox
->log
),
264 gtk_text_buffer_get_mark(text_buffer
, "insert"),
268 static void abox_finalise(GObject
*object
)
270 GObjectClass
*parent_class
;
271 ABox
*abox
= ABOX(object
);
275 g_free(abox
->next_dir
);
276 abox
->next_dir
= NULL
;
277 gtk_timeout_remove(abox
->next_timer
);
280 parent_class
= gtk_type_class(GTK_TYPE_DIALOG
);
282 if (G_OBJECT_CLASS(parent_class
)->finalize
)
283 (*G_OBJECT_CLASS(parent_class
)->finalize
)(object
);
286 static gboolean
show_next_dir(gpointer data
)
288 ABox
*abox
= (ABox
*) data
;
290 gtk_label_set_text(GTK_LABEL(abox
->dir_label
), abox
->next_dir
);
291 g_free(abox
->next_dir
);
292 abox
->next_dir
= NULL
;
297 /* Display this message in the current-object area.
298 * The display won't update too fast, even if you call this very often.
300 void abox_set_current_object(ABox
*abox
, const gchar
*message
)
302 g_return_if_fail(abox
!= NULL
);
303 g_return_if_fail(message
!= NULL
);
304 g_return_if_fail(IS_ABOX(abox
));
306 /* If a string is already set then replace it, but assume the
307 * timer is already running...
311 g_free(abox
->next_dir
);
314 gtk_label_set_text(GTK_LABEL(abox
->dir_label
), message
);
315 abox
->next_timer
= gtk_timeout_add(500, show_next_dir
, abox
);
318 abox
->next_dir
= g_strdup(message
);
321 static void lost_preview(GtkWidget
*window
, ABox
*abox
)
323 abox
->preview
= NULL
;
326 static void select_row_callback(GtkTreeView
*treeview
,
328 GtkTreeViewColumn
*col
,
335 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(abox
->results
));
336 gtk_tree_model_get_iter(model
, &iter
, path
);
337 gtk_tree_model_get(model
, &iter
, 0, &leaf
, 1, &dir
, -1);
341 if (strcmp(abox
->preview
->real_path
, dir
) == 0)
342 display_set_autoselect(abox
->preview
, leaf
);
344 filer_change_to(abox
->preview
, dir
, leaf
);
348 abox
->preview
= filer_opendir(dir
, NULL
);
351 display_set_autoselect(abox
->preview
, leaf
);
352 g_signal_connect_object(abox
->preview
->window
, "destroy",
353 G_CALLBACK(lost_preview
), abox
, 0);
361 /* Add a list-of-results area. You must use this before adding files
362 * with abox_add_filename().
364 void abox_add_results(ABox
*abox
)
366 GtkTreeViewColumn
*column
;
367 GtkWidget
*scroller
, *frame
;
369 GtkCellRenderer
*cell_renderer
;
371 g_return_if_fail(abox
!= NULL
);
372 g_return_if_fail(IS_ABOX(abox
));
373 g_return_if_fail(abox
->results
== NULL
);
375 scroller
= gtk_scrolled_window_new(NULL
, NULL
);
376 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller
),
377 GTK_POLICY_NEVER
, GTK_POLICY_ALWAYS
);
379 frame
= gtk_frame_new(NULL
);
380 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_IN
);
381 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(abox
)->vbox
),
382 frame
, TRUE
, TRUE
, 4);
384 gtk_container_add(GTK_CONTAINER(frame
), scroller
);
386 model
= gtk_list_store_new(2, G_TYPE_STRING
, G_TYPE_STRING
);
387 abox
->results
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(model
));
388 g_object_unref(G_OBJECT(model
));
390 cell_renderer
= gtk_cell_renderer_text_new();
391 column
= gtk_tree_view_column_new_with_attributes(
392 _("Name"), cell_renderer
, "text", 0, NULL
);
393 gtk_tree_view_column_set_resizable(column
, TRUE
);
394 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_GROW_ONLY
);
395 gtk_tree_view_append_column(GTK_TREE_VIEW(abox
->results
), column
);
396 gtk_tree_view_insert_column_with_attributes(
397 GTK_TREE_VIEW(abox
->results
),
398 1, (gchar
*) _("Directory"), cell_renderer
,
401 gtk_container_add(GTK_CONTAINER(scroller
), abox
->results
);
403 gtk_widget_set_size_request(abox
->results
, 100, 100);
404 gtk_box_set_child_packing(GTK_BOX(GTK_DIALOG(abox
)->vbox
),
405 abox
->log_hbox
, FALSE
, TRUE
, 4, GTK_PACK_START
);
407 g_signal_connect(abox
->results
, "row-activated",
408 G_CALLBACK(select_row_callback
), abox
);
411 void abox_add_filename(ABox
*abox
, const gchar
*path
)
417 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(abox
->results
));
419 gtk_list_store_append(GTK_LIST_STORE(model
), &iter
);
421 dir
= g_dirname(path
);
422 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
,
428 /* Clear search results area */
429 void abox_clear_results(ABox
*abox
)
433 g_return_if_fail(abox
!= NULL
);
434 g_return_if_fail(IS_ABOX(abox
));
436 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(abox
->results
));
438 gtk_list_store_clear(GTK_LIST_STORE(model
));
441 void abox_add_combo(ABox
*abox
, GList
*presets
,
442 const gchar
*text
, GtkWidget
*help_button
)
444 GtkWidget
*hbox
, *label
, *combo
;
446 g_return_if_fail(abox
!= NULL
);
447 g_return_if_fail(IS_ABOX(abox
));
448 g_return_if_fail(abox
->entry
== NULL
);
450 hbox
= gtk_hbox_new(FALSE
, 0);
451 label
= gtk_label_new(_("Command:"));
452 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, TRUE
, 4);
454 combo
= gtk_combo_new();
455 gtk_combo_disable_activate(GTK_COMBO(combo
));
456 gtk_combo_set_use_arrows_always(GTK_COMBO(combo
), TRUE
);
457 gtk_combo_set_popdown_strings(GTK_COMBO(combo
), presets
);
458 abox
->entry
= GTK_COMBO(combo
)->entry
;
459 gtk_entry_set_activates_default(GTK_ENTRY(abox
->entry
), TRUE
);
461 gtk_entry_set_text(GTK_ENTRY(abox
->entry
), text
);
462 gtk_box_pack_start(GTK_BOX(hbox
), combo
, TRUE
, TRUE
, 4);
464 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(abox
)->vbox
), hbox
,
466 gtk_box_pack_start(GTK_BOX(hbox
), help_button
, FALSE
, TRUE
, 4);
468 gtk_widget_show_all(hbox
);
473 void abox_add_entry(ABox
*abox
, const gchar
*text
, GtkWidget
*help_button
)
475 GtkWidget
*hbox
, *label
;
477 g_return_if_fail(abox
!= NULL
);
478 g_return_if_fail(IS_ABOX(abox
));
479 g_return_if_fail(abox
->entry
== NULL
);
481 hbox
= gtk_hbox_new(FALSE
, 0);
482 label
= gtk_label_new(_("Expression:"));
483 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, TRUE
, 4);
484 abox
->entry
= gtk_entry_new();
485 gtk_widget_set_name(abox
->entry
, "fixed-style");
486 gtk_entry_set_text(GTK_ENTRY(abox
->entry
), text
);
487 gtk_box_pack_start(GTK_BOX(hbox
), abox
->entry
, TRUE
, TRUE
, 4);
488 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(abox
)->vbox
),
489 hbox
, FALSE
, TRUE
, 4);
490 gtk_box_pack_start(GTK_BOX(hbox
), help_button
,
493 gtk_entry_set_activates_default(GTK_ENTRY(abox
->entry
), TRUE
);
495 gtk_widget_show_all(hbox
);
500 static void shade(ABox
*abox
)
502 GtkDialog
*dialog
= (GtkDialog
*) abox
;
503 gboolean quiet
, on
= abox
->question
;
505 quiet
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(abox
->quiet
));
507 gtk_dialog_set_response_sensitive(dialog
, GTK_RESPONSE_YES
, on
);
508 gtk_dialog_set_response_sensitive(dialog
, GTK_RESPONSE_NO
, on
);
511 gtk_dialog_set_response_sensitive(dialog
, RESPONSE_QUIET
, TRUE
);
513 gtk_dialog_set_response_sensitive(dialog
,
514 RESPONSE_QUIET
, FALSE
);
516 /* Unsetting the focus means that set_default will put it in the
519 gtk_window_set_focus(GTK_WINDOW(abox
), NULL
);
520 /* Note: Gtk+-2.0.0 will segfault on Return if an insensitive
521 * widget is the default.
524 gtk_dialog_set_default_response(dialog
, GTK_RESPONSE_YES
);
526 gtk_dialog_set_default_response(dialog
, RESPONSE_QUIET
);
530 gtk_widget_set_sensitive(abox
->entry
, on
);
532 gtk_widget_grab_focus(abox
->entry
);