Fix generic plugin UI for plugins with only properties
[ardour.git] / gtk2_ardour / keyeditor.cc
index 794e2e258c79e5684157db59f3064d4dd5a57080..a985e4dabacf4665da110f04ac74f2bdd8c29d23 100644 (file)
 #endif
 
 #include <map>
+#include <fstream>
+#include <sstream>
 
 #include <boost/algorithm/string.hpp>
 
-#include <gtkmm/stock.h>
-#include <gtkmm/label.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+
 #include <gtkmm/accelkey.h>
 #include <gtkmm/accelmap.h>
+#include <gtkmm/label.h>
+#include <gtkmm/separator.h>
+#include <gtkmm/stock.h>
+#include <gtkmm/treemodelsort.h>
 #include <gtkmm/uimanager.h>
 
 #include "gtkmm2ext/bindings.h"
 #include "gtkmm2ext/utils.h"
 
+#include "pbd/error.h"
+#include "pbd/openuri.h"
 #include "pbd/strsplit.h"
 
 #include "ardour/filesystem_paths.h"
@@ -43,7 +52,7 @@
 #include "keyboard.h"
 #include "keyeditor.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace Gtk;
@@ -53,10 +62,13 @@ using namespace PBD;
 using Gtkmm2ext::Keyboard;
 using Gtkmm2ext::Bindings;
 
-void bindings_collision_dialog (Gtk::Window& parent)
+sigc::signal<void> KeyEditor::UpdateBindings;
+
+static void bindings_collision_dialog (Gtk::Window& parent, const std::string& bound_name)
 {
        ArdourDialog dialog (parent, _("Colliding keybindings"), true);
-       Label label (_("The key sequence is already bound. Please remove the other binding first."));
+       Label label (string_compose(
+                               _("The key sequence is already bound to '%1'. Please remove the other binding first."), bound_name));
 
        dialog.get_vbox()->pack_start (label, true, true);
        dialog.add_button (_("Ok"), Gtk::RESPONSE_ACCEPT);
@@ -65,7 +77,7 @@ void bindings_collision_dialog (Gtk::Window& parent)
 }
 
 KeyEditor::KeyEditor ()
-       : ArdourWindow (_("Key Bindings"))
+       : ArdourWindow (_("Keyboard Shortcuts"))
        , unbind_button (_("Remove shortcut"))
        , unbind_box (BUTTONBOX_END)
        , filter_entry (_("Search..."), true)
@@ -84,37 +96,53 @@ KeyEditor::KeyEditor ()
        filter_entry.signal_search_string_updated ().connect (sigc::mem_fun (*this, &KeyEditor::search_string_updated));
        vpacker.pack_start (filter_entry, false, false);
 
-       Label* hint = manage (new Label (_("Select an action, then press the key(s) to (re)set its shortcut")));
+       Label* hint = manage (new Label (_("To remove a shortcut, select an action then press this: ")));
        hint->show ();
-       unbind_box.set_spacing (6);
        unbind_box.pack_start (*hint, false, true);
        unbind_box.pack_start (unbind_button, false, false);
        unbind_button.signal_clicked().connect (sigc::mem_fun (*this, &KeyEditor::unbind));
 
+       vpacker.set_spacing (4);
        vpacker.pack_start (unbind_box, false, false);
        unbind_box.show ();
        unbind_button.show ();
 
        reset_button.add (reset_label);
-       reset_label.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Reset Bindings to Defaults")));
+       reset_label.set_markup (string_compose ("  <span size=\"large\" weight=\"bold\">%1</span>  ", _("Reset Bindings to Defaults")));
+
+       print_button.add (print_label);
+       print_label.set_markup (string_compose ("  <span size=\"large\" weight=\"bold\">%1</span>  ", _("Print Bindings (to your web browser)")));
+
+       print_button.signal_clicked().connect (sigc::mem_fun (*this, &KeyEditor::print));
 
        reset_box.pack_start (reset_button, true, false);
+       reset_box.pack_start (print_button, true, false);
        reset_box.show ();
        reset_button.show ();
        reset_label.show ();
+       print_button.show ();
        reset_button.signal_clicked().connect (sigc::mem_fun (*this, &KeyEditor::reset));
+       vpacker.pack_start (*(manage (new  HSeparator())), false, false, 5);
        vpacker.pack_start (reset_box, false, false);
 
        add (vpacker);
 
        unbind_button.set_sensitive (false);
+       _refresh_connection = UpdateBindings.connect (sigc::mem_fun (*this, &KeyEditor::refresh));
 }
 
 void
 KeyEditor::add_tab (string const & name, Bindings& bindings)
 {
        Tab* t = new Tab (*this, name, &bindings);
-       t->populate ();
+
+       if (t->populate () == 0) {
+               /* no bindings */
+               delete t;
+               return;
+       }
+
+       tabs.push_back (t);
        t->show_all ();
        notebook.append_page (*t, name);
 }
@@ -135,6 +163,7 @@ KeyEditor::remove_tab (string const &name)
                        }
                }
        }
+       cerr << "Removed " << name << endl;
 }
 
 void
@@ -293,7 +322,7 @@ KeyEditor::Tab::bind (GdkEventKey* release_event, guint pressed_key)
        Gtkmm2ext::KeyboardKey new_binding (mod, pressed_key);
 
        if (bindings->is_bound (new_binding, Gtkmm2ext::Bindings::Press)) {
-               bindings_collision_dialog (owner);
+               bindings_collision_dialog (owner, bindings->bound_name (new_binding, Gtkmm2ext::Bindings::Press));
                return;
        }
 
@@ -305,7 +334,7 @@ KeyEditor::Tab::bind (GdkEventKey* release_event, guint pressed_key)
        }
 }
 
-void
+uint32_t
 KeyEditor::Tab::populate ()
 {
        vector<string> paths;
@@ -395,6 +424,8 @@ KeyEditor::Tab::populate ()
                }
                row[columns.action] = *a;
        }
+
+       return data_model->children().size();
 }
 
 void
@@ -470,7 +501,12 @@ void
 KeyEditor::reset ()
 {
        Keyboard::the_keyboard().reset_bindings ();
+       refresh ();
+}
 
+void
+KeyEditor::refresh ()
+{
        for (Tabs::iterator t = tabs.begin(); t != tabs.end(); ++t) {
                (*t)->view.get_selection()->unselect_all ();
                (*t)->populate ();
@@ -487,5 +523,56 @@ void
 KeyEditor::search_string_updated (const std::string& filter)
 {
        filter_string = boost::to_lower_copy(filter);
-       current_tab ()->filter->refilter ();
+       KeyEditor::Tab* tab = current_tab ();
+       if (tab) {
+               tab->filter->refilter ();
+       }
+}
+
+void
+KeyEditor::print () const
+{
+       stringstream sstr;
+       Bindings::save_all_bindings_as_html (sstr);
+
+       if (sstr.str().empty()) {
+               return;
+       }
+
+
+       gchar* file_name;
+       GError *err = NULL;
+       gint fd;
+
+       if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
+               if (err) {
+                       error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
+                       g_error_free (err);
+               }
+               return;
+       }
+
+#ifdef PLATFORM_WINDOWS
+       ::close (fd);
+#endif
+
+       err = NULL;
+
+       if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
+#ifndef PLATFORM_WINDOWS
+               ::close (fd);
+#endif
+               g_unlink (file_name);
+               if (err) {
+                       error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
+                       g_error_free (err);
+               }
+               return;
+       }
+
+#ifndef PLATFORM_WINDOWS
+       ::close (fd);
+#endif
+
+       PBD::open_uri (string_compose ("file:///%1", file_name));
 }