Beispiel #1
0
def init_project_gui():
    """
    Called after project load to initialize interface
    """
    # Display media files
    gui.media_list_view.fill_data_model()
    try:  # Fails if current bin is empty
        selection = gui.media_list_view.treeview.get_selection()
        selection.select_path("0")
    except Exception:
        pass

    # Display bins
    gui.bin_list_view.fill_data_model()
    selection = gui.bin_list_view.treeview.get_selection()
    selection.select_path("0")

    # Display sequences
    gui.sequence_list_view.fill_data_model()
    selection = gui.sequence_list_view.treeview.get_selection()
    selected_index = editorstate.project.sequences.index(
        editorstate.current_sequence())
    selection.select_path(str(selected_index))

    # Display media events
    medialog.update_media_log_view()

    render.set_default_values_for_widgets(True)
    gui.tline_left_corner.update_gui()
    projectinfogui.update_project_info()

    # Set render folder selector to last render if prefs require
    folder_path = editorstate.PROJECT().get_last_render_folder()
    if folder_path != None and editorpersistance.prefs.remember_last_render_dir == True:
        gui.render_out_folder.set_current_folder(folder_path)
Beispiel #2
0
def _save_project_in_last_saved_path():
    updater.set_info_icon(Gtk.STOCK_SAVE)

    try:

        persistance.save_project(PROJECT(),
                                 PROJECT().last_save_path)  #<----- HERE

    except IOError as ioe:
        updater.set_info_icon(None)
        primary_txt = "I/O error({0})".format(ioe.errno)
        secondary_txt = ioe.strerror + "."
        dialogutils.warning_message(primary_txt,
                                    secondary_txt,
                                    gui.editor_window.window,
                                    is_info=False)
        return

    PROJECT().events.append(
        projectdata.ProjectEvent(projectdata.EVENT_SAVED,
                                 PROJECT().last_save_path))

    global save_icon_remove_event_id
    save_icon_remove_event_id = GObject.timeout_add(500, remove_save_icon)

    global save_time
    save_time = time.clock()

    projectinfogui.update_project_info()
Beispiel #3
0
def init_project_gui():
    """
    Called after project load to initialize interface
    """
    # Display media files in "Media" tab 
    gui.media_list_view.fill_data_model()
    try: # Fails if current bin is empty
        selection = gui.media_list_view.treeview.get_selection()
        selection.select_path("0")
    except Exception:
        pass

    # Display bins in "Media" tab 
    gui.bin_list_view.fill_data_model()
    selection = gui.bin_list_view.treeview.get_selection()
    selection.select_path("0")

    # Display sequences in "Project" tab
    gui.sequence_list_view.fill_data_model()
    selection = gui.sequence_list_view.treeview.get_selection()
    selected_index = editorstate.project.sequences.index(editorstate.current_sequence())
    selection.select_path(str(selected_index))
  
    # Display logged ranges in "Range Log" tab
    medialog.update_group_select_for_load()
    medialog.update_media_log_view()

    render.set_default_values_for_widgets(True)
    gui.tline_left_corner.update_gui()
    projectinfogui.update_project_info()

    # Set render folder selector to last render if prefs require 
    folder_path = editorstate.PROJECT().get_last_render_folder()
    if folder_path != None and editorpersistance.prefs.remember_last_render_dir == True:
        gui.render_out_folder.set_current_folder(folder_path)
Beispiel #4
0
def _save_project_in_last_saved_path():
    updater.set_info_icon(Gtk.STOCK_SAVE)

    PROJECT().events.append(projectdata.ProjectEvent(projectdata.EVENT_SAVED, PROJECT().last_save_path))

    persistance.save_project(PROJECT(), PROJECT().last_save_path) #<----- HERE

    global save_icon_remove_event_id
    save_icon_remove_event_id = GObject.timeout_add(500, remove_save_icon)

    global save_time
    save_time = time.clock()
    
    projectinfogui.update_project_info()
