weft-qda 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/weft.rb +21 -0
- data/lib/weft/WEFT-VERSION-STRING.rb +1 -0
- data/lib/weft/application.rb +130 -0
- data/lib/weft/backend.rb +39 -0
- data/lib/weft/backend/marshal.rb +26 -0
- data/lib/weft/backend/mysql.rb +267 -0
- data/lib/weft/backend/n6.rb +366 -0
- data/lib/weft/backend/sqlite.rb +633 -0
- data/lib/weft/backend/sqlite/category_tree.rb +104 -0
- data/lib/weft/backend/sqlite/schema.rb +152 -0
- data/lib/weft/backend/sqlite/upgradeable.rb +55 -0
- data/lib/weft/category.rb +157 -0
- data/lib/weft/coding.rb +355 -0
- data/lib/weft/document.rb +118 -0
- data/lib/weft/filters.rb +243 -0
- data/lib/weft/wxgui.rb +687 -0
- data/lib/weft/wxgui/category.xpm +26 -0
- data/lib/weft/wxgui/dialogs.rb +128 -0
- data/lib/weft/wxgui/document.xpm +25 -0
- data/lib/weft/wxgui/error_handler.rb +52 -0
- data/lib/weft/wxgui/inspectors.rb +361 -0
- data/lib/weft/wxgui/inspectors/category.rb +165 -0
- data/lib/weft/wxgui/inspectors/codereview.rb +275 -0
- data/lib/weft/wxgui/inspectors/document.rb +139 -0
- data/lib/weft/wxgui/inspectors/imagedocument.rb +56 -0
- data/lib/weft/wxgui/inspectors/script.rb +35 -0
- data/lib/weft/wxgui/inspectors/search.rb +265 -0
- data/lib/weft/wxgui/inspectors/textcontrols.rb +304 -0
- data/lib/weft/wxgui/lang.rb +17 -0
- data/lib/weft/wxgui/lang/en.rb +45 -0
- data/lib/weft/wxgui/mondrian.xpm +44 -0
- data/lib/weft/wxgui/search.xpm +25 -0
- data/lib/weft/wxgui/sidebar.rb +498 -0
- data/lib/weft/wxgui/utilities.rb +148 -0
- data/lib/weft/wxgui/weft16.xpm +31 -0
- data/lib/weft/wxgui/workarea.rb +249 -0
- data/test/001-document.rb +196 -0
- data/test/002-category.rb +138 -0
- data/test/003-code.rb +370 -0
- data/test/004-application.rb +52 -0
- data/test/006-filters.rb +139 -0
- data/test/009a-backend_sqlite_basic.rb +280 -0
- data/test/009b-backend_sqlite_complex.rb +175 -0
- data/test/009c_backend_sqlite_bench.rb +81 -0
- data/test/010-backend_nudist.rb +5 -0
- data/test/all-tests.rb +1 -0
- data/test/manual-gui-script.txt +24 -0
- data/test/testdata/autocoding-test.txt +15 -0
- data/test/testdata/iso-8859-1.txt +5 -0
- data/test/testdata/sample_doc.txt +19 -0
- data/test/testdata/search_results.txt +1254 -0
- data/test/testdata/text1-dos-ascii.txt +2 -0
- data/test/testdata/text1-unix-utf8.txt +2 -0
- data/weft-qda.rb +28 -0
- metadata +96 -0
@@ -0,0 +1,165 @@
|
|
1
|
+
module QDA
|
2
|
+
module GUI
|
3
|
+
class CategoryWindow < InspectorWindow
|
4
|
+
include Subscriber
|
5
|
+
|
6
|
+
def initialize(cat, app, workarea, layout)
|
7
|
+
@cat = cat
|
8
|
+
@app = app
|
9
|
+
|
10
|
+
super(workarea, @cat.name, layout) do | parent |
|
11
|
+
text_box = CompositeText.new(parent, '', 0, @app)
|
12
|
+
text_box.populate( @app.app.get_text_at_category(@cat) )
|
13
|
+
text_box
|
14
|
+
end
|
15
|
+
|
16
|
+
construct_details_panel()
|
17
|
+
if ! @cat.children.empty?
|
18
|
+
construct_explore_panel()
|
19
|
+
end
|
20
|
+
|
21
|
+
@notebook.evt_notebook_page_changing(@notebook.get_id) do | e |
|
22
|
+
on_change_page(e)
|
23
|
+
end
|
24
|
+
|
25
|
+
set_icon( app.fetch_icon("category.xpm") )
|
26
|
+
|
27
|
+
subscribe(:document_deleted, :category_changed, :category_deleted)
|
28
|
+
end
|
29
|
+
|
30
|
+
# just a mucky method to reduce the length of the initializer -
|
31
|
+
# ideally i guess this would be done using XRC
|
32
|
+
def construct_details_panel()
|
33
|
+
panel2 = Wx::Panel.new(@notebook, -1)
|
34
|
+
sizer2 = Wx::BoxSizer.new(Wx::VERTICAL)
|
35
|
+
|
36
|
+
# the text entry box for the category's name
|
37
|
+
name_box_label = Wx::StaticBox.new(panel2, -1, 'Name')
|
38
|
+
name_box_sizer = Wx::StaticBoxSizer.new(name_box_label,
|
39
|
+
Wx::VERTICAL)
|
40
|
+
@name_field = Wx::TextCtrl.new(panel2, -1, @cat.name)
|
41
|
+
name_box_sizer.add(@name_field, 0,
|
42
|
+
Wx::ADJUST_MINSIZE|Wx::ALL|Wx::GROW, 4)
|
43
|
+
sizer2.add(name_box_sizer,0, Wx::ADJUST_MINSIZE|Wx::ALL|Wx::GROW, 4)
|
44
|
+
|
45
|
+
# Create the statistics panel
|
46
|
+
info_panel = Wx::Panel.new(panel2, -1)
|
47
|
+
info_box_label = Wx::StaticBox.new(info_panel, -1, 'Statistics')
|
48
|
+
info_box_sizer = Wx::StaticBoxSizer.new(info_box_label,
|
49
|
+
Wx::VERTICAL)
|
50
|
+
|
51
|
+
info_sizer = Wx::FlexGridSizer.new(3, 2, 5, 6)
|
52
|
+
info_sizer.add( Wx::StaticText.new(info_panel, -1, 'Documents:') )
|
53
|
+
@num_docs_label = Wx::StaticText.new(info_panel, -1,
|
54
|
+
@cat.num_of_docs.to_s)
|
55
|
+
info_sizer.add( @num_docs_label )
|
56
|
+
|
57
|
+
info_sizer.add( Wx::StaticText.new(info_panel, -1, 'Passages:') )
|
58
|
+
@num_codes_label = Wx::StaticText.new(info_panel, -1,
|
59
|
+
@cat.num_of_codes.to_s)
|
60
|
+
info_sizer.add( @num_codes_label )
|
61
|
+
|
62
|
+
info_sizer.add( Wx::StaticText.new(info_panel, -1, 'Characters:') )
|
63
|
+
|
64
|
+
@num_chars_label = Wx::StaticText.new(info_panel, -1,
|
65
|
+
@cat.num_of_chars.to_s)
|
66
|
+
info_sizer.add(@num_chars_label)
|
67
|
+
info_box_sizer.add(info_sizer, 0,
|
68
|
+
Wx::GROW|Wx::ADJUST_MINSIZE|Wx::ALL, 4)
|
69
|
+
info_panel.set_sizer(info_box_sizer)
|
70
|
+
sizer2.add(info_panel, 0, Wx::GROW|Wx::ADJUST_MINSIZE|Wx::ALL, 2)
|
71
|
+
|
72
|
+
|
73
|
+
memo_label = Wx::StaticBox.new(panel2, -1, 'Memo')
|
74
|
+
memo_sizer = Wx::StaticBoxSizer.new(memo_label, Wx::VERTICAL)
|
75
|
+
|
76
|
+
@memo_box = Wx::TextCtrl.new(panel2, -1, @cat.memo,
|
77
|
+
Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE,
|
78
|
+
Wx::TE_MULTILINE|Wx::TE_NOHIDESEL)
|
79
|
+
|
80
|
+
@memo_box.evt_enter_window do | e |
|
81
|
+
set_cursor Wx::Cursor.new(Wx::CURSOR_IBEAM)
|
82
|
+
end
|
83
|
+
|
84
|
+
@memo_box.evt_leave_window do | e |
|
85
|
+
set_cursor Wx::Cursor.new(Wx::CURSOR_ARROW)
|
86
|
+
end
|
87
|
+
memo_sizer.add(@memo_box, 10, Wx::GROW|Wx::ALL|Wx::ADJUST_MINSIZE, 4)
|
88
|
+
sizer2.add(memo_sizer, 1, Wx::GROW|Wx::ADJUST_MINSIZE, 4)
|
89
|
+
|
90
|
+
|
91
|
+
button = Wx::Button.new(panel2, -1, 'Apply')
|
92
|
+
button.evt_button(button.get_id) { | e | on_save_memo(e) }
|
93
|
+
sizer2.add(button, 0, Wx::ALL|Wx::ALIGN_RIGHT|Wx::ADJUST_MINSIZE, 4)
|
94
|
+
panel2.set_sizer( sizer2 )
|
95
|
+
|
96
|
+
|
97
|
+
@notebook.add_page(panel2, 'details')
|
98
|
+
end
|
99
|
+
|
100
|
+
# cf construct_details_panel
|
101
|
+
def construct_explore_panel()
|
102
|
+
panel = Wx::Panel.new(@notebook, -1)
|
103
|
+
# panel.set_font(GLOBAL_FONT)
|
104
|
+
sizer = Wx::BoxSizer.new(Wx::VERTICAL)
|
105
|
+
# create a local locked copy
|
106
|
+
@tree_list = CategoryTree.new(@app, panel, true)
|
107
|
+
@tree_list.populate([@cat])
|
108
|
+
sizer.add(@tree_list, 10, Wx::GROW|Wx::ALL, 4)
|
109
|
+
panel.set_sizer( sizer )
|
110
|
+
@notebook.add_page(panel, 'explore')
|
111
|
+
end
|
112
|
+
|
113
|
+
def on_save_memo(e)
|
114
|
+
@cat.memo = @memo_box.value
|
115
|
+
@cat.name = @name_field.value
|
116
|
+
Wx::BusyCursor.busy { @app.app.save_category( @cat ) }
|
117
|
+
$wxapp.broadcast(:category_changed, @cat)
|
118
|
+
end
|
119
|
+
|
120
|
+
def on_change_page(e)
|
121
|
+
# relying on the fact we've only got two tabs - so if the
|
122
|
+
# previously selected is 0 (The first page) we should update
|
123
|
+
# the stats as we're going to that page
|
124
|
+
if e.get_selection == 0
|
125
|
+
update_stats()
|
126
|
+
end
|
127
|
+
e.allow()
|
128
|
+
end
|
129
|
+
|
130
|
+
def update_stats()
|
131
|
+
@num_docs_label.set_label( @cat.num_of_docs.to_s )
|
132
|
+
@num_codes_label.set_label( @cat.num_of_codes.to_s )
|
133
|
+
@num_chars_label.set_label( @cat.num_of_chars.to_s )
|
134
|
+
end
|
135
|
+
|
136
|
+
# updates the display from teh currently stored value for @cat,
|
137
|
+
# and refetches the displayed text from the database
|
138
|
+
def refresh()
|
139
|
+
set_title( @cat.name )
|
140
|
+
@text_box.value = ''
|
141
|
+
@text_box.populate( @app.app.get_text_at_category(@cat) )
|
142
|
+
@name_field.value = @cat.name
|
143
|
+
if curr_category = @drop_down.current_category()
|
144
|
+
@text_box.highlight_codingtable(curr_category.codes)
|
145
|
+
end
|
146
|
+
update_stats()
|
147
|
+
end
|
148
|
+
|
149
|
+
def receive_category_changed(category)
|
150
|
+
if category.dbid == @cat.dbid
|
151
|
+
@cat = category
|
152
|
+
refresh()
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def receive_category_deleted(category)
|
157
|
+
close() if category.dbid == @cat.dbid
|
158
|
+
end
|
159
|
+
|
160
|
+
def receive_document_deleted(doc)
|
161
|
+
refresh if @cat.codes.codes?(doc)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
module QDA::GUI
|
2
|
+
class CodeReviewWindow < WorkAreaWindow
|
3
|
+
include Subscriber
|
4
|
+
|
5
|
+
W_WINDOW_DEF_SIZE = [ 0.8, 0.6 ]
|
6
|
+
BASE_COLOUR = Wx::Colour.new(255, 255, 255)
|
7
|
+
HIGHLIGHT_COLOUR = Wx::Colour.new(255, 0, 0)
|
8
|
+
GRID_COLOUR = Wx::Colour.new(223, 223, 233)
|
9
|
+
|
10
|
+
def initialize(obj, app, workarea, layout)
|
11
|
+
super(workarea, "Code Review #{obj.dbid}", nil)
|
12
|
+
@cols, @rows, @contents = [], [], []
|
13
|
+
@count_method = :num_of_docs
|
14
|
+
|
15
|
+
main_sizer = Wx::BoxSizer.new(Wx::VERTICAL)
|
16
|
+
panel = Wx::Panel.new(self)
|
17
|
+
@grid = Wx::Grid.new(panel, -1, Wx::DEFAULT_POSITION,
|
18
|
+
Wx::DEFAULT_SIZE, Wx::SIMPLE_BORDER)
|
19
|
+
@grid.create_grid( 12, 6 )
|
20
|
+
@grid.set_row_label_size(160)
|
21
|
+
@grid.set_grid_line_colour(GRID_COLOUR)
|
22
|
+
@grid.enable_editing(false)
|
23
|
+
0.upto(5) { | i | @grid.set_col_label_value(i, '') }
|
24
|
+
0.upto(11) { | i | @grid.set_row_label_value(i, '') }
|
25
|
+
|
26
|
+
evt_grid_label_left_click() { | evt | on_label_clicked(evt) }
|
27
|
+
|
28
|
+
# the controls panel
|
29
|
+
main_sizer.add(@grid, 1, Wx::GROW|Wx::ALL, 4)
|
30
|
+
# butt_panel = Wx::Panel.new(panel, -1)
|
31
|
+
butt_box_label = Wx::StaticBox.new(panel, -1, 'Select categories')
|
32
|
+
bott_sizer = Wx::StaticBoxSizer.new(butt_box_label,
|
33
|
+
Wx::HORIZONTAL)
|
34
|
+
|
35
|
+
@drop_down = CategoryDropDown.new(app, panel)
|
36
|
+
bott_sizer.add(@drop_down, 3, Wx::ALL, 4)
|
37
|
+
|
38
|
+
button = Wx::Button.new(panel, -1, 'Add as row')
|
39
|
+
button.evt_button(button.get_id) { | e | on_add_row(e) }
|
40
|
+
bott_sizer.add(button, 1, Wx::ALL, 4)
|
41
|
+
|
42
|
+
button = Wx::Button.new(panel, -1, 'Add as column')
|
43
|
+
button.evt_button(button.get_id) { | e | on_add_col(e) }
|
44
|
+
bott_sizer.add(button, 1, Wx::ALL, 4)
|
45
|
+
|
46
|
+
button = Wx::Button.new(panel, -1, 'Remove')
|
47
|
+
button.evt_button(button.get_id) { | e | on_remove(e) }
|
48
|
+
bott_sizer.add(button, 1, Wx::ALL, 4)
|
49
|
+
|
50
|
+
# button = Wx::Button.new(butt_panel, -1, 'Remove column')
|
51
|
+
# button.evt_button(button.get_id) { | e | on_remove_col(e) }
|
52
|
+
# bott_sizer.add(button, 1, Wx::ALL, 4)
|
53
|
+
|
54
|
+
# butt_panel.set_sizer(bott_sizer)
|
55
|
+
main_sizer.add(bott_sizer, 0,
|
56
|
+
Wx::GROW|Wx::ADJUST_MINSIZE|Wx::ALL, 4)
|
57
|
+
|
58
|
+
# the numbers row
|
59
|
+
num_box_label = Wx::StaticBox.new(panel, -1,
|
60
|
+
Lang::DISPLAY_OPTIONS_LABEL)
|
61
|
+
num_sizer = Wx::StaticBoxSizer.new(num_box_label,
|
62
|
+
Wx::HORIZONTAL)
|
63
|
+
|
64
|
+
# num_cbox = Wx::CheckBox.new(num_panel, -1, 'Show numbers')
|
65
|
+
num_sizer.add( Wx::StaticText.new(panel, -1, 'Count what?'),
|
66
|
+
0, Wx::ALL|Wx::ALIGN_RIGHT, 4)
|
67
|
+
@num_list = Wx::Choice.new(panel, -1)
|
68
|
+
@num_list.append('Number of documents')
|
69
|
+
@num_list.append('Number of passages')
|
70
|
+
@num_list.append('Number of characters')
|
71
|
+
@num_list.selection = 0
|
72
|
+
evt_choice( @num_list.get_id() ) { | e | on_change_method(e) }
|
73
|
+
num_sizer.add(@num_list, 0, Wx::ALL, 4)
|
74
|
+
|
75
|
+
main_sizer.add( num_sizer, 0,
|
76
|
+
Wx::GROW|Wx::ADJUST_MINSIZE|Wx::ALL,
|
77
|
+
4)
|
78
|
+
|
79
|
+
panel.set_sizer(main_sizer)
|
80
|
+
main_sizer.set_size_hints(panel)
|
81
|
+
|
82
|
+
subscribe(:category_deleted, :category_changed)
|
83
|
+
end
|
84
|
+
|
85
|
+
def associated_subscribers()
|
86
|
+
[ @drop_down ]
|
87
|
+
end
|
88
|
+
|
89
|
+
# set the currently highlighted row or column as the current item
|
90
|
+
# in the dropdown
|
91
|
+
def on_label_clicked(e)
|
92
|
+
if row = e.row and row >= 0 and @rows[row]
|
93
|
+
@drop_down.receive_focus_category( @rows[row] )
|
94
|
+
end
|
95
|
+
if col = e.col and col >= 0 and @cols[col]
|
96
|
+
@drop_down.receive_focus_category( @cols[col] )
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
METHOD_MAPPING = {
|
101
|
+
'Number of documents' => :num_of_docs,
|
102
|
+
'Number of passages' => :num_of_codes,
|
103
|
+
'Number of characters' => :num_of_chars }
|
104
|
+
|
105
|
+
def on_change_method(e)
|
106
|
+
sel = @num_list.get_string_selection()
|
107
|
+
method = METHOD_MAPPING[ sel ]
|
108
|
+
unless method
|
109
|
+
raise RuntimeError.new("Unexpected selection #{sel}")
|
110
|
+
end
|
111
|
+
self.count_method = method
|
112
|
+
end
|
113
|
+
|
114
|
+
def count_method=(method)
|
115
|
+
if method != @count_method
|
116
|
+
@count_method = method
|
117
|
+
0.upto(@rows.length - 1) { | i | calculate_row(i) }
|
118
|
+
recolour_table()
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def on_add_col(e)
|
123
|
+
category = @drop_down.current_category
|
124
|
+
return false unless category
|
125
|
+
return false if @cols.include?(category)
|
126
|
+
|
127
|
+
@cols.push(category)
|
128
|
+
@grid.append_cols(1) if @cols.length > @grid.number_cols
|
129
|
+
col = @cols.length - 1
|
130
|
+
|
131
|
+
@grid.set_col_label_value( col, category.name )
|
132
|
+
# @grid.set_col_format_number( col )
|
133
|
+
calculate_col(col)
|
134
|
+
recolour_table()
|
135
|
+
end
|
136
|
+
|
137
|
+
def calculate_col(i)
|
138
|
+
col = @cols[i]
|
139
|
+
@rows.each_with_index do | row_cat, j |
|
140
|
+
@contents[j][i] = row_cat.codes.dup.join(col.codes)
|
141
|
+
update_cell(j, i)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def on_add_row(e)
|
146
|
+
category = @drop_down.current_category
|
147
|
+
return false unless category
|
148
|
+
# don't add twice
|
149
|
+
return false if @rows.include?(category)
|
150
|
+
|
151
|
+
@rows.push(category)
|
152
|
+
@grid.append_rows(1) if @rows.length > @grid.number_rows
|
153
|
+
row = @rows.length - 1
|
154
|
+
|
155
|
+
@grid.set_row_label_value( row, category.name )
|
156
|
+
@contents[row] = []
|
157
|
+
# @grid.set_row_format_number( row )
|
158
|
+
calculate_row(row)
|
159
|
+
recolour_table()
|
160
|
+
end
|
161
|
+
|
162
|
+
def calculate_row(i)
|
163
|
+
row = @rows[i]
|
164
|
+
@cols.each_with_index do | col_cat, j |
|
165
|
+
@contents[i][j] = col_cat.codes.dup.join(row.codes)
|
166
|
+
update_cell(i, j)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# removes the selected category from both rows and colums
|
171
|
+
def on_remove(e)
|
172
|
+
on_remove_col(e)
|
173
|
+
on_remove_row(e)
|
174
|
+
end
|
175
|
+
|
176
|
+
def on_remove_col(e)
|
177
|
+
category = @drop_down.current_category
|
178
|
+
return false unless category
|
179
|
+
return false unless idx = @cols.index(category)
|
180
|
+
remove_col(idx)
|
181
|
+
recolour_table()
|
182
|
+
end
|
183
|
+
|
184
|
+
def remove_col(idx)
|
185
|
+
@cols.delete_at(idx)
|
186
|
+
@contents.each { | row | row.delete_at(idx) }
|
187
|
+
@grid.delete_cols(idx, 1)
|
188
|
+
@grid.append_cols(1)
|
189
|
+
update_col_labels()
|
190
|
+
end
|
191
|
+
|
192
|
+
def on_remove_row(e)
|
193
|
+
category = @drop_down.current_category
|
194
|
+
return false unless category
|
195
|
+
return false unless idx = @rows.index(category)
|
196
|
+
remove_row(idx)
|
197
|
+
recolour_table()
|
198
|
+
end
|
199
|
+
|
200
|
+
def remove_row(idx)
|
201
|
+
@rows.delete_at(idx)
|
202
|
+
@contents.delete_at(idx)
|
203
|
+
@grid.delete_rows(idx, 1)
|
204
|
+
@grid.append_rows(1)
|
205
|
+
update_row_labels()
|
206
|
+
end
|
207
|
+
|
208
|
+
def update_cell(x, y)
|
209
|
+
content = @contents[x][y].send(@count_method)
|
210
|
+
@grid.set_cell_value( x, y, content.to_s )
|
211
|
+
end
|
212
|
+
|
213
|
+
def update_col_labels()
|
214
|
+
@cols.each_with_index do | c, i |
|
215
|
+
@grid.set_col_label_value(i, c.name)
|
216
|
+
end
|
217
|
+
# check if we need to clean up deleted and now empty row labels
|
218
|
+
# at the end - Wx 2.4.2 doesn't seem to do this automatically
|
219
|
+
@grid.set_col_label_value(@cols.length, '')
|
220
|
+
return if @cols.length == @grid.number_cols()
|
221
|
+
for empty in ( @cols.length ... @grid.number_cols() )
|
222
|
+
@grid.set_col_label_value(empty, '')
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def update_row_labels()
|
227
|
+
@rows.each_with_index do | c, i |
|
228
|
+
@grid.set_row_label_value(i, c.name)
|
229
|
+
end
|
230
|
+
# check if we need to clean up deleted and now empty row labels
|
231
|
+
# at the end - Wx 2.4.2 doesn't seem to do this automatically
|
232
|
+
return if @rows.length == @grid.number_rows()
|
233
|
+
for empty in ( @rows.length ... @grid.number_rows() )
|
234
|
+
@grid.set_row_label_value(empty, '')
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def recolour_table()
|
239
|
+
max = @contents.flatten.collect { | x | x.send(@count_method) }.max
|
240
|
+
@contents.each_with_index do | row_items, row |
|
241
|
+
row_items.each_with_index do | code_table, col |
|
242
|
+
clr = BASE_COLOUR.mix( HIGHLIGHT_COLOUR,
|
243
|
+
max, code_table.send(@count_method))
|
244
|
+
@grid.set_cell_background_colour(row, col, clr)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def receive_category_changed(cat)
|
250
|
+
if idx = @cols.index(cat)
|
251
|
+
@cols[idx] = cat
|
252
|
+
calculate_col(idx)
|
253
|
+
end
|
254
|
+
|
255
|
+
if idx = @rows.index(cat)
|
256
|
+
@rows[idx] = cat
|
257
|
+
calculate_row(idx)
|
258
|
+
end
|
259
|
+
|
260
|
+
recolour_table()
|
261
|
+
end
|
262
|
+
|
263
|
+
def receive_category_deleted(cat)
|
264
|
+
if idx = @cols.index(cat)
|
265
|
+
remove_col(idx)
|
266
|
+
end
|
267
|
+
|
268
|
+
if idx = @rows.index(cat)
|
269
|
+
remove_row(idx)
|
270
|
+
end
|
271
|
+
|
272
|
+
recolour_table()
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
|
2
|
+
module QDA
|
3
|
+
module GUI
|
4
|
+
class DocumentWindow < InspectorWindow
|
5
|
+
include Subscriber
|
6
|
+
|
7
|
+
def initialize(doc, app, workarea, layout)
|
8
|
+
@doc = doc
|
9
|
+
@app = app
|
10
|
+
|
11
|
+
super(workarea, doc.title, layout) do | txt_parent |
|
12
|
+
text_box = DocTextViewer.new(txt_parent, @doc.dbid)
|
13
|
+
text_box.set_font(@app.display_font)
|
14
|
+
text_box.append_text( @doc.text )
|
15
|
+
text_box.evt_enter_window do | e |
|
16
|
+
set_cursor Wx::Cursor.new(Wx::CURSOR_IBEAM)
|
17
|
+
end
|
18
|
+
text_box.evt_leave_window do | e |
|
19
|
+
set_cursor Wx::Cursor.new(Wx::CURSOR_ARROW)
|
20
|
+
end
|
21
|
+
text_box.show_position(0)
|
22
|
+
text_box
|
23
|
+
end
|
24
|
+
|
25
|
+
construct_details_panel()
|
26
|
+
set_icon( app.fetch_icon("document.xpm") )
|
27
|
+
subscribe(:document_changed, :document_deleted)
|
28
|
+
end
|
29
|
+
|
30
|
+
def receive_document_deleted(doc)
|
31
|
+
close() if doc.dbid == @doc.dbid
|
32
|
+
end
|
33
|
+
|
34
|
+
def receive_document_changed(new_doc)
|
35
|
+
if new_doc.dbid == @doc.dbid
|
36
|
+
@doc = new_doc
|
37
|
+
refresh()
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_set_text_font(font)
|
42
|
+
@text_box.font = font
|
43
|
+
end
|
44
|
+
|
45
|
+
# update the display from the currently stored +@doc+
|
46
|
+
# TODO - currently doesn't update text as this shouldn't ever change
|
47
|
+
def refresh()
|
48
|
+
set_title(@doc.title)
|
49
|
+
label = Time.now.strftime("%a %d/%m/%Y %H:%M:%S")
|
50
|
+
@mod_date_label.set_label( label )
|
51
|
+
end
|
52
|
+
|
53
|
+
def on_save_details(e)
|
54
|
+
@doc.memo = @memo_box.value
|
55
|
+
@doc.title = @title_box.value
|
56
|
+
Wx::BusyCursor.busy { @app.app.save_document( @doc ) }
|
57
|
+
$wxapp.broadcast(:document_changed, @doc)
|
58
|
+
end
|
59
|
+
|
60
|
+
# scroll the window's text box to the line containing the
|
61
|
+
# character at +pos+
|
62
|
+
def jump_to(pos)
|
63
|
+
# p "----"
|
64
|
+
# p pos
|
65
|
+
true_pos = @text_box.true_index_to_pos(pos)
|
66
|
+
# p true_pos
|
67
|
+
# there's something weird going on here. For some reason, if
|
68
|
+
# jump_to is called just after the window has been constructed,
|
69
|
+
# the lines haven't yet been wrapped, and so it jumps to the
|
70
|
+
# wrong position .. weird
|
71
|
+
point = @text_box.position_to_xy(true_pos)
|
72
|
+
# p point.x
|
73
|
+
# p point.y
|
74
|
+
@text_box.show_position( true_pos )
|
75
|
+
end
|
76
|
+
|
77
|
+
def construct_details_panel()
|
78
|
+
main_panel = Wx::Panel.new(@notebook, -1)
|
79
|
+
sizer = Wx::BoxSizer.new(Wx::VERTICAL)
|
80
|
+
title_box_label = Wx::StaticBox.new(main_panel, -1, 'Title')
|
81
|
+
title_box_sizer = Wx::StaticBoxSizer.new(title_box_label,
|
82
|
+
Wx::VERTICAL)
|
83
|
+
@title_box = Wx::TextCtrl.new(main_panel, -1, @doc.title )
|
84
|
+
title_box_sizer.add(@title_box, 0,
|
85
|
+
Wx::ADJUST_MINSIZE|Wx::ALL|Wx::GROW, 4)
|
86
|
+
sizer.add(title_box_sizer,0, Wx::ADJUST_MINSIZE|Wx::ALL|Wx::GROW, 4)
|
87
|
+
|
88
|
+
info_panel = Wx::Panel.new(main_panel, -1)
|
89
|
+
info_box_label = Wx::StaticBox.new(info_panel, -1, 'Information')
|
90
|
+
info_box_sizer = Wx::StaticBoxSizer.new(info_box_label,
|
91
|
+
Wx::VERTICAL)
|
92
|
+
|
93
|
+
info_sizer = Wx::FlexGridSizer.new(2, 2, 5, 6)
|
94
|
+
|
95
|
+
# Create date label
|
96
|
+
info_sizer.add( Wx::StaticText.new(info_panel, -1, 'Created:') )
|
97
|
+
date_text = @doc.create_date.strftime("%a %d/%m/%Y %H:%M:%S")
|
98
|
+
@create_date_label = Wx::StaticText.new(info_panel, -1, date_text )
|
99
|
+
info_sizer.add( @create_date_label )
|
100
|
+
|
101
|
+
# Modified date label
|
102
|
+
info_sizer.add( Wx::StaticText.new(info_panel, -1, 'Modified:') )
|
103
|
+
date_text = @doc.mod_date.strftime("%a %d/%m/%Y %H:%M:%S")
|
104
|
+
@mod_date_label = Wx::StaticText.new(info_panel, -1, date_text)
|
105
|
+
info_sizer.add(@mod_date_label)
|
106
|
+
info_box_sizer.add(info_sizer, 0,
|
107
|
+
Wx::GROW|Wx::ADJUST_MINSIZE|Wx::ALL, 4)
|
108
|
+
info_panel.set_sizer( info_box_sizer )
|
109
|
+
sizer.add(info_panel, 0, Wx::GROW|Wx::ALL|Wx::ADJUST_MINSIZE, 4)
|
110
|
+
|
111
|
+
# The memo box
|
112
|
+
memo_label = Wx::StaticBox.new(main_panel, -1, 'Memo')
|
113
|
+
memo_sizer = Wx::StaticBoxSizer.new(memo_label, Wx::VERTICAL)
|
114
|
+
|
115
|
+
@memo_box = Wx::TextCtrl.new(main_panel, -1, @doc.memo,
|
116
|
+
Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE,
|
117
|
+
Wx::TE_MULTILINE|Wx::TE_NOHIDESEL)
|
118
|
+
@memo_box.evt_enter_window do | e |
|
119
|
+
set_cursor Wx::Cursor.new(Wx::CURSOR_IBEAM)
|
120
|
+
end
|
121
|
+
|
122
|
+
@memo_box.evt_leave_window do | e |
|
123
|
+
set_cursor Wx::Cursor.new(Wx::CURSOR_ARROW)
|
124
|
+
end
|
125
|
+
memo_sizer.add(@memo_box, 10, Wx::GROW|Wx::ALL|Wx::ADJUST_MINSIZE, 4)
|
126
|
+
sizer.add(memo_sizer, 1, Wx::GROW|Wx::ADJUST_MINSIZE, 4)
|
127
|
+
|
128
|
+
|
129
|
+
button = Wx::Button.new(main_panel, -1, 'Apply')
|
130
|
+
button.evt_button(button.get_id) { | e | on_save_details(e) }
|
131
|
+
sizer.add(button, 0, Wx::ALL|Wx::ALIGN_RIGHT|Wx::ADJUST_MINSIZE, 4)
|
132
|
+
main_panel.set_sizer( sizer )
|
133
|
+
|
134
|
+
@notebook.add_page(main_panel, 'details')
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|