Skip to content

Commit 17681d1

Browse files
committed
Add csv_viewer example
1 parent e6a9fee commit 17681d1

1 file changed

Lines changed: 215 additions & 0 deletions

File tree

examples/gallery/csv_viewer.cr

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
require "../../src/uing"
2+
require "csv"
3+
4+
class CSVViewer
5+
# Constants
6+
WINDOW_WIDTH = 600
7+
WINDOW_HEIGHT = 400
8+
SUPPORTED_EXTENSIONS = %w[.csv .tsv]
9+
10+
# Instance variables
11+
@csv_data = [] of Array(String)
12+
@column_count = 0
13+
@table : UIng::Table
14+
@table_model : UIng::Table::Model
15+
@hbox : UIng::Box
16+
@window : UIng::Window
17+
18+
def initialize
19+
UIng.init
20+
21+
# Initialize UI components directly
22+
@hbox = UIng::Box.new :horizontal
23+
24+
# Create initial table model and table directly in initialize
25+
model_handler = UIng::Table::Model::Handler.new do
26+
num_columns { @column_count > 0 ? @column_count : 1 }
27+
column_type { |column| UIng::Table::Value::Type::String }
28+
num_rows { @csv_data.size }
29+
cell_value do |row, column|
30+
if row < @csv_data.size && column < @csv_data[row].size
31+
UIng::Table::Value.new(@csv_data[row][column])
32+
else
33+
UIng::Table::Value.new("")
34+
end
35+
end
36+
set_cell_value { |row, column, value| }
37+
end
38+
39+
@table_model = UIng::Table::Model.new(model_handler)
40+
41+
@table = UIng::Table.new(@table_model) do
42+
if @column_count > 0
43+
(0...@column_count).each do |i|
44+
append_text_column(generate_column_name(i), i, -1)
45+
end
46+
else
47+
# Default single column if no data loaded yet
48+
append_text_column("A", 0, -1)
49+
end
50+
end
51+
52+
@hbox.append(@table, true)
53+
54+
# Create menu after UI components are initialized
55+
setup_menu
56+
57+
@window = UIng::Window.new("CSV Viewer", WINDOW_WIDTH, WINDOW_HEIGHT, menubar: true)
58+
@window.child = @hbox
59+
end
60+
61+
private def generate_column_name(index : Int32) : String
62+
result = ""
63+
temp = index
64+
while temp >= 0
65+
result = ('A'.ord + (temp % 26)).chr.to_s + result
66+
temp = temp // 26 - 1
67+
end
68+
result
69+
end
70+
71+
private def load_csv_data(filename : String) : Int32
72+
separator = File.extname(filename).downcase == ".tsv" ? '\t' : ','
73+
74+
File.open(filename) do |file|
75+
new_data = CSV.parse(file, separator: separator)
76+
return 0 if new_data.empty?
77+
78+
@csv_data.clear
79+
@csv_data.concat(new_data)
80+
columns = @csv_data.first?.try(&.size) || 0
81+
puts "Loaded file: #{filename} (#{@csv_data.size} rows, #{columns} columns)"
82+
columns
83+
end
84+
rescue ex : Exception
85+
puts "Error loading file: #{ex.message}"
86+
0
87+
end
88+
89+
private def create_table_with_columns(column_count : Int32)
90+
model_handler = UIng::Table::Model::Handler.new do
91+
num_columns { column_count }
92+
column_type { |column| UIng::Table::Value::Type::String }
93+
num_rows { @csv_data.size }
94+
cell_value do |row, column|
95+
if row < @csv_data.size && column < @csv_data[row].size
96+
UIng::Table::Value.new(@csv_data[row][column])
97+
else
98+
UIng::Table::Value.new("")
99+
end
100+
end
101+
set_cell_value { |row, column, value| }
102+
end
103+
104+
@table_model = UIng::Table::Model.new(model_handler)
105+
106+
@table = UIng::Table.new(@table_model) do
107+
(0...column_count).each do |i|
108+
append_text_column(generate_column_name(i), i, -1)
109+
end
110+
end
111+
112+
@hbox.append(@table, true)
113+
end
114+
115+
private def clear_table_data
116+
old_count = @csv_data.size
117+
(old_count - 1).downto(0) do |i|
118+
@table_model.row_deleted(i)
119+
end
120+
end
121+
122+
private def destroy_current_table
123+
@hbox.delete(0)
124+
@table.destroy
125+
@table_model.free
126+
end
127+
128+
private def recreate_table(new_column_count : Int32)
129+
puts "Column count changed from #{@column_count} to #{new_column_count}, recreating table"
130+
131+
destroy_current_table
132+
create_table_with_columns(new_column_count)
133+
134+
puts "Table updated with new data"
135+
end
136+
137+
private def update_existing_table
138+
@csv_data.each_with_index do |_, i|
139+
@table_model.row_inserted(i)
140+
end
141+
142+
puts "Table updated with new data"
143+
end
144+
145+
private def update_table_with_file(filename : String) : Bool
146+
puts "Opening file: #{filename}"
147+
148+
# Clear existing data
149+
clear_table_data
150+
151+
new_column_count = load_csv_data(filename)
152+
return false if new_column_count == 0
153+
154+
if new_column_count != @column_count && new_column_count > 0
155+
recreate_table(new_column_count)
156+
else
157+
update_existing_table
158+
end
159+
160+
@column_count = new_column_count
161+
true
162+
end
163+
164+
private def setup_menu
165+
UIng::Menu.new("File") do
166+
append_item("Open").on_clicked do |w|
167+
if filename = w.open_file
168+
update_table_with_file(filename)
169+
end
170+
end
171+
append_separator
172+
append_quit_item
173+
end
174+
end
175+
176+
private def setup_initial_data
177+
return unless ARGV.size > 0
178+
179+
filename = ARGV[0]
180+
return unless File.exists?(filename)
181+
182+
extension = File.extname(filename).downcase
183+
if SUPPORTED_EXTENSIONS.includes?(extension)
184+
update_table_with_file(filename)
185+
else
186+
puts "Error: File must have #{SUPPORTED_EXTENSIONS.join(" or ")} extension"
187+
end
188+
end
189+
190+
# Clean up resources
191+
private def cleanup
192+
@hbox.delete(0)
193+
@table.destroy
194+
@table_model.free
195+
UIng.quit
196+
end
197+
198+
# Main application loop
199+
def run
200+
setup_initial_data
201+
202+
@window.on_closing do
203+
cleanup
204+
true
205+
end
206+
207+
@window.show
208+
UIng.main
209+
ensure
210+
UIng.uninit
211+
end
212+
end
213+
214+
viewer = CSVViewer.new
215+
viewer.run

0 commit comments

Comments
 (0)