Beispiel #5
0
def _save_as_dialog_callback(dialog, response_id):
    if response_id == gtk.RESPONSE_ACCEPT:
        filenames = dialog.get_filenames()
        PROJECT().last_save_path = filenames[0]
        PROJECT().name = os.path.basename(filenames[0])
        updater.set_info_icon(gtk.STOCK_SAVE)

        if len(
                PROJECT().events
        ) == 0:  # Save as... with 0 project events is considered Project creation
            p_event = projectdata.ProjectEvent(
                projectdata.EVENT_CREATED_BY_SAVING,
                PROJECT().last_save_path)
            PROJECT().events.append(p_event)
        else:
            p_event = projectdata.ProjectEvent(
                projectdata.EVENT_SAVED_AS,
                (PROJECT().name, PROJECT().last_save_path))
            PROJECT().events.append(p_event)

        persistance.save_project(PROJECT(),
                                 PROJECT().last_save_path)  #<----- HERE

        app.stop_autosave()
        app.start_autosave()

        global save_icon_remove_event_id
        save_icon_remove_event_id = gobject.timeout_add(500, remove_save_icon)

        global save_time
        save_time = time.clock()

        gui.editor_window.window.set_title(PROJECT().name + " - Flowblade")
        gui.editor_window.uimanager.get_widget(
            "/MenuBar/FileMenu/Save").set_sensitive(False)
        gui.editor_window.uimanager.get_widget(
            "/MenuBar/EditMenu/Undo").set_sensitive(False)
        gui.editor_window.uimanager.get_widget(
            "/MenuBar/EditMenu/Redo").set_sensitive(False)

        editorpersistance.add_recent_project_path(PROJECT().last_save_path)
        editorpersistance.fill_recents_menu_widget(
            gui.editor_window.uimanager.get_widget(
                '/MenuBar/FileMenu/OpenRecent'), open_recent_project)

        projectinfogui.update_project_info()

        dialog.destroy()
    else:
        dialog.destroy()
Beispiel #6
0
def _save_as_dialog_callback(dialog, response_id):
    if response_id == Gtk.ResponseType.ACCEPT:
        filenames = dialog.get_filenames()
        PROJECT().last_save_path = filenames[0]
        PROJECT().name = unicode(os.path.basename(filenames[0]), "utf-8")
        updater.set_info_icon(Gtk.STOCK_SAVE)

        try:
            
            persistance.save_project(PROJECT(), PROJECT().last_save_path) #<----- HERE
            
        except IOError as ioe:
            dialog.destroy()
            updater.set_info_icon(None)
            primary_txt = "I/O error({0})".format(ioe.errno)
            secondary_txt = ioe.strerror + "."
            dialogutils.warning_message(primary_txt, secondary_txt, gui.editor_window.window, is_info=False)
            return

        if len(PROJECT().events) == 0: # Save as... with 0 project events is considered Project creation
            p_event = projectdata.ProjectEvent(projectdata.EVENT_CREATED_BY_SAVING, PROJECT().last_save_path)
            PROJECT().events.append(p_event)
        else:
            p_event = projectdata.ProjectEvent(projectdata.EVENT_SAVED_AS, (PROJECT().name, PROJECT().last_save_path))
            PROJECT().events.append(p_event)
            
        app.stop_autosave()
        app.start_autosave()
        
        global save_icon_remove_event_id
        save_icon_remove_event_id = GObject.timeout_add(500, remove_save_icon)

        global save_time
        save_time = time.clock()

        gui.editor_window.window.set_title(PROJECT().name + " - Flowblade")        
        gui.editor_window.uimanager.get_widget("/MenuBar/FileMenu/Save").set_sensitive(False)
        gui.editor_window.uimanager.get_widget("/MenuBar/EditMenu/Undo").set_sensitive(False)
        gui.editor_window.uimanager.get_widget("/MenuBar/EditMenu/Redo").set_sensitive(False)

        editorpersistance.add_recent_project_path(PROJECT().last_save_path)
        editorpersistance.fill_recents_menu_widget(gui.editor_window.uimanager.get_widget('/MenuBar/FileMenu/OpenRecent'), open_recent_project)
        
        projectinfogui.update_project_info()
        
        dialog.destroy()
    else:
        dialog.destroy()
