diff --git a/src/Widgets/FormatBar.vala b/src/Widgets/FormatBar.vala index 3616d59246..40a3a6bc4c 100644 --- a/src/Widgets/FormatBar.vala +++ b/src/Widgets/FormatBar.vala @@ -22,18 +22,19 @@ public class Code.FormatBar : Gtk.Box { public bool tab_width_set_by_editor_config { get; set; default = false; } private FormatBox line_formatbox; + private Gtk.MenuButton line_menubutton; private FormatBox lang_formatbox; private FormatBox tab_formatbox; private Granite.SwitchModelButton space_tab_modelbutton; private Gtk.Entry goto_entry; private Gtk.InfoBar editorconfig_infobar; - private Gtk.ListBox lang_selection_listbox; - private Gtk.MenuButton line_menubutton; private Gtk.SourceLanguageManager manager; private Gtk.SpinButton width_spinbutton; - private LangEntry normal_entry; + private SimpleAction language_action; + private ulong cursor_handler = 0; + private ulong language_handler = 0; - private unowned Scratch.Services.Document? doc = null; + private unowned Scratch.Services.Document? current_doc = null; construct { get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); @@ -97,7 +98,7 @@ public class Code.FormatBar : Gtk.Box { placeholder_text = _("Filter languages") }; - lang_selection_listbox = new Gtk.ListBox () { + var lang_selection_listbox = new Gtk.ListBox () { selection_mode = SINGLE }; lang_selection_listbox.set_sort_func ((row1, row2) => { @@ -108,16 +109,13 @@ public class Code.FormatBar : Gtk.Box { return (((LangEntry) row).lang_name.down ().contains (lang_selection_filter.text.down ().strip ())); }); - unowned SList group = null; foreach (unowned string id in manager.get_language_ids ()) { weak Gtk.SourceLanguage lang = manager.get_language (id); - var entry = new LangEntry (id, lang.name, group); - group = entry.get_radio_group (); + var entry = new LangEntry (id, lang.name); lang_selection_listbox.add (entry); } - normal_entry = new LangEntry (null, _("Plain Text"), group); - + var normal_entry = new LangEntry ("", _("Plain Text")); lang_selection_listbox.add (normal_entry); var lang_scrolled = new Gtk.ScrolledWindow (null, null) { @@ -187,16 +185,32 @@ public class Code.FormatBar : Gtk.Box { add (lang_menubutton); add (line_menubutton); - lang_selection_listbox.row_activated.connect ((row) => { - var lang_entry = ((LangEntry) row); - select_language (lang_entry); + language_action = new SimpleAction.stateful ("language", VariantType.STRING, new Variant.string ("")); + language_action.change_state.connect ((parameter) => { + language_action.set_state (parameter); + var lang_id = parameter.get_string (); + + if (current_doc.source_view.language.id != lang_id) { // Avoids loop + current_doc.source_view.language = lang_id != "" ? manager.get_language (lang_id) : null; + } + + if (lang_id != "") { + unowned var lang = manager.get_language (lang_id); + lang_formatbox.text = lang.name; + } else { + lang_formatbox.text = _("Plain Text"); + current_doc.source_view.language = null; + } }); + var action_group = new SimpleActionGroup (); + action_group.add_action (language_action); + insert_action_group ("format", action_group); + lang_selection_filter.changed.connect (() => { lang_selection_listbox.invalidate_filter (); }); - format_tab_header_from_global_settings (); width_spinbutton.value_changed.connect (() => { if (!tab_width_set_by_editor_config) { Scratch.settings.set_int ( @@ -215,14 +229,16 @@ public class Code.FormatBar : Gtk.Box { } }); - // We need to connect_after because otherwise, the text isn't parsed into the "value" property and we only get the previous value + // We need to connect_after because otherwise, the text isn't parsed into the "value" property + // and we only get the previous value goto_entry.activate.connect_after (() => { int line, column; goto_entry.text = goto_entry.text.replace (":", "."); goto_entry.text.scanf ("%i.%i", out line, out column); - doc.source_view.go_to_line (line, column - 1); - // Focuses parent to the source view, so that the cursor, which indicates line and column is actually visible. - doc.source_view.grab_focus (); + current_doc.source_view.go_to_line (line, column - 1); + // Focuses parent to the source view, so that the cursor, which indicates line and column + // is actually visible. + current_doc.source_view.grab_focus (); }); Scratch.settings.changed["indent-width"].connect (format_tab_header_from_global_settings); @@ -236,32 +252,60 @@ public class Code.FormatBar : Gtk.Box { line_menubutton.active = true; } - private void select_language (LangEntry lang, bool update_source_view = true) { - lang_selection_listbox.select_row (lang); - lang_formatbox.text = lang.lang_name; - if (update_source_view) { - lang.active = true; - doc.source_view.language = lang.lang_id != null ? manager.get_language (lang.lang_id) : null; + public void set_document (Scratch.Services.Document doc) requires (doc != null) { + if (current_doc != null) { + SignalHandler.disconnect (current_doc, cursor_handler); + SignalHandler.disconnect (current_doc, language_handler); + } + + current_doc = doc; + if (doc.loading) { + Timeout.add (200, () => { + if (doc.loading) { + return Source.CONTINUE; + } else { + update_widgets (); + return Source.REMOVE; + } + }); } else { - lang.selected = true; + update_widgets (); } } - private void format_tab_header_from_global_settings () { - if (!tab_style_set_by_editor_config) { - set_insert_spaces_instead_of_tabs (Scratch.settings.get_boolean ("spaces-instead-of-tabs")); + public void set_insert_spaces_instead_of_tabs (bool use_spaces) requires (current_doc != null) { + space_tab_modelbutton.active = use_spaces; + current_doc.source_view.insert_spaces_instead_of_tabs = use_spaces; + } + + public void set_tab_width (int indent_width) requires (current_doc != null) { + width_spinbutton.@value = indent_width; + if (space_tab_modelbutton.active) { + tab_formatbox.text = ngettext ("%d Space", "%d Spaces", indent_width).printf (indent_width); + } else { + tab_formatbox.text = ngettext ("%d Tab", "%d Tabs", indent_width).printf (indent_width); } - if (!tab_width_set_by_editor_config) { - set_tab_width (Scratch.settings.get_int ("indent-width")); + current_doc.source_view.indent_width = indent_width; + current_doc.source_view.tab_width = indent_width; + } + + private void update_widgets () requires (current_doc != null) { + format_tab_header_from_global_settings (); + update_current_lang (); + format_tab_header_from_global_settings (); + format_line_header (); + if (cursor_handler == 0) { + cursor_handler = current_doc.source_view.buffer.notify["cursor-position"].connect (format_line_header); } - editorconfig_infobar.revealed = tab_style_set_by_editor_config || tab_width_set_by_editor_config; - space_tab_modelbutton.sensitive = !tab_style_set_by_editor_config; + if (language_handler == 0) { + language_handler = current_doc.source_view.notify["language"].connect (update_current_lang); + } } - private void format_line_header () { - var buffer = doc.source_view.buffer; + private void format_line_header () requires (current_doc != null) { + var buffer = current_doc.source_view.buffer; var position = buffer.cursor_position; Gtk.TextIter iter; buffer.get_iter_at_offset (out iter, position); @@ -270,52 +314,24 @@ public class Code.FormatBar : Gtk.Box { goto_entry.text = "%d.%d".printf (line, iter.get_line_offset () + 1); } - public void set_document (Scratch.Services.Document doc) { - if (this.doc != null) { - this.doc.source_view.buffer.notify["cursor-position"].disconnect (format_line_header); - } - - this.doc = doc; - update_current_lang (); - format_tab_header_from_global_settings (); - format_line_header (); - this.doc.source_view.buffer.notify["cursor-position"].connect (format_line_header); + private void update_current_lang () requires (current_doc != null) { + var language = current_doc.source_view.language; + var lang_id = language != null ? language.id : ""; + // Should not directly modify action state + language_action.change_state (new Variant.string (lang_id)); } - public void set_insert_spaces_instead_of_tabs (bool use_spaces) { - space_tab_modelbutton.active = use_spaces; - if (doc != null) { - doc.source_view.insert_spaces_instead_of_tabs = use_spaces; - } - } - - public void set_tab_width (int indent_width) { - width_spinbutton.@value = indent_width; - if (space_tab_modelbutton.active) { - tab_formatbox.text = ngettext ("%d Space", "%d Spaces", indent_width).printf (indent_width); - } else { - tab_formatbox.text = ngettext ("%d Tab", "%d Tabs", indent_width).printf (indent_width); + private void format_tab_header_from_global_settings () { + if (!tab_style_set_by_editor_config) { + set_insert_spaces_instead_of_tabs (Scratch.settings.get_boolean ("spaces-instead-of-tabs")); } - if (doc != null) { - doc.source_view.indent_width = indent_width; - doc.source_view.tab_width = indent_width; + if (!tab_width_set_by_editor_config) { + set_tab_width (Scratch.settings.get_int ("indent-width")); } - } - private void update_current_lang () { - var language = doc.source_view.language; - if (language != null) { - var lang_id = language.id; - lang_selection_listbox.get_children ().foreach ((child) => { - var lang_entry = ((LangEntry) child); - if (lang_entry.lang_id == lang_id) { - select_language (lang_entry, false); - } - }); - } else { - select_language (normal_entry, false); - } + editorconfig_infobar.revealed = tab_style_set_by_editor_config || tab_width_set_by_editor_config; + space_tab_modelbutton.sensitive = !tab_style_set_by_editor_config; } private class FormatBox : Gtk.Box { @@ -348,35 +364,11 @@ public class Code.FormatBar : Gtk.Box { } private class LangEntry : Gtk.ListBoxRow { - public string? lang_id { get; construct; } + public string lang_id { get; construct; } public string lang_name { get; construct; } - public unowned SList group { get; construct; } - - public bool active { - get { - return lang_radio.active; - } - set { - lang_radio.active = value; - } - } - - public bool selected { - get { - return lang_radio.active; - } - - set { - lang_radio.toggled.disconnect (radio_toggled); - lang_radio.active = value; - lang_radio.toggled.connect (radio_toggled); - } - } - - private Gtk.RadioButton lang_radio; - public LangEntry (string? lang_id, string lang_name, SList group) { - Object (group: group, lang_id: lang_id, lang_name: lang_name); + public LangEntry (string lang_id, string lang_name) { + Object (lang_id: lang_id, lang_name: lang_name); } class construct { @@ -384,20 +376,12 @@ public class Code.FormatBar : Gtk.Box { } construct { - lang_radio = new Gtk.RadioButton.with_label (group, lang_name); - - add (lang_radio); - lang_radio.toggled.connect (radio_toggled); - } - - private void radio_toggled () { - if (lang_radio.active) { - activate (); - } - } + var lang_checkbutton = new Gtk.CheckButton.with_label (lang_name) { + action_name = "format.language", + action_target = new Variant.string (lang_id) + }; - public unowned SList get_radio_group () { - return lang_radio.get_group (); + child = lang_checkbutton; } } }