Class JSONTreeView
In: lib/json/editor.rb
Parent: Gtk::TreeView
OptionsMenu EditMenu PopUpMenu FileMenu JSONTreeView MainWindow ParserError NestingError GeneratorError CircularDatastructure StandardError JSONError MissingUnicodeSupport StringScanner Parser State Enumerable TreeIter Gtk::TreeView Gtk::Window MenuExtension lib/json/common.rb Ext Editor lib/json/pure/parser.rb lib/json/pure/generator.rb Integer FalseClass Array Hash Float NilClass Object TrueClass Extend String GeneratorMethods Generator Pure JSON Editor lib/json/editor.rb Gtk dot/f_8.png

This class inherits from Gtk::TreeView, to configure it and to add a lot of behaviour to it.

Methods

Included Modules

Gtk

Attributes

expanded  [RW]  Returns true, if nodes are autoexpanding, false otherwise.
window  [R]  Returns the MainWindow instance of this JSONTreeView.

Public Class methods

Creates a JSONTreeView instance, the parameter window is a MainWindow instance and used for self delegation.

[Source]

     # File lib/json/editor.rb, line 683
683:       def initialize(window)
684:         @window = window
685:         super(TreeStore.new(Gdk::Pixbuf, String, String))
686:         self.selection.mode = SELECTION_BROWSE
687: 
688:         @expanded = false
689:         self.headers_visible = false
690:         add_columns
691:         add_popup_menu
692:       end

Public Instance methods

Ask for an element to be appended parent.

[Source]

     # File lib/json/editor.rb, line 877
877:       def ask_for_element(parent = nil, default_type = nil, value_text = @content)
878:         type_input = value_input = nil
879: 
880:         dialog = Dialog.new(
881:           "New element into #{parent ? parent.type : 'root'}",
882:           nil, nil,
883:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
884:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
885:         )
886:         hbox = HBox.new(false, 5)
887:         hbox.add(Label.new("Type:"))
888:         hbox.pack_start(type_input = ComboBox.new(true))
889:         default_active = 0
890:         types = parent ? ALL_TYPES : CONTAINER_TYPES
891:         types.each_with_index do |t, i|
892:           type_input.append_text(t)
893:           if t == default_type
894:             default_active = i
895:           end
896:         end
897:         type_input.active = default_active
898:         dialog.vbox.add(hbox)
899:         type_input.signal_connect(:changed) do
900:           configure_value(value_input, types[type_input.active])
901:         end
902: 
903:         hbox = HBox.new(false, 5)
904:         hbox.add(Label.new("Value:"))
905:         hbox.pack_start(value_input = Entry.new)
906:         value_input.text = value_text if value_text
907:         configure_value(value_input, types[type_input.active])
908: 
909:         dialog.vbox.add(hbox)
910: 
911:         dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
912:         dialog.show_all
913:         self.focus = dialog
914:         dialog.run do |response| 
915:           if response == Dialog::RESPONSE_ACCEPT
916:             type = types[type_input.active]
917:             @content = case type
918:             when 'Numeric'
919:               Integer(value_input.text) rescue Float(value_input.text) rescue 0
920:             else
921:               value_input.text
922:             end.to_s
923:             return type, @content
924:           end
925:         end
926:         return
927:       ensure
928:         dialog.destroy if dialog
929:       end

Ask for a find term to search for in the tree. Returns the term as a string.

[Source]

     # File lib/json/editor.rb, line 966
966:       def ask_for_find_term
967:         dialog = Dialog.new(
968:           "Find a node matching regex in tree.",
969:           nil, nil,
970:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
971:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
972:         )
973:         hbox = HBox.new(false, 5)
974: 
975:         hbox.add(Label.new("Regex:"))
976:         hbox.pack_start(regex_input = Entry.new)
977:         regex_input.text = @regex || ''
978: 
979:         dialog.vbox.add(hbox)
980: 
981:         dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
982:         dialog.show_all
983:         self.focus = dialog
984:         dialog.run do |response| 
985:           if response == Dialog::RESPONSE_ACCEPT
986:             return @regex = regex_input.text
987:           end
988:         end
989:         return
990:       ensure
991:         dialog.destroy if dialog
992:       end

Ask for a hash key, value pair to be added to the Hash node parent.

[Source]

     # File lib/json/editor.rb, line 808
808:       def ask_for_hash_pair(parent)
809:         key_input = type_input = value_input = nil
810: 
811:         dialog = Dialog.new("New (key, value) pair for Hash", nil, nil,
812:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
813:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
814:         )
815: 
816:         hbox = HBox.new(false, 5)
817:         hbox.pack_start(Label.new("Key:"))
818:         hbox.pack_start(key_input = Entry.new)
819:         key_input.text = @key || ''
820:         dialog.vbox.add(hbox)
821:         key_input.signal_connect(:activate) do
822:           if parent.any? { |c| c.content == key_input.text }
823:             toplevel.display_status('Key already exists in Hash!')
824:             key_input.text = ''
825:           else
826:             toplevel.display_status('Key has been changed.')
827:           end
828:         end
829: 
830:         hbox = HBox.new(false, 5)
831:         hbox.add(Label.new("Type:"))
832:         hbox.pack_start(type_input = ComboBox.new(true))
833:         ALL_TYPES.each { |t| type_input.append_text(t) }
834:         type_input.active = @type || 0
835:         dialog.vbox.add(hbox)
836: 
837:         type_input.signal_connect(:changed) do
838:           value_input.editable = false
839:           case ALL_TYPES[type_input.active]
840:           when 'Array', 'Hash'
841:             value_input.text = ''
842:           when 'TrueClass'
843:             value_input.text = 'true'
844:           when 'FalseClass'
845:             value_input.text = 'false'
846:           when 'NilClass'
847:             value_input.text = 'null'
848:           else
849:             value_input.text = ''
850:             value_input.editable = true
851:           end
852:         end
853: 
854:         hbox = HBox.new(false, 5)
855:         hbox.add(Label.new("Value:"))
856:         hbox.pack_start(value_input = Entry.new)
857:         value_input.text = @value || ''
858:         dialog.vbox.add(hbox)
859: 
860:         dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
861:         dialog.show_all
862:         self.focus = dialog
863:         dialog.run do |response| 
864:           if response == Dialog::RESPONSE_ACCEPT
865:             @key = key_input.text
866:             type = ALL_TYPES[@type = type_input.active]
867:             content = value_input.text
868:             return @key, type, content
869:           end
870:         end
871:         return
872:       ensure
873:         dialog.destroy
874:       end

