Class JSON::Editor::JSONTreeView
In: lib/json/editor.rb
Parent: Gtk::TreeView
StringScanner Parser JSONTreeView MainWindow Gtk::TreeView OptionsMenu EditMenu PopUpMenu FileMenu Gtk::Window Enumerable TreeIter Gtk State lib/json.rb lib/json/editor.rb MenuExtension lib/json/editor.rb Gtk Editor JSON Module: JSON

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 647
647:       def initialize(window)
648:         @window = window
649:         super(TreeStore.new(Gdk::Pixbuf, String, String))
650:         self.selection.mode = SELECTION_BROWSE
651: 
652:         @expanded = false
653:         self.headers_visible = false
654:         add_columns
655:         add_popup_menu
656:       end

Public Instance methods

Ask for an element to be appended parent.

[Source]

     # File lib/json/editor.rb, line 839
839:       def ask_for_element(parent = nil, default_type = nil, value_text = @content)
840:         type_input = value_input = nil
841: 
842:         dialog = Dialog.new(
843:           "New element into #{parent ? parent.type : 'root'}",
844:           nil, nil,
845:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
846:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
847:         )
848:         hbox = HBox.new(false, 5)
849:         hbox.add(Label.new("Type:"))
850:         hbox.pack_start(type_input = ComboBox.new(true))
851:         default_active = 0
852:         ALL_TYPES.each_with_index do |t, i|
853:           type_input.append_text(t)
854:           if t == default_type
855:             default_active = i
856:           end
857:         end
858:         type_input.active = default_active
859:         dialog.vbox.add(hbox)
860:         type_input.signal_connect(:changed) do
861:           configure_value(value_input, ALL_TYPES[type_input.active])
862:         end
863: 
864:         hbox = HBox.new(false, 5)
865:         hbox.add(Label.new("Value:"))
866:         hbox.pack_start(value_input = Entry.new)
867:         value_input.text = value_text if value_text
868:         configure_value(value_input, ALL_TYPES[type_input.active])
869: 
870:         dialog.vbox.add(hbox)
871: 
872:         dialog.show_all
873:         dialog.run do |response| 
874:           if response == Dialog::RESPONSE_ACCEPT
875:             type = ALL_TYPES[type_input.active]
876:             @content = case type
877:             when 'Numeric'
878:               Integer(value_input.text) rescue Float(value_input.text) rescue 0
879:             else
880:               value_input.text
881:             end.to_s
882:             return type, @content
883:           end
884:         end
885:         return
886:       ensure
887:         dialog.destroy if dialog
888:       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 923
923:       def ask_for_find_term
924:         dialog = Dialog.new(
925:           "Find a node matching regex in tree.",
926:           nil, nil,
927:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
928:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
929:         )
930:         hbox = HBox.new(false, 5)
931: 
932:         hbox.add(Label.new("Regex:"))
933:         hbox.pack_start(regex_input = Entry.new)
934:         regex_input.text = @regex || ''
935: 
936:         dialog.vbox.add(hbox)
937: 
938:         dialog.show_all
939:         dialog.run do |response| 
940:           if response == Dialog::RESPONSE_ACCEPT
941:             return @regex = regex_input.text
942:           end
943:         end
944:         return
945:       ensure
946:         dialog.destroy if dialog
947:       end

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

[Source]

     # File lib/json/editor.rb, line 772
