geary/src/client/composer/composer-container.vala
Michael James Gratton 5184a38fe8 Reenable and update code for attached, full pane message composer.
Display attached+un-embedded composer as an additional ConversationViewer
stack page, although it realy should be broken as its own top-level
widget - there's already too much state in ConversationViewer.

* src/client/conversation-viewer/conversation-viewer.vala: Remove old
  composer boxes code. Add new ViewState enum, property and methods to
  define and manipulate the current view state - either conversation or
  composer.
  (do_conversation): New method to put the viewer in conversation mode.
  (do_compose): New method to put the viewer in compose mode, hook up the
  composer widget, and handle ConversationListView selection management
  for now.
  (on_folder_selected, on_conversation_count_changed,
  on_conversations_selected): Ensure these methods do the right thing
  depending on the viewer's current view state.
  (set_paned_composer): Replaced by ::do_compose, fixed call sites.
  (show_multiple_selected): Minor code clean up - moved down to a more
  appropriate location.

* src/client/composer/composer-box.vala (ComposerBox): Don't attempt to
  up-manage it's parent's state, since the parent has a much better idea
  of how best to do that. Likewise move code to manage previous
  ConversationList selection out, provide signal so the a more
  appropriate class can manage it instead.

* src/client/composer/composer-container.vala: Add some method comments.

* ui/conversation-viewer.ui: Add new page to the stack for the composer.
2016-10-04 10:58:17 +11:00

133 lines
5.2 KiB
Vala

/* Copyright 2016 Software Freedom Conservancy Inc.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
/**
* A generic interface for widgets that have a single ComposerWidget-child.
*/
public interface ComposerContainer {
// The ComposerWidget-child.
protected abstract ComposerWidget composer { get; set; }
// Workaround to retrieve all Gtk.Actions with conflicting accelerators
protected const string[] conflicting_actions = {
GearyController.ACTION_MARK_AS_UNREAD,
GearyController.ACTION_FORWARD_MESSAGE
};
// We use old_accelerators to keep track of the accelerators we temporarily disabled.
protected abstract Gee.MultiMap<string, string>? old_accelerators { get; set; }
// The toplevel window for the container. Note that it needs to be a GtkApplicationWindow.
public abstract Gtk.ApplicationWindow top_window { get; }
public virtual void present() {
this.top_window.present();
}
public virtual unowned Gtk.Widget get_focus() {
return this.top_window.get_focus();
}
public abstract void close_container();
/**
* Hides the widget (and possibly its parent). Usecase is when you don't want to close just yet
* but the composer should not be visible any longer (e.g. when you're still saving a draft).
*/
public abstract void vanish();
/**
* Removes the composer from this ComposerContainer (e.g. when detaching)
*/
public abstract void remove_composer();
protected virtual bool on_focus_in() {
if (this.old_accelerators == null) {
this.old_accelerators = new Gee.HashMultiMap<string, string>();
add_accelerators();
}
return false;
}
protected virtual bool on_focus_out() {
if (this.old_accelerators != null) {
remove_accelerators();
this.old_accelerators = null;
}
return false;
}
/**
* Adds the accelerators for the child composer, and temporarily removes conflicting
* accelerators from existing actions.
*/
protected virtual void add_accelerators() {
GearyApplication app = GearyApplication.instance;
// Check for actions with conflicting accelerators
foreach (string action in ComposerWidget.action_accelerators.get_keys()) {
foreach (string accelerator in ComposerWidget.action_accelerators[action]) {
string[] actions = app.get_actions_for_accel(accelerator);
foreach (string conflicting_action in actions) {
remove_conflicting_accelerator(conflicting_action, accelerator);
this.old_accelerators[conflicting_action] = accelerator;
}
}
}
// Very stupid workaround while we still use Gtk.Actions in the GearyController
foreach (string conflicting_action in conflicting_actions)
app.actions.get_action(conflicting_action).disconnect_accelerator();
// Now add our actions to the window and their accelerators
foreach (string action in ComposerWidget.action_accelerators.get_keys()) {
this.top_window.add_action(composer.get_action(action));
app.set_accels_for_action("win." + action,
ComposerWidget.action_accelerators[action].to_array());
}
}
/**
* Removes the accelerators for the child composer, and restores previously removed accelerators.
*/
protected virtual void remove_accelerators() {
foreach (string action in ComposerWidget.action_accelerators.get_keys())
GearyApplication.instance.set_accels_for_action("win." + action, {});
// Very stupid workaround while we still use Gtk.Actions in the GearyController
foreach (string conflicting_action in conflicting_actions)
GearyApplication.instance.actions.get_action(conflicting_action).connect_accelerator();
foreach (string action in old_accelerators.get_keys())
foreach (string accelerator in this.old_accelerators[action])
restore_conflicting_accelerator(action, accelerator);
}
// Helper method. Removes the given conflicting accelerator from the action's accelerators.
private void remove_conflicting_accelerator(string action, string accelerator) {
GearyApplication app = GearyApplication.instance;
string[] accelerators = app.get_accels_for_action(action);
if (accelerators.length == 0)
return;
string[] without_accel = new string[accelerators.length - 1];
foreach (string a in accelerators)
if (a != accelerator)
without_accel += a;
app.set_accels_for_action(action, without_accel);
}
// Helper method. Adds the given accelerator back to the action's accelerators.
private void restore_conflicting_accelerator(string action, string accelerator) {
GearyApplication app = GearyApplication.instance;
string[] accelerators = app.get_accels_for_action(action);
accelerators += accelerator;
app.set_accels_for_action(action, accelerators);
}
}