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 §ors,
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