geary/src/client/composer/composer-container.vala
Niels De Graef ebd788968b Use GLib.Actions in the composer. Bug 770356.
Now using these instead of the old composer's actions. This led to quite
some changes:

* Use GLib.ActionEntry instead of Gtk.ActionEntry in
  composer-widget.vala
* Action names can now be specified in the UI files.
* Use templates for the ComposerHeaderBar. Remove
  Pillbar as superclass, since that was no longer necessary.
* Merge ComposerToolbar into ComposerWidget.
* Since actions can now be parameterized, some methods could be
  merged (e.g. font size methods).
* The menu button in the composer now automatically uses a popover.
* Some methods and classes really deserved more comments.
* necessary POTFILES.in changes

Signed-off-by: Niels De Graef <nielsdegraef@gmail.com>
2016-09-21 15:02:18 +10:00

132 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);
}
}