diff options
author | Perberos <[email protected]> | 2011-11-06 19:30:49 -0300 |
---|---|---|
committer | Perberos <[email protected]> | 2011-11-06 19:30:49 -0300 |
commit | a8d28a6ce7e0c56dacba5d527d9134573a008902 (patch) | |
tree | 8852602004b5a13cc5d1ce3ecd7a314be81d1198 /src/eom-jobs.c | |
download | eom-a8d28a6ce7e0c56dacba5d527d9134573a008902.tar.bz2 eom-a8d28a6ce7e0c56dacba5d527d9134573a008902.tar.xz |
inicial
Diffstat (limited to 'src/eom-jobs.c')
-rw-r--r-- | src/eom-jobs.c | 885 |
1 files changed, 885 insertions, 0 deletions
diff --git a/src/eom-jobs.c b/src/eom-jobs.c new file mode 100644 index 0000000..c3bac3a --- /dev/null +++ b/src/eom-jobs.c @@ -0,0 +1,885 @@ +/* Eye Of Mate - Jobs + * + * Copyright (C) 2006 The Free Software Foundation + * + * Author: Lucas Rocha <[email protected]> + * + * Based on evince code (shell/ev-jobs.c) by: + * - Martin Kretzschmar <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "eom-uri-converter.h" +#include "eom-jobs.h" +#include "eom-job-queue.h" +#include "eom-image.h" +#include "eom-transform.h" +#include "eom-list-store.h" +#include "eom-thumbnail.h" +#include "eom-pixbuf-util.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> + +#define EOM_JOB_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_JOB, EomJobPrivate)) + +G_DEFINE_TYPE (EomJob, eom_job, G_TYPE_OBJECT); +G_DEFINE_TYPE (EomJobThumbnail, eom_job_thumbnail, EOM_TYPE_JOB); +G_DEFINE_TYPE (EomJobLoad, eom_job_load, EOM_TYPE_JOB); +G_DEFINE_TYPE (EomJobModel, eom_job_model, EOM_TYPE_JOB); +G_DEFINE_TYPE (EomJobTransform, eom_job_transform, EOM_TYPE_JOB); +G_DEFINE_TYPE (EomJobSave, eom_job_save, EOM_TYPE_JOB); +G_DEFINE_TYPE (EomJobSaveAs, eom_job_save_as, EOM_TYPE_JOB_SAVE); +G_DEFINE_TYPE (EomJobCopy, eom_job_copy, EOM_TYPE_JOB); + +enum +{ + SIGNAL_FINISHED, + SIGNAL_PROGRESS, + SIGNAL_LAST_SIGNAL +}; + +static guint job_signals[SIGNAL_LAST_SIGNAL]; + +static void eom_job_copy_run (EomJob *ejob); +static void eom_job_load_run (EomJob *ejob); +static void eom_job_model_run (EomJob *ejob); +static void eom_job_save_run (EomJob *job); +static void eom_job_save_as_run (EomJob *job); +static void eom_job_thumbnail_run (EomJob *ejob); +static void eom_job_transform_run (EomJob *ejob); + +static void eom_job_init (EomJob *job) +{ + job->mutex = g_mutex_new(); + job->progress = 0.0; +} + +static void +eom_job_dispose (GObject *object) +{ + EomJob *job; + + job = EOM_JOB (object); + + if (job->error) { + g_error_free (job->error); + job->error = NULL; + } + + if (job->mutex) { + g_mutex_free (job->mutex); + job->mutex = NULL; + } + + (* G_OBJECT_CLASS (eom_job_parent_class)->dispose) (object); +} + +static void +eom_job_run_default (EomJob *job) +{ + g_critical ("Class \"%s\" does not implement the required run action", + G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (job))); +} + +static void +eom_job_class_init (EomJobClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = eom_job_dispose; + + class->run = eom_job_run_default; + + job_signals [SIGNAL_FINISHED] = + g_signal_new ("finished", + EOM_TYPE_JOB, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EomJobClass, finished), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + job_signals [SIGNAL_PROGRESS] = + g_signal_new ("progress", + EOM_TYPE_JOB, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EomJobClass, progress), + NULL, NULL, + g_cclosure_marshal_VOID__FLOAT, + G_TYPE_NONE, 1, + G_TYPE_FLOAT); +} + +void +eom_job_finished (EomJob *job) +{ + g_return_if_fail (EOM_IS_JOB (job)); + + g_signal_emit (job, job_signals[SIGNAL_FINISHED], 0); +} + +/** + * eom_job_run: + * @job: the job to execute. + * + * Executes the job passed as @job. Usually there is no need to call this + * on your own. Jobs should be executed by using the EomJobQueue. + **/ +void +eom_job_run (EomJob *job) +{ + EomJobClass *class; + + g_return_if_fail (EOM_IS_JOB (job)); + + class = EOM_JOB_GET_CLASS (job); + if (class->run) + class->run (job); + else + eom_job_run_default (job); +} +static gboolean +notify_progress (gpointer data) +{ + EomJob *job = EOM_JOB (data); + + g_signal_emit (job, job_signals[SIGNAL_PROGRESS], 0, job->progress); + + return FALSE; +} + +void +eom_job_set_progress (EomJob *job, float progress) +{ + g_return_if_fail (EOM_IS_JOB (job)); + g_return_if_fail (progress >= 0.0 && progress <= 1.0); + + g_mutex_lock (job->mutex); + job->progress = progress; + g_mutex_unlock (job->mutex); + + g_idle_add (notify_progress, job); +} + +static void eom_job_thumbnail_init (EomJobThumbnail *job) { /* Do Nothing */ } + +static void +eom_job_thumbnail_dispose (GObject *object) +{ + EomJobThumbnail *job; + + job = EOM_JOB_THUMBNAIL (object); + + if (job->image) { + g_object_unref (job->image); + job->image = NULL; + } + + if (job->thumbnail) { + g_object_unref (job->thumbnail); + job->thumbnail = NULL; + } + + (* G_OBJECT_CLASS (eom_job_thumbnail_parent_class)->dispose) (object); +} + +static void +eom_job_thumbnail_class_init (EomJobThumbnailClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = eom_job_thumbnail_dispose; + + EOM_JOB_CLASS (class)->run = eom_job_thumbnail_run; +} + +EomJob * +eom_job_thumbnail_new (EomImage *image) +{ + EomJobThumbnail *job; + + job = g_object_new (EOM_TYPE_JOB_THUMBNAIL, NULL); + + if (image) { + job->image = g_object_ref (image); + } + + return EOM_JOB (job); +} + +static void +eom_job_thumbnail_run (EomJob *ejob) +{ + gchar *orig_width, *orig_height; + gint width, height; + GdkPixbuf *pixbuf; + EomJobThumbnail *job; + + g_return_if_fail (EOM_IS_JOB_THUMBNAIL (ejob)); + + job = EOM_JOB_THUMBNAIL (ejob); + + if (ejob->error) { + g_error_free (ejob->error); + ejob->error = NULL; + } + + job->thumbnail = eom_thumbnail_load (job->image, + &ejob->error); + + if (!job->thumbnail) { + ejob->finished = TRUE; + return; + } + + orig_width = g_strdup (gdk_pixbuf_get_option (job->thumbnail, "tEXt::Thumb::Image::Width")); + orig_height = g_strdup (gdk_pixbuf_get_option (job->thumbnail, "tEXt::Thumb::Image::Height")); + + pixbuf = eom_thumbnail_fit_to_size (job->thumbnail, EOM_LIST_STORE_THUMB_SIZE); + g_object_unref (job->thumbnail); + job->thumbnail = eom_thumbnail_add_frame (pixbuf); + g_object_unref (pixbuf); + + if (orig_width) { + sscanf (orig_width, "%i", &width); + g_object_set_data (G_OBJECT (job->thumbnail), + EOM_THUMBNAIL_ORIGINAL_WIDTH, + GINT_TO_POINTER (width)); + g_free (orig_width); + } + if (orig_height) { + sscanf (orig_height, "%i", &height); + g_object_set_data (G_OBJECT (job->thumbnail), + EOM_THUMBNAIL_ORIGINAL_HEIGHT, + GINT_TO_POINTER (height)); + g_free (orig_height); + } + + if (ejob->error) { + g_warning ("%s", ejob->error->message); + } + + ejob->finished = TRUE; +} + +static void eom_job_load_init (EomJobLoad *job) { /* Do Nothing */ } + +static void +eom_job_load_dispose (GObject *object) +{ + EomJobLoad *job; + + job = EOM_JOB_LOAD (object); + + if (job->image) { + g_object_unref (job->image); + job->image = NULL; + } + + (* G_OBJECT_CLASS (eom_job_load_parent_class)->dispose) (object); +} + +static void +eom_job_load_class_init (EomJobLoadClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = eom_job_load_dispose; + EOM_JOB_CLASS (class)->run = eom_job_load_run; +} + +EomJob * +eom_job_load_new (EomImage *image, EomImageData data) +{ + EomJobLoad *job; + + job = g_object_new (EOM_TYPE_JOB_LOAD, NULL); + + if (image) { + job->image = g_object_ref (image); + } + job->data = data; + + return EOM_JOB (job); +} + +static void +eom_job_load_run (EomJob *job) +{ + g_return_if_fail (EOM_IS_JOB_LOAD (job)); + + if (job->error) { + g_error_free (job->error); + job->error = NULL; + } + + eom_image_load (EOM_IMAGE (EOM_JOB_LOAD (job)->image), + EOM_JOB_LOAD (job)->data, + job, + &job->error); + + job->finished = TRUE; +} + +static void eom_job_model_init (EomJobModel *job) { /* Do Nothing */ } + +static void +eom_job_model_dispose (GObject *object) +{ + EomJobModel *job; + + job = EOM_JOB_MODEL (object); + + (* G_OBJECT_CLASS (eom_job_model_parent_class)->dispose) (object); +} + +static void +eom_job_model_class_init (EomJobModelClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = eom_job_model_dispose; + EOM_JOB_CLASS (class)->run = eom_job_model_run; +} + +EomJob * +eom_job_model_new (GSList *file_list) +{ + EomJobModel *job; + + job = g_object_new (EOM_TYPE_JOB_MODEL, NULL); + + job->file_list = file_list; + + return EOM_JOB (job); +} + +static void +filter_files (GSList *files, GList **file_list, GList **error_list) +{ + GSList *it; + GFileInfo *file_info; + + for (it = files; it != NULL; it = it->next) { + GFile *file; + GFileType type = G_FILE_TYPE_UNKNOWN; + + file = (GFile *) it->data; + + if (file != NULL) { + file_info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_TYPE","G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + 0, NULL, NULL); + if (file_info == NULL) { + type = G_FILE_TYPE_UNKNOWN; + } else { + type = g_file_info_get_file_type (file_info); + + /* Workaround for gvfs backends that + don't set the GFileType. */ + if (G_UNLIKELY (type == G_FILE_TYPE_UNKNOWN)) { + const gchar *ctype; + + ctype = g_file_info_get_content_type (file_info); + + /* If the content type is supported + adjust the file_type */ + if (eom_image_is_supported_mime_type (ctype)) + type = G_FILE_TYPE_REGULAR; + } + + g_object_unref (file_info); + } + } + + switch (type) { + case G_FILE_TYPE_REGULAR: + case G_FILE_TYPE_DIRECTORY: + *file_list = g_list_prepend (*file_list, g_object_ref (file)); + break; + default: + *error_list = g_list_prepend (*error_list, + g_file_get_uri (file)); + break; + } + + g_object_unref (file); + } + + *file_list = g_list_reverse (*file_list); + *error_list = g_list_reverse (*error_list); +} + +static void +eom_job_model_run (EomJob *ejob) +{ + GList *filtered_list = NULL; + GList *error_list = NULL; + EomJobModel *job; + + g_return_if_fail (EOM_IS_JOB_MODEL (ejob)); + + job = EOM_JOB_MODEL (ejob); + + filter_files (job->file_list, &filtered_list, &error_list); + + job->store = EOM_LIST_STORE (eom_list_store_new ()); + + eom_list_store_add_files (job->store, filtered_list); + + g_list_foreach (filtered_list, (GFunc) g_object_unref, NULL); + g_list_free (filtered_list); + + g_list_foreach (error_list, (GFunc) g_free, NULL); + g_list_free (error_list); + + ejob->finished = TRUE; +} + +static void eom_job_transform_init (EomJobTransform *job) { /* Do Nothing */ } + +static void +eom_job_transform_dispose (GObject *object) +{ + EomJobTransform *job; + + job = EOM_JOB_TRANSFORM (object); + + if (job->trans) { + g_object_unref (job->trans); + job->trans = NULL; + } + + g_list_foreach (job->images, (GFunc) g_object_unref, NULL); + g_list_free (job->images); + + (* G_OBJECT_CLASS (eom_job_transform_parent_class)->dispose) (object); +} + +static void +eom_job_transform_class_init (EomJobTransformClass *class) +{ + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (class); + + oclass->dispose = eom_job_transform_dispose; + + EOM_JOB_CLASS (class)->run = eom_job_transform_run; +} + +EomJob * +eom_job_transform_new (GList *images, EomTransform *trans) +{ + EomJobTransform *job; + + job = g_object_new (EOM_TYPE_JOB_TRANSFORM, NULL); + + if (trans) { + job->trans = g_object_ref (trans); + } else { + job->trans = NULL; + } + + job->images = images; + + return EOM_JOB (job); +} + +static gboolean +eom_job_transform_image_modified (gpointer data) +{ + g_return_val_if_fail (EOM_IS_IMAGE (data), FALSE); + + eom_image_modified (EOM_IMAGE (data)); + g_object_unref (G_OBJECT (data)); + + return FALSE; +} + +void +eom_job_transform_run (EomJob *ejob) +{ + EomJobTransform *job; + GList *it; + + g_return_if_fail (EOM_IS_JOB_TRANSFORM (ejob)); + + job = EOM_JOB_TRANSFORM (ejob); + + if (ejob->error) { + g_error_free (ejob->error); + ejob->error = NULL; + } + + for (it = job->images; it != NULL; it = it->next) { + EomImage *image = EOM_IMAGE (it->data); + + if (job->trans == NULL) { + eom_image_undo (image); + } else { + eom_image_transform (image, job->trans, ejob); + } + + if (eom_image_is_modified (image) || job->trans == NULL) { + g_object_ref (image); + g_idle_add (eom_job_transform_image_modified, image); + } + } + + ejob->finished = TRUE; +} + +static void eom_job_save_init (EomJobSave *job) { /* do nothing */ } + +static void +eom_job_save_dispose (GObject *object) +{ + EomJobSave *job; + + job = EOM_JOB_SAVE (object); + + if (job->images) { + g_list_foreach (job->images, (GFunc) g_object_unref, NULL); + g_list_free (job->images); + job->images = NULL; + } + + (* G_OBJECT_CLASS (eom_job_save_parent_class)->dispose) (object); +} + +static void +eom_job_save_class_init (EomJobSaveClass *class) +{ + G_OBJECT_CLASS (class)->dispose = eom_job_save_dispose; + EOM_JOB_CLASS (class)->run = eom_job_save_run; +} + +EomJob * +eom_job_save_new (GList *images) +{ + EomJobSave *job; + + job = g_object_new (EOM_TYPE_JOB_SAVE, NULL); + + job->images = images; + job->current_image = NULL; + + return EOM_JOB (job); +} + +static void +save_progress_handler (EomImage *image, gfloat progress, gpointer data) +{ + EomJobSave *job = EOM_JOB_SAVE (data); + guint n_images = g_list_length (job->images); + gfloat job_progress; + + job_progress = (job->current_pos / (gfloat) n_images) + (progress / n_images); + + eom_job_set_progress (EOM_JOB (job), job_progress); +} + +static void +eom_job_save_run (EomJob *ejob) +{ + EomJobSave *job; + GList *it; + + g_return_if_fail (EOM_IS_JOB_SAVE (ejob)); + + job = EOM_JOB_SAVE (ejob); + + job->current_pos = 0; + + for (it = job->images; it != NULL; it = it->next, job->current_pos++) { + EomImage *image = EOM_IMAGE (it->data); + EomImageSaveInfo *save_info = NULL; + gulong handler_id = 0; + gboolean success = FALSE; + + job->current_image = image; + + /* Make sure the image doesn't go away while saving */ + eom_image_data_ref (image); + + if (!eom_image_has_data (image, EOM_IMAGE_DATA_ALL)) { + eom_image_load (image, + EOM_IMAGE_DATA_ALL, + NULL, + &ejob->error); + } + + handler_id = g_signal_connect (G_OBJECT (image), + "save-progress", + G_CALLBACK (save_progress_handler), + job); + + save_info = eom_image_save_info_from_image (image); + + success = eom_image_save_by_info (image, + save_info, + &ejob->error); + + if (save_info) + g_object_unref (save_info); + + if (handler_id != 0) + g_signal_handler_disconnect (G_OBJECT (image), handler_id); + + eom_image_data_unref (image); + + if (!success) break; + } + + ejob->finished = TRUE; +} + +static void eom_job_save_as_init (EomJobSaveAs *job) { /* do nothing */ } + +static void eom_job_save_as_dispose (GObject *object) +{ + EomJobSaveAs *job = EOM_JOB_SAVE_AS (object); + + if (job->converter != NULL) { + g_object_unref (job->converter); + job->converter = NULL; + } + + if (job->file != NULL) { + g_object_unref (job->file); + job->file = NULL; + } + + (* G_OBJECT_CLASS (eom_job_save_as_parent_class)->dispose) (object); +} + +static void +eom_job_save_as_class_init (EomJobSaveAsClass *class) +{ + G_OBJECT_CLASS (class)->dispose = eom_job_save_as_dispose; + EOM_JOB_CLASS (class)->run = eom_job_save_as_run; +} + +EomJob * +eom_job_save_as_new (GList *images, EomURIConverter *converter, GFile *file) +{ + EomJobSaveAs *job; + + g_assert (converter != NULL || g_list_length (images) == 1); + + job = g_object_new (EOM_TYPE_JOB_SAVE_AS, NULL); + + EOM_JOB_SAVE(job)->images = images; + + job->converter = converter ? g_object_ref (converter) : NULL; + job->file = file ? g_object_ref (file) : NULL; + + return EOM_JOB (job); +} + +static void +eom_job_save_as_run (EomJob *ejob) +{ + EomJobSave *job; + EomJobSaveAs *saveas_job; + GList *it; + guint n_images; + + g_return_if_fail (EOM_IS_JOB_SAVE_AS (ejob)); + + job = EOM_JOB_SAVE (ejob); + + n_images = g_list_length (job->images); + + saveas_job = EOM_JOB_SAVE_AS (job); + + job->current_pos = 0; + + for (it = job->images; it != NULL; it = it->next, job->current_pos++) { + GdkPixbufFormat *format; + EomImageSaveInfo *src_info, *dest_info; + EomImage *image = EOM_IMAGE (it->data); + gboolean success = FALSE; + gulong handler_id = 0; + + job->current_image = image; + + eom_image_data_ref (image); + + if (!eom_image_has_data (image, EOM_IMAGE_DATA_ALL)) { + eom_image_load (image, + EOM_IMAGE_DATA_ALL, + NULL, + &ejob->error); + } + + g_assert (ejob->error == NULL); + + handler_id = g_signal_connect (G_OBJECT (image), + "save-progress", + G_CALLBACK (save_progress_handler), + job); + + src_info = eom_image_save_info_from_image (image); + + if (n_images == 1) { + g_assert (saveas_job->file != NULL); + + format = eom_pixbuf_get_format (saveas_job->file); + + dest_info = eom_image_save_info_from_file (saveas_job->file, + format); + + /* SaveAsDialog has already secured permission to overwrite */ + if (dest_info->exists) { + dest_info->overwrite = TRUE; + } + } else { + GFile *dest_file; + gboolean result; + + result = eom_uri_converter_do (saveas_job->converter, + image, + &dest_file, + &format, + NULL); + + g_assert (result); + + dest_info = eom_image_save_info_from_file (dest_file, + format); + } + + success = eom_image_save_as_by_info (image, + src_info, + dest_info, + &ejob->error); + + if (src_info) + g_object_unref (src_info); + + if (dest_info) + g_object_unref (dest_info); + + if (handler_id != 0) + g_signal_handler_disconnect (G_OBJECT (image), handler_id); + + eom_image_data_unref (image); + + if (!success) + break; + } + + ejob->finished = TRUE; +} + +static void eom_job_copy_init (EomJobCopy *job) { /* do nothing */}; + +static void +eom_job_copy_dispose (GObject *object) +{ + EomJobCopy *job = EOM_JOB_COPY (object); + + if (job->dest) { + g_free (job->dest); + job->dest = NULL; + } + + (* G_OBJECT_CLASS (eom_job_copy_parent_class)->dispose) (object); +} + +static void +eom_job_copy_class_init (EomJobCopyClass *class) +{ + G_OBJECT_CLASS (class)->dispose = eom_job_copy_dispose; + EOM_JOB_CLASS (class)->run = eom_job_copy_run; +} + +EomJob * +eom_job_copy_new (GList *images, const gchar *dest) +{ + EomJobCopy *job; + + g_assert (images != NULL && dest != NULL); + + job = g_object_new (EOM_TYPE_JOB_COPY, NULL); + + job->images = images; + job->dest = g_strdup (dest); + + return EOM_JOB (job); +} + +static void +eom_job_copy_progress_callback (goffset current_num_bytes, + goffset total_num_bytes, + gpointer user_data) +{ + gfloat job_progress; + guint n_images; + EomJobCopy *job; + + job = EOM_JOB_COPY (user_data); + n_images = g_list_length (job->images); + + job_progress = ((current_num_bytes / (gfloat) total_num_bytes) + job->current_pos)/n_images; + + eom_job_set_progress (EOM_JOB (job), job_progress); +} + +void +eom_job_copy_run (EomJob *ejob) +{ + EomJobCopy *job; + GList *it; + guint n_images; + GFile *src, *dest; + gchar *filename, *dest_filename; + + g_return_if_fail (EOM_IS_JOB_COPY (ejob)); + + job = EOM_JOB_COPY (ejob); + + n_images = g_list_length (job->images); + + job->current_pos = 0; + + for (it = job->images; it != NULL; it = g_list_next (it), job->current_pos++) { + src = (GFile *) it->data; + filename = g_file_get_basename (src); + dest_filename = g_build_filename (job->dest, filename, NULL); + dest = g_file_new_for_path (dest_filename); + + g_file_copy (src, dest, + G_FILE_COPY_OVERWRITE, NULL, + eom_job_copy_progress_callback, job, + &ejob->error); + g_free (filename); + g_free (dest_filename); + } + + ejob->finished = TRUE; +} |