Beispiel #1
0
def load_filters_xml(services):
    """
    Load filters document and save filters nodes as FilterInfo objects in array.
    Save them also as array of tuples of names and arrays of FilterInfo objects
    that represent named groups of filters as displayd to user.
    """
    _load_icons()
    
    print "Loading filters..."
    
    global filters_doc
    filters_doc = xml.dom.minidom.parse(respaths.FILTERS_XML_DOC)

    load_groups = {}
    filter_nodes = filters_doc.getElementsByTagName(FILTER)
    for f_node in filter_nodes:
        filter_info = FilterInfo(f_node)

        if filter_info.mlt_drop_version != "":
            if editorstate.mlt_version_is_greater_correct(filter_info.mlt_drop_version):
                print filter_info.name + " dropped, MLT version too high for this filter."
                continue

        if filter_info.mlt_min_version != "":
            if not editorstate.mlt_version_is_greater_correct(filter_info.mlt_min_version):
                print filter_info.name + " dropped, MLT version too low for this filter."
                continue

        if (not filter_info.mlt_service_id in services) and len(services) > 0:
            print "MLT service " + filter_info.mlt_service_id + " not found."
            global not_found_filters
            not_found_filters.append(filter_info)
            continue

        if filter_info.mlt_service_id == "volume": # we need this filter to do mutes so save reference to it
            global _volume_filter_info
            _volume_filter_info = filter_info

        if filter_info.mlt_service_id == "brightness": # TODO: maybe add general search fuction for these, if we need a third one this is becoming a bit silly
            global _brightness_filter_info
            _brightness_filter_info = filter_info
            
        # Add filter compositor filters or filter groups
        if filter_info.group == COMPOSITOR_FILTER_GROUP:
            global compositor_filters
            compositor_filters[filter_info.name] = filter_info
        else:
            translated_group_name = _translate_group_name(filter_info.group)
            try:
                group = load_groups[translated_group_name]
                group.append(filter_info)
            except:
                load_groups[translated_group_name] = [filter_info]

    # We used translated group names as keys in load_groups
    # Now we sort them and use them to place data in groups array in the same
    # order as it will be presented to user, so selection indexes in gui components will match
    # group array indexes here.
    sorted_keys = sorted(load_groups.keys())
    global groups
    for gkey in sorted_keys:
        group = load_groups[gkey]
        add_group = sorted(group, key=lambda finfo: translations.get_filter_name(finfo.name) )
        groups.append((gkey, add_group))
def load_filters_xml(services):
    """
    Load filters document and save filters nodes as FilterInfo objects in array.
    Save them also as array of tuples of names and arrays of FilterInfo objects
    that represent named groups of filters as displayd to user.
    """
    _load_icons()

    print("Loading filters...")

    global filters_doc
    filters_doc = xml.dom.minidom.parse(respaths.FILTERS_XML_DOC)

    load_groups = {}
    filter_nodes = filters_doc.getElementsByTagName(FILTER)
    for f_node in filter_nodes:
        filter_info = FilterInfo(f_node)

        if filter_info.mlt_drop_version != "":
            if editorstate.mlt_version_is_greater_correct(
                    filter_info.mlt_drop_version):
                print(filter_info.name +
                      " dropped, MLT version too high for this filter.")
                continue

        if filter_info.mlt_min_version != "":
            if not editorstate.mlt_version_is_greater_correct(
                    filter_info.mlt_min_version):
                print(filter_info.name +
                      " dropped, MLT version too low for this filter.")
                continue

        if (not filter_info.mlt_service_id in services) and len(services) > 0:
            print("MLT service " + filter_info.mlt_service_id + " not found.")
            global not_found_filters
            not_found_filters.append(filter_info)
            continue

        if filter_info.mlt_service_id == "volume":  # we need this filter to do mutes so save reference to it
            global _volume_filter_info
            _volume_filter_info = filter_info

        # These are special cased as filters added from mask add menu
        if filter_info.mlt_service_id == "mask_start" or filter_info.mlt_service_id == "mask_apply":
            global _filter_mask_filters
            _filter_mask_filters[filter_info.filter_mask_filter] = filter_info
            continue

        if filter_info.mlt_service_id == "brightness":
            global _brightness_filter_info
            _brightness_filter_info = filter_info

        if filter_info.mlt_service_id == "frei0r.colorize":
            global _colorize_filter_info
            _colorize_filter_info = filter_info

        # Add filter compositor filters or filter groups
        if filter_info.group == COMPOSITOR_FILTER_GROUP:
            global compositor_filters
            compositor_filters[filter_info.name] = filter_info
        else:
            translated_group_name = _translate_group_name(filter_info.group)
            try:
                group = load_groups[translated_group_name]
                group.append(filter_info)
            except:
                load_groups[translated_group_name] = [filter_info]

    # We used translated group names as keys in load_groups
    # Now we sort them and use them to place data in groups array in the same
    # order as it will be presented to user, so selection indexes in gui components will match
    # group array indexes here.
    sorted_keys = sorted(load_groups.keys())
    global groups
    for gkey in sorted_keys:
        group = load_groups[gkey]
        add_group = sorted(
            group, key=lambda finfo: translations.get_filter_name(finfo.name))
        groups.append((gkey, add_group))
