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 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.
# 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.
# 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.
# 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.
# 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.
# 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
# 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 802 802: def add_popup_menu 803: menu = PopUpMenu.new(self) 804: menu.create 805: 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 = (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
# 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
# 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