772:       def ask_for_hash_pair(parent)
773:         key_input = type_input = value_input = nil
774: 
775:         dialog = Dialog.new("New (key, value) pair for Hash", nil, nil,
776:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
777:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
778:         )
779: 
780:         hbox = HBox.new(false, 5)
781:         hbox.pack_start(Label.new("Key:"))
782:         hbox.pack_start(key_input = Entry.new)
783:         key_input.text = @key || ''
784:         dialog.vbox.add(hbox)
785:         key_input.signal_connect(:activate) do
786:           if parent.any? { |c| c.content == key_input.text }
787:             toplevel.display_status('Key already exists in Hash!')
788:             key_input.text = ''
789:           else
790:             toplevel.display_status('Key has been changed.')
791:           end
792:         end
793: 
794:         hbox = HBox.new(false, 5)
795:         hbox.add(Label.new("Type:"))
796:         hbox.pack_start(type_input = ComboBox.new(true))
797:         ALL_TYPES.each { |t| type_input.append_text(t) }
798:         type_input.active = @type || 0
799:         dialog.vbox.add(hbox)
800: 
801:         type_input.signal_connect(:changed) do
802:           value_input.editable = false
803:           case ALL_TYPES[type_input.active]
804:           when 'Array', 'Hash'
805:             value_input.text = ''
806:           when 'TrueClass'
807:             value_input.text = 'true'
808:           when 'FalseClass'
809:             value_input.text = 'false'
810:           when 'NilClass'
811:             value_input.text = 'null'
812:           else
813:             value_input.text = ''
814:             value_input.editable = true
815:           end
816:         end
817: 
818:         hbox = HBox.new(false, 5)
819:         hbox.add(Label.new("Value:"))
820:         hbox.pack_start(value_input = Entry.new)
821:         value_input.text = @value || ''
822:         dialog.vbox.add(hbox)
823: 
824:         dialog.show_all
825:         dialog.run do |response| 
826:           if response == Dialog::RESPONSE_ACCEPT
827:             @key = key_input.text
828:             type = ALL_TYPES[@type = type_input.active]
829:             content = value_input.text
830:             return @key, type, content
831:           end
832:         end
833:         return
834:       ensure
835:         dialog.destroy
836:       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 893
893:       def ask_for_order
894:         dialog = Dialog.new(
895:           "Give an order criterium for 'x'.",
896:           nil, nil,
897:           [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
898:           [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
899:         )
900:         hbox = HBox.new(false, 5)
901: 
902:         hbox.add(Label.new("Order:"))
903:         hbox.pack_start(order_input = Entry.new)
904:         order_input.text = @order || 'x'
905: 
906:         hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse'))
907: 
908:         dialog.vbox.add(hbox)
909: 
910:         dialog.show_all
911:         dialog.run do |response| 
912:           if response == Dialog::RESPONSE_ACCEPT
913:             return @order = order_input.text, reverse_checkbox.active?
914:           end
915:         end
916:         return
917:       ensure
918:         dialog.destroy if dialog
919:       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 758
758:       def create_node(parent, type, content)
759:         iter = if parent
760:           model.append(parent)
761:         else
762:           new_model = Editor.data2model(nil)
763:           toplevel.view_new_model(new_model)
764:           new_model.iter_first
765:         end
766:         iter.type, iter.content = type, content
767:         expand_collapse(parent) if parent
768:         iter
769:       end

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

[Source]

     # File lib/json/editor.rb, line 951
951:       def expand_collapse(iter)
952:         if expanded
953:           expand_row(iter.path, true)
954:         else
955:           collapse_row(iter.path)
956:         end
957:       end

Private Instance methods

[Source]

     # File lib/json/editor.rb, line 666
666:       def add_columns
667:         cell = CellRendererPixbuf.new
668:         column = TreeViewColumn.new('Icon', cell,
669:           'pixbuf'      => ICON_COL
670:         )
671:         append_column(column)
672: 
673:         cell = CellRendererText.new
674:         column = TreeViewColumn.new('Type', cell,
675:           'text'      => TYPE_COL
676:         )
677:         append_column(column)
678: 
679:         cell = CellRendererText.new
680:         cell.editable = true
681:         column = TreeViewColumn.new('Content', cell,
682:           'text'       => CONTENT_COL
683:         )
684:         cell.signal_connect(:edited, &method(:cell_edited))
685:         append_column(column)
686:       end

[Source]

     # File lib/json/editor.rb, line 748
748:       def add_popup_menu
749:         menu = PopUpMenu.new(self)
750:         menu.create
751:       end

[Source]

     # File lib/json/editor.rb, line 701
701:       def cell_edited(cell, path, value)
702:         iter = model.get_iter(path)
703:         case iter.type
704:         when 'Key'
705:           unify_key(iter, value)
706:           toplevel.display_status('Key has been changed.')
707:         when 'FalseClass'
708:           value.downcase!
709:           if value == 'true'
710:             iter.type, iter.content = 'TrueClass', 'true'
711:           end
712:         when 'TrueClass'
713:           value.downcase!
714:           if value == 'false'
715:             iter.type, iter.content = 'FalseClass', 'false'
716:           end
717:         when 'Numeric'
718:           iter.content = (Integer(value) rescue Float(value) rescue 0).to_s
719:         when 'String'
720:           iter.content = value
721:         when 'Hash', 'Array'
722:           return
723:         else
724:           fail "Unknown type found in model: #{iter.type}"
725:         end
726:         window.change
727:       end

[Source]

     # File lib/json/editor.rb, line 729
729:       def configure_value(value, type)
730:         value.editable = false
731:         case type
732:         when 'Array', 'Hash'
733:           value.text = ''
734:         when 'TrueClass'
735:           value.text = 'true'
736:         when 'FalseClass'
737:           value.text = 'false'
738:         when 'NilClass'
739:           value.text = 'null'
740:         when 'Numeric', 'String'
741:           value.text ||= ''
742:           value.editable = true
743:         else
744:           raise ArgumentError, "unknown type '#{type}' encountered"
745:         end
746:       end

[Source]

     # File lib/json/editor.rb, line 688
688:       def unify_key(iter, key)
689:         return unless iter.type == 'Key'
690:         parent = iter.parent
691:         if parent.any? { |c| c != iter and c.content == key }
692:           old_key = key
693:           i = 0
694:           begin
695:             key = sprintf("%s.%d", old_key, i += 1)
696:           end while parent.any? { |c| c != iter and c.content == key }
697:         end
698:         iter.content = key
699:       end

[Validate]