Commit 2d4a043b authored by Lucas Beeler's avatar Lucas Beeler

Refines the new publishing API so that the plugin host completely encapsulates...

Refines the new publishing API so that the plugin host completely encapsulates operations on temporary files. This way, plugin writers don't have to deal with temporaries. Changed the reference Facebook plugin to conform to the changed API.
parent bcb052e5
......@@ -918,6 +918,10 @@ public class PublishingDialog : Gtk.Dialog {
if (pane is PublishingDialogPane)
((PublishingDialogPane) pane).installed();
}
public Gtk.Widget get_active_pane() {
return active_pane;
}
public void set_large_window_mode() {
set_size_request(LARGE_WINDOW_WIDTH, LARGE_WINDOW_HEIGHT);
......
......@@ -54,9 +54,8 @@ public interface PublishingDialogPane : GLib.Object {
public abstract void on_pane_uninstalled();
}
/* completed fraction is between 0.0 and 1.0 inclusive; status text is displayed as text on the
progress bar */
public delegate void ProgressCallback(string status_text, double completed_fraction);
/* fraction_complete should be between 0.0 and 1.0 inclusive */
public delegate void ProgressCallback(int file_number, double fraction_complete);
public delegate void LoginCallback();
......@@ -91,8 +90,6 @@ public interface PublishingInteractor : GLib.Object {
public abstract void set_dialog_default_widget(Gtk.Widget widget);
public abstract ProgressCallback install_progress_pane();
public abstract int get_config_int(string key, int default_value);
public abstract string? get_config_string(string key, string? default_value);
......@@ -111,12 +108,17 @@ public interface PublishingInteractor : GLib.Object {
public abstract Publishable[] get_publishables();
public abstract ProgressCallback? serialize_publishables(int content_major_axis,
bool strip_metadata = false);
public abstract Spit.Publishing.Publisher.MediaType get_publishable_media_type();
}
public interface Publishable : GLib.Object {
public abstract GLib.File serialize_for_publishing(int content_major_axis,
bool strip_metadata = false) throws Spit.Publishing.PublishingError;
public abstract GLib.File? get_serialized_file();
public abstract string get_publishing_name();
......
......@@ -141,10 +141,6 @@ public class DialogInteractorWrapper : PublishingDialog, Spit.Publishing.Publish
public void set_dialog_default_widget(Gtk.Widget widget) {
plugin_host.set_dialog_default_widget(widget);
}
public Spit.Publishing.ProgressCallback install_progress_pane() {
return plugin_host.install_progress_pane();
}
public Spit.Publishing.Publisher.MediaType get_publishable_media_type() {
return plugin_host.get_publishable_media_type();
......@@ -185,16 +181,37 @@ public class DialogInteractorWrapper : PublishingDialog, Spit.Publishing.Publish
public Spit.Publishing.Publishable[] get_publishables() {
return publishables;
}
public Spit.Publishing.ProgressCallback? serialize_publishables(int content_major_axis,
bool strip_metadata = false) {
return plugin_host.serialize_publishables(content_major_axis, strip_metadata);
}
}
public class MediaSourcePublishableWrapper : Spit.Publishing.Publishable, GLib.Object {
private static int name_ticker = 0;
private MediaSource wrapped;
private GLib.File? serialized_file = null;
public MediaSourcePublishableWrapper(MediaSource to_wrap) {
wrapped = to_wrap;
}
public void clean_up() {
if (serialized_file == null)
return;
debug("cleaning up temporary publishing file '%s'.", serialized_file.get_path());
try {
serialized_file.delete(null);
} catch (Error err) {
warning("couldn't delete temporary publishing file '%s'.", serialized_file.get_path());
}
serialized_file = null;
}
public GLib.File serialize_for_publishing(int content_major_axis,
bool strip_metadata = false) throws Spit.Publishing.PublishingError {
......@@ -215,7 +232,7 @@ public class MediaSourcePublishableWrapper : Spit.Publishing.Publishable, GLib.O
"unable to serialize photo '%s' for publishing.", photo.get_name());
}
return to_file;
serialized_file = to_file;
} else if (wrapped is Video) {
Video video = (Video) wrapped;
......@@ -235,11 +252,12 @@ public class MediaSourcePublishableWrapper : Spit.Publishing.Publishable, GLib.O
"unable to serialize video '%s' for publishing.", video.get_name());
}
return to_file;
serialized_file = to_file;
} else {
error("MediaSourcePublishableWrapper.serialize_for_publishing( ): unknown media type.");
}
return serialized_file;
}
public string get_publishing_name() {
......@@ -271,6 +289,10 @@ public class MediaSourcePublishableWrapper : Spit.Publishing.Publishable, GLib.O
else
return Spit.Publishing.Publisher.MediaType.NONE;
}
public GLib.File? get_serialized_file() {
return serialized_file;
}
}
public class GlueFactory {
......
......@@ -310,16 +310,16 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
interactor.set_button_mode(Spit.Publishing.PublishingInteractor.ButtonMode.CANCEL);
interactor.set_service_locked(true);
progress_reporter = interactor.install_progress_pane();
progress_reporter = interactor.serialize_publishables(MAX_PHOTO_DIMENSION);
Spit.Publishing.Publishable[] publishables = interactor.get_publishables();
FacebookUploader uploader = new FacebookUploader(session, albums[publish_to_album].id,
privacy_setting, publishables);
uploader.status_updated.connect(on_upload_status_updated);
uploader.upload_complete.connect(on_upload_complete);
uploader.upload_error.connect(on_upload_error);
uploader.upload();
uploader.upload(on_upload_status_updated);
}
private void do_create_album(string album_name) {
......@@ -523,7 +523,7 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
do_upload();
}
private void on_upload_status_updated(string status_text, double completed_fraction) {
private void on_upload_status_updated(int file_number, double completed_fraction) {
if (!is_running())
return;
......@@ -531,7 +531,7 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
assert(progress_reporter != null);
progress_reporter(status_text, completed_fraction);
progress_reporter(file_number, completed_fraction);
}
private void on_upload_complete(FacebookUploader uploader, int num_published) {
......@@ -540,7 +540,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
debug("EVENT: uploader reports upload complete; %d items published.", num_published);
uploader.status_updated.disconnect(on_upload_status_updated);
uploader.upload_complete.disconnect(on_upload_complete);
uploader.upload_error.disconnect(on_upload_error);
......@@ -553,7 +552,6 @@ public class FacebookPublisher : Spit.Publishing.Publisher, GLib.Object {
debug("EVENT: uploader reports upload error = '%s'.", err.message);
uploader.status_updated.disconnect(on_upload_status_updated);
uploader.upload_complete.disconnect(on_upload_complete);
uploader.upload_error.disconnect(on_upload_error);
......@@ -1606,20 +1604,13 @@ internal class FacebookRESTXmlDocument {
}
internal class FacebookUploader {
private const string PREPARE_STATUS_DESCRIPTION = _("Preparing for upload");
private const string UPLOAD_STATUS_DESCRIPTION = _("Uploading %d of %d");
private const string TEMP_FILE_PREFIX = "publishing-";
private const double PREPARATION_PHASE_FRACTION = 0.3;
private const double UPLOAD_PHASE_FRACTION = 0.7;
private int current_file = 0;
private Spit.Publishing.Publishable[] publishables = null;
private GLib.File[] temp_files = null;
private FacebookRESTSession session = null;
private string aid;
private string privacy_setting;
private Spit.Publishing.ProgressCallback? status_updated = null;
public signal void status_updated(string description, double fraction_complete);
public signal void upload_complete(int num_photos_published);
public signal void upload_error(Spit.Publishing.PublishingError err);
......@@ -1631,39 +1622,16 @@ internal class FacebookUploader {
this.session = session;
}
private void prepare_files() {
temp_files = new GLib.File[0];
int i = 0;
foreach (Spit.Publishing.Publishable publishable in publishables) {
try {
temp_files += publishable.serialize_for_publishing(MAX_PHOTO_DIMENSION);
} catch (Spit.Publishing.PublishingError err) {
upload_error(err);
return;
}
double phase_fraction_complete = ((double) (i + 1)) / ((double) publishables.length);
double fraction_complete = phase_fraction_complete * PREPARATION_PHASE_FRACTION;
debug("prepare_file( ): fraction_complete = %f.", fraction_complete);
status_updated(PREPARE_STATUS_DESCRIPTION, fraction_complete);
spin_event_loop();
i++;
}
}
private void send_files() {
current_file = 0;
bool stop = false;
foreach (File file in temp_files) {
double fraction_complete = PREPARATION_PHASE_FRACTION +
(current_file * (UPLOAD_PHASE_FRACTION / temp_files.length));
status_updated(_("Uploading %d of %d").printf(current_file + 1, temp_files.length),
fraction_complete);
foreach (Spit.Publishing.Publishable publishable in publishables) {
GLib.File? file = publishable.get_serialized_file();
assert (file != null);
double fraction_complete = ((double) current_file) / publishables.length;
if (status_updated != null)
status_updated(current_file + 1, fraction_complete);
FacebookRESTTransaction txn = new FacebookUploadTransaction(session, aid, privacy_setting,
publishables[current_file], file);
......@@ -1678,7 +1646,6 @@ internal class FacebookUploader {
}
txn.chunk_transmitted.disconnect(on_chunk_transmitted);
delete_file(file);
if (stop)
break;
......@@ -1689,35 +1656,21 @@ internal class FacebookUploader {
if (!stop)
upload_complete(current_file);
}
private void delete_file(GLib.File file) {
try {
debug("Deleting publishing temporary file '%s'", file.get_path());
file.delete(null);
} catch (Error e) {
// if deleting temporary files generates an exception, just print a warning
// message -- temp directory clean-up will be done on launch or at exit or
// both
warning("FacebookUploader: deleting temporary files failed.");
}
}
private void on_chunk_transmitted(int bytes_written_so_far, int total_bytes) {
double file_span = UPLOAD_PHASE_FRACTION / temp_files.length;
double file_span = 1.0 / publishables.length;
double this_file_fraction_complete = ((double) bytes_written_so_far) / total_bytes;
double fraction_complete = PREPARATION_PHASE_FRACTION + (current_file * file_span) +
(this_file_fraction_complete * file_span);
double fraction_complete = (current_file * file_span) + (this_file_fraction_complete *
file_span);
string status_desc = UPLOAD_STATUS_DESCRIPTION.printf(current_file + 1, temp_files.length);
status_updated(status_desc, fraction_complete);
if (status_updated != null)
status_updated(current_file + 1, fraction_complete);
}
public void upload() {
status_updated(_("Preparing for upload"), 0);
prepare_files();
public void upload(Spit.Publishing.ProgressCallback? status_updated = null) {
this.status_updated = status_updated;
if (temp_files.length > 0)
if (publishables.length > 0)
send_files();
}
}
......
......@@ -7,6 +7,12 @@
namespace Spit.Publishing {
public class PublishingHost : Spit.Publishing.PublishingInteractor, GLib.Object {
private const string PREPARE_STATUS_DESCRIPTION = _("Preparing for upload");
private const string UPLOAD_STATUS_DESCRIPTION = _("Uploading %d of %d");
private const double STATUS_PREPARATION_FRACTION = 0.3;
private const double STATUS_UPLOAD_FRACTION = 0.7;
private PublishingDialog dialog = null;
private Spit.Publishing.PublishingDialogPane current_pane = null;
private Spit.Publishing.Publisher active_publisher = null;
......@@ -23,6 +29,36 @@ public class PublishingHost : Spit.Publishing.PublishingInteractor, GLib.Object
current_login_callback();
}
private void clean_up() {
foreach (Publishable publishable in publishables)
((global::Publishing.Glue.MediaSourcePublishableWrapper) publishable).clean_up();
}
private void report_plugin_upload_progress(int file_number, double fraction_complete) {
// if the currently installed pane isn't the progress pane, do nothing
if (!(dialog.get_active_pane() is ProgressPane))
return;
ProgressPane pane = (ProgressPane) dialog.get_active_pane();
string status_string = UPLOAD_STATUS_DESCRIPTION.printf(file_number,
publishables.length);
double status_fraction = STATUS_PREPARATION_FRACTION + (STATUS_UPLOAD_FRACTION *
fraction_complete);
pane.set_status(status_string, status_fraction);
}
private void install_progress_pane() {
ProgressPane progress_pane = new ProgressPane();
if (current_pane != null)
current_pane.on_pane_uninstalled();
current_pane = null;
dialog.install_pane(progress_pane);
}
public void set_active_publisher(Spit.Publishing.Publisher active_publisher) {
this.active_publisher = active_publisher;
}
......@@ -68,6 +104,11 @@ public class PublishingHost : Spit.Publishing.PublishingInteractor, GLib.Object
dialog.show_pango_error_message(msg);
active_publisher.stop();
// post_error( ) tells the active_publisher to stop publishing and displays a
// non-removable error pane that effectively ends the publishing interaction,
// so no problem calling clean_up( ) here.
clean_up();
}
public void stop_publishing() {
......@@ -76,6 +117,8 @@ public class PublishingHost : Spit.Publishing.PublishingInteractor, GLib.Object
if (active_publisher.is_running())
active_publisher.stop();
clean_up();
active_publisher = null;
dialog = null;
}
......@@ -102,6 +145,10 @@ public class PublishingHost : Spit.Publishing.PublishingInteractor, GLib.Object
current_pane = null;
dialog.install_pane(new SuccessPane(media_type));
// the success pane is a terminal pane; once it's installed, the publishing
// interaction is considered over, so clean up
clean_up();
}
public void install_account_fetch_wait_pane() {
......@@ -152,18 +199,6 @@ public class PublishingHost : Spit.Publishing.PublishingInteractor, GLib.Object
widget.can_default = true;
dialog.set_default(widget);
}
public ProgressCallback install_progress_pane() {
ProgressPane progress_pane = new ProgressPane();
if (current_pane != null)
current_pane.on_pane_uninstalled();
current_pane = null;
dialog.install_pane(progress_pane);
return progress_pane.set_status;
}
public Spit.Publishing.Publisher.MediaType get_publishable_media_type() {
return dialog.get_media_type();
......@@ -210,6 +245,35 @@ public class PublishingHost : Spit.Publishing.PublishingInteractor, GLib.Object
public Publishable[] get_publishables() {
return publishables;
}
public Spit.Publishing.ProgressCallback? serialize_publishables(int content_major_axis,
bool strip_metadata = false) {
install_progress_pane();
ProgressPane progress_pane = (ProgressPane) dialog.get_active_pane();
int i = 0;
foreach (Spit.Publishing.Publishable publishable in publishables) {
try {
publishable.serialize_for_publishing(content_major_axis, strip_metadata);
} catch (Spit.Publishing.PublishingError err) {
post_error(err);
return null;
}
double phase_fraction_complete = ((double) (i + 1)) / ((double) publishables.length);
double fraction_complete = phase_fraction_complete * STATUS_PREPARATION_FRACTION;
debug("serialize_publishables( ): fraction_complete = %f.", fraction_complete);
progress_pane.set_status(PREPARE_STATUS_DESCRIPTION, fraction_complete);
spin_event_loop();
i++;
}
return report_plugin_upload_progress;
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment