1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 
3 /***************************************************************************
4  *            project.c
5  *
6  *  mar nov 29 09:32:17 2005
7  *  Copyright  2005  Rouquier Philippe
8  *  brasero-app@wanadoo.fr
9  ***************************************************************************/
10 
11 /*
12  *  Brasero is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  Brasero is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU Library General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to:
24  * 	The Free Software Foundation, Inc.,
25  * 	51 Franklin Street, Fifth Floor
26  * 	Boston, MA  02110-1301, USA.
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #  include <config.h>
31 #endif
32 
33 #include <string.h>
34 
35 #include <glib.h>
36 #include <glib/gstdio.h>
37 #include <glib/gi18n.h>
38 
39 #include <gio/gio.h>
40 
41 #include <gtk/gtk.h>
42 #include <gdk/gdkx.h>
43 
44 #include <gst/gst.h>
45 
46 #include <libxml/xmlerror.h>
47 
48 #include "brasero-units.h"
49 
50 #include "brasero-misc.h"
51 #include "brasero-jacket-edit.h"
52 #include "brasero-pk.h"
53 
54 #include "brasero-tags.h"
55 #include "brasero-session.h"
56 
57 #include "brasero-setting.h"
58 
59 #ifdef BUILD_PREVIEW
60 #include "brasero-player.h"
61 #endif
62 
63 #include "brasero-track-data.h"
64 #include "brasero-track-data-cfg.h"
65 #include "brasero-track-stream-cfg.h"
66 #include "brasero-session-cfg.h"
67 
68 /* These includes are not in the exported *.h files by
69  * libbrasero-burn. */
70 #include "brasero-medium-selection-priv.h"
71 #include "brasero-session-helper.h"
72 #include "brasero-dest-selection.h"
73 #include "brasero-cover.h"
74 #include "brasero-status-dialog.h"
75 #include "brasero-video-options.h"
76 #include "brasero-drive-properties.h"
77 #include "brasero-image-properties.h"
78 #include "burn-plugin-manager.h"
79 
80 #include "brasero-project-type-chooser.h"
81 #include "brasero-app.h"
82 #include "brasero-project.h"
83 #include "brasero-disc.h"
84 #include "brasero-data-disc.h"
85 #include "brasero-audio-disc.h"
86 #include "brasero-video-disc.h"
87 #include "brasero-uri-container.h"
88 #include "brasero-layout-object.h"
89 #include "brasero-disc-message.h"
90 #include "brasero-file-chooser.h"
91 #include "brasero-notify.h"
92 #include "brasero-project-parse.h"
93 #include "brasero-project-name.h"
94 #include "brasero-drive-settings.h"
95 
96 static void brasero_project_class_init (BraseroProjectClass *klass);
97 static void brasero_project_init (BraseroProject *sp);
98 static void brasero_project_iface_uri_container_init (BraseroURIContainerIFace *iface);
99 static void brasero_project_iface_layout_object_init (BraseroLayoutObjectIFace *iface);
100 static void brasero_project_finalize (GObject *object);
101 
102 static void
103 brasero_project_save_cb (GtkAction *action, BraseroProject *project);
104 static void
105 brasero_project_save_as_cb (GtkAction *action, BraseroProject *project);
106 
107 static void
108 brasero_project_add_uris_cb (GtkAction *action, BraseroProject *project);
109 static void
110 brasero_project_remove_selected_uris_cb (GtkAction *action, BraseroProject *project);
111 static void
112 brasero_project_empty_cb (GtkAction *action, BraseroProject *project);
113 
114 static void
115 brasero_project_burn_cb (GtkAction *action, BraseroProject *project);
116 
117 static void
118 brasero_project_burn_clicked_cb (GtkButton *button, BraseroProject *project);
119 
120 static void
121 brasero_project_selection_changed_cb (BraseroDisc *disc,
122 				      BraseroProject *project);
123 
124 static gchar *
125 brasero_project_get_selected_uri (BraseroURIContainer *container);
126 static gboolean
127 brasero_project_get_boundaries (BraseroURIContainer *container,
128 				gint64 *start,
129 				gint64 *end);
130 
131 static void
132 brasero_project_get_proportion (BraseroLayoutObject *object,
133 				gint *header,
134 				gint *center,
135 				gint *footer);
136 
137 static void
138 brasero_project_get_proportion (BraseroLayoutObject *object,
139 				gint *header,
140 				gint *center,
141 				gint *footer);
142 
143 struct BraseroProjectPrivate {
144 	BraseroSessionCfg *session;
145 
146 	GtkWidget *help;
147 	GtkWidget *selection;
148 	GtkWidget *name_display;
149 	GtkWidget *discs;
150 	GtkWidget *audio;
151 	GtkWidget *data;
152 	GtkWidget *video;
153 
154 	GtkWidget *message;
155 
156 	GtkUIManager *manager;
157 
158 	guint status_ctx;
159 
160 	GtkWidget *project_status;
161 
162 	/* header */
163 	GtkWidget *burn;
164 
165 	GtkActionGroup *project_group;
166 	guint merge_id;
167 
168 	gchar *project;
169 
170 	gchar *cover;
171 
172 	gint64 sectors;
173 	BraseroDisc *current;
174 
175 	BraseroURIContainer *current_source;
176 
177 	GCancellable *cancel;
178 
179 	GtkWidget *chooser;
180 	gulong selected_id;
181 	gulong activated_id;
182 
183 	guint is_burning:1;
184 
185     	guint burnt:1;
186 
187 	guint empty:1;
188 	guint modified:1;
189 	guint has_focus:1;
190 	guint oversized:1;
191 	guint selected_uris:1;
192 };
193 
194 static GtkActionEntry entries [] = {
195 	{"Save", GTK_STOCK_SAVE, NULL, NULL,
196 	 N_("Save current project"), G_CALLBACK (brasero_project_save_cb)},
197 	{"SaveAs", GTK_STOCK_SAVE_AS, N_("Save _As…"), NULL,
198 	 N_("Save current project to a different location"), G_CALLBACK (brasero_project_save_as_cb)},
199 	{"Add", GTK_STOCK_ADD, N_("_Add Files"), NULL,
200 	 N_("Add files to the project"), G_CALLBACK (brasero_project_add_uris_cb)},
201 	{"DeleteProject", GTK_STOCK_REMOVE, N_("_Remove Files"), NULL,
202 	 N_("Remove the selected files from the project"), G_CALLBACK (brasero_project_remove_selected_uris_cb)},
203 	/* Translators: "empty" is a verb here */
204 	{"DeleteAll", GTK_STOCK_CLEAR, N_("E_mpty Project"), NULL,
205 	 N_("Remove all files from the project"), G_CALLBACK (brasero_project_empty_cb)},
206 	{"Burn", "media-optical-burn", N_("_Burn…"), NULL,
207 	 N_("Burn the disc"), G_CALLBACK (brasero_project_burn_cb)},
208 };
209 
210 static const gchar *description = {
211 	"<ui>"
212 	    "<menubar name='menubar' >"
213 		"<menu action='ProjectMenu'>"
214 			"<placeholder name='ProjectPlaceholder'>"
215 			    "<menuitem action='Save'/>"
216 			    "<menuitem action='SaveAs'/>"
217 			    "<separator/>"
218 			"<menuitem action='Burn'/>"
219 			"</placeholder>"
220 		"</menu>"
221 
222 		"<menu action='EditMenu'>"
223 			"<placeholder name='EditPlaceholder'>"
224 			    "<menuitem action='Add'/>"
225 			    "<menuitem action='DeleteProject'/>"
226 			    "<menuitem action='DeleteAll'/>"
227 			    "<separator/>"
228 			"</placeholder>"
229 		"</menu>"
230 
231 		"<menu action='ViewMenu'>"
232 		"</menu>"
233 
234 		"<menu action='ToolMenu'>"
235 			"<placeholder name='DiscPlaceholder'/>"
236 		"</menu>"
237 	    "</menubar>"
238 	    "<toolbar name='Toolbar'>"
239 		"<separator/>"
240 		"<toolitem action='Add'/>"
241 		"<toolitem action='DeleteProject'/>"
242 		"<toolitem action='DeleteAll'/>"
243 		"<placeholder name='DiscButtonPlaceholder'/>"
244 	     "</toolbar>"
245 	"</ui>"
246 };
247 
248 static GObjectClass *parent_class = NULL;
249 
250 #define BRASERO_PROJECT_SIZE_WIDGET_BORDER	1
251 
252 #define BRASERO_PROJECT_VERSION "0.2"
253 
254 #define BRASERO_RESPONSE_ADD			1976
255 
256 enum {
257 	TREE_MODEL_ROW = 150,
258 	FILE_NODES_ROW,
259 	TARGET_URIS_LIST,
260 };
261 
262 static GtkTargetEntry ntables_cd[] = {
263 	{"GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, TREE_MODEL_ROW},
264 	{"GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, FILE_NODES_ROW},
265 	{"text/uri-list", 0, TARGET_URIS_LIST}
266 };
267 static guint nb_targets_cd = sizeof (ntables_cd) / sizeof (ntables_cd [0]);
268 
269 GType
brasero_project_get_type()270 brasero_project_get_type ()
271 {
272 	static GType type = 0;
273 
274 	if(type == 0) {
275 		static const GTypeInfo our_info = {
276 			sizeof (BraseroProjectClass),
277 			NULL,
278 			NULL,
279 			(GClassInitFunc)brasero_project_class_init,
280 			NULL,
281 			NULL,
282 			sizeof (BraseroProject),
283 			0,
284 			(GInstanceInitFunc) brasero_project_init,
285 		};
286 
287 		static const GInterfaceInfo uri_container_info =
288 		{
289 			(GInterfaceInitFunc) brasero_project_iface_uri_container_init,
290 			NULL,
291 			NULL
292 		};
293 		static const GInterfaceInfo layout_object =
294 		{
295 			(GInterfaceInitFunc) brasero_project_iface_layout_object_init,
296 			NULL,
297 			NULL
298 		};
299 
300 		type = g_type_register_static (GTK_TYPE_BOX,
301 					       "BraseroProject",
302 					       &our_info, 0);
303 
304 		g_type_add_interface_static (type,
305 					     BRASERO_TYPE_URI_CONTAINER,
306 					     &uri_container_info);
307 		g_type_add_interface_static (type,
308 					     BRASERO_TYPE_LAYOUT_OBJECT,
309 					     &layout_object);
310 	}
311 
312 	return type;
313 }
314 
315 static void
brasero_project_class_init(BraseroProjectClass * klass)316 brasero_project_class_init (BraseroProjectClass *klass)
317 {
318 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
319 
320 	parent_class = g_type_class_peek_parent (klass);
321 	object_class->finalize = brasero_project_finalize;
322 }
323 
324 static void
brasero_project_iface_uri_container_init(BraseroURIContainerIFace * iface)325 brasero_project_iface_uri_container_init (BraseroURIContainerIFace *iface)
326 {
327 	iface->get_selected_uri = brasero_project_get_selected_uri;
328 	iface->get_boundaries = brasero_project_get_boundaries;
329 }
330 
331 static void
brasero_project_iface_layout_object_init(BraseroLayoutObjectIFace * iface)332 brasero_project_iface_layout_object_init (BraseroLayoutObjectIFace *iface)
333 {
334 	iface->get_proportion = brasero_project_get_proportion;
335 }
336 
337 static void
brasero_project_get_proportion(BraseroLayoutObject * object,gint * header,gint * center,gint * footer)338 brasero_project_get_proportion (BraseroLayoutObject *object,
339 				gint *header,
340 				gint *center,
341 				gint *footer)
342 {
343 	GtkAllocation allocation;
344 
345 	if (!BRASERO_PROJECT (object)->priv->name_display)
346 		return;
347 
348 	gtk_widget_get_allocation (gtk_widget_get_parent (BRASERO_PROJECT (object)->priv->name_display),
349 				   &allocation);
350 	*footer = allocation.height;
351 }
352 
353 static void
brasero_project_set_remove_button_state(BraseroProject * project)354 brasero_project_set_remove_button_state (BraseroProject *project)
355 {
356 	GtkAction *action;
357 	gboolean sensitive;
358 
359 	sensitive = (project->priv->has_focus &&
360 	             project->priv->selected_uris);
361 
362 	action = gtk_action_group_get_action (project->priv->project_group, "DeleteProject");
363 	gtk_action_set_sensitive (action, sensitive);
364 }
365 
366 static void
brasero_project_set_add_button_state(BraseroProject * project)367 brasero_project_set_add_button_state (BraseroProject *project)
368 {
369 	GtkAction *action;
370 	GtkWidget *widget;
371 	gboolean sensitive;
372 	GtkWidget *toplevel;
373 
374 	sensitive = ((!project->priv->current_source || !project->priv->has_focus) &&
375 		      !project->priv->oversized && !project->priv->chooser);
376 
377 	action = gtk_action_group_get_action (project->priv->project_group, "Add");
378 	gtk_action_set_sensitive (action, sensitive);
379 
380 	/* set the Add button to be the default for the whole window. That fixes
381 	 * #465175 – Location field not working. GtkFileChooser needs a default
382 	 * widget to be activated. */
383 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (project));
384 	if (!sensitive) {
385 		gtk_window_set_default (GTK_WINDOW (toplevel), NULL);
386 		return;
387 	}
388 
389 	widget = gtk_ui_manager_get_widget (project->priv->manager, "/Toolbar/Add");
390 	if (!widget)
391 		return;
392 
393 	widget = gtk_bin_get_child (GTK_BIN (widget));
394 	gtk_widget_set_can_default (widget, TRUE);
395 
396 	gtk_window_set_default (GTK_WINDOW (toplevel), widget);
397 }
398 
399 static void
brasero_project_focus_changed_cb(GtkContainer * container,GtkWidget * widget,gpointer NULL_data)400 brasero_project_focus_changed_cb (GtkContainer *container,
401 				  GtkWidget *widget,
402 				  gpointer NULL_data)
403 {
404 	BraseroProject *project;
405 
406 	project = BRASERO_PROJECT (container);
407 	project->priv->has_focus = (widget != NULL);
408 
409 	brasero_project_set_remove_button_state (project);
410 	brasero_project_set_add_button_state (project);
411 }
412 
413 static void
brasero_project_name_changed_cb(BraseroProjectName * name,BraseroProject * project)414 brasero_project_name_changed_cb (BraseroProjectName *name,
415 				 BraseroProject *project)
416 {
417 	GtkAction *action;
418 
419 	project->priv->modified = TRUE;
420 
421 	/* the state of the following depends on the existence of an opened project */
422 	action = gtk_action_group_get_action (project->priv->project_group, "Save");
423 	if (project->priv->modified)
424 		gtk_action_set_sensitive (action, TRUE);
425 	else
426 		gtk_action_set_sensitive (action, FALSE);
427 }
428 
429 /********************************** help ***************************************/
430 static GtkWidget *
brasero_utils_disc_find_tree_view_in_container(GtkContainer * container)431 brasero_utils_disc_find_tree_view_in_container (GtkContainer *container)
432 {
433 	GList *children;
434 	GList *iter;
435 
436 	children = gtk_container_get_children (container);
437 	for (iter = children; iter; iter = iter->next) {
438 		GtkWidget *widget;
439 
440 		widget = iter->data;
441 		if (GTK_IS_TREE_VIEW (widget)) {
442 			g_list_free (children);
443 			return widget;
444 		}
445 
446 		if (GTK_IS_CONTAINER (widget)) {
447 			widget = brasero_utils_disc_find_tree_view_in_container (GTK_CONTAINER (widget));
448 			if (widget) {
449 				g_list_free (children);
450 				return widget;
451 			}
452 		}
453 	}
454 	g_list_free (children);
455 
456 	return NULL;
457 }
458 
459 static GtkWidget *
brasero_utils_disc_find_tree_view(BraseroDisc * widget)460 brasero_utils_disc_find_tree_view (BraseroDisc *widget)
461 {
462 	return brasero_utils_disc_find_tree_view_in_container (GTK_CONTAINER (widget));
463 }
464 
465 static void
brasero_utils_disc_hide_use_info_leave_cb(GtkWidget * widget,GdkDragContext * drag_context,guint time,BraseroProject * project)466 brasero_utils_disc_hide_use_info_leave_cb (GtkWidget *widget,
467 					   GdkDragContext *drag_context,
468 					   guint time,
469 					   BraseroProject *project)
470 {
471 	GtkWidget *other_widget;
472 
473 	other_widget = brasero_utils_disc_find_tree_view (project->priv->current);
474 	if (!other_widget)
475 		return;
476 
477 	g_signal_emit_by_name (other_widget,
478 			       "drag-leave",
479 			       drag_context,
480 			       time);
481 }
482 
483 static gboolean
brasero_utils_disc_hide_use_info_drop_cb(GtkWidget * widget,GdkDragContext * drag_context,gint x,gint y,guint time,BraseroProject * project)484 brasero_utils_disc_hide_use_info_drop_cb (GtkWidget *widget,
485 					  GdkDragContext *drag_context,
486 					  gint x,
487 					  gint y,
488 					  guint time,
489 					  BraseroProject *project)
490 {
491 	GdkAtom target = GDK_NONE;
492 	GtkWidget *other_widget;
493 
494 	/* here the treeview is not realized so we'll have a warning message
495 	 * if we ever try to forward the event */
496 	other_widget = brasero_utils_disc_find_tree_view (project->priv->current);
497 	if (!other_widget)
498 		return FALSE;
499 
500 	target = gtk_drag_dest_find_target (other_widget,
501 					    drag_context,
502 					    gtk_drag_dest_get_target_list (GTK_WIDGET (other_widget)));
503 
504 	if (target != GDK_NONE) {
505 		gboolean return_value = FALSE;
506 
507 		/* It's necessary to make sure the treeview
508 		 * is realized already before sending the
509 		 * signal */
510 		gtk_widget_realize (other_widget);
511 
512 		/* The widget must be realized to receive such events. */
513 		g_signal_emit_by_name (other_widget,
514 				       "drag-drop",
515 				       drag_context,
516 				       x,
517 				       y,
518 				       time,
519 				       &return_value);
520 		return return_value;
521 	}
522 
523 	return FALSE;
524 }
525 
526 static void
brasero_utils_disc_hide_use_info_data_received_cb(GtkWidget * widget,GdkDragContext * drag_context,gint x,gint y,GtkSelectionData * data,guint info,guint time,BraseroProject * project)527 brasero_utils_disc_hide_use_info_data_received_cb (GtkWidget *widget,
528 						   GdkDragContext *drag_context,
529 						   gint x,
530 						   gint y,
531 						   GtkSelectionData *data,
532 						   guint info,
533 						   guint time,
534 						   BraseroProject *project)
535 {
536 	GtkWidget *other_widget;
537 
538 	g_return_if_fail(BRASERO_IS_PROJECT(project));
539 
540 	other_widget = brasero_utils_disc_find_tree_view (project->priv->current);
541 	if (!other_widget)
542 		return;
543 
544 	g_signal_emit_by_name (other_widget,
545 			       "drag-data-received",
546 			       drag_context,
547 			       x,
548 			       y,
549 			       data,
550 			       info,
551 			       time);
552 }
553 
554 static gboolean
brasero_utils_disc_hide_use_info_motion_cb(GtkWidget * widget,GdkDragContext * drag_context,gint x,gint y,guint time,GtkNotebook * notebook)555 brasero_utils_disc_hide_use_info_motion_cb (GtkWidget *widget,
556 					    GdkDragContext *drag_context,
557 					    gint x,
558 					    gint y,
559 					    guint time,
560 					    GtkNotebook *notebook)
561 {
562 	return TRUE;
563 }
564 
565 static gboolean
brasero_utils_disc_hide_use_info_button_cb(GtkWidget * widget,GdkEventButton * event,BraseroProject * project)566 brasero_utils_disc_hide_use_info_button_cb (GtkWidget *widget,
567 					    GdkEventButton *event,
568 					    BraseroProject *project)
569 {
570 	GtkWidget *other_widget;
571 	gboolean result;
572 
573 	if (event->button != 3)
574 		return TRUE;
575 
576 	other_widget = brasero_utils_disc_find_tree_view (project->priv->current);
577 	if (!other_widget)
578 		return TRUE;
579 
580 	g_signal_emit_by_name (other_widget,
581 			       "button-press-event",
582 			       event,
583 			       &result);
584 
585 	return result;
586 }
587 
588 static void
brasero_utils_disc_style_changed_cb(GtkWidget * widget,GtkStyle * previous,GtkWidget * event_box)589 brasero_utils_disc_style_changed_cb (GtkWidget *widget,
590 				     GtkStyle *previous,
591 				     GtkWidget *event_box)
592 {
593 	GdkRGBA color;
594 
595 	/* The widget (a treeview here) needs to be realized to get proper style */
596 	gtk_widget_realize (widget);
597 	gdk_rgba_parse (&color, "white");
598 	gtk_widget_override_background_color (event_box, GTK_STATE_NORMAL, &color);
599 }
600 
601 static void
brasero_utils_disc_realized_cb(GtkWidget * event_box,GtkWidget * textview)602 brasero_utils_disc_realized_cb (GtkWidget *event_box,
603 				GtkWidget *textview)
604 {
605 	GdkRGBA color;
606 
607 	/* The widget (a treeview here) needs to be realized to get proper style */
608 	gtk_widget_realize (textview);
609 	gdk_rgba_parse (&color, "white");
610 	gtk_widget_override_background_color (event_box, GTK_STATE_NORMAL, &color);
611 
612 	g_signal_handlers_disconnect_by_func (textview,
613 					      brasero_utils_disc_style_changed_cb,
614 					      event_box);
615 	g_signal_connect (textview,
616 			  "style-set",
617 			  G_CALLBACK (brasero_utils_disc_style_changed_cb),
618 			  event_box);
619 }
620 
621 static GtkWidget *
brasero_disc_get_use_info_notebook(BraseroProject * project)622 brasero_disc_get_use_info_notebook (BraseroProject *project)
623 {
624 	GList *chain;
625 	GtkTextIter iter;
626 	GtkWidget *frame;
627 	GtkWidget *textview;
628 	GtkWidget *notebook;
629 	GtkWidget *alignment;
630 	GtkTextBuffer *buffer;
631 	GtkWidget *event_box;
632 
633 	notebook = gtk_notebook_new ();
634 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
635 	gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
636 
637 	frame = gtk_frame_new (NULL);
638 	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
639 	gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
640 				  frame,
641 				  NULL);
642 
643 	/* Now this event box must be 'transparent' to have the same background
644 	 * color as a treeview */
645 	event_box = gtk_event_box_new ();
646 	gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), TRUE);
647 	gtk_event_box_set_above_child (GTK_EVENT_BOX (event_box), TRUE);
648 	gtk_drag_dest_set (event_box,
649 			   GTK_DEST_DEFAULT_MOTION,
650 			   ntables_cd,
651 			   nb_targets_cd,
652 			   GDK_ACTION_COPY|
653 			   GDK_ACTION_MOVE);
654 
655 	/* the following signals need to be forwarded to the widget underneath */
656 	g_signal_connect (event_box,
657 			  "drag-motion",
658 			  G_CALLBACK (brasero_utils_disc_hide_use_info_motion_cb),
659 			  project);
660 	g_signal_connect (event_box,
661 			  "drag-leave",
662 			  G_CALLBACK (brasero_utils_disc_hide_use_info_leave_cb),
663 			  project);
664 	g_signal_connect (event_box,
665 			  "drag-drop",
666 			  G_CALLBACK (brasero_utils_disc_hide_use_info_drop_cb),
667 			  project);
668 	g_signal_connect (event_box,
669 			  "button-press-event",
670 			  G_CALLBACK (brasero_utils_disc_hide_use_info_button_cb),
671 			  project);
672 	g_signal_connect (event_box,
673 			  "drag-data-received",
674 			  G_CALLBACK (brasero_utils_disc_hide_use_info_data_received_cb),
675 			  project);
676 
677 	gtk_container_add (GTK_CONTAINER (frame), event_box);
678 
679 	/* The alignment to set properly the position of the GtkTextView */
680 	alignment = gtk_alignment_new (0.5, 0.5, 1.0, 0.0);
681 	gtk_container_set_border_width (GTK_CONTAINER (alignment), 10);
682 	gtk_widget_show (alignment);
683 	gtk_container_add (GTK_CONTAINER (event_box), alignment);
684 
685 	/* The TreeView for the message */
686 	buffer = gtk_text_buffer_new (NULL);
687 	gtk_text_buffer_create_tag (buffer, "Title",
688 	                            "scale", 1.1,
689 	                            "justification", GTK_JUSTIFY_CENTER,
690 	                            "foreground", "grey50",
691 	                            "wrap-mode", GTK_WRAP_WORD,
692 	                            NULL);
693 
694 	gtk_text_buffer_get_start_iter (buffer, &iter);
695 	gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, _("To add files to this project click the \"Add\" button or drag files to this area"), -1, "Title", NULL);
696 	gtk_text_buffer_insert (buffer, &iter, "\n\n\n", -1);
697 	gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, _("To remove files select them then click on the \"Remove\" button or press \"Delete\" key"), -1, "Title", NULL);
698 
699 	textview = gtk_text_view_new_with_buffer (buffer);
700 	gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), FALSE);
701 	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textview), FALSE);
702 
703 	gtk_drag_dest_set (textview,
704 			   GTK_DEST_DEFAULT_MOTION,
705 			   ntables_cd,
706 			   nb_targets_cd,
707 			   GDK_ACTION_COPY|
708 			   GDK_ACTION_MOVE);
709 
710 	/* the following signals need to be forwarded to the widget underneath */
711 	g_signal_connect (textview,
712 			  "drag-motion",
713 			  G_CALLBACK (brasero_utils_disc_hide_use_info_motion_cb),
714 			  project);
715 	g_signal_connect (textview,
716 			  "drag-leave",
717 			  G_CALLBACK (brasero_utils_disc_hide_use_info_leave_cb),
718 			  project);
719 	g_signal_connect (textview,
720 			  "drag-drop",
721 			  G_CALLBACK (brasero_utils_disc_hide_use_info_drop_cb),
722 			  project);
723 	g_signal_connect (textview,
724 			  "button-press-event",
725 			  G_CALLBACK (brasero_utils_disc_hide_use_info_button_cb),
726 			  project);
727 	g_signal_connect (textview,
728 			  "drag-data-received",
729 			  G_CALLBACK (brasero_utils_disc_hide_use_info_data_received_cb),
730 			  project);
731 
732 	gtk_container_add (GTK_CONTAINER (alignment), textview);
733 
734 	g_signal_connect (event_box,
735 			  "realize",
736 			  G_CALLBACK (brasero_utils_disc_realized_cb),
737 			  project);
738 
739 	chain = g_list_prepend (NULL, event_box);
740 	gtk_container_set_focus_chain (GTK_CONTAINER (frame), chain);
741 	g_list_free (chain);
742 
743 	chain = g_list_prepend (NULL, alignment);
744 	gtk_container_set_focus_chain (GTK_CONTAINER (event_box), chain);
745 	g_list_free (chain);
746 
747 	chain = g_list_prepend (NULL, textview);
748 	gtk_container_set_focus_chain (GTK_CONTAINER (alignment), chain);
749 	g_list_free (chain);
750 
751 	gtk_widget_show_all (notebook);
752 	return notebook;
753 }
754 
755 /********************************** size ***************************************/
756 static gchar *
brasero_project_get_sectors_string(gint64 sectors,BraseroTrackType * type)757 brasero_project_get_sectors_string (gint64 sectors,
758 				    BraseroTrackType *type)
759 {
760 	gint64 size_bytes;
761 
762 	if (brasero_track_type_get_has_stream (type)) {
763 		if (BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (type)))
764 			/* This is an embarassing problem: this is an approximation
765 			 * based on the fact that 2 hours = 4.3GiB */
766 			size_bytes = sectors * 2048LL * 72000LL / 47LL;
767 		else
768 			size_bytes = sectors * GST_SECOND / 75LL;
769 		return brasero_units_get_time_string (size_bytes, TRUE, FALSE);
770 	}
771 	else {
772 		size_bytes = sectors * 2048LL;
773 		return g_format_size (size_bytes);
774 	}
775 }
776 
777 static void
brasero_project_update_project_size(BraseroProject * project)778 brasero_project_update_project_size (BraseroProject *project)
779 {
780 	BraseroTrackType *session_type;
781 	goffset sectors = 0;
782 	GtkWidget *status;
783 	gchar *size_str;
784 	gchar *string;
785 
786 	status = brasero_app_get_statusbar2 (brasero_app_get_default ());
787 
788 	if (!project->priv->status_ctx)
789 		project->priv->status_ctx = gtk_statusbar_get_context_id (GTK_STATUSBAR (status),
790 									  "size_project");
791 
792 	gtk_statusbar_pop (GTK_STATUSBAR (status), project->priv->status_ctx);
793 
794 	brasero_burn_session_get_size (BRASERO_BURN_SESSION (project->priv->session),
795 				       &sectors,
796 				       NULL);
797 
798 	session_type = brasero_track_type_new ();
799 	brasero_burn_session_get_input_type (BRASERO_BURN_SESSION (project->priv->session), session_type);
800 
801 	string = brasero_project_get_sectors_string (sectors, session_type);
802 	brasero_track_type_free (session_type);
803 
804 	size_str = g_strdup_printf (_("Estimated project size: %s"), string);
805 	g_free (string);
806 
807 	gtk_statusbar_push (GTK_STATUSBAR (status), project->priv->status_ctx, size_str);
808 	g_free (size_str);
809 }
810 
811 static void
brasero_project_update_controls(BraseroProject * project)812 brasero_project_update_controls (BraseroProject *project)
813 {
814 	GtkAction *action;
815 
816 	brasero_project_set_remove_button_state (project);
817 	brasero_project_set_add_button_state (project);
818 
819 	action = gtk_action_group_get_action (project->priv->project_group, "DeleteAll");
820 	gtk_action_set_sensitive (action, (brasero_disc_is_empty (BRASERO_DISC (project->priv->current))));
821 }
822 
823 static void
brasero_project_modified(BraseroProject * project)824 brasero_project_modified (BraseroProject *project)
825 {
826 	GtkAction *action;
827 
828 	brasero_project_update_controls (project);
829 	brasero_project_update_project_size (project);
830 
831 	/* the state of the following depends on the existence of an opened project */
832 	action = gtk_action_group_get_action (project->priv->project_group, "Save");
833 	gtk_action_set_sensitive (action, TRUE);
834 	project->priv->modified = TRUE;
835 }
836 
837 static void
brasero_project_track_removed(BraseroBurnSession * session,BraseroTrack * track,guint former_position,BraseroProject * project)838 brasero_project_track_removed (BraseroBurnSession *session,
839 			       BraseroTrack *track,
840 			       guint former_position,
841 			       BraseroProject *project)
842 {
843 	brasero_project_modified (project);
844 }
845 
846 static void
brasero_project_track_changed(BraseroBurnSession * session,BraseroTrack * track,BraseroProject * project)847 brasero_project_track_changed (BraseroBurnSession *session,
848 			       BraseroTrack *track,
849 			       BraseroProject *project)
850 {
851 	brasero_project_modified (project);
852 }
853 
854 static void
brasero_project_track_added(BraseroBurnSession * session,BraseroTrack * track,BraseroProject * project)855 brasero_project_track_added (BraseroBurnSession *session,
856 			     BraseroTrack *track,
857 			     BraseroProject *project)
858 {
859 	brasero_project_modified (project);
860 }
861 
862 static void
brasero_project_message_response_span_cb(BraseroDiscMessage * message,GtkResponseType response,BraseroProject * project)863 brasero_project_message_response_span_cb (BraseroDiscMessage *message,
864 					  GtkResponseType response,
865 					  BraseroProject *project)
866 {
867 	if (response == GTK_RESPONSE_OK)
868 		brasero_session_span_start (BRASERO_SESSION_SPAN (project->priv->session));
869 }
870 
871 static void
brasero_project_message_response_overburn_cb(BraseroDiscMessage * message,GtkResponseType response,BraseroProject * project)872 brasero_project_message_response_overburn_cb (BraseroDiscMessage *message,
873 					      GtkResponseType response,
874 					      BraseroProject *project)
875 {
876 	if (response == GTK_RESPONSE_OK)
877 		brasero_session_cfg_add_flags (project->priv->session, BRASERO_BURN_FLAG_OVERBURN);
878 }
879 
880 static void
brasero_project_is_valid(BraseroSessionCfg * session,BraseroProject * project)881 brasero_project_is_valid (BraseroSessionCfg *session,
882 			  BraseroProject *project)
883 {
884 	BraseroSessionError valid;
885 	GdkWindow *window;
886 	GdkCursor *cursor;
887 	GtkAction *action;
888 
889 	/* Update the cursor */
890 	window = gtk_widget_get_window (GTK_WIDGET (project));
891 	if (window) {
892 		BraseroStatus *status;
893 
894 		status = brasero_status_new ();
895 		brasero_burn_session_get_status (BRASERO_BURN_SESSION (session), status);
896 		if (brasero_status_get_result (status) == BRASERO_BURN_NOT_READY
897 		||  brasero_status_get_result (status) == BRASERO_BURN_RUNNING) {
898 			cursor = gdk_cursor_new (GDK_WATCH);
899 			gdk_window_set_cursor (window, cursor);
900 			g_object_unref (cursor);
901 		}
902 		else
903 			gdk_window_set_cursor (window, NULL);
904 
905 		g_object_unref (status);
906 	}
907 
908 	valid = brasero_session_cfg_get_error (project->priv->session);
909 
910 	/* Update burn button state */
911 	action = gtk_action_group_get_action (project->priv->project_group, "Burn");
912 	gtk_action_set_sensitive (action, BRASERO_SESSION_IS_VALID (valid));
913 	gtk_widget_set_sensitive (project->priv->burn, BRASERO_SESSION_IS_VALID (valid));
914 
915 	/* FIXME: update option button state as well */
916 
917 	/* NOTE: empty error is the first checked error; so if another errors comes up
918 	 * that means that file selection is not empty */
919 
920 	/* Clean any message */
921 	brasero_notify_message_remove (project->priv->message,
922 				       BRASERO_NOTIFY_CONTEXT_SIZE);
923 
924 	if (valid == BRASERO_SESSION_EMPTY) {
925 		project->priv->empty = TRUE;
926 		project->priv->oversized = FALSE;
927 	}
928 	else if (valid == BRASERO_SESSION_INSUFFICIENT_SPACE) {
929 		goffset min_disc_size;
930 		goffset available_space;
931 
932 		project->priv->oversized = TRUE;
933 		project->priv->empty = FALSE;
934 
935 		min_disc_size = brasero_session_span_get_max_space (BRASERO_SESSION_SPAN (session));
936 
937 		/* One rule should be that the maximum batch size should not exceed the disc size
938 		 * FIXME! we could change it into a dialog telling the user what is the maximum
939 		 * size required. */
940 		available_space = brasero_burn_session_get_available_medium_space (BRASERO_BURN_SESSION (session));
941 
942 		/* Here there is an alternative: we may be able to span the data
943 		 * across multiple media. So try that. */
944 		if (available_space > min_disc_size
945 		&& brasero_session_span_possible (BRASERO_SESSION_SPAN (session)) == BRASERO_BURN_RETRY) {
946 			GtkWidget *message;
947 
948 			message = brasero_notify_message_add (project->priv->message,
949 							      _("Would you like to burn the selection of files across several media?"),
950 							      _("The project is too large for the disc even with the overburn option."),
951 							      -1,
952 							      BRASERO_NOTIFY_CONTEXT_SIZE);
953 			gtk_widget_set_tooltip_text (gtk_info_bar_add_button (GTK_INFO_BAR (message),
954 									      _("_Burn Several Discs"),
955 								    	      GTK_RESPONSE_OK),
956 						     _("Burn the selection of files across several media"));
957 
958 			g_signal_connect (message,
959 					  "response",
960 					  G_CALLBACK (brasero_project_message_response_span_cb),
961 					  project);
962 		}
963 		else
964 			brasero_notify_message_add (project->priv->message,
965 						    _("Please choose another CD or DVD or insert a new one."),
966 						    _("The project is too large for the disc even with the overburn option."),
967 						    -1,
968 						    BRASERO_NOTIFY_CONTEXT_SIZE);
969 	}
970 	else if (valid == BRASERO_SESSION_OVERBURN_NECESSARY) {
971 		GtkWidget *message;
972 
973 		project->priv->empty = FALSE;
974 		project->priv->oversized = TRUE;
975 		message = brasero_notify_message_add (project->priv->message,
976 						      _("Would you like to burn beyond the disc's reported capacity?"),
977 						      _("The project is too large for the disc and you must remove files from it."
978 							"\nYou may want to use this option if you're using 90 or 100 min CD-R(W) which cannot be properly recognized and therefore needs the overburn option."
979 							"\nNote: This option might cause failure."),
980 						      -1,
981 						      BRASERO_NOTIFY_CONTEXT_SIZE);
982 		gtk_widget_set_tooltip_text (gtk_info_bar_add_button (GTK_INFO_BAR (message),
983 								      _("_Overburn"),
984 							    	      GTK_RESPONSE_OK),
985 					     _("Burn beyond the disc's reported capacity"));
986 
987 		g_signal_connect (message,
988 				  "response",
989 				  G_CALLBACK (brasero_project_message_response_overburn_cb),
990 				  project);
991 	}
992 	else if (valid == BRASERO_SESSION_NO_OUTPUT) {
993 		project->priv->empty = FALSE;
994 		brasero_notify_message_add (project->priv->message,
995 					    _("Please insert a writable CD or DVD."),
996 					    NULL,
997 					    -1,
998 					    BRASERO_NOTIFY_CONTEXT_SIZE);
999 	}
1000 	else if (valid == BRASERO_SESSION_NOT_SUPPORTED) {
1001 		project->priv->empty = FALSE;
1002 		brasero_notify_message_add (project->priv->message,
1003 					    _("Please replace the disc with a supported CD or DVD."),
1004 					    NULL,
1005 					    -1,
1006 					    BRASERO_NOTIFY_CONTEXT_SIZE);
1007 	}
1008 	else if (valid == BRASERO_SESSION_NO_CD_TEXT) {
1009 		brasero_notify_message_add (project->priv->message,
1010 					    _("No track information (artist, title, ...) will be written to the disc."),
1011 					    _("This is not supported by the current active burning backend."),
1012 					    -1,
1013 					    BRASERO_NOTIFY_CONTEXT_SIZE);
1014 	}
1015 	else if (brasero_burn_session_is_dest_file (BRASERO_BURN_SESSION (project->priv->session))
1016 	     &&  brasero_medium_selection_get_media_num (BRASERO_MEDIUM_SELECTION (project->priv->selection)) == 1) {
1017 		/* The user may have forgotten to insert a disc so remind him of that if
1018 		 * there aren't any other possibility in the selection */
1019 		brasero_notify_message_add (project->priv->message,
1020 					    _("Please insert a writable CD or DVD if you don't want to write to an image file."),
1021 					    NULL,
1022 					    10000,
1023 					    BRASERO_NOTIFY_CONTEXT_SIZE);
1024 	}
1025 
1026 	if (BRASERO_SESSION_IS_VALID (valid) || valid == BRASERO_SESSION_NOT_READY)
1027 		gtk_notebook_set_current_page (GTK_NOTEBOOK (project->priv->help), 0);
1028 
1029 	if (BRASERO_SESSION_IS_VALID (valid)) {
1030 		project->priv->empty = FALSE;
1031 		project->priv->oversized = FALSE;
1032 	}
1033 
1034 	gtk_notebook_set_current_page (GTK_NOTEBOOK (project->priv->help),
1035 	                               brasero_disc_is_empty (BRASERO_DISC (project->priv->current))? 0:1);
1036 }
1037 
1038 static void
brasero_project_init(BraseroProject * obj)1039 brasero_project_init (BraseroProject *obj)
1040 {
1041 	GtkSizeGroup *name_size_group;
1042 	GtkSizeGroup *size_group;
1043 	GtkWidget *alignment;
1044 	GtkWidget *selector;
1045 	GtkWidget *table;
1046 
1047 	obj->priv = g_new0 (BraseroProjectPrivate, 1);
1048 
1049 	gtk_orientable_set_orientation (GTK_ORIENTABLE (obj), GTK_ORIENTATION_VERTICAL);
1050 
1051 	g_signal_connect (G_OBJECT (obj),
1052 			  "set-focus-child",
1053 			  G_CALLBACK (brasero_project_focus_changed_cb),
1054 			  NULL);
1055 
1056 	obj->priv->message = brasero_notify_new ();
1057 	gtk_box_pack_start (GTK_BOX (obj), obj->priv->message, FALSE, TRUE, 0);
1058 	gtk_widget_show (obj->priv->message);
1059 
1060 	/* bottom */
1061 	table = gtk_table_new (3, 2, FALSE);
1062 	gtk_container_set_border_width (GTK_CONTAINER (table), 6);
1063 	gtk_table_set_col_spacings (GTK_TABLE (table), 6);
1064 	gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1065 	gtk_widget_show (table);
1066 	gtk_box_pack_end (GTK_BOX (obj), table, FALSE, TRUE, 0);
1067 
1068 	/* Media selection widget */
1069 	name_size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
1070 	selector = brasero_dest_selection_new (NULL);
1071 	gtk_size_group_add_widget (GTK_SIZE_GROUP (name_size_group), selector);
1072 	g_object_unref (name_size_group);
1073 
1074 	gtk_widget_show (selector);
1075 	obj->priv->selection = selector;
1076 
1077 	gtk_table_attach (GTK_TABLE (table), selector,
1078 			  0, 2,
1079 			  1, 2,
1080 			  GTK_FILL|GTK_EXPAND,
1081 			  GTK_FILL|GTK_EXPAND,
1082 			  0, 0);
1083 
1084 	size_group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
1085 
1086 	obj->priv->burn = brasero_utils_make_button (_("_Burn…"),
1087 						     NULL,
1088 						     "media-optical-burn",
1089 						     GTK_ICON_SIZE_BUTTON);
1090 	gtk_widget_show (obj->priv->burn);
1091 	gtk_widget_set_sensitive (obj->priv->burn, FALSE);
1092 	gtk_button_set_focus_on_click (GTK_BUTTON (obj->priv->burn), FALSE);
1093 	g_signal_connect (obj->priv->burn,
1094 			  "clicked",
1095 			  G_CALLBACK (brasero_project_burn_clicked_cb),
1096 			  obj);
1097 	gtk_widget_set_tooltip_text (obj->priv->burn,
1098 				     _("Start to burn the contents of the selection"));
1099 	gtk_size_group_add_widget (GTK_SIZE_GROUP (size_group), obj->priv->burn);
1100 
1101 	alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1102 	gtk_widget_show (alignment);
1103 	gtk_container_add (GTK_CONTAINER (alignment), obj->priv->burn);
1104 	gtk_table_attach (GTK_TABLE (table), alignment,
1105 			  2, 3,
1106 			  1, 2,
1107 			  GTK_FILL,
1108 			  GTK_EXPAND,
1109 			  0, 0);
1110 
1111 	/* Name widget */
1112 	obj->priv->name_display = brasero_project_name_new (BRASERO_BURN_SESSION (obj->priv->session));
1113 	gtk_size_group_add_widget (GTK_SIZE_GROUP (name_size_group), obj->priv->name_display);
1114 	gtk_widget_show (obj->priv->name_display);
1115 	gtk_table_attach (GTK_TABLE (table), obj->priv->name_display,
1116 			  0, 2,
1117 			  0, 1,
1118 			  GTK_EXPAND|GTK_FILL,
1119 			  GTK_EXPAND|GTK_FILL,
1120 			  0, 0);
1121 	obj->priv->empty = 1;
1122 
1123 	g_signal_connect (obj->priv->name_display,
1124 			  "name-changed",
1125 			  G_CALLBACK (brasero_project_name_changed_cb),
1126 			  obj);
1127 
1128 	/* The three panes to put into the notebook */
1129 	obj->priv->audio = brasero_audio_disc_new ();
1130 	gtk_widget_show (obj->priv->audio);
1131 	g_signal_connect (G_OBJECT (obj->priv->audio),
1132 			  "selection-changed",
1133 			  G_CALLBACK (brasero_project_selection_changed_cb),
1134 			  obj);
1135 
1136 	obj->priv->data = brasero_data_disc_new ();
1137 	gtk_widget_show (obj->priv->data);
1138 	brasero_data_disc_set_right_button_group (BRASERO_DATA_DISC (obj->priv->data), size_group);
1139 	g_signal_connect (G_OBJECT (obj->priv->data),
1140 			  "selection-changed",
1141 			  G_CALLBACK (brasero_project_selection_changed_cb),
1142 			  obj);
1143 
1144 	obj->priv->video = brasero_video_disc_new ();
1145 	gtk_widget_show (obj->priv->video);
1146 	g_signal_connect (G_OBJECT (obj->priv->video),
1147 			  "selection-changed",
1148 			  G_CALLBACK (brasero_project_selection_changed_cb),
1149 			  obj);
1150 
1151 	obj->priv->help = brasero_disc_get_use_info_notebook (obj);
1152 	gtk_widget_show (obj->priv->help);
1153 
1154 	obj->priv->discs = gtk_notebook_new ();
1155 	gtk_widget_show (obj->priv->discs);
1156 	gtk_notebook_set_show_border (GTK_NOTEBOOK (obj->priv->discs), FALSE);
1157 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (obj->priv->discs), FALSE);
1158 
1159 	gtk_notebook_prepend_page (GTK_NOTEBOOK (obj->priv->discs),
1160 				   obj->priv->video, NULL);
1161 	gtk_notebook_prepend_page (GTK_NOTEBOOK (obj->priv->discs),
1162 				   obj->priv->data, NULL);
1163 	gtk_notebook_prepend_page (GTK_NOTEBOOK (obj->priv->discs),
1164 				   obj->priv->audio, NULL);
1165 
1166 	gtk_notebook_prepend_page (GTK_NOTEBOOK (obj->priv->help),
1167 				   obj->priv->discs, NULL);
1168 
1169 	gtk_box_pack_start (GTK_BOX (obj),
1170 			    obj->priv->help,
1171 			    TRUE,
1172 			    TRUE,
1173 			    0);
1174 
1175 	g_object_unref (size_group);
1176 }
1177 
1178 static void
brasero_project_finalize(GObject * object)1179 brasero_project_finalize (GObject *object)
1180 {
1181 	BraseroProject *cobj;
1182 	cobj = BRASERO_PROJECT(object);
1183 
1184 	if (cobj->priv->cancel) {
1185 		g_cancellable_cancel (cobj->priv->cancel);
1186 		cobj->priv->cancel = NULL;
1187 	}
1188 
1189 	if (cobj->priv->session) {
1190 		g_object_unref (cobj->priv->session);
1191 		cobj->priv->session = NULL;
1192 	}
1193 
1194 	if (cobj->priv->project)
1195 		g_free (cobj->priv->project);
1196 
1197 	if (cobj->priv->cover)
1198 		g_free (cobj->priv->cover);
1199 
1200 	g_free (cobj->priv);
1201 	G_OBJECT_CLASS (parent_class)->finalize (object);
1202 }
1203 
1204 GtkWidget *
brasero_project_new()1205 brasero_project_new ()
1206 {
1207 	BraseroProject *obj;
1208 
1209 	obj = BRASERO_PROJECT (g_object_new (BRASERO_TYPE_PROJECT, NULL));
1210 	gtk_notebook_set_current_page (GTK_NOTEBOOK (obj->priv->discs), 0);
1211 
1212 	return GTK_WIDGET (obj);
1213 }
1214 
1215 /***************************** URIContainer ************************************/
1216 static void
brasero_project_selection_changed_cb(BraseroDisc * disc,BraseroProject * project)1217 brasero_project_selection_changed_cb (BraseroDisc *disc,
1218 				      BraseroProject *project)
1219 {
1220 	project->priv->selected_uris = brasero_disc_get_selected_uri (project->priv->current, NULL);
1221 	brasero_project_set_remove_button_state (project);
1222 	brasero_uri_container_uri_selected (BRASERO_URI_CONTAINER (project));
1223 }
1224 
1225 static gchar *
brasero_project_get_selected_uri(BraseroURIContainer * container)1226 brasero_project_get_selected_uri (BraseroURIContainer *container)
1227 {
1228 	BraseroProject *project;
1229 	gchar *uri = NULL;
1230 
1231 	project = BRASERO_PROJECT (container);
1232 
1233 	/* if we are burning we better not return anything so as to stop
1234 	 * preview widget from carrying on to play */
1235 	if (project->priv->is_burning)
1236 		return NULL;
1237 
1238 	if (brasero_disc_get_selected_uri (project->priv->current, &uri))
1239 		return uri;
1240 
1241 	return NULL;
1242 }
1243 
1244 static gboolean
brasero_project_get_boundaries(BraseroURIContainer * container,gint64 * start,gint64 * end)1245 brasero_project_get_boundaries (BraseroURIContainer *container,
1246 				gint64 *start,
1247 				gint64 *end)
1248 {
1249 	BraseroProject *project;
1250 
1251 	project = BRASERO_PROJECT (container);
1252 
1253 	/* if we are burning we better not return anything so as to stop
1254 	 * preview widget from carrying on to play */
1255 	if (project->priv->is_burning)
1256 		return FALSE;
1257 
1258 	return brasero_disc_get_boundaries (project->priv->current,
1259 					    start,
1260 					    end);
1261 }
1262 
1263 static void
brasero_project_no_song_dialog(BraseroProject * project)1264 brasero_project_no_song_dialog (BraseroProject *project)
1265 {
1266 	brasero_app_alert (brasero_app_get_default (),
1267 			   _("Please add songs to the project."),
1268 			   _("There are no songs to write to disc"),
1269 			   GTK_MESSAGE_WARNING);
1270 }
1271 
1272 static void
brasero_project_no_file_dialog(BraseroProject * project)1273 brasero_project_no_file_dialog (BraseroProject *project)
1274 {
1275 	brasero_app_alert (brasero_app_get_default (),
1276 			   _("Please add files to the project."),
1277 			   _("There are no files to write to disc"),
1278 			   GTK_MESSAGE_WARNING);
1279 }
1280 
1281 static BraseroBurnResult
brasero_project_check_status(BraseroProject * project)1282 brasero_project_check_status (BraseroProject *project)
1283 {
1284         GtkWidget *dialog;
1285         BraseroStatus *status;
1286 	GtkResponseType response;
1287 	BraseroBurnResult result;
1288 
1289         status = brasero_status_new ();
1290         brasero_burn_session_get_status (BRASERO_BURN_SESSION (project->priv->session), status);
1291         result = brasero_status_get_result (status);
1292         g_object_unref (status);
1293 
1294         if (result == BRASERO_BURN_ERR) {
1295                 /* At the moment the only error possible is an empty project */
1296 		if (BRASERO_IS_AUDIO_DISC (project->priv->current))
1297 			brasero_project_no_song_dialog (project);
1298 		else
1299 			brasero_project_no_file_dialog (project);
1300 
1301 		return BRASERO_BURN_ERR;
1302 	}
1303 
1304 	if (result == BRASERO_BURN_OK)
1305 		return BRASERO_BURN_OK;
1306 
1307         dialog = brasero_status_dialog_new (BRASERO_BURN_SESSION (project->priv->session),
1308                                             gtk_widget_get_toplevel (GTK_WIDGET (project)));
1309 
1310 	gtk_widget_show (dialog);
1311         response = gtk_dialog_run (GTK_DIALOG (dialog));
1312         gtk_widget_destroy (dialog);
1313 
1314         return (response == GTK_RESPONSE_OK)? BRASERO_BURN_OK:BRASERO_BURN_CANCEL;
1315 }
1316 
1317 static BraseroBurnResult
brasero_project_install_missing(BraseroPluginErrorType type,const gchar * detail,gpointer user_data)1318 brasero_project_install_missing (BraseroPluginErrorType type,
1319                                  const gchar *detail,
1320                                  gpointer user_data)
1321 {
1322 	BraseroProject *project = BRASERO_PROJECT (user_data);
1323 	GCancellable *cancel;
1324 	BraseroPK *package;
1325 	GtkWidget *parent;
1326 	gboolean res;
1327 	int xid = 0;
1328 
1329 	/* Get the xid */
1330 	parent = gtk_widget_get_toplevel (GTK_WIDGET (project));
1331 	xid = gdk_x11_window_get_xid (gtk_widget_get_window (parent));
1332 
1333 	package = brasero_pk_new ();
1334 	cancel = g_cancellable_new ();
1335 	project->priv->cancel = cancel;
1336 	switch (type) {
1337 		case BRASERO_PLUGIN_ERROR_MISSING_APP:
1338 			res = brasero_pk_install_missing_app (package, detail, xid, cancel);
1339 			break;
1340 
1341 		case BRASERO_PLUGIN_ERROR_MISSING_LIBRARY:
1342 			res = brasero_pk_install_missing_library (package, detail, xid, cancel);
1343 			break;
1344 
1345 		case BRASERO_PLUGIN_ERROR_MISSING_GSTREAMER_PLUGIN:
1346 			res = brasero_pk_install_gstreamer_plugin (package, detail, xid, cancel);
1347 			break;
1348 
1349 		default:
1350 			res = FALSE;
1351 			break;
1352 	}
1353 
1354 	if (package) {
1355 		g_object_unref (package);
1356 		package = NULL;
1357 	}
1358 
1359 	if (g_cancellable_is_cancelled (cancel)) {
1360 		g_object_unref (cancel);
1361 		return BRASERO_BURN_CANCEL;
1362 	}
1363 
1364 	project->priv->cancel = NULL;
1365 	g_object_unref (cancel);
1366 
1367 	if (!res)
1368 		return BRASERO_BURN_ERR;
1369 
1370 	return BRASERO_BURN_RETRY;
1371 }
1372 
1373 static BraseroBurnResult
brasero_project_list_missing(BraseroPluginErrorType type,const gchar * detail,gpointer user_data)1374 brasero_project_list_missing (BraseroPluginErrorType type,
1375                               const gchar *detail,
1376                               gpointer user_data)
1377 {
1378 	GString *string = user_data;
1379 
1380 	if (type == BRASERO_PLUGIN_ERROR_MISSING_APP ||
1381 	    type == BRASERO_PLUGIN_ERROR_SYMBOLIC_LINK_APP ||
1382 	    type == BRASERO_PLUGIN_ERROR_WRONG_APP_VERSION) {
1383 		g_string_append_c (string, '\n');
1384 		/* Translators: %s is the name of a missing application */
1385 		g_string_append_printf (string, _("%s (application)"), detail);
1386 	}
1387 	else if (type == BRASERO_PLUGIN_ERROR_MISSING_LIBRARY ||
1388 	         type == BRASERO_PLUGIN_ERROR_LIBRARY_VERSION) {
1389 		g_string_append_c (string, '\n');
1390 		/* Translators: %s is the name of a missing library */
1391 		g_string_append_printf (string, _("%s (library)"), detail);
1392 	}
1393 	else if (type == BRASERO_PLUGIN_ERROR_MISSING_GSTREAMER_PLUGIN) {
1394 		g_string_append_c (string, '\n');
1395 		/* Translators: %s is the name of a missing GStreamer plugin */
1396 		g_string_append_printf (string, _("%s (GStreamer plugin)"), detail);
1397 	}
1398 
1399 	return BRASERO_BURN_OK;
1400 }
1401 
1402 static BraseroBurnResult
brasero_project_check_plugins_not_ready(BraseroProject * project,BraseroBurnSession * session)1403 brasero_project_check_plugins_not_ready (BraseroProject *project,
1404                                          BraseroBurnSession *session)
1405 {
1406 	BraseroBurnResult result;
1407 	GtkWidget *parent;
1408 	GString *string;
1409 
1410 	parent = gtk_widget_get_toplevel (GTK_WIDGET (project));
1411 	gtk_widget_set_sensitive (parent, FALSE);
1412 
1413 	brasero_burn_session_set_strict_support (BRASERO_BURN_SESSION (session), TRUE);
1414 	result = brasero_burn_session_can_burn (session, FALSE);
1415 	brasero_burn_session_set_strict_support (BRASERO_BURN_SESSION (session), FALSE);
1416 
1417 	if (result == BRASERO_BURN_OK) {
1418 		gtk_widget_set_sensitive (parent, TRUE);
1419 		return result;
1420 	}
1421 
1422 	result = brasero_burn_session_can_burn (session, FALSE);
1423 	if (result != BRASERO_BURN_OK) {
1424 		gtk_widget_set_sensitive (parent, TRUE);
1425 		return result;
1426 	}
1427 
1428 	result = brasero_session_foreach_plugin_error (session,
1429 	                                               brasero_project_install_missing,
1430 	                                               project);
1431 	gtk_widget_set_sensitive (parent, TRUE);
1432 
1433 	if (result == BRASERO_BURN_CANCEL)
1434 		return result;
1435 
1436 	if (result == BRASERO_BURN_OK)
1437 		return result;
1438 
1439 	string = g_string_new (_("Please install the following manually and try again:"));
1440 	brasero_session_foreach_plugin_error (session,
1441 	                                      brasero_project_list_missing,
1442 	                                      string);
1443 
1444 	brasero_utils_message_dialog (parent,
1445 	                              _("All required applications and libraries are not installed."),
1446 	                              string->str,
1447 	                              GTK_MESSAGE_ERROR);
1448 	g_string_free (string, TRUE);
1449 
1450 	return BRASERO_BURN_ERR;
1451 }
1452 
1453 /******************************** burning **************************************/
1454 static void
brasero_project_setup_session(BraseroProject * project,BraseroBurnSession * session)1455 brasero_project_setup_session (BraseroProject *project,
1456 			       BraseroBurnSession *session)
1457 {
1458 	const gchar *label;
1459 
1460 	label = gtk_entry_get_text (GTK_ENTRY (project->priv->name_display));
1461 	brasero_burn_session_set_label (session, label);
1462 
1463 	if (project->priv->cover) {
1464 		GValue *value;
1465 
1466 		value = g_new0 (GValue, 1);
1467 		g_value_init (value, G_TYPE_STRING);
1468 		g_value_set_string (value, project->priv->cover);
1469 		brasero_burn_session_tag_add (session,
1470 					      BRASERO_COVER_URI,
1471 					      value);
1472 	}
1473 }
1474 
1475 static void
brasero_project_output_changed(BraseroBurnSession * session,BraseroMedium * former_medium,GtkDialog * dialog)1476 brasero_project_output_changed (BraseroBurnSession *session,
1477                                 BraseroMedium *former_medium,
1478                                 GtkDialog *dialog)
1479 {
1480 	gtk_dialog_response (dialog, GTK_RESPONSE_CANCEL);
1481 }
1482 
1483 static BraseroBurnResult
brasero_project_drive_properties(BraseroProject * project)1484 brasero_project_drive_properties (BraseroProject *project)
1485 {
1486 	BraseroTrackType *track_type;
1487 	GtkWidget *medium_prop;
1488 	GtkResponseType answer;
1489 	BraseroDrive *drive;
1490 	gchar *display_name;
1491 	GtkWidget *options;
1492 	GtkWidget *button;
1493 	GtkWidget *dialog;
1494 	glong cancel_sig;
1495 	GtkWidget *box;
1496 	gchar *header;
1497 	gchar *string;
1498 
1499 	/* Build dialog */
1500 	drive = brasero_burn_session_get_burner (BRASERO_BURN_SESSION (project->priv->session));
1501 
1502 	display_name = brasero_drive_get_display_name (drive);
1503 	header = g_strdup_printf (_("Properties of %s"), display_name);
1504 	g_free (display_name);
1505 
1506 	dialog = gtk_dialog_new_with_buttons (header,
1507 					      NULL,
1508 					      GTK_DIALOG_MODAL|
1509 					      GTK_DIALOG_DESTROY_WITH_PARENT,
1510 					      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1511 					      NULL);
1512 	g_free (header);
1513 
1514 	/* This is in case the medium gets ejected instead of our locking it */
1515 	cancel_sig = g_signal_connect (project->priv->session,
1516 	                               "output-changed",
1517 	                               G_CALLBACK (brasero_project_output_changed),
1518 	                               dialog);
1519 
1520 	gtk_dialog_add_button (GTK_DIALOG (dialog),
1521 			       _("Burn _Several Copies"),
1522 			       GTK_RESPONSE_ACCEPT);
1523 
1524 	button = brasero_utils_make_button (_("_Burn"),
1525 					    NULL,
1526 					    "media-optical-burn",
1527 					    GTK_ICON_SIZE_BUTTON);
1528 	gtk_widget_show (button);
1529 	gtk_dialog_add_action_widget (GTK_DIALOG (dialog),
1530 				      button,
1531 				      GTK_RESPONSE_OK);
1532 
1533 	box = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
1534 
1535 	track_type = brasero_track_type_new ();
1536 
1537 	brasero_burn_session_get_input_type (BRASERO_BURN_SESSION (project->priv->session), track_type);
1538 	if (brasero_track_type_get_has_stream (track_type)
1539 	&& BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (track_type))) {
1540 		/* Special case for video project */
1541 		options = brasero_video_options_new (BRASERO_BURN_SESSION (project->priv->session));
1542 		gtk_widget_show (options);
1543 
1544 		string = g_strdup_printf ("<b>%s</b>", _("Video Options"));
1545 		options = brasero_utils_pack_properties (string,
1546 							 options,
1547 							 NULL);
1548 		g_free (string);
1549 		gtk_box_pack_start (GTK_BOX (box), options, FALSE, TRUE, 0);
1550 	}
1551 
1552 	brasero_track_type_free (track_type);
1553 
1554 	medium_prop = brasero_drive_properties_new (project->priv->session);
1555 	gtk_box_pack_start (GTK_BOX (box), medium_prop, TRUE, TRUE, 0);
1556 	gtk_widget_show (medium_prop);
1557 
1558 	brasero_app_set_toplevel (brasero_app_get_default (), GTK_WINDOW (dialog));
1559 
1560 	/* launch the dialog */
1561 	answer = gtk_dialog_run (GTK_DIALOG (dialog));
1562 	gtk_widget_destroy (dialog);
1563 
1564 	g_signal_handler_disconnect (project->priv->session, cancel_sig);
1565 
1566 	if (answer == GTK_RESPONSE_OK)
1567 		return BRASERO_BURN_OK;
1568 
1569 	if (answer == GTK_RESPONSE_ACCEPT)
1570 		return BRASERO_BURN_RETRY;
1571 
1572 	return BRASERO_BURN_CANCEL;
1573 }
1574 
1575 static gboolean
brasero_project_image_properties(BraseroProject * project)1576 brasero_project_image_properties (BraseroProject *project)
1577 {
1578 	BraseroTrackType *track_type;
1579 	GtkResponseType answer;
1580 	GtkWidget *button;
1581 	GtkWidget *dialog;
1582 
1583 	/* Build dialog */
1584 	dialog = brasero_image_properties_new ();
1585 
1586 	brasero_app_set_toplevel (brasero_app_get_default (), GTK_WINDOW (dialog));
1587 	gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
1588 	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ON_PARENT);
1589 
1590 	gtk_dialog_add_button (GTK_DIALOG (dialog),
1591 			       GTK_STOCK_CANCEL,
1592 			       GTK_RESPONSE_CANCEL);
1593 
1594 	button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1595 					_("Create _Image"),
1596 				       GTK_RESPONSE_OK);
1597 	gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name ("iso-image-new", GTK_ICON_SIZE_BUTTON));
1598 
1599 	brasero_image_properties_set_session (BRASERO_IMAGE_PROPERTIES (dialog), project->priv->session);
1600 
1601 	track_type = brasero_track_type_new ();
1602 
1603 	brasero_burn_session_get_input_type (BRASERO_BURN_SESSION (project->priv->session), track_type);
1604 	if (brasero_track_type_get_has_stream (track_type)
1605 	&& BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (track_type))) {
1606 		GtkWidget *box;
1607 		GtkWidget *options;
1608 
1609 		/* create video widget */
1610 		options = brasero_video_options_new (BRASERO_BURN_SESSION (project->priv->session));
1611 		gtk_widget_show (options);
1612 
1613 		box = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
1614 		gtk_box_pack_end (GTK_BOX (box), options, FALSE, TRUE, 0);
1615 	}
1616 
1617 	brasero_track_type_free (track_type);
1618 
1619 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
1620 
1621 	/* launch the dialog */
1622 	answer = gtk_dialog_run (GTK_DIALOG (dialog));
1623 	gtk_widget_destroy (dialog);
1624 
1625 	return (answer == GTK_RESPONSE_OK) ? BRASERO_BURN_OK:BRASERO_BURN_ERR;
1626 }
1627 
1628 static void
brasero_project_burn(BraseroProject * project)1629 brasero_project_burn (BraseroProject *project)
1630 {
1631 	BraseroBurnResult res;
1632 	BraseroDisc *current_disc;
1633 	BraseroDriveSettings *settings;
1634 
1635 	/* Check that we are ready */
1636 	if (brasero_project_check_status (project) != BRASERO_BURN_OK)
1637 		return;
1638 
1639 	/* Check that we are not missing any plugin */
1640 	if (brasero_project_check_plugins_not_ready (project, BRASERO_BURN_SESSION (project->priv->session)) != BRASERO_BURN_OK)
1641 		return;
1642 
1643 	/* Set saved parameters for the session */
1644 	settings = brasero_drive_settings_new ();
1645 	brasero_drive_settings_set_session (settings, BRASERO_BURN_SESSION (project->priv->session));
1646 
1647 	if (!brasero_burn_session_is_dest_file (BRASERO_BURN_SESSION (project->priv->session)))
1648 		res = brasero_project_drive_properties (project);
1649 	else
1650 		res = brasero_project_image_properties (project);
1651 
1652 	if (res != BRASERO_BURN_OK
1653 	&&  res != BRASERO_BURN_RETRY) {
1654 		g_object_unref (settings);
1655 		return;
1656 	}
1657 
1658 	project->priv->is_burning = 1;
1659 
1660 	/* This is to avoid having the settings being wrongly reflected or changed */
1661 	current_disc = project->priv->current;
1662 	brasero_disc_set_session_contents (current_disc, NULL);
1663 	project->priv->current = NULL;
1664 
1665 	brasero_dest_selection_set_session (BRASERO_DEST_SELECTION (project->priv->selection), NULL);
1666 	brasero_project_setup_session (project, BRASERO_BURN_SESSION (project->priv->session));
1667 
1668 	/* This is to stop the preview widget from playing */
1669 	brasero_uri_container_uri_selected (BRASERO_URI_CONTAINER (project));
1670 
1671 	/* now setup the burn dialog */
1672 	project->priv->burnt = brasero_app_burn (brasero_app_get_default (),
1673 						 BRASERO_BURN_SESSION (project->priv->session),
1674 						 res == BRASERO_BURN_RETRY);
1675 
1676 	g_object_unref (settings);
1677 
1678 	/* empty the stack of temporary tracks */
1679 	while (brasero_burn_session_pop_tracks (BRASERO_BURN_SESSION (project->priv->session)) == BRASERO_BURN_RETRY);
1680 
1681 	project->priv->current = current_disc;
1682 	brasero_disc_set_session_contents (current_disc, BRASERO_BURN_SESSION (project->priv->session));
1683 	brasero_dest_selection_set_session (BRASERO_DEST_SELECTION (project->priv->selection),
1684 					    BRASERO_BURN_SESSION (project->priv->session));
1685 
1686 	project->priv->is_burning = 0;
1687 
1688 	brasero_project_update_controls (project);
1689 }
1690 
1691 /******************************** cover ****************************************/
1692 void
brasero_project_create_audio_cover(BraseroProject * project)1693 brasero_project_create_audio_cover (BraseroProject *project)
1694 {
1695 	GtkWidget *window;
1696 
1697 	if (!BRASERO_IS_AUDIO_DISC (project->priv->current))
1698 		return;
1699 
1700 	brasero_project_setup_session (project, BRASERO_BURN_SESSION (project->priv->session));
1701 	window = brasero_session_edit_cover (BRASERO_BURN_SESSION (project->priv->session),
1702 					     gtk_widget_get_toplevel (GTK_WIDGET (project)));
1703 
1704 	/* This strange hack is a way to workaround #568358.
1705 	 * At one point we'll need to hide the dialog which means it
1706 	 * will anwer with a GTK_RESPONSE_NONE */
1707 	while (gtk_dialog_run (GTK_DIALOG (window)) == GTK_RESPONSE_NONE)
1708 		gtk_widget_show (GTK_WIDGET (window));
1709 
1710 	gtk_widget_destroy (window);
1711 }
1712 
1713 /********************************     ******************************************/
1714 static void
brasero_project_reset(BraseroProject * project)1715 brasero_project_reset (BraseroProject *project)
1716 {
1717 	gtk_notebook_set_current_page (GTK_NOTEBOOK (project->priv->help), 1);
1718 
1719 	if (project->priv->project_status) {
1720 		gtk_widget_hide (project->priv->project_status);
1721 		gtk_dialog_response (GTK_DIALOG (project->priv->project_status), GTK_RESPONSE_CANCEL);
1722 		project->priv->project_status = NULL;
1723 	}
1724 
1725 	if (project->priv->current) {
1726 		brasero_disc_set_session_contents (project->priv->current, NULL);
1727 		project->priv->current = NULL;
1728 	}
1729 
1730 	if (project->priv->chooser) {
1731 		gtk_widget_destroy (project->priv->chooser);
1732 		project->priv->chooser = NULL;
1733 	}
1734 
1735 	if (project->priv->project) {
1736 		g_free (project->priv->project);
1737 		project->priv->project = NULL;
1738 	}
1739 
1740 	if (project->priv->cover) {
1741 		g_free (project->priv->cover);
1742 		project->priv->cover = NULL;
1743 	}
1744 
1745 	/* remove the buttons from the "toolbar" */
1746 	if (project->priv->merge_id > 0)
1747 		gtk_ui_manager_remove_ui (project->priv->manager,
1748 					  project->priv->merge_id);
1749 
1750 	project->priv->empty = 1;
1751     	project->priv->burnt = 0;
1752 	project->priv->modified = 0;
1753 
1754 	if (project->priv->session) {
1755 		g_signal_handlers_disconnect_by_func (project->priv->session,
1756 						      brasero_project_is_valid,
1757 						      project);
1758 		g_signal_handlers_disconnect_by_func (project->priv->session,
1759 						      brasero_project_track_added,
1760 						      project);
1761 		g_signal_handlers_disconnect_by_func (project->priv->session,
1762 						      brasero_project_track_changed,
1763 						      project);
1764 		g_signal_handlers_disconnect_by_func (project->priv->session,
1765 						      brasero_project_track_removed,
1766 						      project);
1767 
1768 		/* unref session to force it to remove all temporary files */
1769 		g_object_unref (project->priv->session);
1770 		project->priv->session = NULL;
1771 	}
1772 
1773 	brasero_notify_message_remove (project->priv->message, BRASERO_NOTIFY_CONTEXT_SIZE);
1774 	brasero_notify_message_remove (project->priv->message, BRASERO_NOTIFY_CONTEXT_LOADING);
1775 	brasero_notify_message_remove (project->priv->message, BRASERO_NOTIFY_CONTEXT_MULTISESSION);
1776 }
1777 
1778 static void
brasero_project_new_session(BraseroProject * project,BraseroSessionCfg * session)1779 brasero_project_new_session (BraseroProject *project,
1780                              BraseroSessionCfg *session)
1781 {
1782 	if (project->priv->session)
1783 		brasero_project_reset (project);
1784 
1785 	if (session)
1786 		project->priv->session = g_object_ref (session);
1787 	else
1788 		project->priv->session = brasero_session_cfg_new ();
1789 
1790 	brasero_burn_session_set_strict_support (BRASERO_BURN_SESSION (project->priv->session), FALSE);
1791 
1792 	/* NOTE: "is-valid" is emitted whenever there is a change in the
1793 	 * contents of the session. So no need to connect to track-added, ... */
1794 	g_signal_connect (project->priv->session,
1795 			  "is-valid",
1796 			  G_CALLBACK (brasero_project_is_valid),
1797 			  project);
1798 	g_signal_connect (project->priv->session,
1799 			  "track-added",
1800 			  G_CALLBACK (brasero_project_track_added),
1801 			  project);
1802 	g_signal_connect (project->priv->session,
1803 			  "track-changed",
1804 			  G_CALLBACK (brasero_project_track_changed),
1805 			  project);
1806 	g_signal_connect (project->priv->session,
1807 			  "track-removed",
1808 			  G_CALLBACK (brasero_project_track_removed),
1809 			  project);
1810 
1811 	brasero_dest_selection_set_session (BRASERO_DEST_SELECTION (project->priv->selection),
1812 					    BRASERO_BURN_SESSION (project->priv->session));
1813 	brasero_project_name_set_session (BRASERO_PROJECT_NAME (project->priv->name_display),
1814 					  BRASERO_BURN_SESSION (project->priv->session));
1815 }
1816 
1817 static void
brasero_project_switch(BraseroProject * project,BraseroProjectType type)1818 brasero_project_switch (BraseroProject *project, BraseroProjectType type)
1819 {
1820 	GtkAction *action;
1821 
1822 	if (type == BRASERO_PROJECT_TYPE_AUDIO) {
1823 		project->priv->current = BRASERO_DISC (project->priv->audio);
1824 		gtk_notebook_set_current_page (GTK_NOTEBOOK (project->priv->discs), 0);
1825 		brasero_medium_selection_show_media_type (BRASERO_MEDIUM_SELECTION (project->priv->selection),
1826 							  BRASERO_MEDIA_TYPE_WRITABLE|
1827 							  BRASERO_MEDIA_TYPE_FILE|
1828 		                                          BRASERO_MEDIA_TYPE_CD);
1829 	}
1830 	else if (type == BRASERO_PROJECT_TYPE_DATA) {
1831 		project->priv->current = BRASERO_DISC (project->priv->data);
1832 		gtk_notebook_set_current_page (GTK_NOTEBOOK (project->priv->discs), 1);
1833 		brasero_medium_selection_show_media_type (BRASERO_MEDIUM_SELECTION (project->priv->selection),
1834 							  BRASERO_MEDIA_TYPE_WRITABLE|
1835 							  BRASERO_MEDIA_TYPE_FILE);
1836 	}
1837 	else if (type == BRASERO_PROJECT_TYPE_VIDEO) {
1838 		project->priv->current = BRASERO_DISC (project->priv->video);
1839 		gtk_notebook_set_current_page (GTK_NOTEBOOK (project->priv->discs), 2);
1840 		brasero_medium_selection_show_media_type (BRASERO_MEDIUM_SELECTION (project->priv->selection),
1841 							  BRASERO_MEDIA_TYPE_WRITABLE|
1842 							  BRASERO_MEDIA_TYPE_FILE);
1843 	}
1844 
1845 	if (project->priv->current) {
1846 		project->priv->merge_id = brasero_disc_add_ui (project->priv->current,
1847 							       project->priv->manager,
1848 							       project->priv->message);
1849 		brasero_disc_set_session_contents (project->priv->current,
1850 						   BRASERO_BURN_SESSION (project->priv->session));
1851 	}
1852 
1853 	brasero_notify_message_remove (project->priv->message, BRASERO_NOTIFY_CONTEXT_SIZE);
1854 
1855 	/* update the menus */
1856 	action = gtk_action_group_get_action (project->priv->project_group, "Add");
1857 	gtk_action_set_visible (action, TRUE);
1858 	gtk_action_set_sensitive (action, TRUE);
1859 	action = gtk_action_group_get_action (project->priv->project_group, "DeleteProject");
1860 	gtk_action_set_visible (action, TRUE);
1861 	gtk_action_set_sensitive (action, FALSE);
1862 	action = gtk_action_group_get_action (project->priv->project_group, "DeleteAll");
1863 	gtk_action_set_visible (action, TRUE);
1864 	gtk_action_set_sensitive (action, FALSE);
1865 	action = gtk_action_group_get_action (project->priv->project_group, "SaveAs");
1866 	gtk_action_set_sensitive (action, TRUE);
1867 	action = gtk_action_group_get_action (project->priv->project_group, "Save");
1868 	gtk_action_set_sensitive (action, FALSE);
1869 }
1870 
1871 void
brasero_project_set_audio(BraseroProject * project)1872 brasero_project_set_audio (BraseroProject *project)
1873 {
1874 	brasero_project_new_session (project, NULL);
1875 	brasero_project_switch (project, BRASERO_PROJECT_TYPE_AUDIO);
1876 }
1877 
1878 void
brasero_project_set_data(BraseroProject * project)1879 brasero_project_set_data (BraseroProject *project)
1880 {
1881 	brasero_project_new_session (project, NULL);
1882 	brasero_project_switch (project, BRASERO_PROJECT_TYPE_DATA);
1883 }
1884 
1885 void
brasero_project_set_video(BraseroProject * project)1886 brasero_project_set_video (BraseroProject *project)
1887 {
1888 	brasero_project_new_session (project, NULL);
1889 	brasero_project_switch (project, BRASERO_PROJECT_TYPE_VIDEO);
1890 }
1891 
1892 BraseroBurnResult
brasero_project_confirm_switch(BraseroProject * project,gboolean keep_files)1893 brasero_project_confirm_switch (BraseroProject *project,
1894 				gboolean keep_files)
1895 {
1896 	GtkWidget *dialog;
1897 	GtkResponseType answer;
1898 
1899 	if (project->priv->project) {
1900 		if (!project->priv->modified)
1901 			return TRUE;
1902 
1903 		dialog = brasero_app_dialog (brasero_app_get_default (),
1904 					     _("Do you really want to create a new project and discard the current one?"),
1905 					     GTK_BUTTONS_CANCEL,
1906 					     GTK_MESSAGE_WARNING);
1907 
1908 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1909 							  _("If you choose to create a new empty project, all changes will be lost."));
1910 
1911 		gtk_dialog_add_button (GTK_DIALOG (dialog),
1912 				       _("_Discard Changes"),
1913 				       GTK_RESPONSE_OK);
1914 	}
1915 	else if (keep_files) {
1916 		if (project->priv->empty)
1917 			return TRUE;
1918 
1919 		dialog = brasero_app_dialog (brasero_app_get_default (),
1920 					     _("Do you want to discard the file selection or add it to the new project?"),
1921 					     GTK_BUTTONS_CANCEL,
1922 					     GTK_MESSAGE_WARNING);
1923 
1924 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1925 							  _("If you choose to create a new empty project, the file selection will be discarded."));
1926 		gtk_dialog_add_button (GTK_DIALOG (dialog),
1927 				       _("_Discard File Selection"),
1928 				       GTK_RESPONSE_OK);
1929 
1930 		gtk_dialog_add_button (GTK_DIALOG (dialog),
1931 				       _("_Keep File Selection"),
1932 				       GTK_RESPONSE_ACCEPT);
1933 	}
1934 	else {
1935 		if (project->priv->empty)
1936 			return TRUE;
1937 
1938 		dialog = brasero_app_dialog (brasero_app_get_default (),
1939 					     _("Do you really want to create a new project and discard the current one?"),
1940 					     GTK_BUTTONS_CANCEL,
1941 					     GTK_MESSAGE_WARNING);
1942 
1943 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1944 							  _("If you choose to create a new empty project, the file selection will be discarded."));
1945 		gtk_dialog_add_button (GTK_DIALOG (dialog),
1946 				       _("_Discard Project"),
1947 				       GTK_RESPONSE_OK);
1948 	}
1949 
1950 	answer = gtk_dialog_run (GTK_DIALOG (dialog));
1951 	gtk_widget_destroy (dialog);
1952 
1953 	if (answer == GTK_RESPONSE_ACCEPT)
1954 		return BRASERO_BURN_RETRY;
1955 
1956 	if (answer != GTK_RESPONSE_OK)
1957 		return BRASERO_BURN_CANCEL;
1958 
1959 	return BRASERO_BURN_OK;
1960 }
1961 
1962 void
brasero_project_set_none(BraseroProject * project)1963 brasero_project_set_none (BraseroProject *project)
1964 {
1965 	GtkAction *action;
1966 	GtkWidget *status;
1967 
1968 	brasero_project_reset (project);
1969 
1970 	/* update buttons/menus */
1971 	action = gtk_action_group_get_action (project->priv->project_group, "Add");
1972 	gtk_action_set_visible (action, FALSE);
1973 	action = gtk_action_group_get_action (project->priv->project_group, "DeleteProject");
1974 	gtk_action_set_visible (action, FALSE);
1975 	action = gtk_action_group_get_action (project->priv->project_group, "DeleteAll");
1976 	gtk_action_set_visible (action, FALSE);
1977 	action = gtk_action_group_get_action (project->priv->project_group, "SaveAs");
1978 	gtk_action_set_sensitive (action, FALSE);
1979 	action = gtk_action_group_get_action (project->priv->project_group, "Save");
1980 	gtk_action_set_sensitive (action, FALSE);
1981 
1982 	if (project->priv->merge_id)
1983 		gtk_ui_manager_remove_ui (project->priv->manager,
1984 					  project->priv->merge_id);
1985 
1986 	status = brasero_app_get_statusbar2 (brasero_app_get_default ());
1987 
1988 	if (project->priv->status_ctx)
1989 		gtk_statusbar_pop (GTK_STATUSBAR (status), project->priv->status_ctx);
1990 }
1991 
1992 /**************************** manage the relations with the sources ************/
1993 static void
brasero_project_transfer_uris_from_src(BraseroProject * project)1994 brasero_project_transfer_uris_from_src (BraseroProject *project)
1995 {
1996 	gchar **uris;
1997 	gchar **uri;
1998 
1999 	if (!project->priv->current_source)
2000 		return;
2001 
2002 	uris = brasero_uri_container_get_selected_uris (project->priv->current_source);
2003 	if (!uris)
2004 		return;
2005 
2006 	uri = uris;
2007 	while (*uri) {
2008 		brasero_disc_add_uri (project->priv->current, *uri);
2009 		uri ++;
2010 	}
2011 
2012 	g_strfreev (uris);
2013 }
2014 
2015 static void
brasero_project_source_uri_activated_cb(BraseroURIContainer * container,BraseroProject * project)2016 brasero_project_source_uri_activated_cb (BraseroURIContainer *container,
2017 					 BraseroProject *project)
2018 {
2019 	brasero_project_transfer_uris_from_src (project);
2020 }
2021 
2022 static void
brasero_project_source_uri_selected_cb(BraseroURIContainer * container,BraseroProject * project)2023 brasero_project_source_uri_selected_cb (BraseroURIContainer *container,
2024 					BraseroProject *project)
2025 {
2026 	brasero_project_set_add_button_state (project);
2027 }
2028 
2029 void
brasero_project_set_source(BraseroProject * project,BraseroURIContainer * source)2030 brasero_project_set_source (BraseroProject *project,
2031 			    BraseroURIContainer *source)
2032 {
2033 	if (project->priv->chooser)
2034 		gtk_dialog_response (GTK_DIALOG (project->priv->chooser), GTK_RESPONSE_CANCEL);
2035 
2036 	if (project->priv->activated_id) {
2037 		g_signal_handler_disconnect (project->priv->current_source,
2038 					     project->priv->activated_id);
2039 		project->priv->activated_id = 0;
2040 	}
2041 
2042 	if (project->priv->selected_id) {
2043 		g_signal_handler_disconnect (project->priv->current_source,
2044 					     project->priv->selected_id);
2045 		project->priv->selected_id = 0;
2046 	}
2047 
2048 	project->priv->current_source = source;
2049 
2050 	if (source) {
2051 		project->priv->activated_id = g_signal_connect (source,
2052 							        "uri-activated",
2053 							        G_CALLBACK (brasero_project_source_uri_activated_cb),
2054 							        project);
2055 		project->priv->selected_id = g_signal_connect (source,
2056 							       "uri-selected",
2057 							       G_CALLBACK (brasero_project_source_uri_selected_cb),
2058 							       project);
2059 	}
2060 
2061 	brasero_project_set_add_button_state (project);
2062 }
2063 
2064 /******************************* menus/buttons *********************************/
2065 static void
brasero_project_save_cb(GtkAction * action,BraseroProject * project)2066 brasero_project_save_cb (GtkAction *action, BraseroProject *project)
2067 {
2068 	brasero_project_save_project (project);
2069 }
2070 
2071 static void
brasero_project_save_as_cb(GtkAction * action,BraseroProject * project)2072 brasero_project_save_as_cb (GtkAction *action, BraseroProject *project)
2073 {
2074 	brasero_project_save_project_as (project);
2075 }
2076 
2077 static void
brasero_project_file_chooser_activated_cb(GtkWidget * chooser,BraseroProject * project)2078 brasero_project_file_chooser_activated_cb (GtkWidget *chooser,
2079 					   BraseroProject *project)
2080 {
2081 	gboolean sensitive;
2082 	GtkAction *action;
2083 	GSList *uris;
2084 	GSList *iter;
2085 
2086 	if (!project->priv->chooser)
2087 		return;
2088 
2089 	project->priv->chooser = NULL;
2090 	uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser));
2091 	gtk_widget_destroy (GTK_WIDGET (chooser));
2092 
2093 	sensitive = ((!project->priv->current_source || !project->priv->has_focus) &&
2094 		      !project->priv->oversized);
2095 
2096 	action = gtk_action_group_get_action (project->priv->project_group, "Add");
2097 	gtk_action_set_sensitive (action, sensitive);
2098 
2099 	for (iter = uris; iter; iter = iter->next) {
2100 		gchar *uri;
2101 
2102 		uri = iter->data;
2103 		brasero_disc_add_uri (project->priv->current, uri);
2104 	}
2105 	g_slist_foreach (uris, (GFunc) g_free, NULL);
2106 	g_slist_free (uris);
2107 }
2108 
2109 static void
brasero_project_file_chooser_response_cb(GtkWidget * chooser,GtkResponseType response,BraseroProject * project)2110 brasero_project_file_chooser_response_cb (GtkWidget *chooser,
2111 					  GtkResponseType response,
2112 					  BraseroProject *project)
2113 {
2114 	gboolean sensitive;
2115 	GtkAction *action;
2116 	GSList *uris;
2117 	GSList *iter;
2118 
2119 	if (!project->priv->chooser)
2120 		return;
2121 
2122 	sensitive = ((!project->priv->current_source || !project->priv->has_focus) &&
2123 		      !project->priv->oversized);
2124 
2125 	action = gtk_action_group_get_action (project->priv->project_group, "Add");
2126 	gtk_action_set_sensitive (action, sensitive);
2127 
2128 	if (response != BRASERO_RESPONSE_ADD) {
2129 		gtk_widget_destroy (chooser);
2130 		project->priv->chooser = NULL;
2131 		return;
2132 	}
2133 
2134 	project->priv->chooser = NULL;
2135 	uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser));
2136 	gtk_widget_destroy (GTK_WIDGET (chooser));
2137 
2138 	for (iter = uris; iter; iter = iter->next) {
2139 		gchar *uri;
2140 
2141 		uri = iter->data;
2142 		brasero_disc_add_uri (project->priv->current, uri);
2143 	}
2144 	g_slist_foreach (uris, (GFunc) g_free, NULL);
2145 	g_slist_free (uris);
2146 }
2147 
2148 #ifdef BUILD_PREVIEW
2149 static void
brasero_project_preview_ready(BraseroPlayer * player,GtkFileChooser * chooser)2150 brasero_project_preview_ready (BraseroPlayer *player,
2151 			       GtkFileChooser *chooser)
2152 {
2153 	gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
2154 }
2155 
2156 static void
brasero_project_update_preview(GtkFileChooser * chooser,BraseroPlayer * player)2157 brasero_project_update_preview (GtkFileChooser *chooser,
2158 				BraseroPlayer *player)
2159 {
2160 	gchar *uri;
2161 
2162 	gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
2163 
2164 	uri = gtk_file_chooser_get_preview_uri (chooser);
2165 	brasero_player_set_uri (player, uri);
2166 	g_free (uri);
2167 }
2168 #endif
2169 
2170 static void
brasero_project_add_uris_cb(GtkAction * action,BraseroProject * project)2171 brasero_project_add_uris_cb (GtkAction *action,
2172 			     BraseroProject *project)
2173 {
2174 	GtkWidget *toplevel;
2175 	GtkFileFilter *filter;
2176 
2177 	if (project->priv->current_source) {
2178 		brasero_project_transfer_uris_from_src (project);
2179 		return;
2180 	}
2181 
2182 	/* Set the Add button grey as we don't want
2183 	 * the user to be able to click again until the
2184 	 * dialog has been closed */
2185 	gtk_action_set_sensitive (action, FALSE);
2186 
2187 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (project));
2188 	project->priv->chooser = gtk_file_chooser_dialog_new (_("Select Files"),
2189 							      GTK_WINDOW (toplevel),
2190 							      GTK_FILE_CHOOSER_ACTION_OPEN,
2191 							      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2192 							      NULL);
2193 	gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (project->priv->chooser), TRUE);
2194 	gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (project->priv->chooser), FALSE);
2195 	gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (project->priv->chooser), g_get_home_dir ());
2196 	brasero_file_chooser_customize (project->priv->chooser, NULL);
2197 	gtk_widget_show (project->priv->chooser);
2198 
2199 	/* This is to work around a bug in GTK+ which doesn't want to add "Add"
2200 	 * button or anything that is not "Open" or "Cancel" buttons */
2201 	/* Just for the record, file chooser creation uses all GtkResponseType
2202 	 * that are already defined for internal use like GTK_RESPONSE_OK,
2203 	 * *_APPLY and so on (usually to open directories, not add them). So we
2204 	 * have to define on custom here. */
2205 	gtk_dialog_add_button (GTK_DIALOG (project->priv->chooser),
2206 			       GTK_STOCK_ADD,
2207 			       BRASERO_RESPONSE_ADD);
2208 	gtk_dialog_set_default_response (GTK_DIALOG (project->priv->chooser),
2209 					 BRASERO_RESPONSE_ADD);
2210 
2211 	g_signal_connect (project->priv->chooser,
2212 			  "file-activated",
2213 			  G_CALLBACK (brasero_project_file_chooser_activated_cb),
2214 			  project);
2215 	g_signal_connect (project->priv->chooser,
2216 			  "response",
2217 			  G_CALLBACK (brasero_project_file_chooser_response_cb),
2218 			  project);
2219 	g_signal_connect (project->priv->chooser,
2220 			  "close",
2221 			  G_CALLBACK (brasero_project_file_chooser_activated_cb),
2222 			  project);
2223 
2224 	filter = gtk_file_filter_new ();
2225 	gtk_file_filter_set_name (filter, _("All files"));
2226 	gtk_file_filter_add_pattern (filter, "*");
2227 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (project->priv->chooser), filter);
2228 
2229 	filter = gtk_file_filter_new ();
2230 	gtk_file_filter_set_name (filter, _("Audio files"));
2231 	gtk_file_filter_add_mime_type (filter, "audio/*");
2232 	gtk_file_filter_add_mime_type (filter, "application/ogg");
2233 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (project->priv->chooser), filter);
2234 
2235 	if (BRASERO_IS_AUDIO_DISC (project->priv->current))
2236 		gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (project->priv->chooser), filter);
2237 
2238 	filter = gtk_file_filter_new ();
2239 	gtk_file_filter_set_name (filter, _("Movies"));
2240 	gtk_file_filter_add_mime_type (filter, "video/*");
2241 	gtk_file_filter_add_mime_type (filter, "application/ogg");
2242 	gtk_file_filter_add_mime_type (filter, "application/x-flash-video");
2243 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (project->priv->chooser), filter);
2244 
2245 	if (BRASERO_IS_VIDEO_DISC (project->priv->current))
2246 		gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (project->priv->chooser), filter);
2247 
2248 	filter = gtk_file_filter_new ();
2249 	/* Translators: this is an image, a picture, not a "Disc Image" */
2250 	gtk_file_filter_set_name (filter, C_("picture", "Image files"));
2251 	gtk_file_filter_add_mime_type (filter, "image/*");
2252 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (project->priv->chooser), filter);
2253 
2254 #ifdef BUILD_PREVIEW
2255 
2256 	GtkWidget *player;
2257 	gpointer value;
2258 
2259 	brasero_setting_get_value (brasero_setting_get_default (),
2260 	                           BRASERO_SETTING_SHOW_PREVIEW,
2261 	                           &value);
2262 
2263 	if (!GPOINTER_TO_INT (value))
2264 		return;
2265 
2266 	/* if preview is activated add it */
2267 	player = brasero_player_new ();
2268 
2269 	gtk_widget_show (player);
2270 	gtk_file_chooser_set_preview_widget_active (GTK_FILE_CHOOSER (project->priv->chooser), TRUE);
2271 	gtk_file_chooser_set_use_preview_label (GTK_FILE_CHOOSER (project->priv->chooser), FALSE);
2272 	gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (project->priv->chooser), player);
2273 
2274 	g_signal_connect (project->priv->chooser,
2275 			  "update-preview",
2276 			  G_CALLBACK (brasero_project_update_preview),
2277 			  player);
2278 
2279 	g_signal_connect (player,
2280 			  "ready",
2281 			  G_CALLBACK (brasero_project_preview_ready),
2282 			  project->priv->chooser);
2283 #endif
2284 
2285 }
2286 
2287 static void
brasero_project_remove_selected_uris_cb(GtkAction * action,BraseroProject * project)2288 brasero_project_remove_selected_uris_cb (GtkAction *action, BraseroProject *project)
2289 {
2290 	brasero_disc_delete_selected (BRASERO_DISC (project->priv->current));
2291 }
2292 
2293 static void
brasero_project_empty_cb(GtkAction * action,BraseroProject * project)2294 brasero_project_empty_cb (GtkAction *action, BraseroProject *project)
2295 {
2296 	if (!project->priv->empty) {
2297 		GtkWidget *dialog;
2298 		GtkResponseType answer;
2299 
2300 		dialog = brasero_app_dialog (brasero_app_get_default (),
2301 					      _("Do you really want to empty the current project?"),
2302 					     GTK_BUTTONS_CANCEL,
2303 					     GTK_MESSAGE_WARNING);
2304 
2305 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
2306 							  _("Emptying a project will remove all files already added. "
2307 							    "All the work will be lost. "
2308 							    "Note that files will not be deleted from their own location, "
2309 							    "just no longer listed here."));
2310 		gtk_dialog_add_button (GTK_DIALOG (dialog),
2311 					/* Translators: "empty" is a verb here */
2312 				       _("E_mpty Project"),
2313 				       GTK_RESPONSE_OK);
2314 
2315 		answer = gtk_dialog_run (GTK_DIALOG (dialog));
2316 		gtk_widget_destroy (dialog);
2317 
2318 		if (answer != GTK_RESPONSE_OK)
2319 			return;
2320 	}
2321 
2322 	if (!brasero_disc_clear (BRASERO_DISC (project->priv->current)))
2323 		brasero_burn_session_add_track (BRASERO_BURN_SESSION (project->priv->session), NULL, NULL);
2324 }
2325 
2326 static void
brasero_project_burn_cb(GtkAction * action,BraseroProject * project)2327 brasero_project_burn_cb (GtkAction *action, BraseroProject *project)
2328 {
2329 	brasero_project_burn (project);
2330 }
2331 
2332 static void
brasero_project_burn_clicked_cb(GtkButton * button,BraseroProject * project)2333 brasero_project_burn_clicked_cb (GtkButton *button, BraseroProject *project)
2334 {
2335 	brasero_project_burn (project);
2336 }
2337 
2338 void
brasero_project_register_ui(BraseroProject * project,GtkUIManager * manager)2339 brasero_project_register_ui (BraseroProject *project, GtkUIManager *manager)
2340 {
2341 	GError *error = NULL;
2342 	GtkAction *action;
2343 	GtkWidget *toolbar;
2344 
2345 	/* menus */
2346 	project->priv->project_group = gtk_action_group_new ("ProjectActions1");
2347 	gtk_action_group_set_translation_domain (project->priv->project_group, GETTEXT_PACKAGE);
2348 	gtk_action_group_add_actions (project->priv->project_group,
2349 				      entries,
2350 				      G_N_ELEMENTS (entries),
2351 				      project);
2352 
2353 	gtk_ui_manager_insert_action_group (manager, project->priv->project_group, 0);
2354 	if (!gtk_ui_manager_add_ui_from_string (manager,
2355 						description,
2356 						-1,
2357 						&error)) {
2358 		g_message ("building menus/toolbar failed: %s", error->message);
2359 		g_error_free (error);
2360 	}
2361 
2362 	toolbar = gtk_ui_manager_get_widget (manager, "/Toolbar");
2363 	gtk_style_context_add_class (gtk_widget_get_style_context (toolbar),
2364 				     GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
2365 
2366 	action = gtk_action_group_get_action (project->priv->project_group, "Save");
2367 	g_object_set (action,
2368 		      "short-label", _("_Save"), /* for toolbar buttons */
2369 		      NULL);
2370 	gtk_action_set_sensitive (action, FALSE);
2371 	action = gtk_action_group_get_action (project->priv->project_group, "SaveAs");
2372 	gtk_action_set_sensitive (action, FALSE);
2373 
2374 	action = gtk_action_group_get_action (project->priv->project_group, "Burn");
2375 	gtk_action_set_sensitive (action, FALSE);
2376 	action = gtk_action_group_get_action (project->priv->project_group, "Add");
2377 	gtk_action_set_sensitive (action, FALSE);
2378 	g_object_set (action,
2379 		      "short-label", _("_Add"), /* for toolbar buttons */
2380 		      NULL);
2381 	action = gtk_action_group_get_action (project->priv->project_group, "DeleteProject");
2382 	gtk_action_set_sensitive (action, FALSE);
2383 	g_object_set (action,
2384 		      "short-label", _("_Remove"), /* for toolbar buttons */
2385 		      NULL);
2386 	action = gtk_action_group_get_action (project->priv->project_group, "DeleteAll");
2387 	gtk_action_set_sensitive (action, FALSE);
2388 
2389 	project->priv->manager = manager;
2390 
2391 	if (gtk_widget_get_realized (project->priv->name_display))
2392 		gtk_widget_grab_focus (project->priv->name_display);
2393 }
2394 
2395 /******************************* common to save/open ***************************/
2396 static void
brasero_project_add_to_recents(BraseroProject * project,const gchar * uri,gboolean is_project)2397 brasero_project_add_to_recents (BraseroProject *project,
2398 				const gchar *uri,
2399 				gboolean is_project)
2400 {
2401    	GtkRecentManager *recent;
2402 	gchar *groups [] = { "brasero", NULL };
2403 	gchar *open_playlist = "brasero -l %u";
2404 	GtkRecentData recent_data = { NULL,
2405 				      NULL,
2406 				      "application/x-brasero",
2407 				      "brasero",
2408 				      "brasero -p %u",
2409 				      groups,
2410 				      FALSE };
2411 
2412     	recent = gtk_recent_manager_get_default ();
2413 
2414 	if (is_project)
2415 		recent_data.app_exec = open_playlist;
2416 
2417     	gtk_recent_manager_add_full (recent, uri, &recent_data);
2418 }
2419 
2420 static void
brasero_project_set_uri(BraseroProject * project,const gchar * uri,BraseroProjectType type)2421 brasero_project_set_uri (BraseroProject *project,
2422 			 const gchar *uri,
2423 			 BraseroProjectType type)
2424 {
2425      	gchar *name;
2426 	gchar *title;
2427 	GtkAction *action;
2428 	GtkWidget *toplevel;
2429 
2430 	/* possibly reset the name of the project */
2431 	if (uri) {
2432 		if (project->priv->project)
2433 			g_free (project->priv->project);
2434 
2435 		project->priv->project = g_strdup (uri);
2436 	}
2437 
2438 	uri = uri ? uri : project->priv->project;
2439 
2440 	/* add it to recent manager */
2441 	if (brasero_app_is_running (brasero_app_get_default ()))
2442 		brasero_project_add_to_recents (project, uri, TRUE);
2443 
2444 	/* update the name of the main window */
2445     	BRASERO_GET_BASENAME_FOR_DISPLAY (uri, name);
2446 	if (type == BRASERO_PROJECT_TYPE_DATA)
2447 		/* Translators: %s is the name of the project */
2448 		title = g_strdup_printf (_("Brasero — %s (Data Disc)"), name);
2449 	else if (type == BRASERO_PROJECT_TYPE_AUDIO)
2450 		/* Translators: %s is the name of the project */
2451 		title = g_strdup_printf (_("Brasero — %s (Audio Disc)"), name);
2452 	else if (type == BRASERO_PROJECT_TYPE_VIDEO)
2453 		/* Translators: %s is the name of the project */
2454 		title = g_strdup_printf (_("Brasero — %s (Video Disc)"), name);
2455 	else
2456 		title = NULL;
2457 
2458 	g_free (name);
2459 
2460 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (project));
2461 	if (toplevel)
2462 		gtk_window_set_title (GTK_WINDOW (toplevel), title);
2463 	g_free (title);
2464 
2465 	/* update the menus */
2466 	action = gtk_action_group_get_action (project->priv->project_group, "Save");
2467 	gtk_action_set_sensitive (action, FALSE);
2468 }
2469 
2470 static BraseroProjectType
brasero_project_get_session_type(BraseroProject * project)2471 brasero_project_get_session_type (BraseroProject *project)
2472 {
2473 	BraseroTrackType *session_type;
2474 	BraseroProjectType type;
2475 
2476         session_type = brasero_track_type_new ();
2477         brasero_burn_session_get_input_type (BRASERO_BURN_SESSION (project->priv->session), session_type);
2478 
2479 	if (brasero_track_type_get_has_stream (session_type)) {
2480                 if (BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (session_type)))
2481 		        type = BRASERO_PROJECT_TYPE_VIDEO;
2482                 else
2483 		        type = BRASERO_PROJECT_TYPE_AUDIO;
2484         }
2485 	else if (brasero_track_type_get_has_data (session_type))
2486 		type = BRASERO_PROJECT_TYPE_DATA;
2487 	else
2488 		type = BRASERO_PROJECT_TYPE_INVALID;
2489 
2490     	brasero_track_type_free (session_type);
2491 
2492         return type;
2493 }
2494 
2495 /******************************* Projects **************************************/
2496 BraseroProjectType
brasero_project_open_session(BraseroProject * project,BraseroSessionCfg * session)2497 brasero_project_open_session (BraseroProject *project,
2498                               BraseroSessionCfg *session)
2499 {
2500 	GValue *value;
2501 	BraseroProjectType type;
2502 
2503 	brasero_project_new_session (project, session);
2504 
2505 	type = brasero_project_get_session_type (project);
2506         if (type == BRASERO_PROJECT_TYPE_INVALID)
2507                 return type;
2508 
2509 	brasero_project_switch (project, type);
2510 
2511 	if (brasero_burn_session_get_label (BRASERO_BURN_SESSION (project->priv->session))) {
2512 		g_signal_handlers_block_by_func (project->priv->name_display,
2513 						 brasero_project_name_changed_cb,
2514 						 project);
2515 		gtk_entry_set_text (GTK_ENTRY (project->priv->name_display),
2516 					       brasero_burn_session_get_label (BRASERO_BURN_SESSION (project->priv->session)));
2517 		g_signal_handlers_unblock_by_func (project->priv->name_display,
2518 						   brasero_project_name_changed_cb,
2519 						   project);
2520 	}
2521 
2522 	value = NULL;
2523 	brasero_burn_session_tag_lookup (BRASERO_BURN_SESSION (project->priv->session),
2524 					 BRASERO_COVER_URI,
2525 					 &value);
2526 	if (value) {
2527 		if (project->priv->cover)
2528 			g_free (project->priv->cover);
2529 
2530 		project->priv->cover = g_strdup (g_value_get_string (value));
2531 	}
2532 
2533 	project->priv->modified = 0;
2534 
2535 	return type;
2536 }
2537 
2538 BraseroProjectType
brasero_project_convert_to_data(BraseroProject * project)2539 brasero_project_convert_to_data (BraseroProject *project)
2540 {
2541 	GSList *tracks;
2542 	BraseroProjectType type;
2543 	BraseroSessionCfg *newsession;
2544 	BraseroTrackDataCfg *data_track;
2545 
2546 	newsession = brasero_session_cfg_new ();
2547 	data_track = brasero_track_data_cfg_new ();
2548 	brasero_burn_session_add_track (BRASERO_BURN_SESSION (newsession),
2549 					BRASERO_TRACK (data_track),
2550 					NULL);
2551 	g_object_unref (data_track);
2552 
2553 	tracks = brasero_burn_session_get_tracks (BRASERO_BURN_SESSION (project->priv->session));
2554 	for (; tracks; tracks = tracks->next) {
2555 		BraseroTrackStream *track;
2556 		gchar *uri;
2557 
2558 		track = tracks->data;
2559 		uri = brasero_track_stream_get_source (track, TRUE);
2560 		brasero_track_data_cfg_add (data_track, uri, NULL);
2561 		g_free (uri);
2562 	}
2563 
2564 	type = brasero_project_open_session (project, newsession);
2565 	g_object_unref (newsession);
2566 
2567 	return type;
2568 }
2569 
2570 BraseroProjectType
brasero_project_convert_to_stream(BraseroProject * project,gboolean is_video)2571 brasero_project_convert_to_stream (BraseroProject *project,
2572 				   gboolean is_video)
2573 {
2574 	GSList *tracks;
2575 	GtkTreeIter iter;
2576 	BraseroProjectType type;
2577 	BraseroSessionCfg *newsession;
2578 	BraseroTrackDataCfg *data_track;
2579 
2580 	tracks = brasero_burn_session_get_tracks (BRASERO_BURN_SESSION (project->priv->session));
2581 	if (!tracks)
2582 		return BRASERO_PROJECT_TYPE_INVALID;
2583 
2584 	data_track = tracks->data;
2585 	if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (data_track), &iter))
2586 		return BRASERO_PROJECT_TYPE_INVALID;
2587 
2588 	newsession = brasero_session_cfg_new ();
2589 	do {
2590 		gchar *uri;
2591 		BraseroTrackStreamCfg *track;
2592 
2593 		gtk_tree_model_get (GTK_TREE_MODEL (data_track), &iter,
2594 				    BRASERO_DATA_TREE_MODEL_URI, &uri,
2595 				    -1);
2596 
2597 		track = brasero_track_stream_cfg_new ();
2598 		brasero_track_stream_set_source (BRASERO_TRACK_STREAM (track), uri);
2599 		brasero_track_stream_set_format (BRASERO_TRACK_STREAM (track),
2600 						 is_video ? BRASERO_VIDEO_FORMAT_UNDEFINED:BRASERO_AUDIO_FORMAT_UNDEFINED);
2601 		g_free (uri);
2602 
2603 		brasero_burn_session_add_track (BRASERO_BURN_SESSION (newsession),
2604 						BRASERO_TRACK (track),
2605 						NULL);
2606 		g_object_unref (track);
2607 
2608 	} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (data_track), &iter));
2609 
2610 	type = brasero_project_open_session (project, newsession);
2611 	g_object_unref (newsession);
2612 
2613 	return type;
2614 }
2615 
2616 /******************************** save project *********************************/
2617 static void
brasero_project_not_saved_dialog(BraseroProject * project)2618 brasero_project_not_saved_dialog (BraseroProject *project)
2619 {
2620 	xmlError *error;
2621 
2622 	error = xmlGetLastError ();
2623 	brasero_app_alert (brasero_app_get_default (),
2624 			   _("Your project has not been saved."),
2625 			   error? error->message:_("An unknown error occurred"),
2626 			   GTK_MESSAGE_ERROR);
2627 	xmlResetLastError ();
2628 }
2629 
2630 static GtkResponseType
brasero_project_save_project_dialog(BraseroProject * project,gboolean show_cancel)2631 brasero_project_save_project_dialog (BraseroProject *project,
2632 				     gboolean show_cancel)
2633 {
2634 	GtkWidget *dialog;
2635 	GtkResponseType result;
2636 
2637 	dialog = brasero_app_dialog (brasero_app_get_default (),
2638 				     _("Save the changes of current project before closing?"),
2639 				     GTK_BUTTONS_NONE,
2640 				     GTK_MESSAGE_WARNING);
2641 
2642 	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
2643 						  _("If you don't save, changes will be permanently lost."));
2644 
2645 	if (show_cancel)
2646 		gtk_dialog_add_buttons (GTK_DIALOG (dialog),
2647 					_("Cl_ose Without Saving"), GTK_RESPONSE_NO,
2648 					GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2649 					GTK_STOCK_SAVE, GTK_RESPONSE_YES,
2650 					NULL);
2651 	else
2652 		gtk_dialog_add_buttons (GTK_DIALOG (dialog),
2653 					_("Cl_ose Without Saving"), GTK_RESPONSE_NO,
2654 					GTK_STOCK_SAVE, GTK_RESPONSE_YES,
2655 					NULL);
2656 
2657 	result = gtk_dialog_run (GTK_DIALOG (dialog));
2658 	gtk_widget_destroy (dialog);
2659 
2660 	if (result == GTK_RESPONSE_CANCEL)
2661 		return GTK_RESPONSE_CANCEL;
2662 
2663 	if (show_cancel && result == GTK_RESPONSE_DELETE_EVENT)
2664 		return GTK_RESPONSE_CANCEL;
2665 
2666 	if (result != GTK_RESPONSE_YES)
2667 		return GTK_RESPONSE_NO;
2668 
2669 	return GTK_RESPONSE_YES;
2670 }
2671 
2672 static gboolean
brasero_project_save_project_real(BraseroProject * project,const gchar * uri,BraseroProjectSave save_type)2673 brasero_project_save_project_real (BraseroProject *project,
2674 				   const gchar *uri,
2675 				   BraseroProjectSave save_type)
2676 {
2677 	BraseroBurnResult result;
2678 	BraseroProjectType type;
2679 
2680 	g_return_val_if_fail (uri != NULL || project->priv->project != NULL, FALSE);
2681 
2682 	result = brasero_project_check_status (project);
2683 	if (result != BRASERO_BURN_OK)
2684 		return FALSE;
2685 
2686 	brasero_project_setup_session (project, BRASERO_BURN_SESSION (project->priv->session));
2687         type = brasero_project_get_session_type (project);
2688 
2689 	if (save_type == BRASERO_PROJECT_SAVE_XML
2690 	||  type == BRASERO_PROJECT_TYPE_DATA) {
2691 		brasero_project_set_uri (project, uri, type);
2692 		if (!brasero_project_save_project_xml (BRASERO_BURN_SESSION (project->priv->session),
2693 						       uri ? uri : project->priv->project)) {
2694 			brasero_project_not_saved_dialog (project);
2695 			return FALSE;
2696 		}
2697 
2698 		project->priv->modified = 0;
2699 	}
2700 	else if (save_type == BRASERO_PROJECT_SAVE_PLAIN) {
2701 		if (!brasero_project_save_audio_project_plain_text (BRASERO_BURN_SESSION (project->priv->session),
2702 								    uri)) {
2703 			brasero_project_not_saved_dialog (project);
2704 			return FALSE;
2705 		}
2706 	}
2707 
2708 #ifdef BUILD_PLAYLIST
2709 
2710 	else {
2711 		if (!brasero_project_save_audio_project_playlist (BRASERO_BURN_SESSION (project->priv->session),
2712 								  uri,
2713 								  save_type)) {
2714 			brasero_project_not_saved_dialog (project);
2715 			return FALSE;
2716 		}
2717 	}
2718 
2719 #endif
2720 
2721 	return TRUE;
2722 }
2723 
2724 static gchar *
brasero_project_save_project_ask_for_path(BraseroProject * project,BraseroProjectSave * type)2725 brasero_project_save_project_ask_for_path (BraseroProject *project,
2726 					   BraseroProjectSave *type)
2727 {
2728 	GtkWidget *combo = NULL;
2729 	GtkWidget *toplevel;
2730 	GtkWidget *chooser;
2731 	gchar *uri = NULL;
2732 	gint answer;
2733 
2734 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (project));
2735 	chooser = gtk_file_chooser_dialog_new (_("Save Current Project"),
2736 					       GTK_WINDOW (toplevel),
2737 					       GTK_FILE_CHOOSER_ACTION_SAVE,
2738 					       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2739 					       GTK_STOCK_SAVE, GTK_RESPONSE_OK,
2740 					       NULL);
2741 
2742 	gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
2743 	gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
2744 					     g_get_home_dir ());
2745 
2746 	/* if the file chooser is an audio project offer the possibility to save
2747 	 * in plain text a list of the current displayed songs (only in save as
2748 	 * mode) */
2749 	if (type && BRASERO_IS_AUDIO_DISC (project->priv->current)) {
2750 		combo = gtk_combo_box_text_new ();
2751 		gtk_widget_show (combo);
2752 
2753 		gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Save project as a Brasero audio project"));
2754 		gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Save project as a plain text list"));
2755 
2756 #ifdef BUILD_PLAYLIST
2757 
2758 		gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Save project as a PLS playlist"));
2759 		gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Save project as an M3U playlist"));
2760 		gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Save project as an XSPF playlist"));
2761 		gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Save project as an iriver playlist"));
2762 
2763 #endif
2764 
2765 		gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
2766 		gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (chooser), combo);
2767 	}
2768 
2769 	gtk_widget_show (chooser);
2770 	answer = gtk_dialog_run (GTK_DIALOG (chooser));
2771 	if (answer == GTK_RESPONSE_OK) {
2772 		if (combo)
2773 			*type = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
2774 
2775 		uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (chooser));
2776 		if (*uri == '\0') {
2777 			g_free (uri);
2778 			uri = NULL;
2779 		}
2780 	}
2781 
2782 	gtk_widget_destroy (chooser);
2783 	return uri;
2784 }
2785 
2786 gboolean
brasero_project_save_project(BraseroProject * project)2787 brasero_project_save_project (BraseroProject *project)
2788 {
2789 	gchar *uri = NULL;
2790 	gboolean result;
2791 
2792 	if (!project->priv->session)
2793 		return FALSE;
2794 
2795 	if (!project->priv->project && !(uri = brasero_project_save_project_ask_for_path (project, NULL)))
2796 		return FALSE;
2797 
2798 	result = brasero_project_save_project_real (project, uri, BRASERO_PROJECT_SAVE_XML);
2799 	g_free (uri);
2800 
2801 	return result;
2802 }
2803 
2804 gboolean
brasero_project_save_project_as(BraseroProject * project)2805 brasero_project_save_project_as (BraseroProject *project)
2806 {
2807 	BraseroProjectSave type = BRASERO_PROJECT_SAVE_XML;
2808 	gboolean result;
2809 	gchar *uri;
2810 
2811 	if (!project->priv->session)
2812 		return FALSE;
2813 
2814 	uri = brasero_project_save_project_ask_for_path (project, &type);
2815 	if (!uri)
2816 		return FALSE;
2817 
2818 	result = brasero_project_save_project_real (project, uri, type);
2819 	g_free (uri);
2820 
2821 	return result;
2822 }
2823 
2824 /**
2825  * NOTE: this function returns FALSE if it succeeds and TRUE otherwise.
2826  * this value is mainly used by the session object to cancel or not the app
2827  * closing
2828  */
2829 
2830 gboolean
brasero_project_save_session(BraseroProject * project,const gchar * uri,gchar ** saved_uri,gboolean show_cancel)2831 brasero_project_save_session (BraseroProject *project,
2832 			      const gchar *uri,
2833 			      gchar **saved_uri,
2834 			      gboolean show_cancel)
2835 {
2836 	if (!project->priv->session)
2837 		return FALSE;
2838 
2839 	if (!project->priv->current) {
2840 		if (saved_uri)
2841 			*saved_uri = NULL;
2842 
2843 		return FALSE;
2844 	}
2845 
2846 	if (project->priv->empty) {
2847 		/* the project is empty anyway. No need to ask anything.
2848 		 * return FALSE since this is not a tmp project */
2849 		if (saved_uri)
2850 			*saved_uri = NULL;
2851 
2852 		return FALSE;
2853 	}
2854 
2855 	if (project->priv->project) {
2856 		GtkResponseType answer;
2857 
2858 		if (!project->priv->modified) {
2859 			/* there is a saved project but unmodified.
2860 			 * No need to ask anything */
2861 			if (saved_uri)
2862 				*saved_uri = g_strdup (project->priv->project);
2863 
2864 			return FALSE;
2865 		}
2866 
2867 		/* ask the user if he wants to save the changes */
2868 		answer = brasero_project_save_project_dialog (project, show_cancel);
2869 		if (answer == GTK_RESPONSE_CANCEL)
2870 			return TRUE;
2871 
2872 		if (answer != GTK_RESPONSE_YES) {
2873 			if (saved_uri)
2874 				*saved_uri = NULL;
2875 
2876 			return FALSE;
2877 		}
2878 
2879 		if (!brasero_project_save_project_real (project, NULL, BRASERO_PROJECT_SAVE_XML))
2880 			return TRUE;
2881 
2882 		if (saved_uri)
2883 			*saved_uri = g_strdup (project->priv->project);
2884 
2885 		return FALSE;
2886 	}
2887 
2888     	if (project->priv->burnt) {
2889 		GtkResponseType answer;
2890 
2891 		/* the project wasn't saved but burnt ask if the user wants to
2892 		 * keep it for another time by saving it */
2893 		answer = brasero_project_save_project_dialog (project, show_cancel);
2894 		if (answer == GTK_RESPONSE_CANCEL)
2895 			return TRUE;
2896 
2897 		if (answer != GTK_RESPONSE_YES) {
2898 			if (saved_uri)
2899 				*saved_uri = NULL;
2900 
2901 			return FALSE;
2902 		}
2903 
2904 		if (!brasero_project_save_project_as (project))
2905 			return TRUE;
2906 
2907 		if (saved_uri)
2908 			*saved_uri = g_strdup (project->priv->project);
2909 
2910 		return FALSE;
2911 	}
2912 
2913     	if (!uri) {
2914 		if (saved_uri)
2915 			*saved_uri = NULL;
2916 
2917 		return FALSE;
2918 	}
2919 
2920 	brasero_project_setup_session (project, BRASERO_BURN_SESSION (project->priv->session));
2921 	if (!brasero_project_save_project_xml (BRASERO_BURN_SESSION (project->priv->session), uri)) {
2922 		GtkResponseType response;
2923 		GtkWidget *dialog;
2924 
2925 		/* If the automatic saving failed, let the user decide */
2926 		dialog = brasero_app_dialog (brasero_app_get_default (),
2927 					      _("Your project has not been saved."),
2928 					     GTK_BUTTONS_NONE,
2929 					     GTK_MESSAGE_WARNING);
2930 
2931 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
2932 							  _("If you don't save, changes will be permanently lost."));
2933 
2934 		gtk_dialog_add_buttons (GTK_DIALOG (dialog),
2935 		                        _("Cl_ose Without Saving"), GTK_RESPONSE_NO,
2936 		                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2937 		                        NULL);
2938 
2939 		response = gtk_dialog_run (GTK_DIALOG (dialog));
2940 		gtk_widget_destroy (dialog);
2941 
2942 		if (saved_uri)
2943 			*saved_uri = NULL;
2944 
2945 		return (response == GTK_RESPONSE_CANCEL);
2946 	}
2947 
2948 	if (saved_uri)
2949 		*saved_uri = g_strdup (uri);
2950 
2951     	return FALSE;
2952 }
2953