| Class | JSONTreeView |
| In: |
lib/json/editor.rb
|
| Parent: | Gtk::TreeView |
This class inherits from Gtk::TreeView, to configure it and to add a lot of behaviour to it.
| expanded | [RW] | Returns true, if nodes are autoexpanding, false otherwise. |
| window | [R] | Returns the MainWindow instance of this JSONTreeView. |
Creates a JSONTreeView instance, the parameter window is a MainWindow instance and used for self delegation.
# 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
Ask for an element to be appended parent.
# File lib/json/editor.rb, line 902
902: def ask_for_element(parent = nil, default_type = nil, value_text = @content)
903: type_input = value_input = nil
904:
905: dialog = Dialog.new(
906: "New element into #{parent ? parent.type : 'root'}",
907: nil, nil,
908: [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
909: [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
910: )
911: hbox = HBox.new(false, 5)
912: hbox.pack_start(Label.new("Type:"), false)
913: hbox.pack_start(type_input = ComboBox.new(true))
914: default_active = 0
915: types = parent ? ALL_TYPES : CONTAINER_TYPES
916: types.each_with_index do |t, i|
917: type_input.append_text(t)
918: if t == default_type
919: default_active = i
920: end
921: end
922: type_input.active = default_active
923: dialog.vbox.pack_start(hbox, false)
924: type_input.signal_connect(:changed) do
925: configure_value(value_input, types[type_input.active])
926: end
927:
928: hbox = HBox.new(false, 5)
929: hbox.pack_start(Label.new("Value:"), false)
930: hbox.pack_start(value_input = Entry.new)
931: value_input.width_chars = 60
932: value_input.text = value_text if value_text
933: configure_value(value_input, types[type_input.active])
934:
935: dialog.vbox.pack_start(hbox, false)
936:
937: dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
938: dialog.show_all
939: self.focus = dialog
940: dialog.run do |response|
941: if response == Dialog::RESPONSE_ACCEPT
942: type = types[type_input.active]
943: @content = case type
944: when 'Numeric'
945: if (t = value_input.text) == 'Infinity'
946: 1 / 0.0
947: else
948: Integer(t) rescue Float(t) rescue 0
949: end
950: else
951: value_input.text
952: end.to_s
953: return type, @content
954: end
955: end
956: return
957: ensure
958: dialog.destroy if dialog
959: end
Ask for a find term to search for in the tree. Returns the term as a string.
# File lib/json/editor.rb, line 997
997: def ask_for_find_term(search = nil)
998: dialog = Dialog.new(
999: "Find a node matching regex in tree.",
1000: nil, nil,
1001: [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
1002: [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
1003: )
1004: hbox = HBox.new(false, 5)
1005:
1006: hbox.pack_start(Label.new("Regex:"), false)
1007: hbox.pack_start(regex_input = Entry.new)
1008: hbox.pack_start(icase_checkbox = CheckButton.new('Icase'), false)
1009: regex_input.width_chars = 60
1010: if search
1011: regex_input.text = search.source
1012: icase_checkbox.active = search.casefold?
1013: end
1014:
1015: dialog.vbox.pack_start(hbox, false)
1016:
1017: dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
1018: dialog.show_all
1019: self.focus = dialog
1020: dialog.run do |response|
1021: if response == Dialog::RESPONSE_ACCEPT
1022: begin
1023: return Regexp.new(regex_input.text, icase_checkbox.active? ? Regexp::IGNORECASE : 0)
1024: rescue => e
1025: Editor.error_dialog(self, "Evaluation of regex /#{regex_input.text}/ failed: #{e}!")
1026: return
1027: end
1028: end
1029: end
1030: return
1031: ensure
1032: dialog.destroy if dialog
1033: end
Ask for a hash key, value pair to be added to the Hash node parent.
# File lib/json/editor.rb, line 831
831: def ask_for_hash_pair(parent)
832: key_input = type_input = value_input = nil
833:
834: dialog = Dialog.new("New (key, value) pair for Hash", nil, nil,
835: [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
836: [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
837: )
838: dialog.width_request = 640
839:
840: hbox = HBox.new(false, 5)
841: hbox.pack_start(Label.new("Key:"), false)
842: hbox.pack_start(key_input = Entry.new)
843: key_input.text = @key || ''
844: dialog.vbox.pack_start(hbox, false)
845: key_input.signal_connect(:activate) do
846: if parent.any? { |c| c.content == key_input.text }
847: toplevel.display_status('Key already exists in Hash!')
848: key_input.text = ''
849: else
850: toplevel.display_status('Key has been changed.')
851: end
852: end
853:
854: hbox = HBox.new(false, 5)
855: hbox.pack_start(Label.new("Type:"), false)
856: hbox.pack_start(type_input = ComboBox.new(true))
857: ALL_TYPES.each { |t| type_input.append_text(t) }
858: type_input.active = @type || 0
859: dialog.vbox.pack_start(hbox, false)
860:
861: type_input.signal_connect(:changed) do
862: value_input.editable = false
863: case ALL_TYPES[type_input.active]
864: when 'Array', 'Hash'
865: value_input.text = ''
866: when 'TrueClass'
867: value_input.text = 'true'
868: when 'FalseClass'
869: value_input.text = 'false'
870: when 'NilClass'
871: value_input.text = 'null'
872: else
873: value_input.text = ''
874: value_input.editable = true
875: end
876: end
877:
878: hbox = HBox.new(false, 5)
879: hbox.pack_start(Label.new("Value:"), false)
880: hbox.pack_start(value_input = Entry.new)
881: value_input.width_chars = 60
882: value_input.text = @value || ''
883: dialog.vbox.pack_start(hbox, false)
884:
885: dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
886: dialog.show_all
887: self.focus = dialog
888: dialog.run do |response|
889: if response == Dialog::RESPONSE_ACCEPT
890: @key = key_input.text
891: type = ALL_TYPES[@type = type_input.active]
892: content = value_input.text
893: return @key, type, content
894: end
895: end
896: return
897: ensure
898: dialog.destroy
899: 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.
# File lib/json/editor.rb, line 964
964: def ask_for_order
965: dialog = Dialog.new(
966: "Give an order criterium for 'x'.",
967: nil, nil,
968: [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
969: [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
970: )
971: hbox = HBox.new(false, 5)
972:
973: hbox.pack_start(Label.new("Order:"), false)
974: hbox.pack_start(order_input = Entry.new)
975: order_input.text = @order || 'x'
976: order_input.width_chars = 60
977:
978: hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse'), false)
979:
980: dialog.vbox.pack_start(hbox, false)
981:
982: dialog.signal_connect('key-press-event''key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
983: dialog.show_all
984: self.focus = dialog
985: dialog.run do |response|
986: if response == Dialog::RESPONSE_ACCEPT
987: return @order = order_input.text, reverse_checkbox.active?
988: end
989: end
990: return
991: ensure
992: dialog.destroy if dialog
993: 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.
# File lib/json/editor.rb, line 817
817: def create_node(parent, type, content)
818: iter = if parent
819: model.append(parent)
820: else
821: new_model = Editor.data2model(nil)
822: toplevel.view_new_model(new_model)
823: new_model.iter_first
824: end
825: iter.type, iter.content = type, content
826: expand_collapse(parent) if parent
827: iter
828: end
Expand or collapse row pointed to by iter according to the expanded attribute.
# File lib/json/editor.rb, line 1037
1037: def expand_collapse(iter)
1038: if expanded
1039: expand_row(iter.path, true)
1040: else
1041: collapse_row(iter.path)
1042: end
1043: end
# 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
# File lib/json/editor.rb, line 807
807: def add_popup_menu
808: menu = PopUpMenu.new(self)
809: menu.create
810: end
# 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 =
773: if value == 'Infinity'
774: value
775: else
776: (Integer(value) rescue Float(value) rescue 0).to_s
777: end
778: when 'String'
779: iter.content = value
780: when 'Hash', 'Array'
781: return
782: else
783: fail "Unknown type found in model: #{iter.type}"
784: end
785: window.change
786: end
# File lib/json/editor.rb, line 788
788: def configure_value(value, type)
789: value.editable = false
790: case type
791: when 'Array', 'Hash'
792: value.text = ''
793: when 'TrueClass'
794: value.text = 'true'
795: when 'FalseClass'
796: value.text = 'false'
797: when 'NilClass'
798: value.text = 'null'
799: when 'Numeric', 'String'
800: value.text ||= ''
801: value.editable = true
802: else
803: raise ArgumentError, "unknown type '#{type}' encountered"
804: end
805: end
# 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