1 /*
2 * Copyright (c) 2005-2006 Jean-François Wauthy (pollux@xfce.org)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif /* !HAVE_CONFIG_H */
22
23 #ifdef HAVE_STDLIB_H
24 #include <stdlib.h>
25 #endif
26
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <time.h>
35
36 #include <gtk/gtk.h>
37 #include <libxfce4util/libxfce4util.h>
38 #include <libxfce4ui/libxfce4ui.h>
39
40 #include <gio/gio.h>
41
42 #include <exo/exo.h>
43
44 #include <libisofs.h>
45 #include <glib/gstdio.h>
46
47 #include "xfburn-data-composition.h"
48 #include "xfburn-global.h"
49
50 #include "xfburn-adding-progress.h"
51 #include "xfburn-composition.h"
52 #include "xfburn-burn-data-cd-composition-dialog.h"
53 #include "xfburn-burn-data-dvd-composition-dialog.h"
54 #include "xfburn-data-disc-usage.h"
55 #include "xfburn-main-window.h"
56 #include "xfburn-utils.h"
57 #include "xfburn-settings.h"
58 #include "xfburn-main.h"
59
60 #define XFBURN_DATA_COMPOSITION_GET_PRIVATE(obj) (xfburn_data_composition_get_instance_private (XFBURN_DATA_COMPOSITION (obj)))
61
62 enum
63 {
64 DATA_COMPOSITION_COLUMN_ICON,
65 DATA_COMPOSITION_COLUMN_CONTENT,
66 DATA_COMPOSITION_COLUMN_HUMANSIZE,
67 DATA_COMPOSITION_COLUMN_SIZE,
68 DATA_COMPOSITION_COLUMN_PATH,
69 DATA_COMPOSITION_COLUMN_TYPE,
70 DATA_COMPOSITION_N_COLUMNS
71 };
72
73 typedef enum
74 {
75 DATA_COMPOSITION_TYPE_FILE,
76 DATA_COMPOSITION_TYPE_DIRECTORY
77 } DataCompositionEntryType;
78
79
80 /* thread parameters */
81 typedef struct {
82 GSList * filelist;
83 XfburnDataComposition *dc;
84 } ThreadAddFilesCLIParams;
85
86 typedef struct {
87 XfburnDataComposition *dc;
88 GtkTreeModel *model;
89 GtkTreeIter iter_where_insert;
90 DataCompositionEntryType type;
91 } ThreadAddFilesActionParams;
92
93 typedef struct {
94 XfburnDataComposition *composition;
95 DataCompositionEntryType type;
96 GtkWidget *widget;
97 GtkTreeViewDropPosition position;
98 GtkTreeIter iter_dummy;
99 } ThreadAddFilesDragParams;
100
101 /* prototypes */
102 static void composition_interface_init (XfburnCompositionInterface *composition, gpointer iface_data);
103 static void xfburn_data_composition_finalize (GObject * object);
104
105 static void show_custom_controls (XfburnComposition *composition);
106 static void hide_custom_controls (XfburnComposition *composition);
107 static void load_from_file (XfburnComposition *composition, const gchar *file);
108 static void save_to_file (XfburnComposition *composition);
109
110 static gint directory_tree_sortfunc (GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data);
111
112 static void set_default_name (XfburnDataComposition * dc);
113 static gboolean has_default_name (XfburnDataComposition * dc);
114
115 static void action_create_directory (GSimpleAction *, GVariant *, XfburnDataComposition *);
116 static void action_clear (GSimpleAction *, GVariant *, XfburnDataComposition *);
117 static void action_remove_selection (GSimpleAction *, GVariant *, XfburnDataComposition *);
118 static void action_rename_selection (GSimpleAction *, GVariant *, XfburnDataComposition *);
119 static void action_add_or_select (GSimpleAction *, GVariant *, XfburnDataComposition *);
120 static void add_files (gchar * files, XfburnDataComposition *);
121 static void add_cb (GtkWidget * widget, gpointer data);
122
123 static gboolean cb_treeview_button_pressed (GtkTreeView * treeview, GdkEventButton * event, XfburnDataComposition * dc);
124 static void cb_treeview_row_activated (GtkTreeView * treeview, GtkTreePath * path, GtkTreeViewColumn * column, XfburnDataComposition * composition);
125 static void cb_selection_changed (GtkTreeSelection *selection, XfburnDataComposition * dc);
126 static void cb_begin_burn (XfburnDataDiscUsage * du, XfburnDataComposition * dc);
127 static void cb_cell_file_edited (GtkCellRenderer * renderer, gchar * path, gchar * newtext, XfburnDataComposition * dc);
128
129 static void cb_content_drag_data_rcv (GtkWidget * widget, GdkDragContext * dc, guint x, guint y, GtkSelectionData * sd,
130 guint info, guint t, XfburnDataComposition * composition);
131 static void cb_content_drag_data_get (GtkWidget * widget, GdkDragContext * dc, GtkSelectionData * data, guint info,
132 guint timestamp, XfburnDataComposition * content);
133 static void cb_adding_done (XfburnAddingProgress *progress, XfburnDataComposition *dc);
134
135 /* thread entry points */
136 static gpointer thread_add_files_cli (ThreadAddFilesCLIParams *params);
137 static gpointer thread_add_files_action (ThreadAddFilesActionParams *params);
138 static gpointer thread_add_files_drag (ThreadAddFilesDragParams *params);
139
140 /* thread helpers */
141 static gboolean thread_add_file_to_list_with_name (const gchar *name, XfburnDataComposition * dc,
142 GtkTreeModel * model, const gchar * path, GtkTreeIter * iter,
143 GtkTreeIter * insertion, GtkTreeViewDropPosition position);
144 static gboolean thread_add_file_to_list (XfburnDataComposition * dc, GtkTreeModel * model, const gchar * path,
145 GtkTreeIter * iter, GtkTreeIter * insertion, GtkTreeViewDropPosition position);
146 static void concat_free (char * msg, char ** combined_msg);
147 static IsoImage * generate_iso_image (XfburnDataComposition * dc);
148 static gboolean show_add_home_question_dialog (void);
149
150 typedef struct
151 {
152 gchar *filename;
153 gboolean modified;
154
155 guint n_new_directory;
156
157 GList *full_paths_to_add;
158 gchar *selected_files;
159 GtkTreePath *path_where_insert;
160
161 GdkDragContext * dc;
162 gboolean success;
163 gboolean del;
164 guint32 time;
165
166 void *thread_params;
167
168 GSimpleActionGroup *action_group;
169 GtkBuilder *ui_manager;
170
171 GtkWidget *toolbar;
172 GtkWidget *entry_volume_name;
173 GtkWidget *content;
174 GtkWidget *disc_usage;
175 GtkWidget *progress;
176 GtkTreeStore *model;
177 GtkWidget *add_filechooser;
178 gchar * last_directory;
179 GtkWidget *add_window;
180
181 gchar *default_vol_name;
182
183 gboolean large_files;
184 } XfburnDataCompositionPrivate;
185
186 /* globals */
187 static GtkHPanedClass *parent_class = NULL;
188 static guint instances = 0;
189
190 static const GActionEntry action_entries[] = {
191 {.name = "add-file", .activate = (gActionCallback)action_add_or_select},
192 {.name = "create-dir", .activate = (gActionCallback)action_create_directory},
193 {.name = "remove-file", .activate = (gActionCallback)action_remove_selection},
194 {.name = "clear", .activate = (gActionCallback)action_clear},
195 /*{.name = "import-session", .activate = (gActionCallback)action_remove_selection},*/
196 {.name = "rename-file", .activate = (gActionCallback)action_rename_selection},
197 };
198 /*
199 static const GtkActionEntry action_entries[] = {
200 {"add-file", "list-add", N_("Add"), NULL, N_("Add the selected file(s) to the composition"),
201 G_CALLBACK (action_add_or_select),},
202 {"create-dir", "document-new", N_("Create directory"), NULL, N_("Add a new directory to the composition"),
203 G_CALLBACK (action_create_directory),},
204 {"remove-file", "list-remove", N_("Remove"), NULL, N_("Remove the selected file(s) from the composition"),
205 G_CALLBACK (action_remove_selection),},
206 {"clear", "edit-clear", N_("Clear"), NULL, N_("Clear the content of the composition"),
207 G_CALLBACK (action_clear),},
208 /*{"import-session", "xfburn-import-session", N_("Import"), NULL, N_("Import existing session"),}, */
209 /* {"rename-file", "gtk-edit", N_("Rename"), NULL, N_("Rename the selected file"),
210 G_CALLBACK (action_rename_selection),},
211 };*/
212
213 static const gchar *toolbar_actions[] = {
214 "add-file",
215 "remove-file",
216 "create-dir",
217 "clear",
218 "import-session",
219 };
220
221 static GdkPixbuf *icon_directory = NULL, *icon_file = NULL;
222
223 /***************************/
224 /* XfburnDataComposition class */
225 /***************************/
226 G_DEFINE_TYPE_EXTENDED(
227 XfburnDataComposition,
228 xfburn_data_composition,
229 GTK_TYPE_BOX,
230 0,
231 G_ADD_PRIVATE (XfburnDataComposition)
232 G_IMPLEMENT_INTERFACE (XFBURN_TYPE_COMPOSITION, composition_interface_init)
233 );
234
235
236 static void
xfburn_data_composition_class_init(XfburnDataCompositionClass * klass)237 xfburn_data_composition_class_init (XfburnDataCompositionClass * klass)
238 {
239 GObjectClass *object_class = G_OBJECT_CLASS (klass);
240
241 parent_class = g_type_class_peek_parent (klass);
242
243 object_class->finalize = xfburn_data_composition_finalize;
244 }
245
246 static void
composition_interface_init(XfburnCompositionInterface * composition,gpointer iface_data)247 composition_interface_init (XfburnCompositionInterface *composition, gpointer iface_data)
248 {
249 composition->show_custom_controls = show_custom_controls;
250 composition->hide_custom_controls = hide_custom_controls;
251 composition->load = load_from_file;
252 composition->save = save_to_file;
253 }
254
255 static void
xfburn_data_composition_init(XfburnDataComposition * composition)256 xfburn_data_composition_init (XfburnDataComposition * composition)
257 {
258 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (composition);
259
260 gtk_orientable_set_orientation(GTK_ORIENTABLE (composition), GTK_ORIENTATION_VERTICAL);
261
262 gint x, y;
263 // ExoToolbarsModel *model_toolbar;
264 gint toolbar_position;
265 GtkWidget *hbox_toolbar;
266 GtkWidget *hbox, *label;
267 GtkWidget *scrolled_window;
268 GtkTreeStore *model;
269 GtkTreeViewColumn *column_file;
270 GtkCellRenderer *cell_icon, *cell_file;
271 GtkTreeSelection *selection;
272 GAction *action = NULL;
273 GdkScreen *screen;
274 GtkIconTheme *icon_theme;
275
276 GtkTargetEntry gte_src[] = { { "XFBURN_TREE_PATHS", GTK_TARGET_SAME_WIDGET, DATA_COMPOSITION_DND_TARGET_INSIDE } };
277 GtkTargetEntry gte_dest[] = { { "XFBURN_TREE_PATHS", GTK_TARGET_SAME_WIDGET, DATA_COMPOSITION_DND_TARGET_INSIDE },
278 { "text/uri-list", 0, DATA_COMPOSITION_DND_TARGET_TEXT_URI_LIST },
279 { "text/plain;charset=utf-8", 0, DATA_COMPOSITION_DND_TARGET_TEXT_PLAIN },
280 };
281
282 priv->full_paths_to_add = NULL;
283
284 instances++;
285
286 /* initialize static members */
287 screen = gtk_widget_get_screen (GTK_WIDGET (composition));
288 icon_theme = gtk_icon_theme_get_for_screen (screen);
289
290 gtk_icon_size_lookup (GTK_ICON_SIZE_SMALL_TOOLBAR, &x, &y);
291 if (!icon_directory)
292 icon_directory = gtk_icon_theme_load_icon (icon_theme, "folder", x, 0, NULL);
293 if (!icon_file)
294 icon_file = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-regular", x, 0, NULL);
295
296 /* create ui manager */
297 priv->action_group = g_simple_action_group_new ();
298 g_action_map_add_action_entries (G_ACTION_MAP (priv->action_group), action_entries, G_N_ELEMENTS (action_entries),
299 GTK_WIDGET (composition));
300
301 priv->ui_manager = gtk_builder_new ();
302 gtk_builder_set_translation_domain(priv->ui_manager, GETTEXT_PACKAGE);
303
304 xfce_resource_push_path (XFCE_RESOURCE_DATA, DATADIR);
305 gchar *popup_ui = xfce_resource_lookup (XFCE_RESOURCE_DATA, "xfburn/xfburn-popup-menus.ui");
306 gtk_builder_add_from_file (priv->ui_manager, popup_ui, NULL);
307
308 hbox_toolbar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
309 gtk_box_pack_start (GTK_BOX (composition), hbox_toolbar, FALSE, TRUE, 0);
310 gtk_widget_show (hbox_toolbar);
311
312 /* toolbar */
313 /* model_toolbar = exo_toolbars_model_new ();
314 exo_toolbars_model_set_actions (model_toolbar, (gchar **) toolbar_actions, G_N_ELEMENTS (toolbar_actions));
315 toolbar_position = exo_toolbars_model_add_toolbar (model_toolbar, -1, "content-toolbar");
316 exo_toolbars_model_set_style (model_toolbar, GTK_TOOLBAR_BOTH, toolbar_position);
317
318 exo_toolbars_model_add_item (model_toolbar, toolbar_position, -1, "add-file", EXO_TOOLBARS_ITEM_TYPE);
319 exo_toolbars_model_add_item (model_toolbar, toolbar_position, -1, "create-dir", EXO_TOOLBARS_ITEM_TYPE);
320 exo_toolbars_model_add_separator (model_toolbar, toolbar_position, -1);
321 exo_toolbars_model_add_item (model_toolbar, toolbar_position, -1, "remove-file", EXO_TOOLBARS_ITEM_TYPE);
322 exo_toolbars_model_add_item (model_toolbar, toolbar_position, -1, "clear", EXO_TOOLBARS_ITEM_TYPE);
323 //exo_toolbars_model_add_separator (model_toolbar, toolbar_position, -1);
324 //exo_toolbars_model_add_item (model_toolbar, toolbar_position, -1, "import-session", EXO_TOOLBARS_ITEM_TYPE);
325
326 priv->toolbar = exo_toolbars_view_new_with_model (priv->ui_manager, model_toolbar);
327 */
328 priv->toolbar = gtk_toolbar_new ();
329 gtk_toolbar_set_style(GTK_TOOLBAR (priv->toolbar), GTK_TOOLBAR_BOTH);
330 gtk_widget_insert_action_group (priv->toolbar, "win", G_ACTION_GROUP (priv->action_group));
331
332 xfburn_add_button_to_toolbar (GTK_TOOLBAR (priv->toolbar),
333 "list-add", _("Add"), "win.add-file", _("Add the selected file(s) to the composition"));
334 xfburn_add_button_to_toolbar (GTK_TOOLBAR (priv->toolbar),
335 "folder-new", _("Create directory"), "win.create-dir", _("Add a new directory to the composition"));
336
337 gtk_toolbar_insert (GTK_TOOLBAR (priv->toolbar), gtk_separator_tool_item_new(), -1);
338
339 xfburn_add_button_to_toolbar (GTK_TOOLBAR (priv->toolbar),
340 "list-remove", _("Remove"), "win.remove-file", _("Remove the selected file(s) from the composition"));
341 xfburn_add_button_to_toolbar (GTK_TOOLBAR (priv->toolbar),
342 "edit-clear", _("Clear"), "win.clear", _("Clear the content of the composition"));
343
344 gtk_box_pack_start (GTK_BOX (hbox_toolbar), priv->toolbar, TRUE, TRUE, 0);
345 gtk_widget_show_all (priv->toolbar);
346
347 /* volume name */
348 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
349 gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
350 gtk_box_pack_start (GTK_BOX (hbox_toolbar), hbox, FALSE, FALSE, 0);
351 gtk_widget_show (hbox);
352
353 label = gtk_label_new (_("Volume name :"));
354 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
355 gtk_widget_show (label);
356
357 priv->entry_volume_name = gtk_entry_new ();
358
359 set_default_name (composition);
360
361 gtk_box_pack_start (GTK_BOX (hbox), priv->entry_volume_name, FALSE, FALSE, 0);
362 gtk_widget_show (priv->entry_volume_name);
363
364 /* content treeview */
365 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
366 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
367 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
368 gtk_widget_show (scrolled_window);
369 gtk_box_pack_start (GTK_BOX (composition), scrolled_window, TRUE, TRUE, 0);
370
371 priv->content = exo_tree_view_new ();
372 model = gtk_tree_store_new (DATA_COMPOSITION_N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
373 G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_UINT);
374 priv->model = model;
375
376 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model), DATA_COMPOSITION_COLUMN_CONTENT,
377 directory_tree_sortfunc, NULL, NULL);
378 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), DATA_COMPOSITION_COLUMN_CONTENT, GTK_SORT_ASCENDING);
379 gtk_tree_view_set_model (GTK_TREE_VIEW (priv->content), GTK_TREE_MODEL (model));
380 // gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (priv->content), TRUE);
381 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->content));
382 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
383 gtk_widget_show (priv->content);
384 gtk_container_add (GTK_CONTAINER (scrolled_window), priv->content);
385
386 column_file = gtk_tree_view_column_new ();
387 gtk_tree_view_column_set_title (column_file, _("Contents"));
388
389 cell_icon = gtk_cell_renderer_pixbuf_new ();
390 gtk_tree_view_column_pack_start (column_file, cell_icon, FALSE);
391 gtk_tree_view_column_set_attributes (column_file, cell_icon, "pixbuf", DATA_COMPOSITION_COLUMN_ICON, NULL);
392 g_object_set (cell_icon, "xalign", 0.0, "ypad", 0, NULL);
393
394 cell_file = gtk_cell_renderer_text_new ();
395 gtk_tree_view_column_pack_start (column_file, cell_file, TRUE);
396 gtk_tree_view_column_set_attributes (column_file, cell_file, "text", DATA_COMPOSITION_COLUMN_CONTENT, NULL);
397 g_signal_connect (G_OBJECT (cell_file), "edited", G_CALLBACK (cb_cell_file_edited), composition);
398 g_object_set (G_OBJECT (cell_file), "editable", TRUE, NULL);
399
400 gtk_tree_view_append_column (GTK_TREE_VIEW (priv->content), column_file);
401
402 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->content), -1, _("Size"),
403 gtk_cell_renderer_text_new (), "text", DATA_COMPOSITION_COLUMN_HUMANSIZE,
404 NULL);
405 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->content), -1, _("Local Path"),
406 gtk_cell_renderer_text_new (), "text", DATA_COMPOSITION_COLUMN_PATH, NULL);
407
408 /* Contents column */
409 gtk_tree_view_column_set_resizable (gtk_tree_view_get_column (GTK_TREE_VIEW (priv->content), 0), 1);
410 gtk_tree_view_column_set_min_width (gtk_tree_view_get_column (GTK_TREE_VIEW (priv->content), 0), 200);
411 /* Size (HUMANSIZE) column */
412 gtk_tree_view_column_set_resizable (gtk_tree_view_get_column (GTK_TREE_VIEW (priv->content), 1), 1);
413 gtk_tree_view_column_set_min_width (gtk_tree_view_get_column (GTK_TREE_VIEW (priv->content), 1), 60);
414 /* Local Path (PATH) column */
415 gtk_tree_view_column_set_resizable (gtk_tree_view_get_column (GTK_TREE_VIEW (priv->content), 2), 1);
416
417
418 g_signal_connect (G_OBJECT (priv->content), "row-activated", G_CALLBACK (cb_treeview_row_activated), composition);
419 g_signal_connect (G_OBJECT (priv->content), "button-press-event",
420 G_CALLBACK (cb_treeview_button_pressed), composition);
421 g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (cb_selection_changed), composition);
422
423 /* adding progress window */
424 priv->progress = GTK_WIDGET (xfburn_adding_progress_new ());
425 g_signal_connect (G_OBJECT (priv->progress), "adding-done", G_CALLBACK (cb_adding_done), composition);
426 gtk_window_set_transient_for (GTK_WINDOW (priv->progress), GTK_WINDOW (xfburn_main_window_get_instance ()));
427 /* FIXME: progress should have a busy cursor */
428
429 /* disc usage */
430 priv->disc_usage = xfburn_data_disc_usage_new ();
431 gtk_box_pack_start (GTK_BOX (composition), priv->disc_usage, FALSE, FALSE, 5);
432 gtk_widget_show (priv->disc_usage);
433 g_signal_connect (G_OBJECT (priv->disc_usage), "begin-burn", G_CALLBACK (cb_begin_burn), composition);
434
435 /* set up DnD */
436 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (priv->content), GDK_BUTTON1_MASK, gte_src,
437 G_N_ELEMENTS (gte_src), GDK_ACTION_COPY | GDK_ACTION_MOVE);
438 g_signal_connect (G_OBJECT (priv->content), "drag-data-get", G_CALLBACK (cb_content_drag_data_get),
439 composition);
440 gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (priv->content), gte_dest, G_N_ELEMENTS (gte_dest),
441 GDK_ACTION_COPY | GDK_ACTION_MOVE);
442 g_signal_connect (G_OBJECT (priv->content), "drag-data-received", G_CALLBACK (cb_content_drag_data_rcv),
443 composition);
444
445 action = g_action_map_lookup_action (G_ACTION_MAP (priv->action_group), "remove-file");
446 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
447 }
448
449 static void
xfburn_data_composition_finalize(GObject * object)450 xfburn_data_composition_finalize (GObject * object)
451 {
452 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (object);
453
454 g_free (priv->filename);
455
456 /* free static members */
457 instances--;
458 if (instances == 0) {
459 if (icon_directory) {
460 g_object_unref (icon_directory);
461 icon_directory = NULL;
462 }
463 if (icon_file) {
464 g_object_unref (icon_file);
465 icon_file = NULL;
466 }
467 }
468
469 g_object_unref (priv->model);
470
471 G_OBJECT_CLASS (parent_class)->finalize (object);
472 }
473
474 /*************/
475 /* internals */
476 /*************/
477 static void
show_custom_controls(XfburnComposition * composition)478 show_custom_controls (XfburnComposition *composition)
479 {
480 DBG ("show");
481 }
482
483 static void
hide_custom_controls(XfburnComposition * composition)484 hide_custom_controls (XfburnComposition *composition)
485 {
486 DBG ("hide");
487 }
488
489 static void
cb_begin_burn(XfburnDataDiscUsage * du,XfburnDataComposition * dc)490 cb_begin_burn (XfburnDataDiscUsage * du, XfburnDataComposition * dc)
491 {
492 XfburnMainWindow *mainwin = xfburn_main_window_get_instance ();
493 GtkWidget *dialog = NULL;
494 IsoImage *image = NULL;
495
496 if (!iso_init()) {
497 g_critical ("Could not initialize libisofs!");
498 return;
499 }
500
501 image = generate_iso_image (XFBURN_DATA_COMPOSITION (dc));
502
503 switch (xfburn_disc_usage_get_disc_type (XFBURN_DISC_USAGE (du))) {
504 case CD_DISC:
505 dialog = xfburn_burn_data_cd_composition_dialog_new (image, has_default_name (dc));
506 break;
507 case DVD_DISC:
508 dialog = xfburn_burn_data_dvd_composition_dialog_new (image);
509 break;
510 }
511
512 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwin));
513 gtk_dialog_run (GTK_DIALOG (dialog));
514 gtk_widget_destroy (dialog);
515 }
516
517 static void
cb_treeview_row_activated(GtkTreeView * treeview,GtkTreePath * path,GtkTreeViewColumn * column,XfburnDataComposition * composition)518 cb_treeview_row_activated (GtkTreeView * treeview, GtkTreePath * path, GtkTreeViewColumn * column,
519 XfburnDataComposition * composition)
520 {
521 gtk_tree_view_expand_row (treeview, path, FALSE);
522 }
523
524 static void
cb_selection_changed(GtkTreeSelection * selection,XfburnDataComposition * dc)525 cb_selection_changed (GtkTreeSelection *selection, XfburnDataComposition * dc)
526 {
527 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
528 gint n_selected_rows;
529 GAction* action[] = {
530 g_action_map_lookup_action (G_ACTION_MAP (priv->action_group), "add-file"),
531 g_action_map_lookup_action (G_ACTION_MAP (priv->action_group), "create-dir"),
532 g_action_map_lookup_action (G_ACTION_MAP (priv->action_group), "remove-file"),
533 };
534
535 n_selected_rows = gtk_tree_selection_count_selected_rows (selection);
536 if (n_selected_rows == 0) {
537 g_simple_action_set_enabled (G_SIMPLE_ACTION (action[0]), TRUE);
538 g_simple_action_set_enabled (G_SIMPLE_ACTION (action[1]), TRUE);
539 g_simple_action_set_enabled (G_SIMPLE_ACTION (action[2]), FALSE);
540 } else if (n_selected_rows == 1) {
541 g_simple_action_set_enabled (G_SIMPLE_ACTION (action[0]), TRUE);
542 g_simple_action_set_enabled (G_SIMPLE_ACTION (action[1]), TRUE);
543 g_simple_action_set_enabled (G_SIMPLE_ACTION (action[2]), TRUE);
544 } else {
545 g_simple_action_set_enabled (G_SIMPLE_ACTION (action[0]), FALSE);
546 g_simple_action_set_enabled (G_SIMPLE_ACTION (action[1]), FALSE);
547 g_simple_action_set_enabled (G_SIMPLE_ACTION (action[2]), TRUE);
548 }
549 }
550
551 static gboolean
cb_treeview_button_pressed(GtkTreeView * treeview,GdkEventButton * event,XfburnDataComposition * dc)552 cb_treeview_button_pressed (GtkTreeView * treeview, GdkEventButton * event, XfburnDataComposition * dc)
553 {
554 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
555
556 if ((event->button == 1) && (event->type == GDK_BUTTON_PRESS)) {
557 GtkTreePath *path;
558
559 if (gtk_tree_view_get_path_at_pos (treeview, event->x, event->y, &path, NULL, NULL, NULL)) {
560 gtk_tree_path_free (path);
561 } else {
562 GtkTreeSelection *selection;
563
564 selection = gtk_tree_view_get_selection (treeview);
565 gtk_tree_selection_unselect_all (selection);
566 }
567
568 return FALSE;
569 }
570
571 if ((event->button == 3) && (event->type == GDK_BUTTON_PRESS)) {
572 GtkTreeSelection *selection;
573 GtkTreePath *path;
574 GMenuModel *model;
575 GtkWidget *menu_popup;
576 GtkWidget *menuitem_remove;
577 GtkWidget *menuitem_rename;
578
579 selection = gtk_tree_view_get_selection (treeview);
580
581 if (gtk_tree_view_get_path_at_pos (treeview, event->x, event->y, &path, NULL, NULL, NULL)) {
582 gtk_tree_selection_unselect_all (selection);
583 gtk_tree_selection_select_path (selection, path);
584 gtk_tree_path_free (path);
585 }
586
587 model = G_MENU_MODEL (gtk_builder_get_object (priv->ui_manager, "data-popup-menu"));
588 menu_popup = gtk_menu_new_from_model (model);
589 gtk_widget_insert_action_group(GTK_WIDGET(menu_popup), "win", G_ACTION_GROUP(priv->action_group));
590
591 GList *childs = gtk_container_get_children (GTK_CONTAINER (menu_popup));
592 menuitem_remove = GTK_WIDGET (childs->next->next->data);
593 menuitem_rename = GTK_WIDGET (childs->next->data);
594
595 if (gtk_tree_selection_count_selected_rows (selection) >= 1)
596 gtk_widget_set_sensitive (menuitem_remove, TRUE);
597 else
598 gtk_widget_set_sensitive (menuitem_remove, FALSE);
599 if (gtk_tree_selection_count_selected_rows (selection) == 1)
600 gtk_widget_set_sensitive (menuitem_rename, TRUE);
601 else
602 gtk_widget_set_sensitive (menuitem_rename, FALSE);
603
604 GdkRectangle r = {event->x, event->y, 1, 1};
605 gtk_menu_popup_at_rect (GTK_MENU (menu_popup),
606 gtk_widget_get_parent_window (GTK_WIDGET (treeview)),
607 &r, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL);
608 return TRUE;
609 }
610
611 return FALSE;
612 }
613
614 static gint
directory_tree_sortfunc(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)615 directory_tree_sortfunc (GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data)
616 {
617 /* adapted from gnomebaker */
618 gchar *aname, *bname;
619 DataCompositionEntryType atype = -1, btype = -1;
620 gint result = 0;
621
622 gtk_tree_model_get (model, a, DATA_COMPOSITION_COLUMN_CONTENT, &aname, DATA_COMPOSITION_COLUMN_TYPE, &atype, -1);
623 gtk_tree_model_get (model, b, DATA_COMPOSITION_COLUMN_CONTENT, &bname, DATA_COMPOSITION_COLUMN_TYPE, &btype, -1);
624
625 if ( (atype == DATA_COMPOSITION_TYPE_DIRECTORY) && (btype != DATA_COMPOSITION_TYPE_DIRECTORY) )
626 result = -1;
627 else if ( (atype != DATA_COMPOSITION_TYPE_DIRECTORY) && (btype == DATA_COMPOSITION_TYPE_DIRECTORY) )
628 result = 1;
629 else
630 result = g_ascii_strcasecmp (aname, bname);
631
632 g_free (aname);
633 g_free (bname);
634
635 return result;
636 }
637
638 static gboolean
file_exists_on_same_level(GtkTreeModel * model,GtkTreePath * path,gboolean skip_path,const gchar * filename)639 file_exists_on_same_level (GtkTreeModel * model, GtkTreePath * path, gboolean skip_path, const gchar *filename)
640 {
641 GtkTreePath *current_path = NULL;
642 GtkTreeIter current_iter;
643
644 current_path = gtk_tree_path_copy (path);
645 for (;gtk_tree_path_prev (current_path););
646
647 if (gtk_tree_model_get_iter (model, ¤t_iter, current_path)) {
648 do {
649 gchar *current_filename = NULL;
650
651 if (skip_path && gtk_tree_path_compare (path, current_path) == 0) {
652 gtk_tree_path_next (current_path);
653 continue;
654 }
655
656 gtk_tree_model_get (model, ¤t_iter, DATA_COMPOSITION_COLUMN_CONTENT, ¤t_filename, -1);
657 if (strcmp (current_filename, filename) == 0) {
658 g_free (current_filename);
659 gtk_tree_path_free (current_path);
660 return TRUE;
661 }
662
663 g_free (current_filename);
664 gtk_tree_path_next (current_path);
665 } while (gtk_tree_model_iter_next (model, ¤t_iter));
666 }
667
668 gtk_tree_path_free (current_path);
669 return FALSE;
670 }
671
672 static void
cb_cell_file_edited(GtkCellRenderer * renderer,gchar * path,gchar * newtext,XfburnDataComposition * dc)673 cb_cell_file_edited (GtkCellRenderer * renderer, gchar * path, gchar * newtext, XfburnDataComposition * dc)
674 {
675 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
676
677 GtkTreeIter iter;
678 GtkTreeModel *model;
679 GtkTreePath *real_path;
680
681 if (strlen (newtext) == 0) {
682 xfce_dialog_show_error (NULL, NULL, _("You must give a name to the file."));
683 return;
684 }
685
686 model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
687 real_path = gtk_tree_path_new_from_string (path);
688
689 if (gtk_tree_model_get_iter (model, &iter, real_path)) {
690 if (file_exists_on_same_level (model, real_path, TRUE, newtext)) {
691 xfce_dialog_show_error (NULL, NULL, _("A file with the same name is already present in the composition."));
692 }
693 else {
694 gtk_tree_store_set (GTK_TREE_STORE (model), &iter, DATA_COMPOSITION_COLUMN_CONTENT, newtext, -1);
695 }
696 }
697
698 gtk_tree_path_free (real_path);
699 }
700
701 static void
cb_adding_done(XfburnAddingProgress * progress,XfburnDataComposition * dc)702 cb_adding_done (XfburnAddingProgress *progress, XfburnDataComposition *dc)
703 {
704 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
705
706 gtk_widget_hide (priv->progress);
707
708 if (priv->selected_files) {
709 g_free (priv->selected_files);
710 priv->selected_files = NULL;
711 }
712
713 if (priv->path_where_insert) {
714 gtk_tree_path_free (priv->path_where_insert);
715 priv->path_where_insert = NULL;
716 }
717
718 if (priv->full_paths_to_add) {
719 g_list_free_full (priv->full_paths_to_add, (GDestroyNotify) g_free);
720 priv->full_paths_to_add = NULL;
721 }
722
723 g_free (priv->thread_params);
724 xfburn_default_cursor (priv->content);
725 }
726
727 static void
action_rename_selection(GSimpleAction * action,GVariant * param,XfburnDataComposition * dc)728 action_rename_selection (GSimpleAction *action, GVariant *param, XfburnDataComposition *dc)
729 {
730 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
731
732 GtkTreeSelection *selection;
733 GtkTreeModel *model;
734 GList *list;
735 GtkTreePath *path;
736 GtkTreeViewColumn *column;
737
738 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->content));
739 list = gtk_tree_selection_get_selected_rows (selection, &model);
740
741 path = (GtkTreePath *) list->data;
742 column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->content), DATA_COMPOSITION_COLUMN_CONTENT - 1);
743 /* -1 because of COLUMN_ICON */
744
745 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->content), path, column, TRUE);
746
747 gtk_tree_path_free (path);
748 g_list_free (list);
749 }
750
751 static void
action_create_directory(GSimpleAction * action,GVariant * param,XfburnDataComposition * dc)752 action_create_directory (GSimpleAction *action, GVariant *param, XfburnDataComposition *dc)
753 {
754 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
755
756 GtkTreeModel *model;
757 GtkTreeSelection *selection;
758 GList *selected_paths = NULL;
759 GtkTreePath *path_where_insert = NULL;
760 GtkTreeIter iter_where_insert, iter_directory;
761 DataCompositionEntryType type = -1;
762 gchar *humansize = NULL;
763
764 GtkTreePath *inserted_path = NULL;
765 gchar *directory_text = NULL;
766
767 GtkTreeViewColumn *column;
768 GtkTreePath *path = NULL;
769
770 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->content));
771 selected_paths = gtk_tree_selection_get_selected_rows (selection, NULL);
772 model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
773
774 if (selected_paths) {
775 path_where_insert = (GtkTreePath *) (selected_paths->data);
776
777 gtk_tree_model_get_iter (model, &iter_where_insert, path_where_insert);
778 gtk_tree_model_get (model, &iter_where_insert, DATA_COMPOSITION_COLUMN_TYPE, &type, -1);
779 }
780
781 if (type == DATA_COMPOSITION_TYPE_DIRECTORY) {
782 gtk_tree_store_append (GTK_TREE_STORE (model), &iter_directory, &iter_where_insert);
783 gtk_tree_view_expand_row (GTK_TREE_VIEW (priv->content), path_where_insert, FALSE);
784 } else if (type == DATA_COMPOSITION_TYPE_FILE) {
785 GtkTreeIter parent;
786
787 if (gtk_tree_model_iter_parent (model, &parent, &iter_where_insert))
788 gtk_tree_store_append (GTK_TREE_STORE (model), &iter_directory, &parent);
789 else
790 gtk_tree_store_append (GTK_TREE_STORE (model), &iter_directory, NULL);
791 } else {
792 gtk_tree_store_append (GTK_TREE_STORE (model), &iter_directory, NULL);
793 }
794
795 humansize = xfburn_humanreadable_filesize (4);
796
797 inserted_path = gtk_tree_model_get_path (model, &iter_directory);
798 if (file_exists_on_same_level (model, inserted_path, TRUE, _("New directory")))
799 directory_text = g_strdup_printf ("%s %d", _("New directory"), ++(priv->n_new_directory));
800 else
801 directory_text = g_strdup (_("New directory"));
802 gtk_tree_path_free (inserted_path);
803
804 gtk_tree_store_set (GTK_TREE_STORE (model), &iter_directory,
805 DATA_COMPOSITION_COLUMN_ICON, icon_directory,
806 DATA_COMPOSITION_COLUMN_CONTENT, directory_text,
807 DATA_COMPOSITION_COLUMN_HUMANSIZE, humansize,
808 DATA_COMPOSITION_COLUMN_SIZE, (guint64) 4,
809 DATA_COMPOSITION_COLUMN_TYPE, DATA_COMPOSITION_TYPE_DIRECTORY, -1);
810 g_free (directory_text);
811 g_free (humansize);
812
813 xfburn_disc_usage_add_size (XFBURN_DISC_USAGE (priv->disc_usage), 4);
814
815 gtk_widget_realize (priv->content);
816
817 /* put the cell renderer in edition mode */
818 column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->content), DATA_COMPOSITION_COLUMN_CONTENT - 1);
819 /* -1 because of COLUMN_ICON */
820 path = gtk_tree_model_get_path (model, &iter_directory);
821
822 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->content), path, column, TRUE);
823 gtk_tree_path_free (path);
824 }
825
826 static void
remove_row_reference(GtkTreeRowReference * reference,XfburnDataCompositionPrivate * priv)827 remove_row_reference (GtkTreeRowReference *reference, XfburnDataCompositionPrivate *priv)
828 {
829 GtkTreePath *path = NULL;
830 GtkTreeModel *model;
831
832 model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
833
834 path = gtk_tree_row_reference_get_path (reference);
835 if (path) {
836 GtkTreeIter iter;
837
838 if (gtk_tree_model_get_iter (model, &iter, path)) {
839 GtkTreeIter parent, iter_temp;
840 guint64 size = 0;
841
842 gtk_tree_model_get (model, &iter, DATA_COMPOSITION_COLUMN_SIZE, &size, -1);
843 xfburn_disc_usage_sub_size (XFBURN_DISC_USAGE (priv->disc_usage), size);
844
845 iter_temp = iter;
846 while (gtk_tree_model_iter_parent (model, &parent, &iter_temp)) {
847 guint64 old_size;
848 gchar *humansize = NULL;
849
850 /* updates parent directories size */
851 gtk_tree_model_get (model, &parent, DATA_COMPOSITION_COLUMN_SIZE, &old_size, -1);
852
853 humansize = xfburn_humanreadable_filesize (old_size - size);
854 gtk_tree_store_set (GTK_TREE_STORE (model), &parent,
855 DATA_COMPOSITION_COLUMN_HUMANSIZE, humansize,
856 DATA_COMPOSITION_COLUMN_SIZE, old_size - size, -1);
857
858 iter_temp = parent;
859
860 g_free (humansize);
861 }
862
863 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
864 }
865
866 gtk_tree_path_free (path);
867 }
868
869 gtk_tree_row_reference_free (reference);
870 }
871
872 static void
action_remove_selection(GSimpleAction * action,GVariant * param,XfburnDataComposition * dc)873 action_remove_selection (GSimpleAction *action, GVariant *param, XfburnDataComposition *dc)
874 {
875 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
876
877 GtkTreeSelection *selection;
878 GtkTreeModel *model;
879 GList *list_paths = NULL, *el;
880 GList *references = NULL;
881
882 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->content));
883 list_paths = gtk_tree_selection_get_selected_rows (selection, &model);
884
885 el = list_paths;
886 while (el) {
887 GtkTreePath *path = NULL;
888 GtkTreeRowReference *reference = NULL;
889
890 path = (GtkTreePath *) el->data;
891 reference = gtk_tree_row_reference_new (model, path);
892 gtk_tree_path_free (path);
893
894 if (reference)
895 references = g_list_prepend (references, reference);
896
897 el = g_list_next (el);
898 }
899 g_list_free (list_paths);
900
901 g_list_foreach (references, (GFunc) remove_row_reference, priv);
902 g_list_free (references);
903 }
904
905 static void
add_cb(GtkWidget * widget,gpointer data)906 add_cb (GtkWidget * widget, gpointer data)
907 {
908 XfburnDataComposition * dc = XFBURN_DATA_COMPOSITION(data);
909 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
910 gchar *selected_files = NULL;
911
912 GSList *list = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (priv->add_filechooser));
913 GString * str = g_string_new(NULL);
914 GSList * curr;
915
916 priv->last_directory = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER(priv->add_filechooser));
917
918 for (curr = list; curr!=NULL; curr = curr->next) {
919 g_string_append(str, curr->data);
920 g_string_append_c(str, '\n');;
921 }
922
923 g_slist_free_full (list, g_free);
924 selected_files = str->str;
925 g_string_free (str, FALSE);
926 DBG("selected files: %s ", selected_files);
927
928 gtk_widget_destroy (priv->add_window);
929
930 add_files (selected_files, dc);
931 }
932
933 static void
select_files(XfburnDataComposition * dc)934 select_files (XfburnDataComposition * dc)
935 {
936 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
937
938 GtkWidget * window;
939 GtkWidget * add_button;
940 GtkWidget * vbox;
941 GtkWidget * bbox;
942
943 priv->add_window = window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
944 gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DIALOG);
945 gtk_window_set_title (GTK_WINDOW(window), _("File(s) to add to composition"));
946 gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER); // GTK_WINDOW(xfburn_main_window_get_instance()),
947 gtk_container_set_border_width (GTK_CONTAINER(window), 10);
948 gtk_window_set_default_size(GTK_WINDOW(window), 600, 400);
949
950 priv->add_filechooser = gtk_file_chooser_widget_new (GTK_FILE_CHOOSER_ACTION_OPEN);
951
952 gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(priv->add_filechooser), TRUE);
953
954 if(xfburn_main_has_initial_dir ()) {
955 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(priv->add_filechooser), xfburn_main_get_initial_dir ());
956 }
957
958 if (priv->last_directory)
959 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(priv->add_filechooser), priv->last_directory);
960
961 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
962 gtk_container_add(GTK_CONTAINER(window), vbox);
963
964 gtk_box_pack_start(GTK_BOX(vbox), priv->add_filechooser, TRUE, TRUE, 3);
965
966 add_button = gtk_button_new_with_label (_("Add"));
967 g_signal_connect (add_button, "clicked", G_CALLBACK(add_cb), dc);
968 g_signal_connect (priv->add_filechooser, "file-activated", G_CALLBACK(add_cb), dc);
969
970 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
971 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
972 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 3);
973
974 gtk_box_pack_end(GTK_BOX(bbox), add_button, FALSE, FALSE, 3);
975
976 g_signal_connect(window, "destroy",
977 G_CALLBACK(gtk_widget_destroyed), &window);
978
979 gtk_widget_show_all (window);
980 }
981
982 static void
action_add_or_select(GSimpleAction * action,GVariant * param,XfburnDataComposition * dc)983 action_add_or_select (GSimpleAction *action, GVariant *param, XfburnDataComposition *dc)
984 {
985 if (xfburn_settings_get_boolean("show-filebrowser", FALSE)) {
986 XfburnFileBrowser *browser = xfburn_main_window_get_file_browser (xfburn_main_window_get_instance ());
987
988 add_files (xfburn_file_browser_get_selection (browser), dc);
989 } else {
990 select_files(dc);
991 }
992 }
993
994 static void
add_files(gchar * selected_files,XfburnDataComposition * dc)995 add_files(gchar * selected_files, XfburnDataComposition *dc)
996 {
997 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
998
999 xfburn_busy_cursor (priv->content);
1000 if (selected_files) {
1001 GtkTreeSelection *selection;
1002 GList *selected_paths = NULL;
1003 ThreadAddFilesActionParams *params;
1004
1005 xfburn_adding_progress_show (XFBURN_ADDING_PROGRESS (priv->progress));
1006
1007 params = g_new (ThreadAddFilesActionParams, 1);
1008 params->dc = dc;
1009 params->type = -1;
1010 priv->path_where_insert = NULL;
1011
1012 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->content));
1013 selected_paths = gtk_tree_selection_get_selected_rows (selection, NULL);
1014 params->model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
1015
1016 if (selected_paths) {
1017 priv->path_where_insert = gtk_tree_path_copy ((GtkTreePath *) (selected_paths->data));
1018
1019 gtk_tree_model_get_iter (params->model, ¶ms->iter_where_insert, priv->path_where_insert);
1020 gtk_tree_model_get (params->model, ¶ms->iter_where_insert, DATA_COMPOSITION_COLUMN_TYPE, ¶ms->type, -1);
1021 }
1022
1023 priv->selected_files = selected_files;
1024
1025 priv->thread_params = params;
1026 g_thread_new ("data_add_files", (GThreadFunc) thread_add_files_action, params);
1027
1028 g_list_free_full (selected_paths, (GDestroyNotify) gtk_tree_path_free);
1029 }
1030 }
1031
1032 static void
set_default_name(XfburnDataComposition * dc)1033 set_default_name (XfburnDataComposition * dc)
1034 {
1035 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
1036
1037 char timestr[80];
1038 struct tm *today;
1039 time_t tm;
1040 /* FIXME: put i into the class? */
1041 static int i = 0;
1042
1043 tm = time (NULL);
1044 today = localtime (&tm);
1045
1046 if (priv->default_vol_name)
1047 g_free (priv->default_vol_name);
1048
1049 if (tm && strftime (timestr, 80, "%Y-%m-%d", today))
1050 /* Note to translators: first %s is the date in "i18n" format (year-month-day), %d is a running number of compositions */
1051 priv->default_vol_name = g_strdup_printf (_("Data %s~%d"), timestr, ++i);
1052 else
1053 priv->default_vol_name = g_strdup_printf ("%s %d", _(DATA_COMPOSITION_DEFAULT_NAME), ++i);
1054
1055 gtk_entry_set_text (GTK_ENTRY (priv->entry_volume_name), priv->default_vol_name);
1056 }
1057
1058 static gboolean
has_default_name(XfburnDataComposition * dc)1059 has_default_name (XfburnDataComposition * dc)
1060 {
1061 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
1062
1063 const gchar *name;
1064
1065 name = gtk_entry_get_text (GTK_ENTRY (priv->entry_volume_name));
1066
1067 return strcmp (name, priv->default_vol_name) == 0;
1068 }
1069
1070 static void
action_clear(GSimpleAction * action,GVariant * param,XfburnDataComposition * dc)1071 action_clear (GSimpleAction *action, GVariant *param, XfburnDataComposition *dc)
1072 {
1073 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
1074
1075 GtkTreeModel *model;
1076
1077 model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
1078 gtk_tree_store_clear (GTK_TREE_STORE (model));
1079
1080 set_default_name (dc);
1081
1082 xfburn_disc_usage_set_size (XFBURN_DISC_USAGE (priv->disc_usage), 0);
1083 }
1084
1085 static void
cb_content_drag_data_get(GtkWidget * widget,GdkDragContext * dc,GtkSelectionData * data,guint info,guint timestamp,XfburnDataComposition * content)1086 cb_content_drag_data_get (GtkWidget * widget, GdkDragContext * dc,
1087 GtkSelectionData * data, guint info, guint timestamp, XfburnDataComposition * content)
1088 {
1089 if (info == DATA_COMPOSITION_DND_TARGET_INSIDE) {
1090 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1091 GtkTreeModel *model;
1092 GList *selected_rows = NULL, *row = NULL;
1093 GList *references = NULL;
1094
1095 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1096
1097 row = selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
1098
1099 while (row) {
1100 GtkTreeRowReference *reference = NULL;
1101 GtkTreePath *temp;
1102
1103 temp = (GtkTreePath *) row->data;
1104 reference = gtk_tree_row_reference_new (model, temp);
1105 gtk_tree_path_free (temp);
1106
1107 references = g_list_prepend (references, reference);
1108
1109 row = g_list_next (row);
1110 }
1111
1112 g_list_free (selected_rows);
1113
1114 gtk_selection_data_set (data, gdk_atom_intern ("XFBURN_TREE_PATHS", FALSE), 8, (const guchar *) &references,
1115 sizeof (GList **));
1116 }
1117 }
1118
1119 static void
set_modified(XfburnDataCompositionPrivate * priv)1120 set_modified (XfburnDataCompositionPrivate *priv)
1121 {
1122 if (!(priv->modified)) {
1123 /*
1124 XfburnMainWindow *mainwin;
1125 GtkUIManager *ui_manager;
1126 GtkActionGroup *action_group;
1127
1128 mainwin = xfburn_main_window_get_instance ();
1129 ui_manager = xfburn_main_window_get_ui_manager (mainwin);
1130
1131 action_group = (GtkActionGroup *) gtk_ui_manager_get_action_groups (ui_manager)->data;
1132
1133 action = gtk_action_group_get_action (action_group, "save-composition");
1134 gtk_action_set_sensitive (GTK_ACTION (action), TRUE);
1135 */
1136 priv->modified = TRUE;
1137 }
1138 }
1139
1140 static gboolean
thread_add_file_to_list_with_name(const gchar * name,XfburnDataComposition * dc,GtkTreeModel * model,const gchar * path,GtkTreeIter * iter,GtkTreeIter * insertion,GtkTreeViewDropPosition position)1141 thread_add_file_to_list_with_name (const gchar *name, XfburnDataComposition * dc,
1142 GtkTreeModel * model, const gchar * path,
1143 GtkTreeIter * iter, GtkTreeIter * insertion, GtkTreeViewDropPosition position)
1144 {
1145 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
1146
1147 struct stat s;
1148
1149 if ((g_lstat (path, &s) == 0)) {
1150 gchar *humansize = NULL;
1151 GtkTreeIter *parent = NULL;
1152 GtkTreePath *tree_path = NULL;
1153 int parent_type = 0;
1154
1155 if (!(S_ISDIR (s.st_mode) ||S_ISREG (s.st_mode) || S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode) || S_ISLNK (s.st_mode))) {
1156 return FALSE;
1157 }
1158
1159 xfburn_adding_progress_pulse (XFBURN_ADDING_PROGRESS (priv->progress));
1160
1161 /* ensure that we can only drop on top of folders, not files */
1162 if (insertion) {
1163 gdk_threads_enter ();
1164 gtk_tree_model_get (model, insertion, DATA_COMPOSITION_COLUMN_TYPE, &parent_type, -1);
1165 gdk_threads_leave ();
1166
1167 if (parent_type == DATA_COMPOSITION_TYPE_FILE) {
1168 DBG ("Parent is file, and we're dropping into %d", position);
1169 if (position == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
1170 position = GTK_TREE_VIEW_DROP_AFTER;
1171 else if (position == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
1172 position = GTK_TREE_VIEW_DROP_BEFORE;
1173 }
1174 }
1175
1176 /* find parent */
1177 switch (position){
1178 case GTK_TREE_VIEW_DROP_BEFORE:
1179 case GTK_TREE_VIEW_DROP_AFTER:
1180 if (insertion) {
1181 GtkTreeIter iter_parent;
1182
1183 gdk_threads_enter ();
1184 if (gtk_tree_model_iter_parent (model, &iter_parent, insertion)) {
1185 parent = g_new0 (GtkTreeIter, 1);
1186 memcpy (parent, &iter_parent, sizeof (GtkTreeIter));
1187 }
1188 gdk_threads_leave ();
1189 }
1190 break;
1191 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
1192 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
1193 parent = g_new0 (GtkTreeIter, 1);
1194 memcpy (parent, insertion, sizeof (GtkTreeIter));
1195 break;
1196 }
1197
1198 /* check if the filename is valid */
1199 gdk_threads_enter ();
1200 if (parent) {
1201 tree_path = gtk_tree_model_get_path (model, parent);
1202 gtk_tree_path_down (tree_path);
1203 } else {
1204 tree_path = gtk_tree_path_new_first ();
1205 }
1206
1207 if (file_exists_on_same_level (model, tree_path, FALSE, name)) {
1208 xfce_dialog_show_error (NULL, NULL, _("A file with the same name is already present in the composition."));
1209
1210 gtk_tree_path_free (tree_path);
1211 gdk_threads_leave ();
1212 g_free (parent);
1213 return FALSE;
1214 }
1215 gtk_tree_path_free (tree_path);
1216 gdk_threads_leave ();
1217
1218 /* new directory */
1219 if (S_ISDIR (s.st_mode) && !S_ISLNK (s.st_mode)) {
1220 GDir *dir = NULL;
1221 GError *error = NULL;
1222 const gchar *filename = NULL;
1223 guint64 total_size = 4;
1224
1225 dir = g_dir_open (path, 0, &error);
1226 if (!dir) {
1227 g_warning ("unable to open directory : %s", error->message);
1228
1229 g_error_free (error);
1230 g_free (parent);
1231
1232 return FALSE;
1233 }
1234
1235 gdk_threads_enter ();
1236 gtk_tree_store_append (GTK_TREE_STORE (model), iter, parent);
1237
1238 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
1239 DATA_COMPOSITION_COLUMN_ICON, icon_directory,
1240 DATA_COMPOSITION_COLUMN_CONTENT, name,
1241 DATA_COMPOSITION_COLUMN_TYPE, DATA_COMPOSITION_TYPE_DIRECTORY,
1242 DATA_COMPOSITION_COLUMN_PATH, path,
1243 DATA_COMPOSITION_COLUMN_SIZE, (guint64) 4, -1);
1244 xfburn_disc_usage_add_size (XFBURN_DISC_USAGE (priv->disc_usage), (guint64) 4);
1245 gdk_threads_leave ();
1246
1247 while ((filename = g_dir_read_name (dir))) {
1248 GtkTreeIter new_iter;
1249 gchar *new_path = NULL;
1250
1251 new_path = g_build_filename (path, filename, NULL);
1252 if (new_path) {
1253 guint64 size;
1254
1255 if (thread_add_file_to_list (dc, model, new_path, &new_iter, iter, GTK_TREE_VIEW_DROP_INTO_OR_AFTER)) {
1256 gdk_threads_enter ();
1257 gtk_tree_model_get (model, &new_iter, DATA_COMPOSITION_COLUMN_SIZE, &size, -1);
1258 gdk_threads_leave ();
1259 total_size += size;
1260 }
1261
1262 g_free (new_path);
1263 }
1264 }
1265
1266 humansize = xfburn_humanreadable_filesize (total_size);
1267 gdk_threads_enter ();
1268 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
1269 DATA_COMPOSITION_COLUMN_HUMANSIZE, humansize, DATA_COMPOSITION_COLUMN_SIZE, total_size, -1);
1270 gdk_threads_leave ();
1271
1272 g_dir_close (dir);
1273 }
1274 /* new file */
1275 else if (S_ISREG (s.st_mode) || S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode) || S_ISLNK (s.st_mode)) {
1276 GdkScreen *screen;
1277 GtkIconTheme *icon_theme;
1278 GdkPixbuf *mime_icon_pixbuf = NULL;
1279 gint x,y;
1280 GFile *file = NULL;
1281 GFileInfo *info = NULL;
1282 GIcon *mime_icon = NULL;
1283 GtkIconInfo *icon_info = NULL;
1284
1285 if (s.st_size > MAXIMUM_ISO_FILE_SIZE) {
1286 gdk_threads_enter ();
1287 xfce_dialog_show_error (NULL, NULL, _("%s cannot be added to the composition, because it exceeds the maximum allowed file size for iso9660."), path);
1288 gdk_threads_leave ();
1289
1290 return FALSE;
1291 } else if (s.st_size > MAXIMUM_ISO_LEVEL_2_FILE_SIZE && !priv->large_files) {
1292 priv->large_files = TRUE;
1293 gdk_threads_enter ();
1294 xfce_dialog_show_warning (NULL, NULL, _("%s is larger than what iso9660 level 2 allows. This can be a problem for old systems or software."), path);
1295 gdk_threads_leave ();
1296 }
1297
1298 gdk_threads_enter ();
1299 screen = gtk_widget_get_screen (GTK_WIDGET (dc));
1300 icon_theme = gtk_icon_theme_get_for_screen (screen);
1301 gtk_icon_size_lookup (GTK_ICON_SIZE_SMALL_TOOLBAR, &x, &y);
1302
1303 file = g_file_new_for_path(path);
1304 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
1305 mime_icon = g_content_type_get_icon (g_file_info_get_content_type (info));
1306 if (mime_icon != NULL) {
1307 icon_info = gtk_icon_theme_lookup_by_gicon (icon_theme, mime_icon, x, GTK_ICON_LOOKUP_USE_BUILTIN);
1308 if (icon_info != NULL) {
1309 mime_icon_pixbuf = gtk_icon_info_load_icon (icon_info, NULL);
1310 g_object_unref (G_OBJECT (icon_info));
1311 }
1312 }
1313
1314 gtk_tree_store_append (GTK_TREE_STORE (model), iter, parent);
1315
1316 humansize = xfburn_humanreadable_filesize (s.st_size);
1317
1318 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
1319 DATA_COMPOSITION_COLUMN_ICON, (G_IS_OBJECT (mime_icon_pixbuf) ? mime_icon_pixbuf : icon_file),
1320 DATA_COMPOSITION_COLUMN_CONTENT, name,
1321 DATA_COMPOSITION_COLUMN_HUMANSIZE, humansize,
1322 DATA_COMPOSITION_COLUMN_SIZE, (guint64) s.st_size,
1323 DATA_COMPOSITION_COLUMN_PATH, path,
1324 DATA_COMPOSITION_COLUMN_TYPE, DATA_COMPOSITION_TYPE_FILE, -1);
1325
1326 xfburn_disc_usage_add_size (XFBURN_DISC_USAGE (priv->disc_usage), s.st_size);
1327
1328 if (G_LIKELY (G_IS_OBJECT (mime_icon)))
1329 g_object_unref (mime_icon);
1330 if (G_LIKELY (G_IS_OBJECT (file)))
1331 g_object_unref(file);
1332 gdk_threads_leave ();
1333 }
1334 g_free (humansize);
1335 g_free (parent);
1336
1337 set_modified (priv);
1338 return TRUE;
1339 }
1340
1341 return FALSE;
1342 }
1343
1344 /* thread entry point */
1345 static gpointer
thread_add_files_cli(ThreadAddFilesCLIParams * params)1346 thread_add_files_cli (ThreadAddFilesCLIParams *params)
1347 {
1348 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (params->dc);
1349 GtkTreeIter iter;
1350
1351 GtkTreeModel *model;
1352 GSList * list_iter;
1353
1354 gdk_threads_enter ();
1355 model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
1356 gdk_threads_leave ();
1357
1358 for (list_iter = params->filelist; list_iter != NULL; list_iter = g_slist_next (list_iter)) {
1359 gchar * full_path = (gchar *) list_iter->data;
1360
1361 g_message ("Adding %s to the data composition... (might take a while)", full_path);
1362 thread_add_file_to_list (params->dc, model, full_path, &iter, NULL, GTK_TREE_VIEW_DROP_AFTER);
1363
1364 g_free (full_path);
1365 }
1366 g_slist_free (params->filelist);
1367 xfburn_adding_progress_done (XFBURN_ADDING_PROGRESS (priv->progress));
1368 return NULL;
1369 }
1370
1371 static gboolean
show_add_home_question_dialog(void)1372 show_add_home_question_dialog (void)
1373 {
1374 gboolean ok = TRUE;
1375
1376 gdk_threads_enter ();
1377 DBG ("Adding home directory");
1378 ok = xfburn_ask_yes_no (GTK_MESSAGE_WARNING, ((const gchar *) _("Adding home directory")),
1379 _("You are about to add your home directory to the composition. " \
1380 "This is likely to take a very long time, and also to be too big to fit on one disc.\n\n" \
1381 "Are you sure you want to proceed?")
1382 );
1383
1384 gdk_threads_leave ();
1385
1386 return ok;
1387 }
1388
1389 /* thread entry point */
1390 static gpointer
thread_add_files_action(ThreadAddFilesActionParams * params)1391 thread_add_files_action (ThreadAddFilesActionParams *params)
1392 {
1393 XfburnDataComposition *dc = params->dc;
1394 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
1395 GtkTreeModel *model = params->model;
1396 GtkTreeIter iter_where_insert = params->iter_where_insert;
1397 GtkTreePath *path_where_insert = priv->path_where_insert;
1398 gchar ** files = NULL;
1399 int i;
1400
1401
1402 files = g_strsplit (priv->selected_files, "\n", -1);
1403
1404 if (files)
1405 for (i=0; files[i] != NULL && files[i][0] != '\0'; i++) {
1406 GtkTreeIter iter;
1407 gchar *full_path = NULL;
1408
1409 if (g_str_has_prefix (files[i], "file://"))
1410 full_path = g_build_filename (&files[i][7], NULL);
1411 else if (g_str_has_prefix (files[i], "file:"))
1412 full_path = g_build_filename (&files[i][5], NULL);
1413 else
1414 full_path = g_build_filename (files[i], NULL);
1415
1416 if (full_path[strlen (full_path) - 1] == '\r')
1417 full_path[strlen (full_path) - 1] = '\0';
1418
1419 if (strcmp (full_path, g_getenv ("HOME")) == 0) {
1420 if (!show_add_home_question_dialog ()) {
1421 g_free (full_path);
1422 break;
1423 }
1424 }
1425
1426 /* add files to the disc content */
1427 if (params->type == DATA_COMPOSITION_TYPE_DIRECTORY) {
1428 guint64 old_size, size;
1429 gchar *humansize = NULL;
1430
1431 thread_add_file_to_list (dc, model, full_path, &iter, &iter_where_insert, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
1432 gdk_threads_enter ();
1433 gtk_tree_view_expand_row (GTK_TREE_VIEW (priv->content), path_where_insert, FALSE);
1434
1435 /* update parent directory size */
1436 gtk_tree_model_get (model, &iter_where_insert, DATA_COMPOSITION_COLUMN_SIZE, &old_size, -1);
1437 gtk_tree_model_get (model, &iter, DATA_COMPOSITION_COLUMN_SIZE, &size, -1);
1438 gdk_threads_leave ();
1439
1440 humansize = xfburn_humanreadable_filesize (old_size + size);
1441
1442 gdk_threads_enter ();
1443 gtk_tree_store_set (GTK_TREE_STORE (model), &iter_where_insert,
1444 DATA_COMPOSITION_COLUMN_HUMANSIZE, humansize,
1445 DATA_COMPOSITION_COLUMN_SIZE, old_size + size, -1);
1446 gdk_threads_leave ();
1447
1448 g_free (humansize);
1449 } else if (params->type == DATA_COMPOSITION_TYPE_FILE) {
1450 GtkTreeIter parent;
1451 gboolean has_parent;
1452
1453 gdk_threads_enter ();
1454 has_parent = gtk_tree_model_iter_parent (model, &parent, &iter_where_insert);
1455 gdk_threads_leave ();
1456
1457 if (has_parent)
1458 thread_add_file_to_list (dc, model, full_path, &iter, &parent, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
1459 else
1460 thread_add_file_to_list (dc, model, full_path, &iter, NULL, GTK_TREE_VIEW_DROP_AFTER);
1461 } else {
1462 thread_add_file_to_list (dc, model, full_path, &iter, NULL, GTK_TREE_VIEW_DROP_AFTER);
1463 }
1464
1465 g_free (full_path);
1466 }
1467 /* end if files */
1468
1469 g_strfreev (files);
1470
1471 xfburn_adding_progress_done (XFBURN_ADDING_PROGRESS (priv->progress));
1472 return NULL;
1473 }
1474
1475 static gboolean
thread_add_file_to_list(XfburnDataComposition * dc,GtkTreeModel * model,const gchar * path,GtkTreeIter * iter,GtkTreeIter * insertion,GtkTreeViewDropPosition position)1476 thread_add_file_to_list (XfburnDataComposition * dc, GtkTreeModel * model,
1477 const gchar * path, GtkTreeIter * iter, GtkTreeIter * insertion, GtkTreeViewDropPosition position)
1478 {
1479 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
1480 struct stat s;
1481 gboolean ret = FALSE;
1482
1483 if (xfburn_adding_progress_is_aborted (XFBURN_ADDING_PROGRESS (priv->progress))) {
1484 DBG ("Adding aborted");
1485 xfburn_adding_progress_done (XFBURN_ADDING_PROGRESS (priv->progress));
1486 /* FIXME: does this properly release the resources allocated in this thread? */
1487 g_thread_exit (NULL);
1488 }
1489
1490 if ((stat (path, &s) == 0)) {
1491 gchar *basename = NULL;
1492
1493 basename = g_path_get_basename (path);
1494
1495 ret = thread_add_file_to_list_with_name (basename, dc, model, path, iter, insertion, position);
1496
1497 g_free (basename);
1498 }
1499
1500 return ret;
1501 }
1502
1503 static gboolean
copy_entry_to(XfburnDataComposition * dc,GtkTreeIter * src,GtkTreeIter * dest,GtkTreeViewDropPosition position)1504 copy_entry_to (XfburnDataComposition *dc, GtkTreeIter *src, GtkTreeIter *dest, GtkTreeViewDropPosition position)
1505 {
1506 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
1507
1508 gboolean ret = FALSE;
1509
1510 GtkTreeModel *model;
1511 GtkTreeIter iter_new;
1512
1513 GdkPixbuf *icon = NULL;
1514 gchar *name = NULL;
1515 gchar *humansize = NULL;
1516 guint64 size = 0;
1517 gchar *path = NULL;
1518 DataCompositionEntryType type;
1519
1520 GtkTreePath *path_level = NULL;
1521
1522 guint n_children = 0;
1523 guint i;
1524 GtkTreePath *path_src = NULL;
1525
1526 model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
1527
1528 gtk_tree_model_get (model, src, DATA_COMPOSITION_COLUMN_ICON, &icon, DATA_COMPOSITION_COLUMN_CONTENT, &name,
1529 DATA_COMPOSITION_COLUMN_HUMANSIZE, &humansize, DATA_COMPOSITION_COLUMN_SIZE, &size,
1530 DATA_COMPOSITION_COLUMN_PATH, &path, DATA_COMPOSITION_COLUMN_TYPE, &type, -1);
1531
1532 switch (position) {
1533 case GTK_TREE_VIEW_DROP_BEFORE:
1534 case GTK_TREE_VIEW_DROP_AFTER:
1535 gtk_tree_store_insert_before (GTK_TREE_STORE (model), &iter_new, NULL, dest);
1536 break;
1537 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
1538 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
1539 if (dest) {
1540 path_level = gtk_tree_model_get_path (model, dest);
1541 gtk_tree_path_down (path_level);
1542 } else {
1543 path_level = gtk_tree_path_new_first ();
1544 }
1545
1546 if (file_exists_on_same_level (model, path_level, FALSE, name)) {
1547 xfce_dialog_show_warning(NULL, NULL, _("A file named \"%s\" already exists in this directory, the file hasn't been added."), name);
1548 goto cleanup;
1549 }
1550
1551 gtk_tree_path_free (path_level);
1552
1553 gtk_tree_store_append (GTK_TREE_STORE (model), &iter_new, dest);
1554 break;
1555 }
1556
1557 gtk_tree_store_set (GTK_TREE_STORE (model), &iter_new, DATA_COMPOSITION_COLUMN_ICON, icon,
1558 DATA_COMPOSITION_COLUMN_CONTENT, name, DATA_COMPOSITION_COLUMN_HUMANSIZE, humansize,
1559 DATA_COMPOSITION_COLUMN_SIZE, size, DATA_COMPOSITION_COLUMN_PATH, path,
1560 DATA_COMPOSITION_COLUMN_TYPE, type, -1);
1561
1562 /* copy children */
1563 n_children = gtk_tree_model_iter_n_children (model, src);
1564
1565 for (i = 0; i < n_children; i++) {
1566 GtkTreeIter iter_child;
1567
1568 if (gtk_tree_model_iter_nth_child (model, &iter_child, src, i))
1569 copy_entry_to (dc, &iter_child, &iter_new, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
1570 }
1571
1572 path_src = gtk_tree_model_get_path (model, src);
1573 if (n_children > 0 && gtk_tree_view_row_expanded (GTK_TREE_VIEW (priv->content), path_src)) {
1574 GtkTreePath *path_new = NULL;
1575
1576 path_new = gtk_tree_model_get_path (model, &iter_new);
1577 gtk_tree_view_expand_row (GTK_TREE_VIEW (priv->content), path_new, FALSE);
1578
1579 gtk_tree_path_free (path_new);
1580 }
1581 gtk_tree_path_free (path_src);
1582
1583 ret = TRUE;
1584
1585 cleanup:
1586 if (G_LIKELY (G_IS_OBJECT (icon)))
1587 g_object_unref (icon);
1588 g_free (name);
1589 g_free (humansize);
1590 g_free (path);
1591
1592 return ret;
1593 }
1594
1595 static void
cb_content_drag_data_rcv(GtkWidget * widget,GdkDragContext * dc,guint x,guint y,GtkSelectionData * sd,guint info,guint t,XfburnDataComposition * composition)1596 cb_content_drag_data_rcv (GtkWidget * widget, GdkDragContext * dc, guint x, guint y, GtkSelectionData * sd,
1597 guint info, guint t, XfburnDataComposition * composition)
1598 {
1599 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (composition);
1600
1601 GtkTreeModel *model;
1602 GtkTreePath *path_where_insert = NULL;
1603 GtkTreeViewDropPosition position;
1604 GtkTreeIter iter_where_insert;
1605
1606 g_return_if_fail (sd);
1607 g_return_if_fail (gtk_selection_data_get_data (sd));
1608
1609 model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
1610
1611 gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), x, y, &path_where_insert, &position);
1612
1613 xfburn_busy_cursor (priv->content);
1614
1615 /* move a selection inside of the composition window */
1616 if (gtk_selection_data_get_target(sd) == gdk_atom_intern ("XFBURN_TREE_PATHS", FALSE)) {
1617 GList *row = NULL, *selected_rows = NULL;
1618 GtkTreeIter *iter = NULL;
1619 DataCompositionEntryType type_dest = -1;
1620
1621 xfburn_adding_progress_show (XFBURN_ADDING_PROGRESS (priv->progress));
1622
1623 row = selected_rows = *((GList **) gtk_selection_data_get_data(sd));
1624
1625 if (path_where_insert) {
1626 gtk_tree_model_get_iter (model, &iter_where_insert, path_where_insert);
1627 iter = &iter_where_insert;
1628
1629 gtk_tree_model_get (model, &iter_where_insert, DATA_COMPOSITION_COLUMN_TYPE, &type_dest, -1);
1630
1631 if (type_dest == DATA_COMPOSITION_TYPE_FILE) {
1632 if (position == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
1633 position = GTK_TREE_VIEW_DROP_AFTER;
1634 else if (position == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
1635 position = GTK_TREE_VIEW_DROP_BEFORE;
1636 }
1637 } else {
1638 position = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
1639 }
1640
1641 /* copy selection */
1642 while (row) {
1643 GtkTreePath *path_src = NULL;
1644 GtkTreeIter iter_src;
1645 GtkTreeRowReference *reference = NULL;
1646 DataCompositionEntryType type;
1647 guint64 size = 0;
1648
1649 reference = (GtkTreeRowReference *) row->data;
1650
1651 path_src = gtk_tree_row_reference_get_path (reference);
1652 if (!path_src) {
1653 gtk_tree_row_reference_free (reference);
1654
1655 row = g_list_next (row);
1656 continue;
1657 }
1658
1659 if (path_where_insert && (position == GTK_TREE_VIEW_DROP_AFTER || position == GTK_TREE_VIEW_DROP_BEFORE)
1660 && (gtk_tree_path_get_depth (path_where_insert) == gtk_tree_path_get_depth (path_src))) {
1661 gtk_tree_path_free (path_src);
1662 gtk_tree_row_reference_free (reference);
1663
1664 row = g_list_next (row);
1665 continue;
1666 }
1667
1668 if (path_where_insert && type == DATA_COMPOSITION_TYPE_DIRECTORY
1669 && gtk_tree_path_is_descendant (path_where_insert, path_src)) {
1670
1671 gtk_tree_path_free (path_src);
1672 gtk_tree_path_free (path_where_insert);
1673 gtk_tree_row_reference_free (reference);
1674
1675 gtk_drag_finish (dc, FALSE, FALSE, t);
1676 return;
1677 }
1678
1679 gtk_tree_model_get_iter (model, &iter_src, path_src);
1680 gtk_tree_model_get (model, &iter_src, DATA_COMPOSITION_COLUMN_TYPE, &type,
1681 DATA_COMPOSITION_COLUMN_SIZE, &size, -1);
1682
1683 /* copy entry */
1684 if (copy_entry_to (composition, &iter_src, iter, position)) {
1685 GtkTreePath *path_parent = gtk_tree_path_copy (path_src);
1686
1687 /* update new parent size */
1688 if (iter && (position == GTK_TREE_VIEW_DROP_INTO_OR_AFTER
1689 || position == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)) {
1690 guint64 old_size = 0;
1691 gchar *parent_humansize = NULL;
1692
1693 gtk_tree_model_get (model, iter, DATA_COMPOSITION_COLUMN_SIZE, &old_size, -1);
1694
1695 parent_humansize = xfburn_humanreadable_filesize (old_size + size);
1696 gtk_tree_store_set (GTK_TREE_STORE (model), iter, DATA_COMPOSITION_COLUMN_HUMANSIZE, parent_humansize,
1697 DATA_COMPOSITION_COLUMN_SIZE, old_size + size, -1);
1698
1699 g_free (parent_humansize);
1700 }
1701
1702 if (gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE) {
1703 /* remove source entry */
1704 if (gtk_tree_path_up (path_parent) && path_where_insert &&
1705 !gtk_tree_path_is_descendant (path_where_insert, path_parent)) {
1706 /* update parent size and humansize */
1707 GtkTreeIter iter_parent;
1708 guint64 old_size;
1709 gchar *parent_humansize = NULL;
1710
1711 gtk_tree_model_iter_parent (model, &iter_parent, &iter_src);
1712 gtk_tree_model_get (model, &iter_parent, DATA_COMPOSITION_COLUMN_SIZE, &old_size, -1);
1713
1714 parent_humansize = xfburn_humanreadable_filesize (old_size - size);
1715 gtk_tree_store_set (GTK_TREE_STORE (model), &iter_parent,
1716 DATA_COMPOSITION_COLUMN_HUMANSIZE, parent_humansize,
1717 DATA_COMPOSITION_COLUMN_SIZE, old_size - size, -1);
1718 g_free (parent_humansize);
1719 }
1720
1721 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter_src);
1722 } else {
1723 xfburn_disc_usage_add_size (XFBURN_DISC_USAGE (priv->disc_usage), size);
1724 }
1725
1726 gtk_tree_path_free (path_parent);
1727 }
1728
1729 gtk_tree_path_free (path_src);
1730 gtk_tree_row_reference_free (reference);
1731
1732 row = g_list_next (row);
1733 }
1734
1735 g_list_free (selected_rows);
1736 gtk_drag_finish (dc, TRUE, FALSE, t);
1737
1738 if (path_where_insert)
1739 gtk_tree_path_free (path_where_insert);
1740 gtk_widget_hide (priv->progress);
1741 xfburn_default_cursor (priv->content);
1742 }
1743 /* drag from the file selector, or nautilus */
1744 else if (gtk_selection_data_get_target(sd) == gdk_atom_intern ("text/plain;charset=utf-8", FALSE)) {
1745 ThreadAddFilesDragParams *params;
1746 gchar **files = NULL;
1747 gchar *full_paths;
1748 int i;
1749
1750 xfburn_adding_progress_show (XFBURN_ADDING_PROGRESS (priv->progress));
1751
1752 full_paths = (gchar *) gtk_selection_data_get_text (sd);
1753
1754 files = g_strsplit ((gchar *) full_paths, "\n", -1);
1755
1756 if (files) {
1757
1758 for (i=0; files[i] != NULL && files[i][0] != '\0'; i++) {
1759 gchar *full_path;
1760
1761 if (g_str_has_prefix (files[i], "file://"))
1762 full_path = g_build_filename (&files[i][7], NULL);
1763 else if (g_str_has_prefix (files[i], "file:"))
1764 full_path = g_build_filename (&files[i][5], NULL);
1765 else
1766 full_path = g_build_filename (files[i], NULL);
1767
1768 if (full_path[strlen (full_path) - 1] == '\r')
1769 full_path[strlen (full_path) - 1] = '\0';
1770
1771 DBG ("Adding path '%s'", full_path);
1772
1773 /* remember path to add it later in another thread */
1774 priv->full_paths_to_add = g_list_append (priv->full_paths_to_add, full_path);
1775 }
1776 g_strfreev (files);
1777 g_free (full_paths);
1778
1779 priv->full_paths_to_add = g_list_reverse (priv->full_paths_to_add);
1780 /* FIXME: path_where_insert is always NULL here */
1781 priv->path_where_insert = path_where_insert;
1782
1783 params = g_new (ThreadAddFilesDragParams, 1);
1784 params->composition = composition;
1785 params->position = position;
1786 params->widget = widget;
1787
1788 /* append a dummy row so that gtk doesn't freak out */
1789 gtk_tree_store_append (GTK_TREE_STORE (model), ¶ms->iter_dummy, NULL);
1790
1791 priv->thread_params = params;
1792 g_thread_new ("data_add_dnd_plain", (GThreadFunc) thread_add_files_drag, params);
1793 }
1794
1795 gtk_drag_finish (dc, TRUE, FALSE, t);
1796 }
1797 else if (gtk_selection_data_get_target(sd) == gdk_atom_intern ("text/uri-list", FALSE)) {
1798 GList *vfs_paths = NULL;
1799 GList *vfs_path;
1800 GList *lp;
1801 gchar *full_path;
1802 gchar **uris;
1803 gsize n;
1804
1805 uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data(sd));
1806
1807 for (n = 0; uris != NULL && uris[n] != NULL; ++n)
1808 vfs_paths = g_list_append (vfs_paths, g_file_new_for_uri (uris[n]));
1809
1810 g_strfreev (uris);
1811
1812 if (G_LIKELY (vfs_paths != NULL)) {
1813 ThreadAddFilesDragParams *params;
1814 priv->full_paths_to_add = NULL;
1815 for (vfs_path = vfs_paths; vfs_path != NULL; vfs_path = g_list_next (vfs_path)) {
1816 GFile *path = vfs_path->data;
1817 if (path == NULL)
1818 continue;
1819 /* unable to handle non-local files */
1820 if (G_UNLIKELY (!g_file_has_uri_scheme (path, "file"))) {
1821 g_object_unref (path);
1822 continue;
1823 }
1824 full_path = g_file_get_path (path);
1825 /* if there is no local path, use the URI (which always works) */
1826 if (full_path == NULL)
1827 full_path = g_file_get_uri (path);
1828 /* release the location */
1829 g_debug ("adding uri path: %s", full_path);
1830 priv->full_paths_to_add = g_list_prepend (priv->full_paths_to_add, full_path);
1831 }
1832
1833 for (lp = vfs_paths; lp != NULL; lp = lp->next)
1834 g_object_unref (lp->data);
1835 g_list_free (vfs_paths);
1836
1837 priv->full_paths_to_add = g_list_reverse (priv->full_paths_to_add);
1838 /* FIXME: path_where_insert is always NULL here */
1839 priv->path_where_insert = path_where_insert;
1840
1841 params = g_new (ThreadAddFilesDragParams, 1);
1842 params->composition = composition;
1843 params->position = position;
1844 params->widget = widget;
1845
1846 /* append a dummy row so that gtk doesn't freak out */
1847 gtk_tree_store_append (GTK_TREE_STORE (model), ¶ms->iter_dummy, NULL);
1848
1849 priv->thread_params = params;
1850 g_thread_new ("data_add_dnd_uri", (GThreadFunc) thread_add_files_drag, params);
1851
1852 gtk_drag_finish (dc, TRUE, FALSE, t);
1853 } else {
1854 g_warning("There were no files in the uri list!");
1855 gtk_drag_finish (dc, FALSE, FALSE, t);
1856 xfburn_default_cursor (priv->content);
1857 }
1858 }
1859 else {
1860 g_warning ("Trying to receive an unsupported drag target, this should not happen.");
1861 gtk_drag_finish (dc, FALSE, FALSE, t);
1862 xfburn_default_cursor (priv->content);
1863 }
1864 }
1865
1866 /* thread entry point */
1867 static gpointer
thread_add_files_drag(ThreadAddFilesDragParams * params)1868 thread_add_files_drag (ThreadAddFilesDragParams *params)
1869 {
1870 XfburnDataComposition *composition = params->composition;
1871 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (composition);
1872
1873 GtkTreeViewDropPosition position = params->position;
1874 GtkWidget *widget = params->widget;
1875
1876 GtkTreeModel *model;
1877 GtkTreeIter iter_where_insert;
1878 GtkTreeIter *iter_insert = (priv->path_where_insert) ? &iter_where_insert : NULL;
1879 gboolean expand = (position == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || position == GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
1880 gboolean success = FALSE;
1881 GList *files = priv->full_paths_to_add;
1882
1883 gdk_threads_enter ();
1884 model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
1885
1886 /* remove the dummy row again */
1887 gtk_tree_store_remove (GTK_TREE_STORE (model), ¶ms->iter_dummy);
1888 gdk_threads_leave ();
1889
1890 for (; files; files = g_list_next (files)) {
1891 gchar *full_path = (gchar *) files->data;
1892 GtkTreeIter iter;
1893
1894 if (priv->path_where_insert) {
1895 gdk_threads_enter ();
1896 gtk_tree_model_get_iter (model, &iter_where_insert, priv->path_where_insert);
1897 gdk_threads_leave ();
1898 }
1899
1900 success = thread_add_file_to_list (composition, model, full_path, &iter, iter_insert, position);
1901
1902 if (success && expand && priv->path_where_insert) {
1903 gdk_threads_enter ();
1904 gtk_tree_view_expand_row (GTK_TREE_VIEW (widget), priv->path_where_insert, FALSE);
1905 gdk_threads_leave ();
1906 }
1907
1908 }
1909 xfburn_adding_progress_done (XFBURN_ADDING_PROGRESS (priv->progress));
1910 return NULL;
1911 }
1912
1913 static void
fill_image_with_composition(GtkTreeModel * model,IsoImage * image,IsoDir * parent,GtkTreeIter * iter,GSList ** errors)1914 fill_image_with_composition (GtkTreeModel *model, IsoImage *image, IsoDir * parent, GtkTreeIter *iter, GSList **errors)
1915 {
1916 do {
1917 DataCompositionEntryType type;
1918 gchar *name = NULL;
1919 gchar *src = NULL;
1920 IsoNode *node = NULL;
1921 IsoDir *dir = NULL;
1922 int r;
1923 gchar *basename;
1924
1925 gtk_tree_model_get (model, iter, DATA_COMPOSITION_COLUMN_TYPE, &type,
1926 DATA_COMPOSITION_COLUMN_CONTENT, &name, DATA_COMPOSITION_COLUMN_PATH, &src, -1);
1927
1928 if (type == DATA_COMPOSITION_TYPE_DIRECTORY && src == NULL) {
1929 /* a directory which the user added for this composition */
1930 r = iso_tree_add_new_dir (parent, name, &dir);
1931 node = (IsoNode *) dir;
1932
1933 /* if the new directory is part of the root of the iso,
1934 * then its owner will be set to root:root. Not sure what a better
1935 * default could be, so I'll just leave it like that. */
1936 } else {
1937 /* something existing on the filesystem, creating a node
1938 * will copy its attributes */
1939 r = iso_tree_add_node (image, parent, src, &node);
1940 }
1941
1942 if (r < 0) {
1943 char * msg;
1944
1945 if (r == ISO_NULL_POINTER)
1946 g_error (_("%s: null pointer"), src);
1947 else if (r == ISO_OUT_OF_MEM)
1948 g_error (_("%s: out of memory"), src);
1949 else if (r == ISO_NODE_NAME_NOT_UNIQUE)
1950 msg = g_strdup_printf (_("%s: node name not unique"), src);
1951 else
1952 msg = g_strdup_printf (_("%s: %s (code %X)"), src, iso_error_to_msg(r), r);
1953
1954 g_warning ("%s", msg);
1955 *errors = g_slist_prepend (*errors, msg);
1956
1957 g_free (name);
1958 g_free (src);
1959 continue;
1960 }
1961
1962 if (src != NULL && *src != '\0') {
1963 basename = g_path_get_basename (src);
1964
1965 /* check if the file has been renamed */
1966 if (strcmp (basename, name) != 0) {
1967 /* rename the iso_node */
1968 r = iso_node_set_name (node, name);
1969
1970 if (r == 0) {
1971 /* The first string is the renamed name, the second one the original name */
1972 xfce_dialog_show_warning(NULL, NULL, _("Duplicate filename '%s' for '%s'"), name, src);
1973
1974 g_free (basename);
1975 g_free (name);
1976 g_free (src);
1977
1978 continue;
1979 }
1980 }
1981
1982 g_free (basename);
1983 }
1984
1985 g_free (name);
1986 g_free (src);
1987
1988 if (type == DATA_COMPOSITION_TYPE_DIRECTORY && gtk_tree_model_iter_has_child (model, iter)) {
1989 GtkTreeIter child;
1990
1991 if (iso_node_get_type(node) != LIBISO_DIR)
1992 g_error ("Expected %s to be a directory, but it isn't...\n", src);
1993
1994 dir = (IsoDir *)node;
1995
1996 gtk_tree_model_iter_children (model, &child, iter);
1997 fill_image_with_composition (model, image, dir, &child, errors);
1998 }
1999 } while (gtk_tree_model_iter_next (model, iter));
2000 }
2001
2002 static
concat_free(char * msg,char ** combined_msg)2003 void concat_free (char * msg, char ** combined_msg)
2004 {
2005 *combined_msg = g_strconcat (*combined_msg, msg, "\n", NULL);
2006 free (msg);
2007 }
2008
2009 static IsoImage *
generate_iso_image(XfburnDataComposition * dc)2010 generate_iso_image (XfburnDataComposition * dc)
2011 {
2012 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
2013 IsoImage *image = NULL;
2014 GtkTreeModel *model;
2015 GtkTreeIter iter;
2016 GSList *errors = NULL;
2017
2018 iso_image_new (gtk_entry_get_text (GTK_ENTRY (priv->entry_volume_name)), &image);
2019 iso_image_set_application_id (image, "Xfburn");
2020 iso_image_set_data_preparer_id (image, "Xfburn");
2021
2022 model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
2023 if (gtk_tree_model_get_iter_first (model, &iter)) {
2024 fill_image_with_composition (model, image, iso_image_get_root (image), &iter, &errors);
2025
2026 if (errors != NULL) {
2027 gchar * combined_msg = "";
2028 GtkWidget * dialog, * label, * textview, * scrolled;
2029 GtkTextBuffer * buffer;
2030 XfburnMainWindow *mainwin = xfburn_main_window_get_instance ();
2031 gchar * title;
2032
2033 errors = g_slist_reverse (errors);
2034
2035 g_slist_foreach (errors, (GFunc) concat_free, &combined_msg);
2036
2037 title = _("Error(s) occured while adding files");
2038 dialog = gtk_dialog_new_with_buttons (title,
2039 GTK_WINDOW (mainwin),
2040 GTK_DIALOG_DESTROY_WITH_PARENT,
2041 _("OK"),
2042 GTK_RESPONSE_OK,
2043 NULL);
2044
2045 label = gtk_label_new (NULL);
2046 title = g_strdup_printf ("<b>%s</b>", title);
2047 gtk_label_set_markup(GTK_LABEL (label), title);
2048 g_free (title);
2049
2050 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label);
2051
2052 textview = gtk_text_view_new ();
2053 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
2054 gtk_text_buffer_set_text (buffer, combined_msg, -1);
2055 gtk_text_view_set_editable (GTK_TEXT_VIEW(textview), FALSE);
2056
2057 scrolled = gtk_scrolled_window_new (NULL, NULL);
2058 gtk_container_add (GTK_CONTAINER (scrolled), textview);
2059 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2060 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area(GTK_DIALOG(dialog))), scrolled);
2061
2062 gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 200);
2063
2064 gtk_widget_show (label);
2065 gtk_widget_show (textview);
2066 gtk_widget_show (scrolled);
2067
2068 gtk_dialog_run (GTK_DIALOG (dialog));
2069
2070 gtk_widget_destroy (dialog);
2071 g_free (combined_msg);
2072 }
2073 }
2074
2075 return image;
2076 }
2077
2078 /****************/
2079 /* loading code */
2080 /****************/
2081 typedef struct
2082 {
2083 gboolean started;
2084 XfburnDataComposition *dc;
2085 GQueue *queue_iter;
2086 } LoadParserStruct;
2087
2088 /*
2089 static gint
2090 _find_attribute (const gchar ** attribute_names, const gchar * attr)
2091 {
2092 gint i;
2093
2094 for (i = 0; attribute_names[i]; i++) {
2095 if (!strcmp (attribute_names[i], attr))
2096 return i;
2097 }
2098
2099 return -1;
2100 }
2101 */
2102
2103 static void
load_composition_start(GMarkupParseContext * context,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer data,GError ** error)2104 load_composition_start (GMarkupParseContext * context, const gchar * element_name,
2105 const gchar ** attribute_names, const gchar ** attribute_values,
2106 gpointer data, GError ** error)
2107 {
2108 g_error ("This method needs to get fixed, and does not work right now!");
2109 /*
2110 LoadParserStruct * parserinfo = (LoadParserStruct *) data;
2111 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (parserinfo->dc);
2112
2113
2114 if (!(parserinfo->started) && !strcmp (element_name, "xfburn-composition"))
2115 parserinfo->started = TRUE;
2116 else if (!(parserinfo->started))
2117 return;
2118
2119 if (!strcmp (element_name, "file")) {
2120 int i, j;
2121
2122 if ((i = _find_attribute (attribute_names, "name")) != -1 &&
2123 (j = _find_attribute (attribute_names, "source")) != -1) {
2124 //GtkTreeIter iter;
2125 GtkTreeIter *parent;
2126 GtkTreeModel *model;
2127
2128 model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
2129 parent = g_queue_peek_head (parserinfo->queue_iter);
2130
2131 add_file_to_list_with_name (attribute_values[i], parserinfo->dc, model, attribute_values[j], &iter,
2132 parent, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
2133 }
2134 } else if (!strcmp (element_name, "directory")) {
2135 int i, j;
2136
2137 if ((i = _find_attribute (attribute_names, "name")) != -1 &&
2138 (j = _find_attribute (attribute_names, "source")) != -1) {
2139 //GtkTreeIter iter;
2140 GtkTreeModel *model;
2141
2142 model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
2143
2144 //add_directory_to_list (attribute_values[i], parserinfo->dc, model, attribute_values[j], &iter, parent);
2145 }
2146 }
2147 */
2148 }
2149
2150 static void
load_composition_end(GMarkupParseContext * context,const gchar * element_name,gpointer user_data,GError ** error)2151 load_composition_end (GMarkupParseContext * context, const gchar * element_name, gpointer user_data, GError ** error)
2152 {
2153 LoadParserStruct *parserinfo = (LoadParserStruct *) user_data;
2154
2155 if (!parserinfo->started)
2156 return;
2157
2158 if (!strcmp (element_name, "xfburn-composition"))
2159 parserinfo->started = FALSE;
2160
2161 if (!strcmp (element_name, "directory"))
2162 parserinfo->queue_iter = g_queue_pop_head (parserinfo->queue_iter);
2163 }
2164
2165 static void
load_from_file(XfburnComposition * composition,const gchar * filename)2166 load_from_file (XfburnComposition * composition, const gchar * filename)
2167 {
2168 gchar *file_contents = NULL;
2169 GMarkupParseContext *gpcontext = NULL;
2170 struct stat st;
2171 LoadParserStruct parserinfo;
2172 GMarkupParser gmparser = {
2173 load_composition_start, load_composition_end, NULL, NULL, NULL
2174 };
2175 GError *err = NULL;
2176 #ifdef HAVE_MMAP
2177 gint fd = -1;
2178 void *maddr = NULL;
2179 #endif
2180 g_return_if_fail (filename != NULL);
2181 if (stat (filename, &st) < 0) {
2182 g_warning ("Unable to open %s", filename);
2183 goto cleanup;
2184 }
2185
2186 #ifdef HAVE_MMAP
2187 fd = open (filename, O_RDONLY, 0);
2188 if (fd < 0)
2189 goto cleanup;
2190 maddr = mmap (NULL, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);
2191 if (maddr)
2192 file_contents = maddr;
2193 #endif
2194 if (!file_contents && !g_file_get_contents (filename, &file_contents, NULL, &err)) {
2195 if (err) {
2196 g_warning ("Unable to read file '%s' (%d): %s", filename, err->code, err->message);
2197 g_error_free (err);
2198 }
2199 goto cleanup;
2200 }
2201
2202 parserinfo.started = FALSE;
2203 parserinfo.dc = XFBURN_DATA_COMPOSITION (composition);
2204 parserinfo.queue_iter = g_queue_new ();
2205 gpcontext = g_markup_parse_context_new (&gmparser, 0, &parserinfo, NULL);
2206 if (!g_markup_parse_context_parse (gpcontext, file_contents, st.st_size, &err)) {
2207 g_warning ("Error parsing composition (%d): %s", err->code, err->message);
2208 g_error_free (err);
2209 goto cleanup;
2210 }
2211
2212 if (g_markup_parse_context_end_parse (gpcontext, NULL)) {
2213 DBG ("parsed");
2214 }
2215
2216 g_queue_free (parserinfo.queue_iter);
2217
2218 cleanup:
2219 if (gpcontext)
2220 g_markup_parse_context_free (gpcontext);
2221 #ifdef HAVE_MMAP
2222 if (maddr) {
2223 munmap (maddr, st.st_size);
2224 file_contents = NULL;
2225 }
2226 if (fd > -1)
2227 close (fd);
2228 #endif
2229 if (file_contents)
2230 g_free (file_contents);
2231 }
2232
2233
2234 /***************/
2235 /* saving code */
2236 /***************/
2237 typedef struct
2238 {
2239 FILE *file_content;
2240 gint last_depth;
2241 } CompositionSaveInfo;
2242
2243 static gboolean
foreach_save(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,CompositionSaveInfo * info)2244 foreach_save (GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, CompositionSaveInfo *info)
2245 {
2246 gchar *space = NULL;
2247 gint i;
2248 gchar *name = NULL;
2249 gchar *source_path = NULL;
2250 DataCompositionEntryType type;
2251
2252 space = g_strnfill (gtk_tree_path_get_depth (path), '\t');
2253
2254 for (i = info->last_depth; i > gtk_tree_path_get_depth (path); i--) {
2255 gchar *space2 = NULL;
2256
2257 space2 = g_strnfill (i - 1, '\t');
2258 fprintf (info->file_content, "%s</directory>\n", space2);
2259
2260 g_free (space2);
2261 }
2262
2263 gtk_tree_model_get (model, iter, DATA_COMPOSITION_COLUMN_CONTENT, &name,
2264 DATA_COMPOSITION_COLUMN_PATH, &source_path,
2265 DATA_COMPOSITION_COLUMN_TYPE, &type, -1);
2266
2267 fprintf (info->file_content, "%s", space);
2268 switch (type) {
2269 case DATA_COMPOSITION_TYPE_FILE:
2270 fprintf (info->file_content, "<file name=\"%s\" source=\"%s\" />\n", name, source_path);
2271 break;
2272 case DATA_COMPOSITION_TYPE_DIRECTORY:
2273 fprintf (info->file_content, "<directory name=\"%s\" source=\"%s\"", name, source_path);
2274
2275 if (gtk_tree_model_iter_has_child (model, iter))
2276 fprintf (info->file_content, ">\n");
2277 else
2278 fprintf (info->file_content, "/>\n");
2279
2280 break;
2281 }
2282
2283
2284 info->last_depth = gtk_tree_path_get_depth (path);
2285
2286 g_free (space);
2287 g_free (name);
2288 g_free (source_path);
2289
2290 return FALSE;
2291 }
2292
2293 static void
save_to_file(XfburnComposition * composition)2294 save_to_file (XfburnComposition * composition)
2295 {
2296 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (composition);
2297 FILE *file_content;
2298 GtkTreeModel *model;
2299 CompositionSaveInfo info;
2300 gint i;
2301
2302 if (!(priv->filename)) {
2303 priv->filename = g_strdup ("/tmp/gna");
2304
2305 g_signal_emit_by_name (G_OBJECT (composition), "name-changed", priv->filename);
2306 }
2307
2308 file_content = fopen (priv->filename, "w+");
2309 fprintf (file_content, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
2310 fprintf (file_content, "<xfburn-composition version=\"0.1\">\n");
2311
2312 model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->content));
2313 info.file_content = file_content;
2314 info.last_depth = 0;
2315 gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) foreach_save, &info);
2316
2317 for (i = info.last_depth; i > 1; i--) {
2318 gchar *space2 = NULL;
2319
2320 space2 = g_strnfill (i - 1, '\t');
2321 fprintf (info.file_content, "%s</directory>\n", space2);
2322
2323 g_free (space2);
2324 }
2325
2326 fprintf (file_content, "</xfburn-composition>\n");
2327 fclose (file_content);
2328 }
2329
2330 /******************/
2331 /* public methods */
2332 /******************/
2333 GtkWidget *
xfburn_data_composition_new(void)2334 xfburn_data_composition_new (void)
2335 {
2336 return g_object_new (xfburn_data_composition_get_type (), NULL);
2337 }
2338
2339 void
xfburn_data_composition_add_files(XfburnDataComposition * dc,GSList * filelist)2340 xfburn_data_composition_add_files (XfburnDataComposition *dc, GSList * filelist)
2341 {
2342 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (dc);
2343 ThreadAddFilesCLIParams *params;
2344
2345 if (filelist != NULL) {
2346 params = g_new (ThreadAddFilesCLIParams, 1);
2347
2348 params->filelist = filelist;
2349 params->dc = dc;
2350
2351 xfburn_adding_progress_show (XFBURN_ADDING_PROGRESS (priv->progress));
2352 xfburn_busy_cursor (priv->content);
2353
2354 priv->thread_params = params;
2355 g_thread_new ("data_add_files_cli", (GThreadFunc) thread_add_files_cli, params);
2356 }
2357 }
2358
2359 void
xfburn_data_composition_hide_toolbar(XfburnDataComposition * composition)2360 xfburn_data_composition_hide_toolbar (XfburnDataComposition * composition)
2361 {
2362 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (composition);
2363
2364 gtk_widget_hide (priv->toolbar);
2365 }
2366
2367 void
xfburn_data_composition_show_toolbar(XfburnDataComposition * composition)2368 xfburn_data_composition_show_toolbar (XfburnDataComposition * composition)
2369 {
2370 XfburnDataCompositionPrivate *priv = XFBURN_DATA_COMPOSITION_GET_PRIVATE (composition);
2371
2372 gtk_widget_show (priv->toolbar);
2373 }
2374
2375