Ask for an order criteria for sorting, using x for the element in question. Returns the order criterium, and true/false for reverse sorting.

[Source]

     # File lib/json/editor.rb, line 934
934:       def ask_for_order
935:         dialog = Dialog.new(
936:           "Give an order criterium for 'x'.",
937:           nil, nil,
938:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
939:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
940:         )
941:         hbox = HBox.new(false, 5)
942: 
943:         hbox.add(Label.new("Order:"))
944:         hbox.pack_start(order_input = Entry.new)
945:         order_input.text = @order || 'x'
946: 
947:         hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse'))
948: 
949:         dialog.vbox.add(hbox)
950: 
951:         dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
952:         dialog.show_all
953:         self.focus = dialog
954:         dialog.run do |response| 
955:           if response == Dialog::RESPONSE_ACCEPT
956:             return @order = order_input.text, reverse_checkbox.active?
957:           end
958:         end
959:         return
960:       ensure
961:         dialog.destroy if dialog
962:       end

Create a type node with content content, and add it to parent in the model. If parent is nil, create a new model and put it into the editor treeview.

[Source]

     # File lib/json/editor.rb, line 794
794:       def create_node(parent, type, content)
795:         iter = if parent
796:           model.append(parent)
797:         else
798:           new_model = Editor.data2model(nil)
799:           toplevel.view_new_model(new_model)
800:           new_model.iter_first
801:         end
802:         iter.type, iter.content = type, content
803:         expand_collapse(parent) if parent
804:         iter
805:       end

Expand or collapse row pointed to by iter according to the expanded attribute.

[Source]

      # File lib/json/editor.rb, line 996
 996:       def expand_collapse(iter)
 997:         if expanded
 998:           expand_row(iter.path, true)
 999:         else
1000:           collapse_row(iter.path)
1001:         end
1002:       end

Private Instance methods

[Source]

     # File lib/json/editor.rb, line 702
702:       def add_columns
703:         cell = CellRendererPixbuf.new
704:         column = TreeViewColumn.new('Icon', cell,
705:           'pixbuf'      => ICON_COL
706:         )
707:         append_column(column)
708: 
709:         cell = CellRendererText.new
710:         column = TreeViewColumn.new('Type', cell,
711:           'text'      => TYPE_COL
712:         )
713:         append_column(column)
714: 
715:         cell = CellRendererText.new
716:         cell.editable = true
717:         column = TreeViewColumn.new('Content', cell,
718:           'text'       => CONTENT_COL
719:         )
720:         cell.signal_connect(:edited, &method(:cell_edited))
721:         append_column(column)
722:       end

[Source]

     # File lib/json/editor.rb, line 784
784:       def add_popup_menu
785:         menu = PopUpMenu.new(self)
786:         menu.create
787:       end

[Source]

     # File lib/json/editor.rb, line 737
737:       def cell_edited(cell, path, value)
738:         iter = model.get_iter(path)
739:         case iter.type
740:         when 'Key'
741:           unify_key(iter, value)
742:           toplevel.display_status('Key has been changed.')
743:         when 'FalseClass'
744:           value.downcase!
745:           if value == 'true'
746:             iter.type, iter.content = 'TrueClass', 'true'
747:           end
748:         when 'TrueClass'
749:           value.downcase!
750:           if value == 'false'
751:             iter.type, iter.content = 'FalseClass', 'false'
752:           end
753:         when 'Numeric'
754:           iter.content = (Integer(value) rescue Float(value) rescue 0).to_s
755:         when 'String'
756:           iter.content = value
757:         when 'Hash', 'Array'
758:           return
759:         else
760:           fail "Unknown type found in model: #{iter.type}"
761:         end
762:         window.change
763:       end

[Source]

     # File lib/json/editor.rb, line 765
765:       def configure_value(value, type)
766:         value.editable = false
767:         case type
768:         when 'Array', 'Hash'
769:           value.text = ''
770:         when 'TrueClass'
771:           value.text = 'true'
772:         when 'FalseClass'
773:           value.text = 'false'
774:         when 'NilClass'
775:           value.text = 'null'
776:         when 'Numeric', 'String'
777:           value.text ||= ''
778:           value.editable = true
779:         else
780:           raise ArgumentError, "unknown type '#{type}' encountered"
781:         end
782:       end

[Source]

     # File lib/json/editor.rb, line 724
724:       def unify_key(iter, key)
725:         return unless iter.type == 'Key'
726:         parent = iter.parent
727:         if parent.any? { |c| c != iter and c.content == key }
728:           old_key = key
729:           i = 0
730:           begin
731:             key = sprintf("%s.%d", old_key, i += 1)
732:           end while parent.any? { |c| c != iter and c.content == key }
733:         end
734:         iter.content = key
735:       end

[Validate]