Commit a7c90ca1 authored by Jim Nelson's avatar Jim Nelson

#56: Sort by EXIF date.

parent 5d3d128f
......@@ -47,6 +47,10 @@ public abstract class LayoutItem : Gtk.Alignment {
return null;
}
public string get_title() {
return title.get_text();
}
public abstract Gdk.Pixbuf? get_full_pixbuf();
public abstract Exif.Orientation get_orientation();
......@@ -108,6 +112,8 @@ public abstract class LayoutItem : Gtk.Alignment {
}
}
public delegate int CompareLayoutItem(LayoutItem a, LayoutItem b);
public class CollectionLayout : Gtk.Layout {
public static const int TOP_PADDING = 16;
public static const int BOTTOM_PADDING = 16;
......@@ -120,9 +126,11 @@ public class CollectionLayout : Gtk.Layout {
private Gee.ArrayList<LayoutItem> items = new Gee.ArrayList<LayoutItem>();
private Gtk.Label message = null;
private CompareLayoutItem cmp = null;
public CollectionLayout() {
modify_bg(Gtk.StateType.NORMAL, AppWindow.BG_COLOR);
expose_event += on_expose;
size_allocate += on_resize;
}
......@@ -138,8 +146,44 @@ public class CollectionLayout : Gtk.Layout {
display_message();
}
public void append(LayoutItem item) {
public void set_comparator(CompareLayoutItem cmp) {
this.cmp = cmp;
// re-sort list with new comparator
Gee.ArrayList<LayoutItem> resorted = new Gee.ArrayList<LayoutItem>();
foreach (LayoutItem item in items) {
// add to new list and remove from Gtk.Layout
sorted_add_item(resorted, cmp, item);
remove(item);
}
items = resorted;
}
private static void sorted_add_item(Gee.ArrayList<LayoutItem> items, CompareLayoutItem cmp,
LayoutItem item) {
if (cmp == null) {
items.add(item);
return;
}
for (int ctr = 0; ctr < items.size; ctr++) {
if (cmp(item, items.get(ctr)) < 0) {
// smaller, insert before this element
items.insert(ctr, item);
return;
}
}
// went off the end of the list, so add at end
items.add(item);
}
public void add_item(LayoutItem item) {
sorted_add_item(items, cmp, item);
// this demolishes any message that's been set
if (message != null) {
......@@ -172,15 +216,18 @@ public class CollectionLayout : Gtk.Layout {
}
public void clear() {
// remove page message
if (message != null) {
remove(message);
message = null;
}
// remove all items from Gtk.Layout
foreach (LayoutItem item in items) {
remove(item);
}
// clear internal list
items.clear();
}
......
......@@ -2,6 +2,16 @@
public class CollectionPage : CheckerboardPage {
public static const int THUMB_X_PADDING = 20;
public static const int THUMB_Y_PADDING = 20;
public static const int SORT_BY_MIN = 0;
public static const int SORT_BY_NAME = 0;
public static const int SORT_BY_EXPOSURE_DATE = 1;
public static const int SORT_BY_MAX = 1;
public static const int SORT_ORDER_MIN = 0;
public static const int SORT_ORDER_ASCENDING = 0;
public static const int SORT_ORDER_DESCENDING = 1;
public static const int SORT_ORDER_MAX = 1;
// steppings should divide evenly into (Thumbnail.MAX_SCALE - Thumbnail.MIN_SCALE)
public static const int MANUAL_STEPPING = 16;
......@@ -33,6 +43,7 @@ public class CollectionPage : CheckerboardPage {
{ "Mirror", null, "_Mirror", "<Ctrl>M", "Make mirror images of the selected photos", on_mirror },
{ "ViewMenu", null, "_View", null, null, null },
{ "SortPhotos", null, "_Sort Photos", null, null, null },
{ "HelpMenu", null, "_Help", null, null, null }
};
......@@ -41,20 +52,25 @@ public class CollectionPage : CheckerboardPage {
{ "ViewTitle", null, "_Titles", "<Ctrl><Shift>T", "Display the title of each photo", on_display_titles, true }
};
// TODO: Mark fields for translation
/*
private const Gtk.ActionEntry[] RIGHT_CLICK_ACTIONS = {
{ "Remove", Gtk.STOCK_DELETE, "_Remove", "Delete", "Remove the selected photos from the library", on_remove },
{ "CollectionRotateClockwise", STOCK_CLOCKWISE, "Rotate c_lockwise", "<Ctrl>R", "Rotate the selected photos clockwise", on_rotate_clockwise },
{ "CollectionRotateCounterclockwise", STOCK_COUNTERCLOCKWISE, "Rotate c_ounterclockwise", "<Ctrl><Shift>R", "Rotate the selected photos counterclockwise", on_rotate_counterclockwise },
{ "CollectionMirror", null, "_Mirror", "<Ctrl>M", "Make mirror images of the selected photos", on_mirror }
private const Gtk.RadioActionEntry[] SORT_CRIT_ACTIONS = {
{ "SortByName", null, "By _Name", null, "Sort photos by name", SORT_BY_NAME },
{ "SortByExposureDate", null, "By Exposure _Date", null, "Sort photos by exposure date", SORT_BY_EXPOSURE_DATE }
};
private const Gtk.RadioActionEntry[] SORT_ORDER_ACTIONS = {
{ "SortAscending", null, "_Ascending", null, "Sort photos in an ascending order", SORT_ORDER_ASCENDING },
{ "SortDescending", null, "D_escending", null, "Sort photos in a descending order", SORT_ORDER_DESCENDING }
};
*/
construct {
init_ui("collection.ui", "/CollectionMenuBar", "CollectionActionGroup", ACTIONS, TOGGLE_ACTIONS);
init_ui_start("collection.ui", "CollectionActionGroup", ACTIONS, TOGGLE_ACTIONS);
actionGroup.add_radio_actions(SORT_CRIT_ACTIONS, SORT_BY_NAME, on_sort_changed);
actionGroup.add_radio_actions(SORT_ORDER_ACTIONS, SORT_ORDER_ASCENDING, on_sort_changed);
init_ui_bind("/CollectionMenuBar");
init_context_menu("/CollectionContextMenu");
set_layout_comparator(thumbnail_name_comparator);
// set up page's toolbar (used by AppWindow for layout)
//
// rotate tool
......@@ -367,5 +383,72 @@ public class CollectionPage : CheckerboardPage {
return false;
}
private int get_sort_criteria() {
// any member of the group knows the current value
Gtk.RadioAction action = (Gtk.RadioAction) ui.get_action("/CollectionMenuBar/ViewMenu/SortPhotos/SortByName");
assert(action != null);
int value = action.get_current_value();
assert(value >= SORT_BY_MIN);
assert(value <= SORT_BY_MAX);
return value;
}
private int get_sort_order() {
// any member of the group knows the current value
Gtk.RadioAction action = (Gtk.RadioAction) ui.get_action("/CollectionMenuBar/ViewMenu/SortPhotos/SortAscending");
assert(action != null);
int value = action.get_current_value();
assert(value >= SORT_ORDER_MIN);
assert(value <= SORT_ORDER_MAX);
return value;
}
private static int thumbnail_name_comparator(LayoutItem a, LayoutItem b) {
return strcmp(((Thumbnail) a).get_name(), ((Thumbnail) b).get_name());
}
private static int thumbnail_reverse_name_comparator(LayoutItem a, LayoutItem b) {
return strcmp(((Thumbnail) b).get_name(), ((Thumbnail) a).get_name());
}
private static int thumbnail_exposure_comparator(LayoutItem a, LayoutItem b) {
return (int) ((Thumbnail) a).get_time_t() - (int) ((Thumbnail) b).get_time_t();
}
private static int thumbnail_reverse_exposure_comparator(LayoutItem a, LayoutItem b) {
return (int) ((Thumbnail) b).get_time_t() - (int) ((Thumbnail) a).get_time_t();
}
private void on_sort_changed() {
CompareLayoutItem cmp = null;
switch (get_sort_criteria()) {
case SORT_BY_NAME: {
if (get_sort_order() == SORT_ORDER_ASCENDING) {
cmp = thumbnail_name_comparator;
} else {
cmp = thumbnail_reverse_name_comparator;
}
} break;
case SORT_BY_EXPOSURE_DATE: {
if (get_sort_order() == SORT_ORDER_ASCENDING) {
cmp = thumbnail_exposure_comparator;
} else {
cmp = thumbnail_reverse_exposure_comparator;
}
} break;
}
if (cmp == null)
return;
set_layout_comparator(cmp);
refresh();
}
}
......@@ -100,7 +100,13 @@ public abstract class Page : Gtk.ScrolledWindow {
return false;
}
protected void init_ui(string uiFilename, string menuBarPath, string actionGroupName,
protected void init_ui(string uiFilename, string? menuBarPath, string actionGroupName,
Gtk.ActionEntry[]? entries = null, Gtk.ToggleActionEntry[]? toggleEntries = null) {
init_ui_start(uiFilename, actionGroupName, entries, toggleEntries);
init_ui_bind(menuBarPath);
}
protected void init_ui_start(string uiFilename, string actionGroupName,
Gtk.ActionEntry[]? entries = null, Gtk.ToggleActionEntry[]? toggleEntries = null) {
File uiFile = data_dir.get_child(uiFilename);
......@@ -115,7 +121,9 @@ public abstract class Page : Gtk.ScrolledWindow {
actionGroup.add_actions(entries, this);
if (toggleEntries != null)
actionGroup.add_toggle_actions(toggleEntries, this);
}
protected void init_ui_bind(string? menuBarPath) {
ui.insert_action_group(actionGroup, 0);
ui.insert_action_group(AppWindow.get_instance().get_common_action_group(), 0);
......@@ -237,6 +245,10 @@ public abstract class CheckerboardPage : Page {
layout.set_message(message);
}
public void set_layout_comparator(CompareLayoutItem cmp) {
layout.set_comparator(cmp);
}
public LayoutItem? get_item_at(double x, double y) {
return layout.get_item_at(x, y);
}
......@@ -251,7 +263,7 @@ public abstract class CheckerboardPage : Page {
public void add_item(LayoutItem item) {
items.add(item);
layout.append(item);
layout.add_item(item);
}
public void remove_item(LayoutItem item) {
......
......@@ -69,6 +69,10 @@ public class Thumbnail : LayoutItem {
return file;
}
public string get_name() {
return file.get_basename();
}
public int64 get_filesize() {
int64 fileSize = -1;
try {
......
......@@ -21,6 +21,14 @@
<menu name="ViewMenu" action="ViewMenu">
<menuitem name="ViewTitle" action="ViewTitle" />
<separator />
<menu name="SortPhotos" action="SortPhotos">
<menuitem name="SortByName" action="SortByName" />
<menuitem name="SortByExposureDate" action="SortByExposureDate" />
<separator />
<menuitem name="SortAscending" action="SortAscending" />
<menuitem name="SortDescending" action="SortDescending" />
</menu>
</menu>
<menu name="HelpMenu" action="HelpMenu">
......
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