Beispiel #7
0
def _do_rendering():
    print "timeline render..."
    
    global aborted
    aborted = False
    render_consumer = get_render_consumer()
    if render_consumer == None:
        return

    # Set render start and end points
    if widgets.range_cb.get_active() == 0:
        start_frame = 0
        end_frame = -1 # renders till finish
    else:
        start_frame = current_sequence().tractor.mark_in
        end_frame = current_sequence().tractor.mark_out

    # Only render a range if it is defined.
    if start_frame == -1 or end_frame == -1:
        if widgets.range_cb.get_active() == 1:
            rendergui.no_good_rander_range_info()
            return

    file_path = get_file_path()
    project_event = projectdata.ProjectEvent(projectdata.EVENT_RENDERED, file_path)
    PROJECT().events.append(project_event)
    projectinfogui.update_project_info()

    # See if project and render fps match
    cnum = render_consumer.profile().frame_rate_num()
    cden = render_consumer.profile().frame_rate_den()
    pnum = PROJECT().profile.frame_rate_num()
    pden = PROJECT().profile.frame_rate_den()
    
    if (cnum == pnum) and (cden == pden):
        frames_rates_match = True
    else:
        frames_rates_match = False

    global progress_window
    progress_window = rendergui.render_progress_dialog(_render_cancel_callback,
                                                       gui.editor_window.window,
                                                       frames_rates_match)
                                                       
    set_render_gui()

    render_launch = RenderLauncher(render_consumer, start_frame, end_frame)
    render_launch.start()
Beispiel #8
0
def _do_rendering():
    print "timeline render..."

    global aborted
    aborted = False
    render_consumer = get_render_consumer()
    if render_consumer == None:
        return

    # Set render start and end points
    if widgets.range_cb.get_active() == 0:
        start_frame = 0
        end_frame = -1  # renders till finish
    else:
        start_frame = current_sequence().tractor.mark_in
        end_frame = current_sequence().tractor.mark_out

    # Only render a range if it is defined.
    if start_frame == -1 or end_frame == -1:
        if widgets.range_cb.get_active() == 1:
            rendergui.no_good_rander_range_info()
            return

    file_path = get_file_path()
    project_event = projectdata.ProjectEvent(projectdata.EVENT_RENDERED,
                                             file_path)
    PROJECT().events.append(project_event)
    projectinfogui.update_project_info()

    # See if project and render fps match
    cnum = render_consumer.profile().frame_rate_num()
    cden = render_consumer.profile().frame_rate_den()
    pnum = PROJECT().profile.frame_rate_num()
    pden = PROJECT().profile.frame_rate_den()

    if (cnum == pnum) and (cden == pden):
        frames_rates_match = True
    else:
        frames_rates_match = False

    global progress_window
    progress_window = rendergui.render_progress_dialog(
        _render_cancel_callback, gui.editor_window.window, frames_rates_match)

    set_render_gui()

    render_launch = RenderLauncher(render_consumer, start_frame, end_frame)
    render_launch.start()
