[regexxer] Replace menubar & toolbar with an HeaderBar



commit 2b77017de5166b037901041412b0c505fdd7391d
Author: Fabien Parent <parent f gmail com>
Date:   Sun Feb 23 16:00:07 2014 +0100

    Replace menubar & toolbar with an HeaderBar

 Makefile.am         |    3 +-
 configure.ac        |    2 +-
 src/controller.cc   |   43 +-------
 src/controller.h    |   19 ---
 src/globalstrings.h |    2 +
 src/mainwindow.cc   |  193 ++++++++++++++++++++++++-------
 src/mainwindow.h    |   25 ++++-
 ui/gear-menu.xml    |   82 +++++++++++++
 ui/mainwindow.ui    |  319 ++++-----------------------------------------------
 9 files changed, 285 insertions(+), 403 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 3929ed0..5729337 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -78,7 +78,8 @@ AM_CPPFLAGS = $(global_defs) -I$(top_builddir) $(REGEXXER_MODULES_CFLAGS) $(REGE
 
 src_regexxer_LDADD        = $(REGEXXER_MODULES_LIBS) $(INTLLIBS)
 
-dist_pkgdata_DATA   = ui/mainwindow.ui ui/prefdialog.ui ui/app-menu.xml
+dist_pkgdata_DATA   = ui/mainwindow.ui ui/prefdialog.ui ui/app-menu.xml \
+ui/gear-menu.xml
 
 iconthemedir        = $(datadir)/icons/hicolor
 appicondir          = $(iconthemedir)/48x48/apps
diff --git a/configure.ac b/configure.ac
index 9051782..ad6ce71 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,7 +36,7 @@ AM_GNU_GETTEXT_VERSION([0.11])
 AM_GLIB_GNU_GETTEXT
 
 PKG_CHECK_MODULES([REGEXXER_MODULES],
-                  [gtkmm-3.0 >= 3.4 glibmm-2.4 >= 2.27.94
+                  [gtkmm-3.0 >= 3.10 glibmm-2.4 >= 2.27.94
                   gtksourceviewmm-3.0 >= 2.91.5])
 
 DK_PKG_PATH_PROG([GDK_PIXBUF_CSOURCE], [gdk-pixbuf-2.0], [gdk-pixbuf-csource])
diff --git a/src/controller.cc b/src/controller.cc
index 465a9fc..a43c74d 100644
--- a/src/controller.cc
+++ b/src/controller.cc
@@ -156,38 +156,11 @@ void ControlGroup::set_enabled(bool enable)
 Controller::Controller()
 :
   match_actions (true),
-  edit_actions  (false),
-  save_file     (false),
-  save_all      (false),
-  undo          (false),
   find_files    (false),
-  find_matches  (false),
-  next_file     (false),
-  prev_file     (false),
-  next_match    (false),
-  prev_match    (false),
-  replace       (false),
-  replace_file  (false),
-  replace_all   (false),
-  cut           (true),
-  copy          (true),
-  paste         (true),
-  erase         (true)
+  find_matches  (false)
 {
-  match_actions.add(undo);
   match_actions.add(find_files);
   match_actions.add(find_matches);
-  match_actions.add(next_file);
-  match_actions.add(prev_file);
-  match_actions.add(next_match);
-  match_actions.add(prev_match);
-  match_actions.add(replace);
-  match_actions.add(replace_file);
-  match_actions.add(replace_all);
-  edit_actions.add(cut);
-  edit_actions.add(copy);
-  edit_actions.add(paste);
-  edit_actions.add(erase);
 }
 
 Controller::~Controller()
@@ -195,20 +168,6 @@ Controller::~Controller()
 
 void Controller::load_xml(const Glib::RefPtr<Gtk::Builder>& xml)
 {
-  save_file   .add_widgets(xml, "menuitem_save",         "button_save");
-  save_all    .add_widgets(xml, "menuitem_save_all",     "button_save_all");
-  undo        .add_widgets(xml, "menuitem_undo",         "button_undo");
-  cut         .add_widgets(xml, "menuitem_cut",          0);
-  copy        .add_widgets(xml, "menuitem_copy",         0);
-  paste       .add_widgets(xml, "menuitem_paste",        0);
-  erase       .add_widgets(xml, "menuitem_delete",       0);
-  next_file   .add_widgets(xml, "menuitem_next_file",    "button_next_file");
-  prev_file   .add_widgets(xml, "menuitem_prev_file",    "button_prev_file");
-  next_match  .add_widgets(xml, "menuitem_next_match",   "button_next_match");
-  prev_match  .add_widgets(xml, "menuitem_prev_match",   "button_prev_match");
-  replace     .add_widgets(xml, "menuitem_replace",      "button_replace");
-  replace_file.add_widgets(xml, "menuitem_replace_file", "button_replace_file");
-  replace_all .add_widgets(xml, "menuitem_replace_all",  "button_replace_all");
   find_files  .add_widgets(xml, 0,                       "button_find_files");
   find_matches.add_widgets(xml, 0,                       "button_find_matches");
 }
diff --git a/src/controller.h b/src/controller.h
index 62a35be..1ac6671 100644
--- a/src/controller.h
+++ b/src/controller.h
@@ -93,29 +93,10 @@ public:
   // Group for all controls that could change matches
   // or require match information to operate.
   ControlGroup  match_actions;
-  ControlGroup  edit_actions;
-
-  ControlItem   save_file;
-  ControlItem   save_all;
-  ControlItem   undo;
 
   ControlItem   find_files;
   ControlItem   find_matches;
 
-  ControlItem   next_file;
-  ControlItem   prev_file;
-  ControlItem   next_match;
-  ControlItem   prev_match;
-
-  ControlItem   replace;
-  ControlItem   replace_file;
-  ControlItem   replace_all;
-
-  ControlItem   cut;
-  ControlItem   copy;
-  ControlItem   paste;
-  ControlItem   erase;
-
   void load_xml(const Glib::RefPtr<Gtk::Builder>& xml);
 
 private:
diff --git a/src/globalstrings.h b/src/globalstrings.h
index 8720462..4df304c 100644
--- a/src/globalstrings.h
+++ b/src/globalstrings.h
@@ -56,6 +56,8 @@ const char *const ui_prefdialog_filename       = REGEXXER_PKGDATADIR G_DIR_SEPAR
                                                  "prefdialog.ui";
 const char *const ui_appmenu_filename          = REGEXXER_PKGDATADIR G_DIR_SEPARATOR_S
                                                  "app-menu.xml";
+const char *const ui_gearmenu_filename         = REGEXXER_PKGDATADIR G_DIR_SEPARATOR_S
+                                                 "gear-menu.xml";
 
 } // namespace Regexxer
 
diff --git a/src/mainwindow.cc b/src/mainwindow.cc
index fbc4f84..fcbab81 100644
--- a/src/mainwindow.cc
+++ b/src/mainwindow.cc
@@ -179,7 +179,8 @@ public:
 
 MainWindow::MainWindow()
 :
-  toolbar_                (0),
+  headerbar_              (0),
+  button_gear_            (0),
   grid_file_              (0),
   button_folder_          (0),
   combo_entry_pattern_    (Gtk::manage(new Gtk::ComboBoxText(true))),
@@ -202,7 +203,10 @@ MainWindow::MainWindow()
   busy_action_running_    (false),
   busy_action_cancel_     (false),
   busy_action_iteration_  (0),
-  undo_stack_             (new UndoStack())
+  undo_stack_             (new UndoStack()),
+  match_action_group_     (Gio::SimpleActionGroup::create()),
+  edit_action_group_      (Gio::SimpleActionGroup::create()),
+  save_action_group_      (Gio::SimpleActionGroup::create())
 {
   load_xml();
 
@@ -211,6 +215,8 @@ MainWindow::MainWindow()
 
   textview_->set_buffer(FileBuffer::create());
   window_->set_title(PACKAGE_NAME);
+  headerbar_->set_title(PACKAGE_NAME);
+  headerbar_->set_show_close_button(true);
 
   vbox_main_->pack_start(*statusline_, Gtk::PACK_SHRINK);
   scrollwin_filetree_->add(*filetree_);
@@ -218,6 +224,7 @@ MainWindow::MainWindow()
 
   scrollwin_textview_->add(*textview_);
 
+  headerbar_->show_all();
   statusline_->show_all();
   filetree_->show_all();
   combo_entry_pattern_->show_all();
@@ -252,6 +259,19 @@ void MainWindow::initialize(const Glib::RefPtr<Gtk::Application>& application,
   if (maximized)
     window_->maximize();
 
+  init_actions();
+  set_sensitive(match_action_group_, false);
+  set_sensitive(edit_action_group_, false);
+  set_sensitive(save_action_group_, true);
+  set_sensitive("save", false);
+  set_sensitive("save-all", false);
+
+  Glib::RefPtr<Gtk::Builder> builder =
+      Gtk::Builder::create_from_file(ui_gearmenu_filename);
+  Glib::RefPtr<Gio::MenuModel> gearmenu =
+    Glib::RefPtr<Gio::MenuModel>::cast_static(builder->get_object("gearmenu"));
+  button_gear_->set_menu_model(gearmenu);
+
   textview_->set_show_line_numbers(settings->get_boolean(conf_key_show_line_numbers));
   textview_->set_highlight_current_line(settings->get_boolean(conf_key_highlight_current_line));
   textview_->set_auto_indent(settings->get_boolean(conf_key_auto_indentation));
@@ -307,13 +327,6 @@ void MainWindow::initialize(const Glib::RefPtr<Gtk::Application>& application,
   if (init.feedback)
     filetree_->signal_feedback.connect(&print_location);
 
-  Glib::RefPtr<Gtk::StyleContext> style_context =
-      toolbar_->get_style_context ();
-  if (style_context)
-  {
-    style_context->add_class (GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
-  }
-
   // Strangely, folder_exists seems to be always true, probably because the
   // file chooser works asynchronously but the GLib main loop isn't running
   // yet.  As a work-around, explicitely check whether the directory exists
@@ -328,6 +341,35 @@ void MainWindow::initialize(const Glib::RefPtr<Gtk::Application>& application,
 
 /**** Regexxer::MainWindow -- private **************************************/
 
+void MainWindow::set_sensitive(const Glib::RefPtr<Gio::SimpleActionGroup>& group,
+                               bool sensitive)
+{
+  std::vector<Glib::ustring> actions = group->list_actions();
+  for (std::vector<Glib::ustring>::iterator i = actions.begin();
+       i != actions.end();
+       ++i)
+  {
+    Glib::RefPtr<Gio::SimpleAction> action =
+        Glib::RefPtr<Gio::SimpleAction>::cast_static(group->lookup_action(*i));
+    if (!action_enabled_.count(*i))
+        action_enabled_[*i] = true;
+    action->set_enabled(action_enabled_[*i] && sensitive);
+  }
+
+  action_group_enabled_[group] = sensitive;
+}
+
+void MainWindow::set_sensitive(const Glib::ustring& action_name, bool sensitive)
+{
+  Glib::RefPtr<Gio::SimpleActionGroup> group = action_to_group_[action_name];
+  Glib::RefPtr<Gio::SimpleAction> action =
+      Glib::RefPtr<Gio::SimpleAction>::cast_static
+          (group->lookup_action(action_name));
+
+  action->set_enabled(action_group_enabled_[group] && sensitive);
+  action_enabled_[action_name] = sensitive;
+}
+
 void MainWindow::on_startup()
 {
   static struct
@@ -358,6 +400,76 @@ void MainWindow::on_startup()
   application_->set_app_menu(appmenu);
 }
 
+void MainWindow::init_actions()
+{
+  struct actions
+  {
+    const char *const name;
+    sigc::slot<void> slot;
+  };
+
+  static struct actions match_actions[] =
+  {
+    {"undo", sigc::mem_fun(*this, &MainWindow::on_undo)},
+    {"previous-file", sigc::bind(sigc::mem_fun(*this, &MainWindow::on_go_next_file), false)},
+    {"back", sigc::bind(sigc::mem_fun(*this, &MainWindow::on_go_next), false)},
+    {"forward", sigc::bind(sigc::mem_fun(*this, &MainWindow::on_go_next), true)},
+    {"next-file", sigc::bind(sigc::mem_fun(*this, &MainWindow::on_go_next_file), true)},
+    {"replace-current", sigc::mem_fun(*this, &MainWindow::on_replace)},
+    {"replace-in-file", sigc::mem_fun(*this, &MainWindow::on_replace_file)},
+    {"replace-in-all-files", sigc::mem_fun(*this, &MainWindow::on_replace_all)},
+    {0},
+  };
+
+  for (int i = 0; match_actions[i].name; i++)
+  {
+    Glib::RefPtr<Gio::SimpleAction> action =
+        Gio::SimpleAction::create(match_actions[i].name);
+    action->signal_activate().connect(sigc::hide(match_actions[i].slot));
+    match_action_group_->insert(action);
+    action_to_group_[match_actions[i].name] = match_action_group_;
+  }
+
+  static struct actions edit_actions[] =
+  {
+    {"cut", sigc::mem_fun(*this, &MainWindow::on_cut)},
+    {"copy", sigc::mem_fun(*this, &MainWindow::on_copy)},
+    {"paste", sigc::mem_fun(*this, &MainWindow::on_paste)},
+    {"delete", sigc::mem_fun(*this, &MainWindow::on_erase)},
+  };
+
+  for (int i = 0; edit_actions[i].name; i++)
+  {
+    Glib::RefPtr<Gio::SimpleAction> action =
+        Gio::SimpleAction::create(edit_actions[i].name);
+    action->signal_activate().connect(sigc::hide(edit_actions[i].slot));
+    edit_action_group_->insert(action);
+    action_to_group_[edit_actions[i].name] = edit_action_group_;
+  }
+
+  static struct actions save_actions[] =
+  {
+    {"save", sigc::mem_fun(*this, &MainWindow::on_save_file)},
+    {"save-all", sigc::mem_fun(*this, &MainWindow::on_save_all)},
+  };
+
+  for (int i = 0; save_actions[i].name; i++)
+  {
+    Glib::RefPtr<Gio::SimpleAction> action =
+        Gio::SimpleAction::create(save_actions[i].name);
+    action->signal_activate().connect(sigc::hide(save_actions[i].slot));
+    save_action_group_->insert(action);
+    action_to_group_[save_actions[i].name] = save_action_group_;
+  }
+
+  window_->insert_action_group("match", match_action_group_);
+  window_->insert_action_group("edit", edit_action_group_);
+  window_->insert_action_group("save", save_action_group_);
+
+//  controller_.find_files  .connect(mem_fun(*this, &MainWindow::on_find_files));
+//  controller_.find_matches.connect(mem_fun(*this, &MainWindow::on_exec_search));
+}
+
 void MainWindow::load_xml()
 {
   const Glib::RefPtr<Gtk::Builder> xml = Gtk::Builder::create_from_file(ui_mainwindow_filename);
@@ -366,7 +478,8 @@ void MainWindow::load_xml()
   xml->get_widget("mainwindow", mainwindow);
   window_.reset(mainwindow);
 
-  xml->get_widget("toolbar",             toolbar_);
+  xml->get_widget("headerbar",           headerbar_);
+  xml->get_widget("button_gear",         button_gear_);
   xml->get_widget("button_folder",       button_folder_);
   xml->get_widget("button_recursive",    button_recursive_);
   xml->get_widget("button_hidden",       button_hidden_);
@@ -399,22 +512,8 @@ void MainWindow::connect_signals()
   entry_substitution_->signal_activate().connect(controller_.find_matches.slot());
   entry_substitution_->signal_changed ().connect(mem_fun(*this, &MainWindow::update_preview));
 
-  controller_.save_file   .connect(mem_fun(*this, &MainWindow::on_save_file));
-  controller_.save_all    .connect(mem_fun(*this, &MainWindow::on_save_all));
-  controller_.undo        .connect(mem_fun(*this, &MainWindow::on_undo));
-  controller_.cut         .connect(mem_fun(*this, &MainWindow::on_cut));
-  controller_.copy        .connect(mem_fun(*this, &MainWindow::on_copy));
-  controller_.paste       .connect(mem_fun(*this, &MainWindow::on_paste));
-  controller_.erase       .connect(mem_fun(*this, &MainWindow::on_erase));
   controller_.find_files  .connect(mem_fun(*this, &MainWindow::on_find_files));
   controller_.find_matches.connect(mem_fun(*this, &MainWindow::on_exec_search));
-  controller_.next_file   .connect(bind(mem_fun(*this, &MainWindow::on_go_next_file), true));
-  controller_.prev_file   .connect(bind(mem_fun(*this, &MainWindow::on_go_next_file), false));
-  controller_.next_match  .connect(bind(mem_fun(*this, &MainWindow::on_go_next), true));
-  controller_.prev_match  .connect(bind(mem_fun(*this, &MainWindow::on_go_next), false));
-  controller_.replace     .connect(mem_fun(*this, &MainWindow::on_replace));
-  controller_.replace_file.connect(mem_fun(*this, &MainWindow::on_replace_file));
-  controller_.replace_all .connect(mem_fun(*this, &MainWindow::on_replace_all));
 
   Settings::instance()->signal_changed().connect(mem_fun(*this, &MainWindow::on_conf_value_changed));
 
@@ -750,9 +849,9 @@ void MainWindow::on_filetree_switch_buffer(FileInfoPtr fileinfo, int file_index)
 
     set_title_filename(fileinfo->fullname);
 
-    controller_.replace_file.set_enabled(buffer->get_match_count() > 0);
-    controller_.save_file.set_enabled(buffer->get_modified());
-    controller_.edit_actions.set_enabled(!fileinfo->load_failed);
+    set_sensitive("replace-in-file", buffer->get_match_count() > 0);
+    set_sensitive("save", buffer->get_modified());
+    set_sensitive(edit_action_group_, !fileinfo->load_failed);
 
     statusline_->set_match_count(buffer->get_original_match_count());
     statusline_->set_match_index(buffer->get_match_index());
@@ -765,10 +864,12 @@ void MainWindow::on_filetree_switch_buffer(FileInfoPtr fileinfo, int file_index)
     textview_->set_cursor_visible(false);
 
     window_->set_title(PACKAGE_NAME);
+    headerbar_->set_title(PACKAGE_NAME);
+    headerbar_->set_subtitle("");
 
-    controller_.replace_file.set_enabled(false);
-    controller_.save_file.set_enabled(false);
-    controller_.edit_actions.set_enabled(false);
+    set_sensitive("replace-in-file", false);
+    set_sensitive("save", false);
+    set_sensitive(edit_action_group_, false);
 
     statusline_->set_match_count(0);
     statusline_->set_match_index(0);
@@ -783,14 +884,14 @@ void MainWindow::on_bound_state_changed()
 {
   BoundState bound = filetree_->get_bound_state();
 
-  controller_.prev_file.set_enabled((bound & BOUND_FIRST) == 0);
-  controller_.next_file.set_enabled((bound & BOUND_LAST)  == 0);
+  set_sensitive("previous-file", (bound & BOUND_FIRST) == 0);
+  set_sensitive("next-file", (bound & BOUND_LAST) == 0);
 
   if (const FileBufferPtr buffer = FileBufferPtr::cast_static(textview_->get_buffer()))
     bound &= buffer->get_bound_state();
 
-  controller_.prev_match.set_enabled((bound & BOUND_FIRST) == 0);
-  controller_.next_match.set_enabled((bound & BOUND_LAST)  == 0);
+  set_sensitive("back", (bound & BOUND_FIRST) == 0);
+  set_sensitive("forward", (bound & BOUND_LAST) == 0);
 }
 
 void MainWindow::on_filetree_file_count_changed()
@@ -803,20 +904,23 @@ void MainWindow::on_filetree_file_count_changed()
 
 void MainWindow::on_filetree_match_count_changed()
 {
-  controller_.replace_all.set_enabled(filetree_->get_match_count() > 0);
+  set_sensitive("replace-in-all-files", filetree_->get_match_count() > 0);
 
   if (const FileBufferPtr buffer = FileBufferPtr::cast_static(textview_->get_buffer()))
-    controller_.replace_file.set_enabled(buffer->get_match_count() > 0);
+  {
+    set_sensitive("replace-in-file", buffer->get_match_count() > 0);
+    set_sensitive("replace-current", buffer->get_match_count() > 0);
+  }
 }
 
 void MainWindow::on_filetree_modified_count_changed()
 {
-  controller_.save_all.set_enabled(filetree_->get_modified_count() > 0);
+  set_sensitive("save-all", filetree_->get_modified_count() > 0);
 }
 
 void MainWindow::on_buffer_modified_changed()
 {
-  controller_.save_file.set_enabled(textview_->get_buffer()->get_modified());
+  set_sensitive("save", textview_->get_buffer()->get_modified());
 }
 
 void MainWindow::on_go_next_file(bool move_forward)
@@ -922,7 +1026,7 @@ void MainWindow::on_save_all()
 void MainWindow::on_undo_stack_push(UndoActionPtr action)
 {
   undo_stack_->push(action);
-  controller_.undo.set_enabled(true);
+  set_sensitive("undo", true);
 }
 
 void MainWindow::on_undo()
@@ -931,13 +1035,13 @@ void MainWindow::on_undo()
   {
     BusyAction busy (*this);
     undo_stack_->undo_step(sigc::mem_fun(*this, &MainWindow::on_busy_action_pulse));
-    controller_.undo.set_enabled(!undo_stack_->empty());
+    set_sensitive("undo", !undo_stack_->empty());
   }
 }
 
 void MainWindow::undo_stack_clear()
 {
-  controller_.undo.set_enabled(false);
+  set_sensitive("undo", false);
   undo_stack_.reset(new UndoStack());
 }
 
@@ -954,7 +1058,7 @@ void MainWindow::update_preview()
     const int pos = buffer->get_line_preview(entry_substitution_->get_text(), preview);
 
     entry_preview_->set_text(preview);
-    controller_.replace.set_enabled(pos >= 0);
+    set_sensitive("replace-current", pos >= 0);
 
     // Beware, strange code ahead!
     //
@@ -995,6 +1099,9 @@ void MainWindow::set_title_filename(const std::string& filename)
   title += ") \342\200\223 " PACKAGE_NAME; // U+2013 EN DASH
 
   window_->set_title(title);
+  headerbar_->set_title(Glib::filename_display_basename(filename));
+  headerbar_->set_subtitle(Util::filename_short_display_name
+      (Glib::path_get_dirname(filename)));
 }
 
 void MainWindow::busy_action_enter()
@@ -1002,6 +1109,7 @@ void MainWindow::busy_action_enter()
   g_return_if_fail(!busy_action_running_);
 
   controller_.match_actions.set_enabled(false);
+  set_sensitive(match_action_group_, false);
 
   statusline_->pulse_start();
 
@@ -1019,6 +1127,7 @@ void MainWindow::busy_action_leave()
   statusline_->pulse_stop();
 
   controller_.match_actions.set_enabled(true);
+  set_sensitive(match_action_group_, true);
 }
 
 bool MainWindow::on_busy_action_pulse()
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 850a2c8..b4f27a9 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -36,12 +36,13 @@
 
 namespace Gtk
 {
+class HeaderBar;
+class MenuButton;
 class Button;
 class CheckButton;
 class Dialog;
 class Entry;
 class FileChooser;
-class Toolbar;
 class ApplicationWindow;
 class Window;
 class ComboBox;
@@ -52,6 +53,11 @@ class Grid;
 class EntryCompletion;
 }
 
+namespace Gio
+{
+class SimpleActionGroup;
+}
+
 namespace Gsv
 {
 class View;
@@ -101,7 +107,8 @@ private:
 
   Gtk::Box*                   vbox_main_;
 
-  Gtk::Toolbar*               toolbar_;
+  Gtk::HeaderBar*             headerbar_;
+  Gtk::MenuButton*            button_gear_;
 
   Gtk::Grid*                  grid_file_;
   Gtk::FileChooser*           button_folder_;
@@ -143,11 +150,25 @@ private:
   std::auto_ptr<Gtk::Dialog>  about_dialog_;
   std::auto_ptr<PrefDialog>   pref_dialog_;
 
+  Glib::RefPtr<Gio::SimpleActionGroup> match_action_group_;
+  Glib::RefPtr<Gio::SimpleActionGroup> edit_action_group_;
+  Glib::RefPtr<Gio::SimpleActionGroup> save_action_group_;
+
+  std::map<Glib::RefPtr<Gio::SimpleActionGroup>, bool> action_group_enabled_;
+  std::map<Glib::ustring, bool> action_enabled_;
+  std::map<Glib::ustring,
+           Glib::RefPtr<Gio::SimpleActionGroup> > action_to_group_;
+
+  void set_sensitive(const Glib::RefPtr<Gio::SimpleActionGroup>& group,
+                     bool sensitive);
+  void set_sensitive(const Glib::ustring& action_name, bool sensitive);
+
   void on_startup();
   void load_xml();
   void connect_signals();
   bool autorun_idle();
   void save_window_state();
+  void init_actions();
 
   void on_hide();
   void on_style_updated();
diff --git a/ui/gear-menu.xml b/ui/gear-menu.xml
new file mode 100644
index 0000000..56718ca
--- /dev/null
+++ b/ui/gear-menu.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <menu id="gearmenu">
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Save</attribute>
+        <attribute name="action">save.save</attribute>
+        <attribute name="accel"><![CDATA[<Ctrl>S]]></attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Save _all</attribute>
+        <attribute name="action">save.save-all</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Undo</attribute>
+        <attribute name="action">match.undo</attribute>
+        <attribute name="accel"><![CDATA[<Ctrl>Z]]></attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Cu_t</attribute>
+        <attribute name="action">edit.cut</attribute>
+        <attribute name="accel"><![CDATA[<Ctrl>X]]></attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Copy</attribute>
+        <attribute name="action">edit.copy</attribute>
+        <attribute name="accel"><![CDATA[<Ctrl>C]]></attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Paste</attribute>
+        <attribute name="action">edit.paste</attribute>
+        <attribute name="accel"><![CDATA[<Ctrl>V]]></attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Delete</attribute>
+        <attribute name="action">edit.delete</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Previous file</attribute>
+        <attribute name="action">match.previous-file</attribute>
+        <attribute name="accel"><![CDATA[<Ctrl>P]]></attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Back</attribute>
+        <attribute name="action">match.back</attribute>
+        <attribute name="accel"><![CDATA[<Ctrl>B]]></attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Forward</attribute>
+        <attribute name="action">match.forward</attribute>
+        <attribute name="accel"><![CDATA[<Ctrl>N]]></attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Next file</attribute>
+        <attribute name="action">match.next-file</attribute>
+        <attribute name="accel"><![CDATA[<Ctrl>E]]></attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Replace current</attribute>
+        <attribute name="action">match.replace-current</attribute>
+        <attribute name="accel"><![CDATA[<Ctrl>R]]></attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Replace in this file</attribute>
+        <attribute name="action">match.replace-in-file</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Replace in all files</attribute>
+        <attribute name="action">match.replace-in-all-files</attribute>
+      </item>
+    </section>
+  </menu>
+</interface>
diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui
index 86c0d64..028eead 100644
--- a/ui/mainwindow.ui
+++ b/ui/mainwindow.ui
@@ -10,323 +10,50 @@
     <accel-groups>
       <group name="mainwindow_accelgroup"/>
     </accel-groups>
-    <child>
-      <object class="GtkBox" id="vbox_main">
+    <child type="titlebar">
+      <object class="GtkHeaderBar" id="headerbar">
         <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="orientation">vertical</property>
+        <property name="show_close_button">False</property>
         <child>
-          <object class="GtkMenuBar" id="menubar">
+          <object class="GtkButton" id="save_button">
             <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <child>
-              <object class="GtkMenuItem" id="menuitem_file">
-                <property name="use_action_appearance">False</property>
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">_File</property>
-                <property name="use_underline">True</property>
-                <child type="submenu">
-                  <object class="GtkMenu" id="menuitem_file_menu">
-                    <property name="can_focus">False</property>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_save">
-                        <property name="label">gtk-save</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                        <accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_save_all">
-                        <property name="label">Save all</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="GtkMenuItem" id="menuitem_edit">
-                <property name="use_action_appearance">False</property>
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">_Edit</property>
-                <property name="use_underline">True</property>
-                <child type="submenu">
-                  <object class="GtkMenu" id="menuitem_edit_menu">
-                    <property name="can_focus">False</property>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_undo">
-                        <property name="label">gtk-undo</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                        <accelerator key="z" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkSeparatorMenuItem" id="menuitem_separator2">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_cut">
-                        <property name="label">gtk-cut</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                        <accelerator key="x" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_copy">
-                        <property name="label">gtk-copy</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                        <accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_paste">
-                        <property name="label">gtk-paste</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                        <accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_delete">
-                        <property name="label">gtk-delete</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-            </child>
+            <property name="tooltip_text" translatable="yes">Save all</property>
+            <property name="action_name">save.save-all</property>
             <child>
-              <object class="GtkMenuItem" id="menuitem_match">
-                <property name="use_action_appearance">False</property>
+              <object class="GtkImage" id="image_save">
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">_Match</property>
-                <property name="use_underline">True</property>
-                <child type="submenu">
-                  <object class="GtkMenu" id="menuitem_match_menu">
-                    <property name="can_focus">False</property>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_prev_file">
-                        <property name="label">_Previous file</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                        <accelerator key="p" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_prev_match">
-                        <property name="label">gtk-go-back</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                        <accelerator key="b" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_next_match">
-                        <property name="label">gtk-go-forward</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                        <accelerator key="n" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_next_file">
-                        <property name="label">_Next file</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                        <accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkSeparatorMenuItem" id="menuitem_separator4">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_replace">
-                        <property name="label">Replace _current</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                        <accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_replace_file">
-                        <property name="label">Replace in _this file</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                      </object>
-                    </child>
-                    <child>
-                      <object class="GtkImageMenuItem" id="menuitem_replace_all">
-                        <property name="label">Replace in _all files</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                        <property name="accel_group">mainwindow_accelgroup</property>
-                      </object>
-                    </child>
-                  </object>
-                </child>
+                <property name="icon_size">1</property>
+                <property name="icon_name">document-save-symbolic</property>
               </object>
             </child>
           </object>
           <packing>
-            <property name="expand">False</property>
-            <property name="fill">False</property>
-            <property name="position">0</property>
+            <property name="pack_type">start</property>
           </packing>
         </child>
         <child>
-          <object class="GtkToolbar" id="toolbar">
+          <object class="GtkMenuButton" id="button_gear">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <child>
-              <object class="GtkToolButton" id="button_save">
-                <property name="use_action_appearance">False</property>
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="is_important">True</property>
-                <property name="stock_id">gtk-save</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="homogeneous">True</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkToolButton" id="button_save_all">
-                <property name="use_action_appearance">False</property>
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="is_important">True</property>
-                <property name="stock_id">regexxer-save-all</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="homogeneous">True</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkSeparatorToolItem" id="separatortoolitem1">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="homogeneous">False</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkToolButton" id="button_undo">
-                <property name="use_action_appearance">False</property>
+              <object class="GtkImage" id="image_gear">
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="is_important">True</property>
-                <property name="stock_id">gtk-undo</property>
+                <property name="icon_size">1</property>
+                <property name="icon_name">emblem-system-symbolic</property>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="homogeneous">True</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkSeparatorToolItem" id="separatortoolitem2">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="homogeneous">False</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkToolButton" id="button_quit">
-                <property name="use_action_appearance">False</property>
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="is_important">True</property>
-                <property name="stock_id">gtk-quit</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="homogeneous">True</property>
-              </packing>
             </child>
           </object>
           <packing>
-            <property name="expand">False</property>
-            <property name="fill">False</property>
-            <property name="position">1</property>
+            <property name="pack_type">end</property>
           </packing>
         </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkBox" id="vbox_main">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
         <child>
           <object class="GtkBox" id="vbox_interior">
             <property name="visible">True</property>
@@ -1102,7 +829,7 @@
           <packing>
             <property name="expand">True</property>
             <property name="fill">True</property>
-            <property name="position">2</property>
+            <property name="position">0</property>
           </packing>
         </child>
         <child>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]