Class JSONTreeView
In: lib/json/editor.rb
Parent: Gtk::TreeView
OptionsMenu EditMenu PopUpMenu FileMenu MainWindow JSONTreeView Enumerable TreeIter JSONError GeneratorError ParserError MissingUnicodeSupport CircularDatastructure NestingError StandardError StringScanner Parser State Gtk::Window Gtk::TreeView MenuExtension Editor lib/json/editor.rb Gtk lib/json/common.rb Ext Editor lib/json/pure/parser.rb lib/json/pure/generator.rb Object Integer FalseClass Array Hash Float NilClass TrueClass Extend String GeneratorMethods Generator Pure JSON dot/f_1.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 701
701:       def initialize(window)
702:         @window = window
703:         super(TreeStore.new(Gdk::Pixbuf, String, String))
704:         self.selection.mode = SELECTION_BROWSE
705: 
706:         @expanded = false
707:         self.headers_visible = false
708:         add_columns
709:         add_popup_menu
710:       end

Public Instance methods

Ask for an element to be appended parent.

[Source]

     # File lib/json/editor.rb, line 897
897:       def ask_for_element(parent = nil, default_type = nil, value_text = @content)
898:         type_input = value_input = nil
899: 
900:         dialog = Dialog.new(
901:           "New element into #{parent ? parent.type : 'root'}",
902:           nil, nil,
903:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
904:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
905:         )
906:         hbox = HBox.new(false, 5)
907:         hbox.pack_start(Label.new("Type:"), false)
908:         hbox.pack_start(type_input = ComboBox.new(true))
909:         default_active = 0
910:         types = parent ? ALL_TYPES : CONTAINER_TYPES
911:         types.each_with_index do |t, i|
912:           type_input.append_text(t)
913:           if t == default_type
914:             default_active = i
915:           end
916:         end
917:         type_input.active = default_active
918:         dialog.vbox.pack_start(hbox, false)
919:         type_input.signal_connect(:changed) do
920:           configure_value(value_input, types[type_input.active])
921:         end
922: 
923:         hbox = HBox.new(false, 5)
924:         hbox.pack_start(Label.new("Value:"), false)
925:         hbox.pack_start(value_input = Entry.new)
926:         value_input.width_chars = 60
927:         value_input.text = value_text if value_text
928:         configure_value(value_input, types[type_input.active])
929: 
930:         dialog.vbox.pack_start(hbox, false)
931: 
932:         dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
933:         dialog.show_all
934:         self.focus = dialog
935:         dialog.run do |response| 
936:           if response == Dialog::RESPONSE_ACCEPT
937:             type = types[type_input.active]
938:             @content = case type
939:             when 'Numeric'
940:               Integer(value_input.text) rescue Float(value_input.text) rescue 0
941:             else
942:               value_input.text
943:             end.to_s
944:             return type, @content
945:           end
946:         end
947:         return
948:       ensure
949:         dialog.destroy if dialog
950:       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 988
 988:       def ask_for_find_term(search = nil)
 989:         dialog = Dialog.new(
 990:           "Find a node matching regex in tree.",
 991:           nil, nil,
 992:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
 993:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
 994:         )
 995:         hbox = HBox.new(false, 5)
 996: 
 997:         hbox.pack_start(Label.new("Regex:"), false)
 998:         hbox.pack_start(regex_input = Entry.new)
 999:         hbox.pack_start(icase_checkbox = CheckButton.new('Icase'), false)
1000:         regex_input.width_chars = 60
1001:         if search
1002:           regex_input.text = search.source
1003:           icase_checkbox.active = search.casefold?
1004:         end
1005: 
1006:         dialog.vbox.pack_start(hbox, false)
1007: 
1008:         dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
1009:         dialog.show_all
1010:         self.focus = dialog
1011:         dialog.run do |response| 
1012:           if response == Dialog::RESPONSE_ACCEPT
1013:             begin
1014:               return Regexp.new(regex_input.text, icase_checkbox.active? ? Regexp::IGNORECASE : 0)
1015:             rescue => e
1016:               Editor.error_dialog(self, "Evaluation of regex /#{regex_input.text}/ failed: #{e}!")
1017:               return
1018:             end
1019:           end
1020:         end
1021:         return
1022:       ensure
1023:         dialog.destroy if dialog
1024:       end

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

[Source]

     # File lib/json/editor.rb, line 826
