Commit b907fdae authored by Allison Barlow's avatar Allison Barlow

Fixes #733 (rename events in place) and #2199 (allow me to rename sidebar items using F2).

parent e1ab69cb
......@@ -294,6 +294,7 @@ public class FullscreenWindow : PageWindow {
public abstract class PageWindow : Gtk.Window {
private Page current_page = null;
private int busy_counter = 0;
private int keyboard_trapping = 0;
protected virtual void switched_pages(Page? old_page, Page? new_page) {
}
......@@ -330,15 +331,19 @@ public abstract class PageWindow : Gtk.Window {
}
private override bool key_press_event(Gdk.EventKey event) {
if (current_page != null && current_page.notify_app_key_pressed(event))
return true;
if (keyboard_trapping == 0) {
if (current_page != null && current_page.notify_app_key_pressed(event))
return true;
}
return (base.key_press_event != null) ? base.key_press_event(event) : false;
}
private override bool key_release_event(Gdk.EventKey event) {
if (current_page != null && current_page.notify_app_key_released(event))
return true;
if (keyboard_trapping == 0) {
if (current_page != null && current_page.notify_app_key_released(event))
return true;
}
return (base.key_release_event != null) ? base.key_release_event(event) : false;
}
......@@ -385,6 +390,19 @@ public abstract class PageWindow : Gtk.Window {
window.set_cursor(new Gdk.Cursor(Gdk.CursorType.LEFT_PTR));
spin_event_loop();
}
public virtual bool pause_keyboard_trapping() {
return (keyboard_trapping++ == 0);
}
public virtual bool resume_keyboard_trapping() {
if (keyboard_trapping <= 0)
keyboard_trapping = 0;
else
return (--keyboard_trapping == 0);
return false;
}
}
// AppWindow is the parent window for most windows in Shotwell (FullscreenWindow is the exception).
......
......@@ -1042,32 +1042,6 @@ public class AddTagsDialog : TextEntryDialogMediator {
}
}
public class RenameTagDialog : TextEntryDialogMediator {
private string current_name;
public RenameTagDialog(string current_name) {
base (Resources.RENAME_TAG_TITLE, _("Name:"), current_name);
this.current_name = current_name;
}
public string? execute() {
string? name = _execute();
if (name == null)
return null;
// don't want to return null unless the user chose cancel, however, on_modify_validate
// ensures that prep_tag_name won't return null
return Tag.prep_tag_name(name);
}
protected override bool on_modify_validate(string text) {
string? prepped = Tag.prep_tag_name(text);
return !is_string_empty(prepped) && prepped != current_name;
}
}
public class ModifyTagsDialog : TextEntryDialogMediator {
public ModifyTagsDialog(LibraryPhoto photo) {
base (Resources.MODIFY_TAGS_LABEL, _("Tags (separated by commas):"),
......
......@@ -420,19 +420,12 @@ public class EventPage : CollectionPage {
page_event.set_primary_photo(((Thumbnail) view).get_photo());
}
public void rename(string name) {
page_event.rename(name);
set_page_name(page_event.get_name());
}
private void on_rename() {
EventRenameDialog rename_dialog = new EventRenameDialog(page_event.get_raw_name());
string? new_name = rename_dialog.execute();
if (new_name == null)
return;
RenameEventCommand command = new RenameEventCommand(page_event, new_name);
get_command_manager().execute(command);
LibraryWindow.get_app().sidebar_rename_in_place(this);
}
public override void rename(string new_name) {
get_command_manager().execute(new RenameEventCommand(page_event, new_name));
}
}
......
......@@ -87,7 +87,9 @@ public class LibraryWindow : AppWindow {
private Gtk.VPaned sidebar_paned = new Gtk.VPaned();
private Gtk.HPaned client_paned = new Gtk.HPaned();
private Gtk.Frame bottom_frame = new Gtk.Frame(null);
private Gtk.AccelGroup? accel_group = null;
private class FileImportJob : BatchImportJob {
private File file_or_dir;
private bool copy_to_library;
......@@ -129,6 +131,12 @@ public class LibraryWindow : AppWindow {
protected abstract Page construct_page();
public abstract string get_name();
public abstract bool is_renameable();
public virtual void rename(string new_name) {
get_page().rename(new_name);
}
public bool has_page() {
return page != null;
......@@ -220,7 +228,11 @@ public class LibraryWindow : AppWindow {
public override string get_name() {
return page_name;
}
public override bool is_renameable() {
return false;
}
public bool matches(SubEventsDirectoryPage.DirectoryType type, Time time) {
if (type != this.type)
return false;
......@@ -246,6 +258,10 @@ public class LibraryWindow : AppWindow {
public override string get_name() {
return event.get_name();
}
public override bool is_renameable() {
return (event != null);
}
protected override Page construct_page() {
debug("Creating new event page for %s", event.get_name());
......@@ -264,6 +280,10 @@ public class LibraryWindow : AppWindow {
return tag.get_name();
}
public override bool is_renameable() {
return (tag != null);
}
protected override Page construct_page() {
debug("Creating new tag page for %s", tag.get_name());
return new TagPage(tag);
......@@ -1011,11 +1031,15 @@ public class LibraryWindow : AppWindow {
if (event.equals(stub.event)) {
SubEventsDirectoryPageStub old_parent =
(SubEventsDirectoryPageStub) sidebar.get_parent_page(stub);
// only re-add to sidebar if the event has changed directories or shares its dir
// only re-add to sidebar if the event has changed directories or shares its dir
if (sidebar.get_children_count(old_parent.get_marker()) > 1 ||
!(old_parent.get_month() == Time.local(event.get_start_time()).month &&
old_parent.get_year() == Time.local(event.get_start_time()).year)) {
// this prevents the cursor from jumping back to the library photos page
// should it be on this page as we re-sort by removing and reinserting it
sidebar.cursor_changed.disconnect(on_sidebar_cursor_changed);
// remove from sidebar
remove_event_tree(stub, false);
......@@ -1028,8 +1052,10 @@ public class LibraryWindow : AppWindow {
if (get_current_page() is EventPage &&
((EventPage) get_current_page()).page_event.equals(event))
sidebar.place_cursor(stub);
sidebar.cursor_changed.connect(on_sidebar_cursor_changed);
}
// refresh name
SidebarMarker marker = stub.get_marker();
sidebar.rename(marker, event.get_name());
......@@ -1060,11 +1086,22 @@ public class LibraryWindow : AppWindow {
TagPageStub page_stub = tag_map.get((Tag) object);
assert(page_stub != null);
// this prevents the cursor from jumping back to the library photos page
// should it be on this page as we re-sort by removing and reinserting it
sidebar.cursor_changed.disconnect(on_sidebar_cursor_changed);
bool expanded = sidebar.is_branch_expanded(tags_marker);
bool selected = sidebar.is_page_selected(page_stub);
sidebar.remove_page(page_stub);
sidebar.insert_child_sorted(tags_marker, page_stub, tag_page_comparator);
if (expanded)
sidebar.expand_branch(tags_marker);
if (selected)
sidebar.place_cursor(page_stub);
sidebar.cursor_changed.connect(on_sidebar_cursor_changed);
}
private SidebarMarker? find_parent_marker(PageStub page) {
......@@ -1708,5 +1745,39 @@ public class LibraryWindow : AppWindow {
}
}
#endif
private override bool key_press_event(Gdk.EventKey event) {
return (sidebar.has_focus && Gdk.keyval_name(event.keyval) == "F2") ?
sidebar.key_press_event(event) : base.key_press_event(event);
}
public void sidebar_rename_in_place(Page page) {
sidebar.expand_tree(page.get_marker());
sidebar.place_cursor(page);
sidebar.rename_in_place();
}
public override bool pause_keyboard_trapping() {
if (base.pause_keyboard_trapping()) {
accel_group = AppWindow.get_instance().get_current_page().ui.get_accel_group();
if (accel_group != null)
AppWindow.get_instance().remove_accel_group(accel_group);
return true;
}
return false;
}
public override bool resume_keyboard_trapping() {
if (base.resume_keyboard_trapping()) {
if (accel_group != null)
AppWindow.get_instance().add_accel_group(accel_group);
return true;
}
return false;
}
}
......@@ -95,6 +95,13 @@ public abstract class Page : Gtk.ScrolledWindow, SidebarPage {
return page_name;
}
public virtual bool is_renameable() {
return false;
}
public virtual void rename(string new_name) {
}
public virtual void set_page_name(string page_name) {
this.page_name = page_name;
}
......
......@@ -32,6 +32,10 @@ public interface SidebarPage : Object {
public abstract void clear_marker();
public abstract string get_page_name();
public abstract bool is_renameable();
public abstract void rename(string new_name);
public abstract Gtk.Menu? get_page_context_menu();
......@@ -44,11 +48,16 @@ public class Sidebar : Gtk.TreeView {
public signal void drop_received(Gdk.DragContext context, int x, int y,
Gtk.SelectionData selection_data, uint info, uint time, Gtk.TreePath? path, SidebarPage? page);
private Gtk.CellRendererText text;
private Gtk.Entry? text_entry = null;
public Sidebar() {
set_model(store);
Gtk.CellRendererText text = new Gtk.CellRendererText();
text = new Gtk.CellRendererText();
text.editing_canceled.connect(on_editing_canceled);
text.editing_started.connect(on_editing_started);
Gtk.TreeViewColumn text_column = new Gtk.TreeViewColumn();
text_column.pack_start(text, true);
text_column.add_attribute(text, "markup", 0);
......@@ -76,17 +85,35 @@ public class Sidebar : Gtk.TreeView {
enable_model_drag_dest(LibraryWindow.DEST_TARGET_ENTRIES, Gdk.DragAction.ASK);
popup_menu.connect(on_context_menu_keypress);
cursor_changed.connect(on_cursor_changed);
}
~Sidebar() {
cursor_changed.disconnect(on_cursor_changed);
text.editing_canceled.disconnect(on_editing_canceled);
text.editing_started.disconnect(on_editing_started);
}
public void place_cursor(SidebarPage page) {
if (page.get_marker() != null) {
get_selection().select_path(page.get_marker().get_path());
set_cursor(page.get_marker().get_path(), null, false);
// scroll to page in sidebar, if needed
scroll_to_page(page.get_marker());
}
}
public bool is_page_selected(SidebarPage page) {
return (page.get_marker() != null) ? get_selection().path_is_selected(page.get_marker().get_path()) : false;
}
public void on_cursor_changed() {
SidebarPage page = locate_page(current_path);
text.editable = (page != null && page.is_renameable());
}
public void expand_branch(SidebarMarker marker) {
expand_row(marker.get_path(), false);
}
......@@ -349,8 +376,13 @@ public class Sidebar : Gtk.TreeView {
} else if (event.button == 1 && event.type == Gdk.EventType.2BUTTON_PRESS) {
// double left click
Gtk.TreePath? path = get_path_from_event(event);
if (path != null)
if (path != null) {
toggle_branch_expansion(path);
if (rename_path(path))
return false;
}
}
return base.button_press_event(event);
......@@ -360,9 +392,25 @@ public class Sidebar : Gtk.TreeView {
if (Gdk.keyval_name(event.keyval) == "Return" || Gdk.keyval_name(event.keyval) == "KP_Enter") {
toggle_branch_expansion(current_path);
return false;
} else if (Gdk.keyval_name(event.keyval) == "F2") {
return rename_in_place();
}
return base.key_press_event(event);
bool return_val = base.key_press_event(event);
if (has_grab() && !return_val) {
AppWindow.get_instance().key_press_event(event);
}
return return_val;
}
public bool rename_in_place() {
Gtk.TreePath? cursor_path;
Gtk.TreeViewColumn? cursor_column;
get_cursor(out cursor_path, out cursor_column);
set_cursor(cursor_path, cursor_column, true);
return !rename_path(current_path);
}
public void rename(SidebarMarker marker, string name) {
......@@ -491,4 +539,41 @@ public class Sidebar : Gtk.TreeView {
return has_dest;
}
// should return true if path is renameable by user
private bool rename_path(Gtk.TreePath path) {
SidebarPage? page = locate_page(path);
if (page == null || !page.is_renameable())
return false;
get_selection().select_path(path);
return true;
}
private void on_editing_started(Gtk.CellEditable editable, string path) {
if (editable is Gtk.Entry) {
text_entry = (Gtk.Entry) editable;
text_entry.editing_done.connect(on_editing_done);
}
AppWindow.get_instance().pause_keyboard_trapping();
}
private void on_editing_canceled() {
AppWindow.get_instance().resume_keyboard_trapping();
text_entry.editing_done.disconnect(on_editing_done);
}
private void on_editing_done() {
AppWindow.get_instance().resume_keyboard_trapping();
SidebarPage? page = locate_page(current_path);
if (page != null && page.is_renameable())
page.rename(text_entry.get_text());
text_entry.editing_done.disconnect(on_editing_done);
}
}
......@@ -107,23 +107,18 @@ public class TagPage : CollectionPage {
return base.get_page_context_menu();
}
private void on_rename_tag() {
for (;;) {
RenameTagDialog dialog = new RenameTagDialog(tag.get_name());
string? new_name = dialog.execute();
if (new_name == null)
return;
if (!Tag.global.exists(new_name)) {
get_command_manager().execute(new RenameTagCommand(tag, new_name));
return;
}
AppWindow.error_message(Resources.rename_tag_exists_message(new_name));
}
public override void rename(string new_name) {
if (is_string_empty(new_name))
return;
if (!Tag.global.exists(new_name))
get_command_manager().execute(new RenameTagCommand(tag, new_name));
else if (new_name != tag.get_name())
AppWindow.error_message(Resources.rename_tag_exists_message(new_name));
}
private void on_rename_tag() {
LibraryWindow.get_app().sidebar_rename_in_place(this);
}
private void on_delete_tag() {
......
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