Beispiel #3
0
def main(root_path):
    """
    Called at application start.
    Initializes application with a default project.
    """
    # DEBUG: Direct output to log file if log file set
    if _log_file != None:
        log_print_output_to_file()

    set_quiet_if_requested()

    print("Application version: " + editorstate.appversion)

    # Print OS, Python version and GTK+ version
    try:
        os_release_file = open("/etc/os-release","r")
        os_text = os_release_file.read()
        s_index = os_text.find("PRETTY_NAME=")
        e_index = os_text.find("\n", s_index)
        print("OS: " + os_text[s_index + 13:e_index - 1])
    except:
        pass

    print("Python", sys.version)

    gtk_version = "%s.%s.%s" % (Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version())
    print("GTK+ version:", gtk_version)
    editorstate.gtk_version = gtk_version
    try:
        editorstate.mlt_version = mlt.LIBMLT_VERSION
    except:
        editorstate.mlt_version = "0.0.99" # magic string for "not found"

    # Create user folders if needed and determine if we're using xdg or dotfile user folders.
    userfolders.init()
    
    # Flatpak still needs to use standard home XDG cache folder for Blender.
    # Flatpak only uses XDG cache folder for Blender and we are keeping this around if we ever
    # succeed in getting Blender going for Flatpak.
    if editorstate.app_running_from == editorstate.RUNNING_FROM_FLATPAK:
        userfolders.init_user_cache_for_flatpak()

    # Set paths.
    respaths.set_paths(root_path)

    # Load editor prefs and list of recent projects
    editorpersistance.load()
    if editorpersistance.prefs.theme != appconsts.LIGHT_THEME:
        respaths.apply_dark_theme()
    if editorpersistance.prefs.display_all_audio_levels == False:
        editorstate.display_all_audio_levels = False

    editorpersistance.save()

    # Init translations module with translations data
    translations.init_languages()
    translations.load_filters_translations()
    mlttransitions.init_module()

    # Keyboard shortcuts
    shortcuts.load_shortcut_files()
    shortcuts.load_shortcuts()
    shortcuts.update_custom_shortcuts(editorpersistance.prefs.shortcuts)

    # The test for len != 4 is to make sure that if we change the number of values below the prefs are reset to the correct list
    # So when we add or remove a value, make sure we also change the len test
    # Only use positive numbers.
    if( not editorpersistance.prefs.AUTO_SAVE_OPTS or len(editorpersistance.prefs.AUTO_SAVE_OPTS) != 4):
        print("Initializing Auto Save Options")
        editorpersistance.prefs.AUTO_SAVE_OPTS = ((0, _("No Autosave")),(1, _("1 min")),(2, _("2 min")),(5, _("5 min")))

    # We need respaths and translations data available so we need to do init in a function.
    workflow.init_data()

    # RHEL7/CentOS compatibility fix
    if gtk_version == "3.8.8":
        GObject.threads_init()

    # Init gtk threads
    Gdk.threads_init()
    Gdk.threads_enter()

    # Handle userfolders init error and quit.
    if userfolders.get_init_error() != None:
        _xdg_error_exit(userfolders.get_init_error())
        return

    # After moving to Python 3 we need at least MLT 6.18
    if editorstate.mlt_version_is_greater_correct("6.17.99") == False:
        _too_low_mlt_version_exit()
        return

    # Apply custom themes.
    if editorpersistance.prefs.theme == appconsts.FLOWBLADE_THEME \
        or editorpersistance.prefs.theme == appconsts.FLOWBLADE_THEME_GRAY \
        or editorpersistance.prefs.theme == appconsts.FLOWBLADE_THEME_NEUTRAL:
        success = gui.apply_gtk_css(editorpersistance.prefs.theme)
        if not success:
            print("Applying custom theme failed.")
            editorpersistance.prefs.theme = appconsts.LIGHT_THEME
            editorpersistance.save()

    if editorpersistance.prefs.theme != appconsts.LIGHT_THEME:
        Gtk.Settings.get_default().set_property("gtk-application-prefer-dark-theme", True)
        
    # Load drag'n'drop images
    dnd.init()

    # Save screen size data and modify rendering based on screen size/s and number of monitors. 
    scr_w, scr_h = _set_screen_size_data()
    _set_draw_params()

    # Refuse to run on too small screen.
    if scr_w < 1151 or scr_h < 767:
        _too_small_screen_exit()
        return

    # Splash screen
    if editorpersistance.prefs.display_splash_screen == True: 
        show_splash_screen()

    # Init MLT framework
    repo = mlt.Factory().init()
    processutils.prepare_mlt_repo(repo)

    # Set numeric locale to use "." as radix, MLT initilizes this to OS locale and this causes bugs.
    locale.setlocale(locale.LC_NUMERIC, 'C')

    # Check for codecs and formats on the system.
    mltenv.check_available_features(repo)
    renderconsumer.load_render_profiles()

    # Load filter and compositor descriptions from xml files.
    mltfilters.load_filters_xml(mltenv.services)
    mlttransitions.load_compositors_xml(mltenv.transitions)
    
    # Replace some services if better replacements available.
    mltfilters.replace_services(mltenv.services)

    # Create list of available mlt profiles.
    mltprofiles.load_profile_list()

    # If we have crashed we could have large amount of disk space wasted unless we delete all files here.
    tlinerender.app_launch_clean_up()

    # Save assoc file path if found in arguments.
    global assoc_file_path
    assoc_file_path = get_assoc_file_path()
        
    # There is always a project open, so at startup we create a default project.
    # Set default project as the project being edited.
    editorstate.project = projectdata.get_default_project()
    check_crash = True

    # Audiomonitoring being available needs to be known before GUI creation.
    audiomonitoring.init(editorstate.project.profile)

    # Set trim view mode to current default value.
    editorstate.show_trim_view = editorpersistance.prefs.trim_view_default

    # Check for tools and init tools integration.
    gmic.test_availablity()
    containerclip.test_blender_availebility()
    toolsintegration.init()

    # Media Plugins
    mediaplugin.init()

    # Create player object.
    create_player()

    # Create main window and set widget handles in gui.py for more convenient reference.
    create_gui()

    # Inits widgets with project data.
    init_project_gui()

    # Inits widgets with current sequence data.
    init_sequence_gui()

    # Launch player now that data and gui exist
    launch_player()

    # Editor and modules need some more initializing.
    init_editor_state()

    # Tracks need to be recentered if window is resized.
    # Connect listener for this now that the tline panel size allocation is sure to be available.
    global window_resize_id, window_state_id
    window_resize_id = gui.editor_window.window.connect("size-allocate", lambda w, e:updater.window_resized())
    window_state_id = gui.editor_window.window.connect("window-state-event", lambda w, e:updater.window_resized())

    # Get existing autosave files
    autosave_files = get_autosave_files()

    # Show splash
    if ((editorpersistance.prefs.display_splash_screen == True) and len(autosave_files) == 0) and not editorstate.runtime_version_greater_then_test_version(editorpersistance.prefs.workflow_dialog_last_version_shown, editorstate.appversion):
        global splash_timeout_id
        splash_timeout_id = GLib.timeout_add(2600, destroy_splash_screen)
        splash_screen.show_all()

    appconsts.SAVEFILE_VERSION = projectdata.SAVEFILE_VERSION # THIS IS A QUESTIONABLE IDEA TO SIMPLIFY IMPORTS, NOT DRY. WHEN DOING TOOLS THAT RUN IN ANOTHER PROCESSES AND SAVE PROJECTS, THIS LINE NEEDS TO BE THERE ALSO.

    # Every running instance has unique autosave file which is deleted at exit
    set_instance_autosave_id()

    # Existance of autosave file hints that program was exited abnormally.
    if check_crash == True and len(autosave_files) > 0:
        if len(autosave_files) == 1:
            GObject.timeout_add(10, autosave_recovery_dialog)
        else:
            GObject.timeout_add(10, autosaves_many_recovery_dialog)
    else:
        tlinerender.init_session()
        start_autosave()

    projectaction.clear_changed_since_last_save_flags()
    
    # We prefer to monkeypatch some callbacks into some modules, usually to
    # maintain a simpler and/or non-circular import structure.
    monkeypatch_callbacks()

    # File in assoc_file_path is opened after very short delay.
    if not(check_crash == True and len(autosave_files) > 0):
        if assoc_file_path != None:
            print("Launch assoc file:", assoc_file_path)
            global assoc_timeout_id
            assoc_timeout_id = GObject.timeout_add(10, open_assoc_file)
        
    # SDL 2 consumer needs to created after Gtk.main() has run enough for window to be visble
    #if editorstate.get_sdl_version() == editorstate.SDL_2: # needs more state considerion still
    #    print "SDL2 timeout launch"
    #    global sdl2_timeout_id
    #    sdl2_timeout_id = GObject.timeout_add(1500, create_sdl_2_consumer)
    
    # In PositionNumericalEntries we are using Gtk.Entry objects in a way that works for us nicely, but is somehow "error" for Gtk, so we just kill this.
    Gtk.Settings.get_default().set_property("gtk-error-bell", False)
    
    # Show first run worflow info dialog if not shown for this version of application.
    if editorstate.runtime_version_greater_then_test_version(editorpersistance.prefs.workflow_dialog_last_version_shown, editorstate.appversion):
        GObject.timeout_add(500, show_worflow_info_dialog)
        
    # Copy to XDG.
    if userfolders.data_copy_needed():
        GObject.timeout_add(500, show_user_folders_copy_dialog)
    else:
        print("No user folders actions needed.")

    global disk_cache_timeout_id
    disk_cache_timeout_id = GObject.timeout_add(2500, check_disk_cache_size)

    # Launch gtk+ main loop
    Gtk.main()

    Gdk.threads_leave()