826:       def ask_for_hash_pair(parent)
827:         key_input = type_input = value_input = nil
828: 
829:         dialog = Dialog.new("New (key, value) pair for Hash", nil, nil,
830:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
831:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
832:         )
833:         dialog.width_request = 640
834: 
835:         hbox = HBox.new(false, 5)
836:         hbox.pack_start(Label.new("Key:"), false)
837:         hbox.pack_start(key_input = Entry.new)
838:         key_input.text = @key || ''
839:         dialog.vbox.pack_start(hbox, false)
840:         key_input.signal_connect(:activate) do
841:           if parent.any? { |c| c.content == key_input.text }
842:             toplevel.display_status('Key already exists in Hash!')
843:             key_input.text = ''
844:           else
845:             toplevel.display_status('Key has been changed.')
846:           end
847:         end
848: 
849:         hbox = HBox.new(false, 5)
850:         hbox.pack_start(Label.new("Type:"), false)
851:         hbox.pack_start(type_input = ComboBox.new(true))
852:         ALL_TYPES.each { |t| type_input.append_text(t) }
853:         type_input.active = @type || 0
854:         dialog.vbox.pack_start(hbox, false)
855: 
856:         type_input.signal_connect(:changed) do
857:           value_input.editable = false
858:           case ALL_TYPES[type_input.active]
859:           when 'Array', 'Hash'
860:             value_input.text = ''
861:           when 'TrueClass'
862:             value_input.text = 'true'
863:           when 'FalseClass'
864:             value_input.text = 'false'
865:           when 'NilClass'
866:             value_input.text = 'null'
867:           else
868:             value_input.text = ''
869:             value_input.editable = true
870:           end
871:         end
872: 
873:         hbox = HBox.new(false, 5)
874:         hbox.pack_start(Label.new("Value:"), false)
875:         hbox.pack_start(value_input = Entry.new)
876:         value_input.width_chars = 60
877:         value_input.text = @value || ''
878:         dialog.vbox.pack_start(hbox, false)
879: 
880:         dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
881:         dialog.show_all
882:         self.focus = dialog
883:         dialog.run do |response| 
884:           if response == Dialog::RESPONSE_ACCEPT
885:             @key = key_input.text
886:             type = ALL_TYPES[@type = type_input.active]
887:             content = value_input.text
888:             return @key, type, content
889:           end
890:         end
891:         return
892:       ensure
893:         dialog.destroy
894:       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 955
955:       def ask_for_order
956:         dialog = Dialog.new(
957:           "Give an order criterium for 'x'.",
958:           nil, nil,
959:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
960:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
961:         )
962:         hbox = HBox.new(false, 5)
963: 
964:         hbox.pack_start(Label.new("Order:"), false)
965:         hbox.pack_start(order_input = Entry.new)
966:         order_input.text = @order || 'x'
967:         order_input.width_chars = 60
968: 
969:         hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse'), false)
970: 
971:         dialog.vbox.pack_start(hbox, false)
972: 
973:         dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
974:         dialog.show_all
975:         self.focus = dialog
976:         dialog.run do |response| 
977:           if response == Dialog::RESPONSE_ACCEPT
978:             return @order = order_input.text, reverse_checkbox.active?
979:           end
980:         end
981:         return
982:       ensure
983:         dialog.destroy if dialog
984:       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 812
812:       def create_node(parent, type, content)
813:         iter = if parent
814:           model.append(parent)
815:         else
816:           new_model = Editor.data2model(nil)
817:           toplevel.view_new_model(new_model)
818:           new_model.iter_first
819:         end
820:         iter.type, iter.content = type, content
821:         expand_collapse(parent) if parent
822:         iter
823:       end

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

[Source]

      # File lib/json/editor.rb, line 1028
1028:       def expand_collapse(iter)
1029:         if expanded
1030:           expand_row(iter.path, true)
1031:         else
1032:           collapse_row(iter.path)
1033:         end
1034:       end

Private Instance methods

[Source]

     # File lib/json/editor.rb, line 720
720:       def add_columns
721:         cell = CellRendererPixbuf.new
722:         column = TreeViewColumn.new('Icon', cell,
723:           'pixbuf'      => ICON_COL
724:         )
725:         append_column(column)
726: 
727:         cell = CellRendererText.new
728:         column = TreeViewColumn.new('Type', cell,
729:           'text'      => TYPE_COL
730:         )
731:         append_column(column)
732: 
733:         cell = CellRendererText.new
734:         cell.editable = true
735:         column = TreeViewColumn.new('Content', cell,
736:           'text'       => CONTENT_COL
737:         )
738:         cell.signal_connect(:edited, &method(:cell_edited))
739:         append_column(column)
740:       end

[Source]

     # File lib/json/editor.rb, line 802
802:       def add_popup_menu
803:         menu = PopUpMenu.new(self)
804:         menu.create
805:       end

[Source]

     # File lib/json/editor.rb, line 755
755:       def cell_edited(cell, path, value)
756:         iter = model.get_iter(path)
757:         case iter.type
758:         when 'Key'
759:           unify_key(iter, value)
760:           toplevel.display_status('Key has been changed.')
761:         when 'FalseClass'
762:           value.downcase!
763:           if value == 'true'
764:             iter.type, iter.content = 'TrueClass', 'true'
765:           end
766:         when 'TrueClass'
767:           value.downcase!
768:           if value == 'false'
769:             iter.type, iter.content = 'FalseClass', 'false'
770:           end
771:         when 'Numeric'
772:           iter.content = (Integer(value) rescue Float(value) rescue 0).to_s
773:         when 'String'
774:           iter.content = value
775:         when 'Hash', 'Array'
776:           return
777:         else
778:           fail "Unknown type found in model: #{iter.type}"
779:         end
780:         window.change
781:       end

[Source]

     # File lib/json/editor.rb, line 783
783:       def configure_value(value, type)
784:         value.editable = false
785:         case type
786:         when 'Array', 'Hash'
787:           value.text = ''
788:         when 'TrueClass'
789:           value.text = 'true'
790:         when 'FalseClass'
791:           value.text = 'false'
792:         when 'NilClass'
793:           value.text = 'null'
794:         when 'Numeric', 'String'
795:           value.text ||= ''
796:           value.editable = true
797:         else
798:           raise ArgumentError, "unknown type '#{type}' encountered"
799:         end
800:       end

[Source]

     # File lib/json/editor.rb, line 742
742:       def unify_key(iter, key)
743:         return unless iter.type == 'Key'
744:         parent = iter.parent
745:         if parent.any? { |c| c != iter and c.content == key }
746:           old_key = key
747:           i = 0
748:           begin
749:             key = sprintf("%s.%d", old_key, i += 1)
750:           end while parent.any? { |c| c != iter and c.content == key }
751:         end
752:         iter.content = key
753:       end

[Validate]