Beispiel #9
0
def _save_as_dialog_callback(dialog, response_id):
    if response_id == gtk.RESPONSE_ACCEPT:
        filenames = dialog.get_filenames()
        PROJECT().last_save_path = filenames[0]
        PROJECT().name = os.path.basename(filenames[0])
        updater.set_info_icon(gtk.STOCK_SAVE)

        if len(PROJECT().events) == 0: # Save as... with 0 project events is considered Project creation
            p_event = projectdata.ProjectEvent(projectdata.EVENT_CREATED_BY_SAVING, PROJECT().last_save_path)
            PROJECT().events.append(p_event)
        else:
            p_event = projectdata.ProjectEvent(projectdata.EVENT_SAVED_AS, (PROJECT().name, PROJECT().last_save_path))
            PROJECT().events.append(p_event)
            
        persistance.save_project(PROJECT(), PROJECT().last_save_path) #<----- HERE
        
        app.stop_autosave()
        app.start_autosave()
        
        global save_icon_remove_event_id
        save_icon_remove_event_id = gobject.timeout_add(500, remove_save_icon)

        global save_time
        save_time = time.clock()

        gui.editor_window.window.set_title(PROJECT().name + " - Flowblade")        
        gui.editor_window.uimanager.get_widget("/MenuBar/FileMenu/Save").set_sensitive(False)
        gui.editor_window.uimanager.get_widget("/MenuBar/EditMenu/Undo").set_sensitive(False)
        gui.editor_window.uimanager.get_widget("/MenuBar/EditMenu/Redo").set_sensitive(False)

        editorpersistance.add_recent_project_path(PROJECT().last_save_path)
        editorpersistance.fill_recents_menu_widget(gui.editor_window.uimanager.get_widget('/MenuBar/FileMenu/OpenRecent'), open_recent_project)
        
        projectinfogui.update_project_info()
        
        dialog.destroy()
    else:
        dialog.destroy()
Beispiel #10
0
def _save_project_in_last_saved_path():
    updater.set_info_icon(Gtk.STOCK_SAVE)

    try:
        
        persistance.save_project(PROJECT(), PROJECT().last_save_path) #<----- HERE
        
    except IOError as ioe:
        updater.set_info_icon(None)
        primary_txt = "I/O error({0})".format(ioe.errno)
        secondary_txt = ioe.strerror + "."
        dialogutils.warning_message(primary_txt, secondary_txt, gui.editor_window.window, is_info=False)
        return

    PROJECT().events.append(projectdata.ProjectEvent(projectdata.EVENT_SAVED, PROJECT().last_save_path))
    
    global save_icon_remove_event_id
    save_icon_remove_event_id = GObject.timeout_add(500, remove_save_icon)

    global save_time
    save_time = time.clock()
    
    projectinfogui.update_project_info()
