summaryrefslogtreecommitdiff
path: root/src/data_imports/DataImportsPluginHost.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/data_imports/DataImportsPluginHost.vala')
-rw-r--r--src/data_imports/DataImportsPluginHost.vala482
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();
+}
+
+}
+