Commit b3a2d47c authored by Norbert Preining's avatar Norbert Preining Committed by Lucas Beeler

Adds the capability to annotate events with comments. Closes #6271.

parent 7d382d19
......@@ -47,6 +47,12 @@
<description>True if photo comments are to be displayed beneath thumbnails in collection views, false otherwise.</description>
</key>
<key name="display-event-comments" type="b">
<default>false</default>
<summary>display event comments</summary>
<description>True if event comments are to be displayed beneath thumbnails in event views, false otherwise.</description>
</key>
<key name="display-photo-tags" type="b">
<default>true</default>
<summary>display photo tags</summary>
......
......@@ -665,6 +665,26 @@ public class RenameEventCommand : SimpleProxyableCommand {
}
}
public class EditEventCommentCommand : SimpleProxyableCommand {
private string new_comment;
private string? old_comment;
public EditEventCommentCommand(Event event, string new_comment) {
base(event, Resources.EDIT_COMMENT_LABEL, "");
this.new_comment = new_comment;
old_comment = event.get_comment();
}
public override void execute_on_source(DataSource source) {
((Event) source).set_comment(new_comment);
}
public override void undo_on_source(DataSource source) {
((Event) source).set_comment(old_comment);
}
}
public class SetKeyPhotoCommand : SingleDataSourceCommand {
private MediaSource new_primary_source;
private MediaSource old_primary_source;
......
......@@ -94,6 +94,9 @@ public class EventSourceCollection : ContainerSourceCollection {
public class Event : EventSource, ContainerSource, Proxyable, Indexable {
public const string TYPENAME = "event";
// SHOW_COMMENTS (bool)
public const string PROP_SHOW_COMMENTS = "show-comments";
// In 24-hour time.
public const int EVENT_BOUNDARY_HOUR = 4;
......@@ -172,6 +175,7 @@ public class Event : EventSource, ContainerSource, Proxyable, Indexable {
private bool unlinking = false;
private bool relinking = false;
private string? indexable_keywords = null;
private string? comment = null;
private Event(EventRow event_row, int64 object_id = INVALID_OBJECT_ID) {
base (object_id);
......@@ -181,6 +185,7 @@ public class Event : EventSource, ContainerSource, Proxyable, Indexable {
this.event_id = event_row.event_id;
this.raw_name = event_row.name;
this.comment = event_row.comment;
Gee.Collection<string> event_source_ids =
MediaCollectionRegistry.get_instance().get_source_ids_for_event_id(event_id);
......@@ -470,7 +475,7 @@ public class Event : EventSource, ContainerSource, Proxyable, Indexable {
// the event. That must be done manually.
public static Event? create_empty_event(MediaSource source) {
try {
Event event = new Event(EventTable.get_instance().create(source.get_source_id()));
Event event = new Event(EventTable.get_instance().create(source.get_source_id(), null));
global.add(event);
debug("Created empty event %s", event.to_string());
......@@ -634,7 +639,7 @@ public class Event : EventSource, ContainerSource, Proxyable, Indexable {
// no Event so far fits the bill for this photo or video, so create a new one
try {
Event event = new Event(EventTable.get_instance().create(media.get_source_id()));
Event event = new Event(EventTable.get_instance().create(media.get_source_id(), null));
if (event_name != null)
event.rename(event_name);
......@@ -755,6 +760,10 @@ public class Event : EventSource, ContainerSource, Proxyable, Indexable {
return raw_name;
}
public override string? get_comment() {
return comment;
}
public bool rename(string? name) {
string? new_name = prep_event_name(name);
......@@ -773,6 +782,18 @@ public class Event : EventSource, ContainerSource, Proxyable, Indexable {
return renamed;
}
public override bool set_comment(string? comment) {
string? new_comment = MediaSource.prep_comment(comment);
bool committed = event_table.set_comment(event_id, new_comment);
if (committed) {
this.comment = new_comment;
notify_altered(new Alteration.from_list("metadata:comment, indexable:keywords"));
}
return committed;
}
public time_t get_creation_time() {
return event_table.get_time_created(event_id);
}
......
......@@ -160,7 +160,7 @@ public abstract class MediaSource : ThumbnailSource, Indexable {
public abstract string? get_title();
public abstract string? get_comment();
public abstract void set_title(string? title);
public abstract void set_comment(string? comment);
public abstract bool set_comment(string? comment);
public static string? prep_title(string? title) {
return prepare_input_text(title,
......
......@@ -2237,13 +2237,13 @@ public abstract class Photo : PhotoSource, Dateable {
notify_altered(new Alteration("metadata", "name"));
}
public override void set_comment(string? comment) {
public override bool set_comment(string? comment) {
string? new_comment = prep_comment(comment);
bool committed = false;
lock (row) {
if (new_comment == row.comment)
return;
return true;
committed = PhotoTable.get_instance().set_comment(row.photo_id, new_comment);
if (committed)
......@@ -2252,6 +2252,8 @@ public abstract class Photo : PhotoSource, Dateable {
if (committed)
notify_altered(new Alteration("metadata", "comment"));
return committed;
}
public void set_import_id(ImportID import_id) {
......
......@@ -52,7 +52,7 @@ private abstract class Properties : Gtk.Table {
attach(label, 0, 1, line_count, line_count + 1, Gtk.AttachOptions.FILL, Gtk.AttachOptions.FILL, 0, 0);
if (multi_line) {
attach(info, 1, 2, line_count, line_count + 1, Gtk.AttachOptions.FILL,
attach(info, 1, 2, line_count, line_count + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL,
Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0);
} else {
attach_defaults(info, 1, 2, line_count, line_count + 1);
......@@ -451,6 +451,7 @@ private class ExtendedPropertiesWindow : Gtk.Dialog {
private class ExtendedProperties : Properties {
private const string NO_VALUE = "";
// Photo stuff
private string file_path;
private uint64 filesize;
private Dimensions? original_dim;
......@@ -467,6 +468,12 @@ private class ExtendedPropertiesWindow : Gtk.Dialog {
private string copyright;
private string software;
private string exposure_bias;
// Event stuff
// nothing here which is not already shown in the BasicProperties but
// comments, which are common, see below
// common stuff
private string comment;
protected override void clear_properties() {
......@@ -493,74 +500,84 @@ private class ExtendedPropertiesWindow : Gtk.Dialog {
protected override void get_single_properties(DataView view) {
base.get_single_properties(view);
MediaSource media = view.get_source() as MediaSource;
if (media == null)
DataSource source = view.get_source();
if (source == null)
return;
file_path = media.get_master_file().get_path();
filesize = media.get_filesize();
comment = media.get_comment();
// as of right now, all extended properties other than filesize, filepath & comment aren't
// applicable to non-photo media types, so if the current media source isn't a photo,
// just do a short-circuit return
Photo photo = media as Photo;
if (photo == null)
return;
if (source is PhotoSource || source is PhotoImportSource) {
MediaSource media = (MediaSource) source;
file_path = media.get_master_file().get_path();
filesize = media.get_filesize();
// as of right now, all extended properties other than filesize, filepath & comment aren't
// applicable to non-photo media types, so if the current media source isn't a photo,
// just do a short-circuit return
Photo photo = media as Photo;
if (photo == null)
return;
PhotoMetadata? metadata = photo.get_metadata();
if (metadata == null)
return;
PhotoMetadata? metadata = photo.get_metadata();
if (metadata == null)
return;
original_dim = metadata.get_pixel_dimensions();
camera_make = metadata.get_camera_make();
camera_model = metadata.get_camera_model();
flash = metadata.get_flash_string();
focal_length = metadata.get_focal_length_string();
metadata.get_gps(out gps_long, out gps_long_ref, out gps_lat, out gps_lat_ref, out gps_alt);
artist = metadata.get_artist();
copyright = metadata.get_copyright();
software = metadata.get_software();
exposure_bias = metadata.get_exposure_bias();
original_dim = metadata.get_pixel_dimensions();
camera_make = metadata.get_camera_make();
camera_model = metadata.get_camera_model();
flash = metadata.get_flash_string();
focal_length = metadata.get_focal_length_string();
metadata.get_gps(out gps_long, out gps_long_ref, out gps_lat, out gps_lat_ref, out gps_alt);
artist = metadata.get_artist();
copyright = metadata.get_copyright();
software = metadata.get_software();
exposure_bias = metadata.get_exposure_bias();
comment = media.get_comment();
} else if (source is EventSource) {
Event event = (Event) source;
comment = event.get_comment();
}
}
public override void internal_update_properties(Page page) {
base.internal_update_properties(page);
add_line(_("Location:"), (file_path != "" && file_path != null) ?
file_path.replace("&", "&amp;") : NO_VALUE);
if (page is EventsDirectoryPage) {
// nothing special to be done for now for Events
} else {
add_line(_("Location:"), (file_path != "" && file_path != null) ?
file_path.replace("&", "&amp;") : NO_VALUE);
add_line(_("File size:"), (filesize > 0) ?
format_size((int64) filesize) : NO_VALUE);
add_line(_("File size:"), (filesize > 0) ?
format_size((int64) filesize) : NO_VALUE);
add_line(_("Original dimensions:"), (original_dim != null && original_dim.has_area()) ?
"%d &#215; %d".printf(original_dim.width, original_dim.height) : NO_VALUE);
add_line(_("Original dimensions:"), (original_dim != null && original_dim.has_area()) ?
"%d &#215; %d".printf(original_dim.width, original_dim.height) : NO_VALUE);
add_line(_("Camera make:"), (camera_make != "" && camera_make != null) ?
camera_make : NO_VALUE);
add_line(_("Camera make:"), (camera_make != "" && camera_make != null) ?
camera_make : NO_VALUE);
add_line(_("Camera model:"), (camera_model != "" && camera_model != null) ?
camera_model : NO_VALUE);
add_line(_("Camera model:"), (camera_model != "" && camera_model != null) ?
camera_model : NO_VALUE);
add_line(_("Flash:"), (flash != "" && flash != null) ? flash : NO_VALUE);
add_line(_("Flash:"), (flash != "" && flash != null) ? flash : NO_VALUE);
add_line(_("Focal length:"), (focal_length != "" && focal_length != null) ?
focal_length : NO_VALUE);
add_line(_("Focal length:"), (focal_length != "" && focal_length != null) ?
focal_length : NO_VALUE);
add_line(_("Exposure bias:"), (exposure_bias != "" && exposure_bias != null) ? exposure_bias : NO_VALUE);
add_line(_("Exposure bias:"), (exposure_bias != "" && exposure_bias != null) ? exposure_bias : NO_VALUE);
add_line(_("GPS latitude:"), (gps_lat != -1 && gps_lat_ref != "" &&
gps_lat_ref != null) ? "%f °%s".printf(gps_lat, gps_lat_ref) : NO_VALUE);
add_line(_("GPS latitude:"), (gps_lat != -1 && gps_lat_ref != "" &&
gps_lat_ref != null) ? "%f °%s".printf(gps_lat, gps_lat_ref) : NO_VALUE);
add_line(_("GPS longitude:"), (gps_long != -1 && gps_long_ref != "" &&
gps_long_ref != null) ? "%f °%s".printf(gps_long, gps_long_ref) : NO_VALUE);
add_line(_("GPS longitude:"), (gps_long != -1 && gps_long_ref != "" &&
gps_long_ref != null) ? "%f °%s".printf(gps_long, gps_long_ref) : NO_VALUE);
add_line(_("Artist:"), (artist != "" && artist != null) ? artist : NO_VALUE);
add_line(_("Artist:"), (artist != "" && artist != null) ? artist : NO_VALUE);
add_line(_("Copyright:"), (copyright != "" && copyright != null) ? copyright : NO_VALUE);
add_line(_("Copyright:"), (copyright != "" && copyright != null) ? copyright : NO_VALUE);
add_line(_("Software:"), (software != "" && software != null) ? software : NO_VALUE);
add_line(_("Software:"), (software != "" && software != null) ? software : NO_VALUE);
}
bool has_comment = (comment != "" && comment != null);
add_line(_("Comment:"), has_comment ? comment : NO_VALUE, has_comment);
}
......
......@@ -593,25 +593,27 @@ public class Video : VideoSource, Flaggable, Monitorable, Dateable {
}
}
public override void set_comment(string? comment) {
public override bool set_comment(string? comment) {
string? new_comment = prep_title(comment);
lock (backing_row) {
if (backing_row.comment == new_comment)
return;
return true;
try {
VideoTable.get_instance().set_comment(backing_row.video_id, new_comment);
} catch (DatabaseError e) {
AppWindow.database_error(e);
return;
return false;
}
// if we didn't short-circuit return in the catch clause above, then the change was
// successfully committed to the database, so update it in the in-memory row cache
backing_row.comment = new_comment;
}
notify_altered(new Alteration("metadata", "comment"));
return true;
}
......
......@@ -31,6 +31,7 @@ public enum ConfigurableProperty {
DIRECT_WINDOW_MAXIMIZE,
DIRECT_WINDOW_WIDTH,
DISPLAY_BASIC_PROPERTIES,
DISPLAY_EVENT_COMMENTS,
DISPLAY_EXTENDED_PROPERTIES,
DISPLAY_SIDEBAR,
DISPLAY_PHOTO_RATINGS,
......@@ -134,6 +135,9 @@ public enum ConfigurableProperty {
case DISPLAY_PHOTO_COMMENTS:
return "DISPLAY_PHOTO_COMMENTS";
case DISPLAY_EVENT_COMMENTS:
return "DISPLAY_EVENT_COMMENTS";
case EVENT_PHOTOS_SORT_ASCENDING:
return "EVENT_PHOTOS_SORT_ASCENDING";
......@@ -670,6 +674,27 @@ public abstract class ConfigurationFacade : Object {
}
}
//
// display event comments
//
public virtual bool get_display_event_comments() {
try {
return get_engine().get_bool_property(ConfigurableProperty.DISPLAY_EVENT_COMMENTS);
} catch (ConfigurationError err) {
on_configuration_error(err);
return false;
}
}
public virtual void set_display_event_comments(bool display) {
try {
get_engine().set_bool_property(ConfigurableProperty.DISPLAY_EVENT_COMMENTS, display);
} catch (ConfigurationError err) {
on_configuration_error(err);
}
}
//
// event photos sort
//
......
......@@ -50,6 +50,7 @@ public class GSettingsConfigurationEngine : ConfigurationEngine, GLib.Object {
schema_names[ConfigurableProperty.DISPLAY_PHOTO_TAGS] = UI_PREFS_SCHEMA_NAME;
schema_names[ConfigurableProperty.DISPLAY_PHOTO_TITLES] = UI_PREFS_SCHEMA_NAME;
schema_names[ConfigurableProperty.DISPLAY_PHOTO_COMMENTS] = UI_PREFS_SCHEMA_NAME;
schema_names[ConfigurableProperty.DISPLAY_EVENT_COMMENTS] = UI_PREFS_SCHEMA_NAME;
schema_names[ConfigurableProperty.EVENT_PHOTOS_SORT_ASCENDING] = UI_PREFS_SCHEMA_NAME;
schema_names[ConfigurableProperty.EVENT_PHOTOS_SORT_BY] = UI_PREFS_SCHEMA_NAME;
schema_names[ConfigurableProperty.EVENTS_SORT_ASCENDING] = UI_PREFS_SCHEMA_NAME;
......@@ -110,6 +111,7 @@ public class GSettingsConfigurationEngine : ConfigurationEngine, GLib.Object {
key_names[ConfigurableProperty.DISPLAY_PHOTO_TAGS] = "display-photo-tags";
key_names[ConfigurableProperty.DISPLAY_PHOTO_TITLES] = "display-photo-titles";
key_names[ConfigurableProperty.DISPLAY_PHOTO_COMMENTS] = "display-photo-comments";
key_names[ConfigurableProperty.DISPLAY_EVENT_COMMENTS] = "display-event-comments";
key_names[ConfigurableProperty.EVENT_PHOTOS_SORT_ASCENDING] = "event-photos-sort-ascending";
key_names[ConfigurableProperty.EVENT_PHOTOS_SORT_BY] = "event-photos-sort-by";
key_names[ConfigurableProperty.EVENTS_SORT_ASCENDING] = "events-sort-ascending";
......
......@@ -73,14 +73,18 @@ public abstract class EventSource : ThumbnailSource {
}
public abstract time_t get_start_time();
public abstract time_t get_end_time();
public abstract uint64 get_total_filesize();
public abstract int get_media_count();
public abstract Gee.Collection<MediaSource> get_media();
public abstract string? get_comment();
public abstract bool set_comment(string? comment);
}
//
......
......@@ -21,7 +21,7 @@ public abstract class DatabaseTable {
* tables are created on demand and tables and columns are easily ignored when already present.
* However, the change should be noted in upgrade_database() as a comment.
***/
public const int SCHEMA_VERSION = 17;
public const int SCHEMA_VERSION = 18;
protected static Sqlite.Database db;
......
......@@ -312,6 +312,19 @@ private VerifyResult upgrade_database(int input_version) {
version = 17;
//
// Version 18:
// * Added comment column to EventTable
//
if (!DatabaseTable.has_column("EventTable", "comment")) {
message("upgrade_database: adding comment column to EventTable");
if (!DatabaseTable.add_column("EventTable", "comment", "TEXT"))
return VerifyResult.UPGRADE_ERROR;
}
version = 18;
//
// Finalize the upgrade process
//
......
......@@ -27,6 +27,7 @@ public class EventRow {
public string? name;
public time_t time_created;
public string? primary_source_id;
public string? comment;
}
public class EventTable : DatabaseTable {
......@@ -39,7 +40,8 @@ public class EventTable : DatabaseTable {
+ "name TEXT, "
+ "primary_photo_id INTEGER, "
+ "time_created INTEGER,"
+ "primary_source_id TEXT"
+ "primary_source_id TEXT,"
+ "comment TEXT"
+ ")", -1, out stmt);
assert(res == Sqlite.OK);
......@@ -69,12 +71,12 @@ public class EventTable : DatabaseTable {
return null;
}
public EventRow create(string? primary_source_id) throws DatabaseError {
public EventRow create(string? primary_source_id, string? comment) throws DatabaseError {
assert(primary_source_id != null && primary_source_id != "");
Sqlite.Statement stmt;
int res = db.prepare_v2(
"INSERT INTO EventTable (primary_source_id, time_created) VALUES (?, ?)",
"INSERT INTO EventTable (primary_source_id, time_created, comment) VALUES (?, ?, ?)",
-1, out stmt);
assert(res == Sqlite.OK);
......@@ -84,6 +86,8 @@ public class EventTable : DatabaseTable {
assert(res == Sqlite.OK);
res = stmt.bind_int64(2, time_created);
assert(res == Sqlite.OK);
res = stmt.bind_text(3, comment);
assert(res == Sqlite.OK);
res = stmt.step();
if (res != Sqlite.DONE)
......@@ -94,6 +98,7 @@ public class EventTable : DatabaseTable {
row.name = null;
row.primary_source_id = primary_source_id;
row.time_created = time_created;
row.comment = comment;
return row;
}
......@@ -103,7 +108,7 @@ public class EventTable : DatabaseTable {
// the primary photo ID).
public EventID create_from_row(EventRow row) {
Sqlite.Statement stmt;
int res = db.prepare_v2("INSERT INTO EventTable (name, primary_photo_id, primary_source_id, time_created) VALUES (?, ?, ?, ?)",
int res = db.prepare_v2("INSERT INTO EventTable (name, primary_photo_id, primary_source_id, time_created, comment) VALUES (?, ?, ?, ?, ?)",
-1, out stmt);
assert(res == Sqlite.OK);
......@@ -115,6 +120,8 @@ public class EventTable : DatabaseTable {
assert(res == Sqlite.OK);
res = stmt.bind_int64(4, row.time_created);
assert(res == Sqlite.OK);
res = stmt.bind_text(5, row.comment);
assert(res == Sqlite.OK);
res = stmt.step();
if (res != Sqlite.DONE) {
......@@ -129,7 +136,7 @@ public class EventTable : DatabaseTable {
public EventRow? get_row(EventID event_id) {
Sqlite.Statement stmt;
int res = db.prepare_v2(
"SELECT name, primary_photo_id, primary_source_id, time_created FROM EventTable WHERE id=?", -1, out stmt);
"SELECT name, primary_photo_id, primary_source_id, time_created, comment FROM EventTable WHERE id=?", -1, out stmt);
assert(res == Sqlite.OK);
res = stmt.bind_int64(1, event_id.id);
......@@ -145,6 +152,7 @@ public class EventTable : DatabaseTable {
row.name = null;
row.primary_source_id = source_id_upgrade(stmt.column_int64(1), stmt.column_text(2));
row.time_created = (time_t) stmt.column_int64(3);
row.comment = stmt.column_text(4);
return row;
}
......@@ -155,7 +163,7 @@ public class EventTable : DatabaseTable {
public Gee.ArrayList<EventRow?> get_events() {
Sqlite.Statement stmt;
int res = db.prepare_v2("SELECT id, name, primary_photo_id, primary_source_id, time_created FROM EventTable",
int res = db.prepare_v2("SELECT id, name, primary_photo_id, primary_source_id, time_created, comment FROM EventTable",
-1, out stmt);
assert(res == Sqlite.OK);
......@@ -176,6 +184,7 @@ public class EventTable : DatabaseTable {
row.name = stmt.column_text(1);
row.primary_source_id = source_id_upgrade(stmt.column_int64(2), stmt.column_text(3));
row.time_created = (time_t) stmt.column_int64(4);
row.comment = stmt.column_text(5);
event_rows.add(row);
}
......@@ -216,6 +225,11 @@ public class EventTable : DatabaseTable {
return (time_t) stmt.column_int64(0);
}
public bool set_comment(EventID event_id, string new_comment) {
return update_text_by_id(event_id.id, "comment", new_comment != null ? new_comment : "");
}
}
......@@ -20,7 +20,7 @@ class EventDirectoryItem : CheckerboardItem {
private Gdk.Rectangle paul_lynde = Gdk.Rectangle();
public EventDirectoryItem(Event event) {
base (event, Dimensions(CROPPED_SCALE, CROPPED_SCALE), get_formatted_title(event), null, true,
base (event, Dimensions(CROPPED_SCALE, CROPPED_SCALE), get_formatted_title(event), event.get_comment(), true,
Pango.Alignment.CENTER);
this.event = event;
......@@ -113,6 +113,7 @@ class EventDirectoryItem : CheckerboardItem {
}
private void on_events_altered(Gee.Map<DataObject, Alteration> map) {
update_comment();
if (map.has_key(event))
set_title(get_formatted_title(event), true, Pango.Alignment.CENTER);
}
......@@ -162,6 +163,16 @@ class EventDirectoryItem : CheckerboardItem {
Gdk.cairo_set_source_pixbuf(ctx, pixbuf, origin.x, origin.y);
ctx.paint();
}
private void update_comment(bool init = false) {
string comment = event.get_comment();
if (is_string_empty(comment))
clear_comment();
else if (!init)
set_comment(comment);
else
set_comment("");
}
}
......@@ -51,6 +51,9 @@ public abstract class EventsDirectoryPage : CheckerboardPage {
event_comparator_predicate);
get_view().monitor_source_collection(Event.global, view_manager, null, initial_events);
get_view().set_property(Event.PROP_SHOW_COMMENTS,
Config.Facade.get_instance().get_display_event_comments());
init_item_context_menu("/EventsDirectoryContextMenu");
this.view_manager = view_manager;
......@@ -111,9 +114,26 @@ public abstract class EventsDirectoryPage : CheckerboardPage {
merge.label = Resources.MERGE_MENU;
actions += merge;
Gtk.ActionEntry comment = { "EditComment", null, TRANSLATABLE, null, Resources.EDIT_COMMENT_MENU,
on_edit_comment };
comment.label = Resources.EDIT_COMMENT_MENU;
actions += comment;
return actions;
}
protected override Gtk.ToggleActionEntry[] init_collect_toggle_action_entries() {
Gtk.ToggleActionEntry[] toggle_actions = base.init_collect_toggle_action_entries();
Gtk.ToggleActionEntry comments = { "ViewComment", null, TRANSLATABLE, "<Ctrl><Shift>C",
TRANSLATABLE, on_display_comments, Config.Facade.get_instance().get_display_event_comments() };
comments.label = _("_Comments");
comments.tooltip = _("Display the comment of each event");
toggle_actions += comments;
return toggle_actions;
}
protected override void init_actions(int selected_count, int count) {
base.init_actions(selected_count, count);
......@@ -126,6 +146,7 @@ public abstract class EventsDirectoryPage : CheckerboardPage {
set_action_sensitive("Merge", selected_count > 1);
set_action_important("Merge", true);
set_action_sensitive("Rename", selected_count == 1);
set_action_sensitive("EditComment", selected_count == 1);
base.update_actions(selected_count, count);
}
......@@ -168,6 +189,22 @@ public abstract class EventsDirectoryPage : CheckerboardPage {
get_command_manager().execute(command);
}
protected void on_edit_comment() {
// only edit one at a time
if (get_view().get_selected_count() != 1)
return;
EventDirectoryItem item = (EventDirectoryItem) get_view().get_selected_at(0);
EditCommentDialog edit_comment_dialog = new EditCommentDialog(item.event.get_comment());
string? new_comment = edit_comment_dialog.execute();
if (new_comment == null)
return;
EditEventCommentCommand command = new EditEventCommentCommand(item.event, new_comment);
get_command_manager().execute(command);
}
private void on_merge() {
if (get_view().get_selected_count() <= 1)
return;
......@@ -176,6 +213,14 @@ public abstract class EventsDirectoryPage : CheckerboardPage {
get_command_manager().execute(command);
}
private void on_display_comments(Gtk.Action action) {
bool display = ((Gtk.ToggleAction) action).get_active();
set_display_comments(display);
Config.Facade.get_instance().set_display_event_comments(display);
}
public override SearchViewFilter get_search_view_filter() {
return search_filter;
}
......
......@@ -28,6 +28,8 @@
<menuitem name="DisplaySearchbar" action="CommonDisplaySearchbar" />
<menuitem name="DisplaySidebar" action="CommonDisplaySidebar" />
<separator />
<menuitem name="ViewComment" action="ViewComment" />
<separator />
<menu name="SortEvents" action="CommonSortEvents">
<menuitem name="SortEventsAscending" action="CommonSortEventsAscending" />
<menuitem name="SortEventsDescending" action="CommonSortEventsDescending" />
......@@ -39,6 +41,7 @@
<menu name="EventsMenu" action="EventsMenu">
<menuitem name="EventMerge" action="Merge" />
<menuitem name="EventRename" action="Rename" />
<menuitem name="EditComment" action="EditComment" />
</menu>
<menu name="HelpMenu" action="HelpMenu">
......@@ -53,6 +56,7 @@
<popup name="EventsDirectoryContextMenu">
<menuitem name="ContextMerge" action="Merge" />
<menuitem name="ContextRename" action="Rename" />
<menuitem name="ContextEditComment" action="EditComment" />
</popup>
</ui>
......
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