Beispiel #11
0
    def run(self):
        copy_txt = _("Copying project media assets")
        project_txt = _("Saving project file")
        
        Gdk.threads_enter()
        dialog = dialogs.save_snaphot_progess(copy_txt, project_txt)
        Gdk.threads_leave()
        
        media_folder = self.root_folder_path +  "media/"

        d = os.path.dirname(media_folder)
        os.mkdir(d)

        asset_paths = {}

        # Copy media files
        for idkey, media_file in PROJECT().media_files.items():
            if media_file.type == appconsts.PATTERN_PRODUCER:
                continue

            # Copy asset file and fix path
            directory, file_name = os.path.split(media_file.path)
            
            # Message
            Gdk.threads_enter()
            dialog.media_copy_info.set_text(copy_txt + "... " +  file_name)
            Gdk.threads_leave()
            
            # Other media types than image sequences
            if media_file.type != appconsts.IMAGE_SEQUENCE:
                media_file_copy = media_folder + file_name
                if media_file_copy in asset_paths: # Create different filename for files 
                                                   # that have same filename but different path
                    file_name = get_snapshot_unique_name(media_file.path, file_name)
                    media_file_copy = media_folder + file_name
                    
                shutil.copyfile(media_file.path, media_file_copy)
                asset_paths[media_file.path] = media_file_copy
            else: # Image Sequences
                asset_folder, asset_file_name =  os.path.split(media_file.path)
                lookup_filename = utils.get_img_seq_glob_lookup_name(asset_file_name)
                lookup_path = asset_folder + "/" + lookup_filename
                copyfolder = media_folder.rstrip("/") + asset_folder + "/"
                os.makedirs(copyfolder)
                listing = glob.glob(lookup_path)
                for orig_path in listing:
                    orig_folder, orig_file_name = os.path.split(orig_path)
                    shutil.copyfile(orig_path, copyfolder + orig_file_name)

        # Copy clip producers paths. This is needed just for rendered files as clips
        # from media file objects should be covered as media files can't be destroyed 
        # if a clip made from them exists...I think
        for seq in PROJECT().sequences:
            for track in seq.tracks:
                for i in range(0, len(track.clips)):
                    clip = track.clips[i]
                    
                    # Image sequence files can't be rendered files
                    if clip.is_blanck_clip == False and clip.media_type == appconsts.IMAGE_SEQUENCE:
                        continue

                    # Only producer clips are affected
                    if (clip.is_blanck_clip == False and (clip.media_type != appconsts.PATTERN_PRODUCER)):
                        directory, file_name = os.path.split(clip.path)
                        clip_file_copy = media_folder + file_name
                        if not os.path.isfile(clip_file_copy):
                            directory, file_name = os.path.split(clip.path)
                            Gdk.threads_enter()
                            dialog.media_copy_info.set_text(copy_txt + "... " +  file_name)
                            Gdk.threads_leave()
                            shutil.copyfile(clip.path, clip_file_copy) # only rendered files are copied here
                            asset_paths[clip.path] = clip_file_copy # This stuff is already md5 hashed, so no duplicate problems here
            for compositor in seq.compositors:
                if compositor.type_id == "##wipe": # Wipe may have user luma and needs to be looked up relatively
                    copy_comp_resourse_file(compositor, "resource", media_folder)
                if compositor.type_id == "##region": # Wipe may have user luma and needs to be looked up relatively
                    copy_comp_resourse_file(compositor, "composite.luma", media_folder)

        Gdk.threads_enter()
        dialog.media_copy_info.set_text(copy_txt + "    " +  u"\u2713")
        Gdk.threads_leave()
        
        save_path = self.root_folder_path + self.project_name

        persistance.snapshot_paths = asset_paths
        persistance.save_project(PROJECT(), save_path)
        persistance.snapshot_paths = None

        Gdk.threads_enter()
        dialog.saving_project_info.set_text(project_txt + "    " +  u"\u2713")
        Gdk.threads_leave()

        time.sleep(2)

        Gdk.threads_enter()
        dialog.destroy()
        Gdk.threads_leave()
        
        project_event = projectdata.ProjectEvent(projectdata.EVENT_SAVED_SNAPSHOT, self.root_folder_path)
        PROJECT().events.append(project_event)

        Gdk.threads_enter()
        projectinfogui.update_project_info()
        Gdk.threads_leave()
