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.
Files changed (55) hide show
  1. data/lib/weft.rb +21 -0
  2. data/lib/weft/WEFT-VERSION-STRING.rb +1 -0
  3. data/lib/weft/application.rb +130 -0
  4. data/lib/weft/backend.rb +39 -0
  5. data/lib/weft/backend/marshal.rb +26 -0
  6. data/lib/weft/backend/mysql.rb +267 -0
  7. data/lib/weft/backend/n6.rb +366 -0
  8. data/lib/weft/backend/sqlite.rb +633 -0
  9. data/lib/weft/backend/sqlite/category_tree.rb +104 -0
  10. data/lib/weft/backend/sqlite/schema.rb +152 -0
  11. data/lib/weft/backend/sqlite/upgradeable.rb +55 -0
  12. data/lib/weft/category.rb +157 -0
  13. data/lib/weft/coding.rb +355 -0
  14. data/lib/weft/document.rb +118 -0
  15. data/lib/weft/filters.rb +243 -0
  16. data/lib/weft/wxgui.rb +687 -0
  17. data/lib/weft/wxgui/category.xpm +26 -0
  18. data/lib/weft/wxgui/dialogs.rb +128 -0
  19. data/lib/weft/wxgui/document.xpm +25 -0
  20. data/lib/weft/wxgui/error_handler.rb +52 -0
  21. data/lib/weft/wxgui/inspectors.rb +361 -0
  22. data/lib/weft/wxgui/inspectors/category.rb +165 -0
  23. data/lib/weft/wxgui/inspectors/codereview.rb +275 -0
  24. data/lib/weft/wxgui/inspectors/document.rb +139 -0
  25. data/lib/weft/wxgui/inspectors/imagedocument.rb +56 -0
  26. data/lib/weft/wxgui/inspectors/script.rb +35 -0
  27. data/lib/weft/wxgui/inspectors/search.rb +265 -0
  28. data/lib/weft/wxgui/inspectors/textcontrols.rb +304 -0
  29. data/lib/weft/wxgui/lang.rb +17 -0
  30. data/lib/weft/wxgui/lang/en.rb +45 -0
  31. data/lib/weft/wxgui/mondrian.xpm +44 -0
  32. data/lib/weft/wxgui/search.xpm +25 -0
  33. data/lib/weft/wxgui/sidebar.rb +498 -0
  34. data/lib/weft/wxgui/utilities.rb +148 -0
  35. data/lib/weft/wxgui/weft16.xpm +31 -0
  36. data/lib/weft/wxgui/workarea.rb +249 -0
  37. data/test/001-document.rb +196 -0
  38. data/test/002-category.rb +138 -0
  39. data/test/003-code.rb +370 -0
  40. data/test/004-application.rb +52 -0
  41. data/test/006-filters.rb +139 -0
  42. data/test/009a-backend_sqlite_basic.rb +280 -0
  43. data/test/009b-backend_sqlite_complex.rb +175 -0
  44. data/test/009c_backend_sqlite_bench.rb +81 -0
  45. data/test/010-backend_nudist.rb +5 -0
  46. data/test/all-tests.rb +1 -0
  47. data/test/manual-gui-script.txt +24 -0
  48. data/test/testdata/autocoding-test.txt +15 -0
  49. data/test/testdata/iso-8859-1.txt +5 -0
  50. data/test/testdata/sample_doc.txt +19 -0
  51. data/test/testdata/search_results.txt +1254 -0
  52. data/test/testdata/text1-dos-ascii.txt +2 -0
  53. data/test/testdata/text1-unix-utf8.txt +2 -0
  54. data/weft-qda.rb +28 -0
  55. 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