Commit aae7fc3f authored by Jim Nelson's avatar Jim Nelson

Taking advantage of the new units in the last commit, I've moved some of the...

Taking advantage of the new units in the last commit, I've moved some of the pages into their appropriate units.
parent dd601ce7
......@@ -40,10 +40,7 @@ UNUNITIZED_SRC_FILES = \
CheckerboardLayout.vala \
PhotoPage.vala \
Page.vala \
ImportPage.vala \
GPhoto.vala \
SortedList.vala \
EventsDirectoryPage.vala \
Dimensions.vala \
Box.vala \
Photo.vala \
......@@ -54,7 +51,6 @@ UNUNITIZED_SRC_FILES = \
Debug.vala \
ColorTransformation.vala \
EditingTools.vala \
CameraTable.vala \
Properties.vala \
CustomComponents.vala \
Config.vala \
......@@ -69,16 +65,12 @@ UNUNITIZED_SRC_FILES = \
LibraryFiles.vala \
Printing.vala \
Tag.vala \
TagPage.vala \
PiwigoConnector.vala \
Screensaver.vala \
MimicManager.vala \
TrashPage.vala \
Exporter.vala \
DirectoryMonitor.vala \
LibraryMonitor.vala \
OfflinePage.vala \
LastImportPage.vala \
VideoSupport.vala \
Tombstone.vala \
MetadataWriter.vala \
......@@ -87,7 +79,6 @@ UNUNITIZED_SRC_FILES = \
MediaPage.vala \
MediaDataRepresentation.vala \
DesktopIntegration.vala \
FlaggedPage.vala \
MediaInterfaces.vala \
MediaMetadata.vala \
VideoMetadata.vala \
......
......@@ -1470,200 +1470,3 @@ public class ImportPage : CheckerboardPage {
}
}
public class ImportQueuePage : SinglePhotoPage {
public const string NAME = _("Importing...");
private Gee.ArrayList<BatchImport> queue = new Gee.ArrayList<BatchImport>();
private Gee.HashSet<BatchImport> cancel_unallowed = new Gee.HashSet<BatchImport>();
private BatchImport current_batch = null;
private Gtk.ProgressBar progress_bar = new Gtk.ProgressBar();
private bool stopped = false;
public signal void batch_added(BatchImport batch_import);
public signal void batch_removed(BatchImport batch_import);
public ImportQueuePage() {
base (NAME, false);
// Set up toolbar
Gtk.Toolbar toolbar = get_toolbar();
// Stop button
Gtk.ToolButton stop_button = new Gtk.ToolButton.from_stock(Gtk.Stock.STOP);
stop_button.set_related_action(get_action("Stop"));
toolbar.insert(stop_button, -1);
// separator to force progress bar to right side of toolbar
Gtk.SeparatorToolItem separator = new Gtk.SeparatorToolItem();
separator.set_draw(false);
toolbar.insert(separator, -1);
// Progress bar
Gtk.ToolItem progress_item = new Gtk.ToolItem();
progress_item.set_expand(true);
progress_item.add(progress_bar);
toolbar.insert(progress_item, -1);
}
protected override void init_collect_ui_filenames(Gee.List<string> ui_filenames) {
ui_filenames.add("import_queue.ui");
base.init_collect_ui_filenames(ui_filenames);
}
protected override Gtk.ActionEntry[] init_collect_action_entries() {
Gtk.ActionEntry[] actions = base.init_collect_action_entries();
Gtk.ActionEntry file = { "FileMenu", null, TRANSLATABLE, null, null, null };
file.label = _("_File");
actions += file;
Gtk.ActionEntry stop = { "Stop", Gtk.Stock.STOP, TRANSLATABLE, null, TRANSLATABLE,
on_stop };
stop.label = _("_Stop Import");
stop.tooltip = _("Stop importing photos");
actions += stop;
Gtk.ActionEntry view = { "ViewMenu", null, TRANSLATABLE, null, null, null };
view.label = _("_View");
actions += view;
Gtk.ActionEntry help = { "HelpMenu", null, TRANSLATABLE, null, null, null };
help.label = _("_Help");
actions += help;
return actions;
}
public void enqueue_and_schedule(BatchImport batch_import, bool allow_user_cancel) {
assert(!queue.contains(batch_import));
batch_import.starting.connect(on_starting);
batch_import.preparing.connect(on_preparing);
batch_import.progress.connect(on_progress);
batch_import.imported.connect(on_imported);
batch_import.import_complete.connect(on_import_complete);
batch_import.fatal_error.connect(on_fatal_error);
if (!allow_user_cancel)
cancel_unallowed.add(batch_import);
queue.add(batch_import);
batch_added(batch_import);
if (queue.size == 1)
batch_import.schedule();
update_stop_action();
}
public int get_batch_count() {
return queue.size;
}
private void update_stop_action() {
set_action_sensitive("Stop", !cancel_unallowed.contains(current_batch) && queue.size > 0);
}
private void on_stop() {
update_stop_action();
if (queue.size == 0)
return;
AppWindow.get_instance().set_busy_cursor();
stopped = true;
// mark all as halted and let each signal failure
foreach (BatchImport batch_import in queue)
batch_import.user_halt();
}
private void on_starting(BatchImport batch_import) {
update_stop_action();
current_batch = batch_import;
}
private void on_preparing() {
progress_bar.set_text(_("Preparing to import..."));
progress_bar.pulse();
}
private void on_progress(uint64 completed_bytes, uint64 total_bytes) {
double pct = (completed_bytes <= total_bytes) ? (double) completed_bytes / (double) total_bytes
: 0.0;
progress_bar.set_fraction(pct);
}
private void on_imported(ThumbnailSource source, Gdk.Pixbuf pixbuf, int to_follow) {
// only interested in updating the display for the last of the bunch
if (to_follow > 0 || !is_in_view())
return;
set_pixbuf(pixbuf, Dimensions.for_pixbuf(pixbuf));
// set the singleton collection to this item
get_view().clear();
(source is LibraryPhoto) ? get_view().add(new PhotoView(source as LibraryPhoto)) :
get_view().add(new VideoView(source as Video));
progress_bar.set_ellipsize(Pango.EllipsizeMode.MIDDLE);
progress_bar.set_text(_("Imported %s").printf(source.get_name()));
}
private void on_import_complete(BatchImport batch_import, ImportManifest manifest,
BatchImportRoll import_roll) {
assert(batch_import == current_batch);
current_batch = null;
assert(queue.size > 0);
assert(queue.get(0) == batch_import);
bool removed = queue.remove(batch_import);
assert(removed);
// fail quietly if cancel was allowed
cancel_unallowed.remove(batch_import);
// strip signal handlers
batch_import.starting.disconnect(on_starting);
batch_import.preparing.disconnect(on_preparing);
batch_import.progress.disconnect(on_progress);
batch_import.imported.disconnect(on_imported);
batch_import.import_complete.disconnect(on_import_complete);
batch_import.fatal_error.disconnect(on_fatal_error);
// schedule next if available
if (queue.size > 0) {
queue.get(0).schedule();
} else {
// reset UI
progress_bar.set_ellipsize(Pango.EllipsizeMode.NONE);
progress_bar.set_text("");
progress_bar.set_fraction(0.0);
// blank the display
blank_display();
// reset cursor if cancelled
if (stopped)
AppWindow.get_instance().set_normal_cursor();
stopped = false;
}
update_stop_action();
// report the batch has been removed from the queue after everything else is set
batch_removed(batch_import);
}
private void on_fatal_error(ImportResult result, string message) {
AppWindow.error_message(message);
}
}
......@@ -11,7 +11,10 @@ UNIT_DIR := camera
#
# NOTE: Do *not* include the unit's master file, i.e. UNIT_NAME.vala.
UNIT_FILES := \
Branch.vala
Branch.vala \
CameraTable.vala \
GPhoto.vala \
ImportPage.vala
# Any unit this unit relies upon (and should be initialized before it's initialized) should
# be listed here using its Vala namespace.
......
/* Copyright 2011 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.
*/
class EventDirectoryItem : CheckerboardItem {
private static int CROPPED_SCALE {
get {
return ThumbnailCache.Size.MEDIUM.get_scale()
+ ((ThumbnailCache.Size.BIG.get_scale() - ThumbnailCache.Size.MEDIUM.get_scale()) / 2);
}
}
public static Scaling squared_scaling = Scaling.to_fill_viewport(Dimensions(CROPPED_SCALE,
CROPPED_SCALE));
public Event event;
private Gdk.Rectangle paul_lynde = Gdk.Rectangle();
public EventDirectoryItem(Event event) {
base (event, Dimensions(CROPPED_SCALE, CROPPED_SCALE), get_formatted_title(event), true,
Pango.Alignment.CENTER);
this.event = event;
// find the center square
paul_lynde = get_paul_lynde_rect(event.get_primary_source());
// don't display yet, but claim its dimensions
clear_image(Dimensions.for_rectangle(paul_lynde));
// monitor the event for changes
Event.global.items_altered.connect(on_events_altered);
}
~EventDirectoryItem() {
Event.global.items_altered.disconnect(on_events_altered);
}
// square the photo's dimensions and locate the pixbuf's center square
private static Gdk.Rectangle get_paul_lynde_rect(MediaSource source) {
Dimensions scaled = squared_scaling.get_scaled_dimensions(source.get_dimensions());
Gdk.Rectangle paul_lynde = Gdk.Rectangle();
paul_lynde.x = (scaled.width - CROPPED_SCALE).clamp(0, scaled.width) / 2;
paul_lynde.y = (scaled.height - CROPPED_SCALE).clamp(0, scaled.height) / 2;
paul_lynde.width = CROPPED_SCALE;
paul_lynde.height = CROPPED_SCALE;
return paul_lynde;
}
// scale and crop the center square of the media
private static Gdk.Pixbuf get_paul_lynde(MediaSource media, Gdk.Rectangle paul_lynde) throws Error {
Gdk.Pixbuf pixbuf = media.get_preview_pixbuf(squared_scaling);
// to catch rounding errors in the two algorithms
paul_lynde = clamp_rectangle(paul_lynde, Dimensions.for_pixbuf(pixbuf));
// crop the center square
return new Gdk.Pixbuf.subpixbuf(pixbuf, paul_lynde.x, paul_lynde.y, paul_lynde.width,
paul_lynde.height);
}
private static string get_formatted_title(Event event) {
bool has_photos = MediaSourceCollection.has_photo(event.get_media());
bool has_videos = MediaSourceCollection.has_video(event.get_media());
int count = event.get_media_count();
string count_text = "";
if (has_photos && has_videos)
count_text = ngettext("%d Photo/Video", "%d Photos/Videos", count).printf(count);
else if (has_videos)
count_text = ngettext("%d Video", "%d Videos", count).printf(count);
else
count_text = ngettext("%d Photo", "%d Photos", count).printf(count);
string? daterange = event.get_formatted_daterange();
if (daterange != null)
return "<b>%s</b>\n%s\n%s".printf(guarded_markup_escape_text(event.get_name()),
guarded_markup_escape_text(count_text), guarded_markup_escape_text(daterange));
else
return "<b>%s</b>\n%s".printf(guarded_markup_escape_text(event.get_name()),
guarded_markup_escape_text(count_text));
}
public override void exposed() {
if (is_exposed())
return;
try {
set_image(get_paul_lynde(event.get_primary_source(), paul_lynde));
} catch (Error err) {
critical("Unable to fetch preview for %s: %s", event.to_string(), err.message);
}
base.exposed();
}
public override void unexposed() {
if (!is_exposed())
return;
clear_image(Dimensions.for_rectangle(paul_lynde));
base.unexposed();
}
private void on_events_altered(Gee.Map<DataObject, Alteration> map) {
if (map.has_key(event))
set_title(get_formatted_title(event), true, Pango.Alignment.CENTER);
}
protected override void thumbnail_altered() {
MediaSource media = event.get_primary_source();
// get new center square
paul_lynde = get_paul_lynde_rect(media);
if (is_exposed()) {
try {
set_image(get_paul_lynde(media, paul_lynde));
} catch (Error err) {
critical("Unable to fetch preview for %s: %s", event.to_string(), err.message);
}
} else {
clear_image(Dimensions.for_rectangle(paul_lynde));
}
base.thumbnail_altered();
}
protected override void paint_border(Cairo.Context ctx, Dimensions object_dimensions,
Gdk.Point object_origin, int border_width) {
Dimensions dimensions = get_border_dimensions(object_dimensions, border_width);
Gdk.Point origin = get_border_origin(object_origin, border_width);
draw_rounded_corners_filled(ctx, dimensions, origin, 6.0);
}
protected override void paint_image(Cairo.Context ctx, Gdk.Pixbuf pixbuf,
Gdk.Point origin) {
Dimensions dimensions = Dimensions.for_pixbuf(pixbuf);
if (pixbuf.get_has_alpha())
draw_rounded_corners_filled(ctx, dimensions, origin, 6.0);
// use rounded corners on events
context_rounded_corners(ctx, dimensions, origin, 6.0);
Gdk.cairo_set_source_pixbuf(ctx, pixbuf, origin.x, origin.y);
ctx.paint();
}
}
/* Copyright 2009-2011 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.
*/
public class EventPage : CollectionPage {
private Event page_event;
public EventPage(Event page_event) {
base (page_event.get_name());
this.page_event = page_event;
page_event.mirror_photos(get_view(), create_thumbnail);
init_page_context_menu("/EventContextMenu");
Event.global.items_altered.connect(on_events_altered);
}
~EventPage() {
Event.global.items_altered.disconnect(on_events_altered);
get_view().halt_mirroring();
}
protected override void init_collect_ui_filenames(Gee.List<string> ui_filenames) {
base.init_collect_ui_filenames(ui_filenames);
ui_filenames.add("event.ui");
}
protected override Gtk.ActionEntry[] init_collect_action_entries() {
Gtk.ActionEntry[] new_actions = base.init_collect_action_entries();
Gtk.ActionEntry make_primary = { "MakePrimary", Resources.MAKE_PRIMARY,
TRANSLATABLE, null, TRANSLATABLE, on_make_primary };
make_primary.label = Resources.MAKE_KEY_PHOTO_MENU;
make_primary.tooltip = Resources.MAKE_KEY_PHOTO_TOOLTIP;
new_actions += make_primary;
Gtk.ActionEntry rename = { "Rename", null, TRANSLATABLE, null, TRANSLATABLE, on_rename };
rename.label = Resources.RENAME_EVENT_MENU;
rename.tooltip = Resources.RENAME_EVENT_TOOLTIP;
new_actions += rename;
return new_actions;
}
protected override void init_actions(int selected_count, int count) {
base.init_actions(selected_count, count);
}
protected override void update_actions(int selected_count, int count) {
set_action_sensitive("MakePrimary", selected_count == 1);
// hide this command in CollectionPage, as it does not apply here
set_action_visible("CommonJumpToEvent", false);
base.update_actions(selected_count, count);
}
protected override void get_config_photos_sort(out bool sort_order, out int sort_by) {
Config.get_instance().get_event_photos_sort(out sort_order, out sort_by);
}
protected override void set_config_photos_sort(bool sort_order, int sort_by) {
Config.get_instance().set_event_photos_sort(sort_order, sort_by);
}
private void on_events_altered(Gee.Map<DataObject, Alteration> map) {
if (map.has_key(page_event))
set_page_name(page_event.get_name());
}
private void on_make_primary() {
if (get_view().get_selected_count() != 1)
return;
page_event.set_primary_source((MediaSource) get_view().get_selected_at(0).get_source());
}
private void on_rename() {
LibraryWindow.get_app().rename_event_in_sidebar(page_event);
}
}
public class NoEventPage : CollectionPage {
public const string NAME = _("No Event");
// This seems very similar to EventSourceCollection -> ViewManager
private class NoEventViewManager : CollectionViewManager {
public NoEventViewManager(NoEventPage page) {
base (page);
}
// this is not threadsafe
public override bool include_in_view(DataSource source) {
return (((MediaSource) source).get_event_id().id != EventID.INVALID) ? false :
base.include_in_view(source);
}
}
private static Alteration no_event_page_alteration = new Alteration("metadata", "event");
public NoEventPage() {
base (NAME);
ViewManager filter = new NoEventViewManager(this);
get_view().monitor_source_collection(LibraryPhoto.global, filter, no_event_page_alteration);
get_view().monitor_source_collection(Video.global, filter, no_event_page_alteration);
}
protected override void get_config_photos_sort(out bool sort_order, out int sort_by) {
Config.get_instance().get_event_photos_sort(out sort_order, out sort_by);
}
protected override void set_config_photos_sort(bool sort_order, int sort_by) {
Config.get_instance().set_event_photos_sort(sort_order, sort_by);
}
}
......@@ -4,157 +4,6 @@
* See the COPYING file in this distribution.
*/
class EventDirectoryItem : CheckerboardItem {
private static int CROPPED_SCALE {
get {
return ThumbnailCache.Size.MEDIUM.get_scale()
+ ((ThumbnailCache.Size.BIG.get_scale() - ThumbnailCache.Size.MEDIUM.get_scale()) / 2);
}
}
public static Scaling squared_scaling = Scaling.to_fill_viewport(Dimensions(CROPPED_SCALE,
CROPPED_SCALE));
public Event event;
private Gdk.Rectangle paul_lynde = Gdk.Rectangle();
public EventDirectoryItem(Event event) {
base (event, Dimensions(CROPPED_SCALE, CROPPED_SCALE), get_formatted_title(event), true,
Pango.Alignment.CENTER);
this.event = event;
// find the center square
paul_lynde = get_paul_lynde_rect(event.get_primary_source());
// don't display yet, but claim its dimensions
clear_image(Dimensions.for_rectangle(paul_lynde));
// monitor the event for changes
Event.global.items_altered.connect(on_events_altered);
}
~EventDirectoryItem() {
Event.global.items_altered.disconnect(on_events_altered);
}
// square the photo's dimensions and locate the pixbuf's center square
private static Gdk.Rectangle get_paul_lynde_rect(MediaSource source) {
Dimensions scaled = squared_scaling.get_scaled_dimensions(source.get_dimensions());
Gdk.Rectangle paul_lynde = Gdk.Rectangle();
paul_lynde.x = (scaled.width - CROPPED_SCALE).clamp(0, scaled.width) / 2;
paul_lynde.y = (scaled.height - CROPPED_SCALE).clamp(0, scaled.height) / 2;
paul_lynde.width = CROPPED_SCALE;
paul_lynde.height = CROPPED_SCALE;
return paul_lynde;
}
// scale and crop the center square of the media
private static Gdk.Pixbuf get_paul_lynde(MediaSource media, Gdk.Rectangle paul_lynde) throws Error {
Gdk.Pixbuf pixbuf = media.get_preview_pixbuf(squared_scaling);
// to catch rounding errors in the two algorithms
paul_lynde = clamp_rectangle(paul_lynde, Dimensions.for_pixbuf(pixbuf));
// crop the center square
return new Gdk.Pixbuf.subpixbuf(pixbuf, paul_lynde.x, paul_lynde.y, paul_lynde.width,
paul_lynde.height);
}
private static string get_formatted_title(Event event) {
bool has_photos = MediaSourceCollection.has_photo(event.get_media());
bool has_videos = MediaSourceCollection.has_video(event.get_media());
int count = event.get_media_count();
string count_text = "";
if (has_photos && has_videos)
count_text = ngettext("%d Photo/Video", "%d Photos/Videos", count).printf(count);
else if (has_videos)
count_text = ngettext("%d Video", "%d Videos", count).printf(count);
else
count_text = ngettext("%d Photo", "%d Photos", count).printf(count);
string? daterange = event.get_formatted_daterange();
if (daterange != null)
return "<b>%s</b>\n%s\n%s".printf(guarded_markup_escape_text(event.get_name()),
guarded_markup_escape_text(count_text), guarded_markup_escape_text(daterange));
else
return "<b>%s</b>\n%s".printf(guarded_markup_escape_text(event.get_name()),
guarded_markup_escape_text(count_text));
}
public override void exposed() {
if (is_exposed())
return;
try {
set_image(get_paul_lynde(event.get_primary_source(), paul_lynde));
} catch (Error err) {
critical("Unable to fetch preview for %s: %s", event.to_string(), err.message);
}
base.exposed();
}
public override void unexposed() {
if (!is_exposed())
return;
clear_image(Dimensions.for_rectangle(paul_lynde));
base.unexposed();
}
private void on_events_altered(Gee.Map<DataObject, Alteration> map) {
if (map.has_key(event))
set_title(get_formatted_title(event), true, Pango.Alignment.CENTER);
}
protected override void thumbnail_altered() {
MediaSource media = event.get_primary_source();
// get new center square
paul_lynde = get_paul_lynde_rect(media);
if (is_exposed()) {
try {
set_image(get_paul_lynde(media, paul_lynde));
} catch (Error err) {
critical("Unable to fetch preview for %s: %s", event.to_string(), err.message);
}
} else {
clear_image(Dimensions.for_rectangle(paul_lynde));
}
base.thumbnail_altered();
}
protected override void paint_border(Cairo.Context ctx, Dimensions object_dimensions,
Gdk.Point object_origin, int border_width) {
Dimensions dimensions = get_border_dimensions(object_dimensions, border_width);
Gdk.Point origin = get_border_origin(object_origin, border_width);
draw_rounded_corners_filled(ctx, dimensions, origin, 6.0);
}
protected override void paint_image(Cairo.Context ctx, Gdk.Pixbuf pixbuf,
Gdk.Point origin) {
Dimensions dimensions = Dimensions.for_pixbuf(pixbuf);
if (pixbuf.get_has_alpha())
draw_rounded_corners_filled(ctx, dimensions, origin, 6.0);
// use rounded corners on events
context_rounded_corners(ctx, dimensions, origin, 6.0);
Gdk.cairo_set_source_pixbuf(ctx, pixbuf, origin.x, origin.y);
ctx.paint();
}
}
public abstract class EventsDirectoryPage : CheckerboardPage {
public class EventDirectoryManager : ViewManager {
public override DataView create_view(DataSource source) {
......@@ -354,122 +203,6 @@ public abstract class EventsDirectoryPage : CheckerboardPage {
}
}
public class NoEventPage : CollectionPage {
public const string NAME = _("No Event");
// This seems very similar to EventSourceCollection -> ViewManager
private class NoEventViewManager : CollectionViewManager {
public NoEventViewManager(NoEventPage page) {
base (page);
}
// this is not threadsafe
public override bool include_in_view(DataSource source) {
return (((MediaSource) source).get_event_id().id != EventID.INVALID) ? false :
base.include_in_view(source);
}
}
private static Alteration no_event_page_alteration = new Alteration("metadata", "event");