Beispiel #12
0
    def run(self):
        copy_txt = _("Copying project media assets")
        project_txt = _("Saving project file")

        gtk.gdk.threads_enter()
        dialog = dialogs.save_snaphot_progess(copy_txt, project_txt)
        gtk.gdk.threads_leave()

        media_folder = self.root_folder_path + "media/"

        d = os.path.dirname(media_folder)
        os.mkdir(d)

        asset_paths = {}

        # Copy media files
        for idkey, media_file in PROJECT().media_files.items():
            if media_file.type == appconsts.PATTERN_PRODUCER:
                continue

            # Copy asset file and fix path
            directory, file_name = os.path.split(media_file.path)
            gtk.gdk.threads_enter()
            dialog.media_copy_info.set_text(copy_txt + "... " + file_name)
            gtk.gdk.threads_leave()
            media_file_copy = media_folder + file_name
            if media_file_copy in asset_paths:  # Create different filename for files
                # that have same filename but different path
                file_name = get_snapshot_unique_name(media_file.path,
                                                     file_name)
                media_file_copy = media_folder + file_name

            shutil.copyfile(media_file.path, media_file_copy)
            asset_paths[media_file.path] = media_file_copy

        # Copy clip producers paths
        for seq in PROJECT().sequences:
            for track in seq.tracks:
                for i in range(0, len(track.clips)):
                    clip = track.clips[i]
                    # Only producer clips are affected
                    if (clip.is_blanck_clip == False and
                        (clip.media_type != appconsts.PATTERN_PRODUCER)):
                        directory, file_name = os.path.split(clip.path)
                        clip_file_copy = media_folder + file_name
                        if not os.path.isfile(clip_file_copy):
                            directory, file_name = os.path.split(clip.path)
                            gtk.gdk.threads_enter()
                            dialog.media_copy_info.set_text(copy_txt + "... " +
                                                            file_name)
                            gtk.gdk.threads_leave()
                            shutil.copyfile(
                                clip.path, clip_file_copy
                            )  # only rendered files are copied here
                            asset_paths[
                                clip.
                                path] = clip_file_copy  # This stuff is already md5 hashed, so no duplicate problems here
            for compositor in seq.compositors:
                if compositor.type_id == "##wipe":  # Wipe may have user luma and needs to be looked up relatively
                    copy_comp_resourse_file(compositor, "resource",
                                            media_folder)
                if compositor.type_id == "##region":  # Wipe may have user luma and needs to be looked up relatively
                    copy_comp_resourse_file(compositor, "composite.luma",
                                            media_folder)

        gtk.gdk.threads_enter()
        dialog.media_copy_info.set_text(copy_txt + "    " + u"\u2713")
        gtk.gdk.threads_leave()

        save_path = self.root_folder_path + self.project_name

        persistance.snapshot_paths = asset_paths
        persistance.save_project(PROJECT(), save_path)
        persistance.snapshot_paths = None

        gtk.gdk.threads_enter()
        dialog.saving_project_info.set_text(project_txt + "    " + u"\u2713")
        gtk.gdk.threads_leave()

        time.sleep(2)

        gtk.gdk.threads_enter()
        dialog.destroy()
        gtk.gdk.threads_leave()

        project_event = projectdata.ProjectEvent(
            projectdata.EVENT_SAVED_SNAPSHOT, self.root_folder_path)
        PROJECT().events.append(project_event)

        gtk.gdk.threads_enter()
        projectinfogui.update_project_info()
        gtk.gdk.threads_leave()
Beispiel #13
0
def _save_as_dialog_callback(dialog, response_id):
    if response_id == Gtk.ResponseType.ACCEPT:
        filenames = dialog.get_filenames()
        PROJECT().last_save_path = filenames[0]
        PROJECT().name = unicode(os.path.basename(filenames[0]), "utf-8")
        updater.set_info_icon(Gtk.STOCK_SAVE)

        try:

            persistance.save_project(PROJECT(),
                                     PROJECT().last_save_path)  #<----- HERE

        except IOError as ioe:
            dialog.destroy()
            updater.set_info_icon(None)
            primary_txt = "I/O error({0})".format(ioe.errno)
            secondary_txt = ioe.strerror + "."
            dialogutils.warning_message(primary_txt,
                                        secondary_txt,
                                        gui.editor_window.window,
                                        is_info=False)
            return

        if len(
                PROJECT().events
        ) == 0:  # Save as... with 0 project events is considered Project creation
            p_event = projectdata.ProjectEvent(
                projectdata.EVENT_CREATED_BY_SAVING,
                PROJECT().last_save_path)
            PROJECT().events.append(p_event)
        else:
            p_event = projectdata.ProjectEvent(
                projectdata.EVENT_SAVED_AS,
                (PROJECT().name, PROJECT().last_save_path))
            PROJECT().events.append(p_event)

        app.stop_autosave()
        app.start_autosave()

        global save_icon_remove_event_id
        save_icon_remove_event_id = GObject.timeout_add(500, remove_save_icon)

        global save_time
        save_time = time.clock()

        gui.editor_window.window.set_title(PROJECT().name + " - Flowblade")
        gui.editor_window.uimanager.get_widget(
            "/MenuBar/FileMenu/Save").set_sensitive(False)
        gui.editor_window.uimanager.get_widget(
            "/MenuBar/EditMenu/Undo").set_sensitive(False)
        gui.editor_window.uimanager.get_widget(
            "/MenuBar/EditMenu/Redo").set_sensitive(False)

        editorpersistance.add_recent_project_path(PROJECT().last_save_path)
        editorpersistance.fill_recents_menu_widget(
            gui.editor_window.uimanager.get_widget(
                '/MenuBar/FileMenu/OpenRecent'), open_recent_project)

        projectinfogui.update_project_info()

        dialog.destroy()
    else:
        dialog.destroy()
