diff options
Diffstat (limited to 'src/data_imports/DataImportsPluginHost.vala')
-rw-r--r-- | src/data_imports/DataImportsPluginHost.vala | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/src/data_imports/DataImportsPluginHost.vala b/src/data_imports/DataImportsPluginHost.vala new file mode 100644 index 0000000..f92bc53 --- /dev/null +++ b/src/data_imports/DataImportsPluginHost.vala @@ -0,0 +1,482 @@ +/* Copyright 2011-2014 Yorba Foundation + * + * This software is licensed under the GNU Lesser General Public License + * (version 2.1 or later). See the COPYING file in this distribution. + */ + +namespace Spit.DataImports { + +private class CoreImporter { + private weak Spit.DataImports.PluginHost host; + public int imported_items_count = 0; + public BatchImportRoll? current_import_roll = null; + + public CoreImporter(Spit.DataImports.PluginHost host) { + this.host = host; + } + + public void prepare_media_items_for_import( + ImportableMediaItem[] items, + double progress, + double host_progress_delta = 0.0, + string? progress_message = null + ) { + host.update_import_progress_pane(progress, progress_message); + // + SortedList<DataImportJob> jobs = + new SortedList<DataImportJob>(import_job_comparator); + Gee.ArrayList<DataImportJob> already_imported = + new Gee.ArrayList<DataImportJob>(); + Gee.ArrayList<DataImportJob> failed = + new Gee.ArrayList<DataImportJob>(); + + int item_idx = 0; + double item_progress_delta = host_progress_delta / items.length; + foreach (ImportableMediaItem src_item in items) { + DataImportSource import_source = new DataImportSource(src_item); + + if (!import_source.was_backing_file_found()) { + message("Skipping import of %s: backing file not found", + import_source.get_filename()); + failed.add(new DataImportJob(import_source)); + + continue; + } + + if (import_source.is_already_imported()) { + message("Skipping import of %s: checksum detected in library", + import_source.get_filename()); + already_imported.add(new DataImportJob(import_source)); + + continue; + } + + jobs.add(new DataImportJob(import_source)); + item_idx++; + host.update_import_progress_pane(progress + item_idx * item_progress_delta); + } + + if (jobs.size > 0) { + // If there it no current import roll, create one to ensure that all + // imported items end up in the same roll even if this method is called + // several times + if (current_import_roll == null) + current_import_roll = new BatchImportRoll(); + string db_name = _("%s Database").printf(host.get_data_importer().get_service().get_pluggable_name()); + BatchImport batch_import = new BatchImport(jobs, db_name, data_import_reporter, + failed, already_imported, null, current_import_roll); + + LibraryWindow.get_app().enqueue_batch_import(batch_import, true); + imported_items_count += jobs.size; + } + + host.update_import_progress_pane(progress + host_progress_delta); + } + + public void finalize_import() { + // Send an empty job to the queue to mark the end of the import + string db_name = _("%s Database").printf(host.get_data_importer().get_service().get_pluggable_name()); + BatchImport batch_import = new BatchImport( + new Gee.ArrayList<BatchImportJob>(), db_name, data_import_reporter, null, null, null, current_import_roll + ); + LibraryWindow.get_app().enqueue_batch_import(batch_import, true); + current_import_roll = null; + } +} + +public class ConcreteDataImportsHost : Plugins.StandardHostInterface, + Spit.DataImports.PluginHost { + + private Spit.DataImports.DataImporter active_importer = null; + private weak DataImportsUI.DataImportsDialog dialog = null; + private DataImportsUI.ProgressPane? progress_pane = null; + private bool importing_halted = false; + private CoreImporter core_importer; + + public ConcreteDataImportsHost(Service service, DataImportsUI.DataImportsDialog dialog) { + base(service, "data_imports"); + this.dialog = dialog; + + this.active_importer = service.create_data_importer(this); + this.core_importer = new CoreImporter(this); + } + + public DataImporter get_data_importer() { + return active_importer; + } + + public void start_importing() { + if (get_data_importer().is_running()) + return; + + debug("ConcreteDataImportsHost.start_importing( ): invoked."); + + get_data_importer().start(); + } + + public void stop_importing() { + debug("ConcreteDataImportsHost.stop_importing( ): invoked."); + + if (get_data_importer().is_running()) + get_data_importer().stop(); + + clean_up(); + + importing_halted = true; + } + + private void clean_up() { + progress_pane = null; + } + + public void set_button_mode(Spit.DataImports.PluginHost.ButtonMode mode) { + if (mode == Spit.DataImports.PluginHost.ButtonMode.CLOSE) + dialog.set_close_button_mode(); + else if (mode == Spit.DataImports.PluginHost.ButtonMode.CANCEL) + dialog.set_cancel_button_mode(); + else + error("unrecognized button mode enumeration value"); + } + + // Pane handling methods + + public void post_error(Error err) { + post_error_message(err.message); + } + + public void post_error_message(string message) { + string msg = _("Importing from %s can't continue because an error occurred:").printf( + active_importer.get_service().get_pluggable_name()); + msg += GLib.Markup.printf_escaped("\n\n<i>%s</i>\n\n", message); + msg += _("To try importing from another service, select one from the above menu."); + + dialog.install_pane(new DataImportsUI.StaticMessagePane.with_pango(msg)); + dialog.set_close_button_mode(); + dialog.unlock_service(); + + get_data_importer().stop(); + + // post_error_message( ) tells the active_importer to stop importing and displays a + // non-removable error pane that effectively ends the publishing interaction, + // so no problem calling clean_up( ) here. + clean_up(); + } + + public void install_dialog_pane(Spit.DataImports.DialogPane pane, + Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) { + debug("DataImports.PluginHost: install_dialog_pane( ): invoked."); + + if (get_data_importer() == null || (!get_data_importer().is_running())) + return; + + dialog.install_pane(pane); + + set_button_mode(button_mode); + } + + public void install_static_message_pane(string message, + Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) { + + set_button_mode(button_mode); + + dialog.install_pane(new DataImportsUI.StaticMessagePane.with_pango(message)); + } + + public void install_library_selection_pane( + string welcome_message, + ImportableLibrary[] discovered_libraries, + string? file_select_label + ) { + if (discovered_libraries.length == 0 && file_select_label == null) + post_error_message("Libraries or file option needed"); + else + dialog.install_pane(new DataImportsUI.LibrarySelectionPane( + this, + welcome_message, + discovered_libraries, + file_select_label + )); + set_button_mode(Spit.DataImports.PluginHost.ButtonMode.CLOSE); + } + + public void install_import_progress_pane( + string message + ) { + progress_pane = new DataImportsUI.ProgressPane(message); + dialog.install_pane(progress_pane); + set_button_mode(Spit.DataImports.PluginHost.ButtonMode.CANCEL); + // initialize the import + core_importer.imported_items_count = 0; + core_importer.current_import_roll = null; + } + + public void update_import_progress_pane( + double progress, + string? progress_message = null + ) { + if (progress_pane != null) { + progress_pane.update_progress(progress, progress_message); + } + } + + public void prepare_media_items_for_import( + ImportableMediaItem[] items, + double progress, + double host_progress_delta = 0.0, + string? progress_message = null + ) { + core_importer.prepare_media_items_for_import(items, progress, host_progress_delta, progress_message); + } + + public void finalize_import( + ImportedItemsCountCallback report_imported_items_count, + string? finalize_message = null + ) { + update_import_progress_pane(1.0, finalize_message); + set_button_mode(Spit.DataImports.PluginHost.ButtonMode.CLOSE); + core_importer.finalize_import(); + report_imported_items_count(core_importer.imported_items_count); + if (core_importer.imported_items_count > 0) + LibraryWindow.get_app().switch_to_import_queue_page(); + } +} + +public class WelcomeDataImportsHost : Plugins.StandardHostInterface, + Spit.DataImports.PluginHost { + + private weak WelcomeImportMetaHost meta_host; + private Spit.DataImports.DataImporter active_importer = null; + private bool importing_halted = false; + private CoreImporter core_importer; + + public WelcomeDataImportsHost(Service service, WelcomeImportMetaHost meta_host) { + base(service, "data_imports"); + + this.active_importer = service.create_data_importer(this); + this.core_importer = new CoreImporter(this); + this.meta_host = meta_host; + } + + public DataImporter get_data_importer() { + return active_importer; + } + + public void start_importing() { + if (get_data_importer().is_running()) + return; + + debug("WelcomeDataImportsHost.start_importing( ): invoked."); + + get_data_importer().start(); + } + + public void stop_importing() { + debug("WelcomeDataImportsHost.stop_importing( ): invoked."); + + if (get_data_importer().is_running()) + get_data_importer().stop(); + + clean_up(); + + importing_halted = true; + } + + private void clean_up() { + } + + // Pane handling methods + + public void post_error(Error err) { + post_error_message(err.message); + } + + public void post_error_message(string message) { + string msg = _("Importing from %s can't continue because an error occurred:").printf( + active_importer.get_service().get_pluggable_name()); + + debug(msg); + + get_data_importer().stop(); + + // post_error_message( ) tells the active_importer to stop importing and displays a + // non-removable error pane that effectively ends the publishing interaction, + // so no problem calling clean_up( ) here. + clean_up(); + } + + public void install_dialog_pane(Spit.DataImports.DialogPane pane, + Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) { + // do nothing + } + + public void install_static_message_pane(string message, + Spit.DataImports.PluginHost.ButtonMode button_mode = Spit.DataImports.PluginHost.ButtonMode.CANCEL) { + // do nothing + } + + public void install_library_selection_pane( + string welcome_message, + ImportableLibrary[] discovered_libraries, + string? file_select_label + ) { + debug("WelcomeDataImportsHost: Installing library selection pane for %s".printf(get_data_importer().get_service().get_pluggable_name())); + if (discovered_libraries.length > 0) { + meta_host.install_service_entry(new WelcomeImportServiceEntry( + this, + get_data_importer().get_service().get_pluggable_name(), + discovered_libraries + )); + } + } + + public void install_import_progress_pane( + string message + ) { + // empty implementation + } + + public void update_import_progress_pane( + double progress, + string? progress_message = null + ) { + // empty implementation + } + + public void prepare_media_items_for_import( + ImportableMediaItem[] items, + double progress, + double host_progress_delta = 0.0, + string? progress_message = null + ) { + core_importer.prepare_media_items_for_import(items, progress, host_progress_delta, progress_message); + } + + public void finalize_import( + ImportedItemsCountCallback report_imported_items_count, + string? finalize_message = null + ) { + core_importer.finalize_import(); + report_imported_items_count(core_importer.imported_items_count); + meta_host.finalize_import(this); + } +} + + +//public delegate void WelcomeImporterCallback(); + +public class WelcomeImportServiceEntry : GLib.Object, WelcomeServiceEntry { + private string pluggable_name; + private ImportableLibrary[] discovered_libraries; + private Spit.DataImports.PluginHost host; + + public WelcomeImportServiceEntry( + Spit.DataImports.PluginHost host, + string pluggable_name, ImportableLibrary[] discovered_libraries) { + + this.host = host; + this.pluggable_name = pluggable_name; + this.discovered_libraries = discovered_libraries; + } + + public string get_service_name() { + return pluggable_name; + } + + public void execute() { + foreach (ImportableLibrary library in discovered_libraries) { + host.get_data_importer().on_library_selected(library); + } + } +} + +public class WelcomeImportMetaHost : GLib.Object { + private WelcomeDialog dialog; + + public WelcomeImportMetaHost(WelcomeDialog dialog) { + this.dialog = dialog; + } + + public void start() { + Service[] services = load_all_services(); + foreach (Service service in services) { + WelcomeDataImportsHost host = new WelcomeDataImportsHost(service, this); + host.start_importing(); + } + } + + public void finalize_import(WelcomeDataImportsHost host) { + host.stop_importing(); + } + + public void install_service_entry(WelcomeServiceEntry entry) { + debug("WelcomeImportMetaHost: Installing service entry for %s".printf(entry.get_service_name())); + dialog.install_service_entry(entry); + } +} + +public static Spit.DataImports.Service[] load_all_services() { + return load_services(true); +} + +public static Spit.DataImports.Service[] load_services(bool load_all = false) { + Spit.DataImports.Service[] loaded_services = new Spit.DataImports.Service[0]; + + // load publishing services from plug-ins + Gee.Collection<Spit.Pluggable> pluggables = Plugins.get_pluggables_for_type( + typeof(Spit.DataImports.Service), null, load_all); + // TODO: include sorting function to ensure consistent order + + debug("DataImportsDialog: discovered %d pluggable data import services.", pluggables.size); + + foreach (Spit.Pluggable pluggable in pluggables) { + int pluggable_interface = pluggable.get_pluggable_interface( + Spit.DataImports.CURRENT_INTERFACE, Spit.DataImports.CURRENT_INTERFACE); + if (pluggable_interface != Spit.DataImports.CURRENT_INTERFACE) { + warning("Unable to load data import plugin %s: reported interface %d.", + Plugins.get_pluggable_module_id(pluggable), pluggable_interface); + + continue; + } + + Spit.DataImports.Service service = + (Spit.DataImports.Service) pluggable; + + debug("DataImportsDialog: discovered pluggable data import service '%s'.", + service.get_pluggable_name()); + + loaded_services += service; + } + + // Sort import services by name. + // TODO: extract to a function to sort it on initial request + Posix.qsort(loaded_services, loaded_services.length, sizeof(Spit.DataImports.Service), + (a, b) => {return utf8_cs_compare((*((Spit.DataImports.Service**) a))->get_pluggable_name(), + (*((Spit.DataImports.Service**) b))->get_pluggable_name()); + }); + + return loaded_services; +} + +private ImportManifest? meta_manifest = null; + +private void data_import_reporter(ImportManifest manifest, BatchImportRoll import_roll) { + if (manifest.all.size > 0) { + if (meta_manifest == null) + meta_manifest = new ImportManifest(); + foreach (BatchImportResult result in manifest.all) { + meta_manifest.add_result(result); + } + } else { + DataImportsUI.DataImportsDialog.terminate_instance(); + ImportUI.report_manifest(meta_manifest, true); + meta_manifest = null; + } +} + +private int64 import_job_comparator(void *a, void *b) { + return ((DataImportJob *) a)->get_exposure_time() + - ((DataImportJob *) b)->get_exposure_time(); +} + +} + |