Beispiel #14
0
    def run(self):
        copy_txt = _("Copying project media assets")
        project_txt = _("Saving project file")
        
        gtk.gdk.threads_enter()
        dialog = dialogs.save_snaphot_progess(copy_txt, project_txt)
        gtk.gdk.threads_leave()
        
        media_folder = self.root_folder_path +  "media/"

        d = os.path.dirname(media_folder)
        os.mkdir(d)

        asset_paths = {}

        # Copy media files
        for idkey, media_file in PROJECT().media_files.items():
            if media_file.type == appconsts.PATTERN_PRODUCER:
                continue

            # Copy asset file and fix path
            directory, file_name = os.path.split(media_file.path)
            gtk.gdk.threads_enter()
            dialog.media_copy_info.set_text(copy_txt + "... " +  file_name)
            gtk.gdk.threads_leave()
            media_file_copy = media_folder + file_name
            if media_file_copy in asset_paths: # Create different filename for files 
                                               # that have same filename but different path
                file_name = get_snapshot_unique_name(media_file.path, file_name)
                media_file_copy = media_folder + file_name
                
            shutil.copyfile(media_file.path, media_file_copy)
            asset_paths[media_file.path] = media_file_copy

        # Copy clip producers paths
        for seq in PROJECT().sequences:
            for track in seq.tracks:
                for i in range(0, len(track.clips)):
                    clip = track.clips[i]
                    # Only producer clips are affected
                    if (clip.is_blanck_clip == False and (clip.media_type != appconsts.PATTERN_PRODUCER)):
                        directory, file_name = os.path.split(clip.path)
                        clip_file_copy = media_folder + file_name
                        if not os.path.isfile(clip_file_copy):
                            directory, file_name = os.path.split(clip.path)
                            gtk.gdk.threads_enter()
                            dialog.media_copy_info.set_text(copy_txt + "... " +  file_name)
                            gtk.gdk.threads_leave()
                            shutil.copyfile(clip.path, clip_file_copy) # only rendered files are copied here
                            asset_paths[clip.path] = clip_file_copy # This stuff is already md5 hashed, so no duplicate problems here
            for compositor in seq.compositors:
                if compositor.type_id == "##wipe": # Wipe may have user luma and needs to be looked up relatively
                    copy_comp_resourse_file(compositor, "resource", media_folder)
                if compositor.type_id == "##region": # Wipe may have user luma and needs to be looked up relatively
                    copy_comp_resourse_file(compositor, "composite.luma", media_folder)

        gtk.gdk.threads_enter()
        dialog.media_copy_info.set_text(copy_txt + "    " +  u"\u2713")
        gtk.gdk.threads_leave()
        
        save_path = self.root_folder_path + self.project_name

        persistance.snapshot_paths = asset_paths
        persistance.save_project(PROJECT(), save_path)
        persistance.snapshot_paths = None

        gtk.gdk.threads_enter()
        dialog.saving_project_info.set_text(project_txt + "    " +  u"\u2713")
        gtk.gdk.threads_leave()

        time.sleep(2)

        gtk.gdk.threads_enter()
        dialog.destroy()
        gtk.gdk.threads_leave()
        
        project_event = projectdata.ProjectEvent(projectdata.EVENT_SAVED_SNAPSHOT, self.root_folder_path)
        PROJECT().events.append(project_event)

        gtk.gdk.threads_enter()
        projectinfogui.update_project_info()
        gtk.gdk.threads_leave()