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,26 @@
1
+ /* XPM */
2
+ static char *category[] = {
3
+ /* columns rows colors chars-per-pixel */
4
+ "16 16 4 1",
5
+ " c black",
6
+ ". c gray60",
7
+ "X c gray100",
8
+ "o c None",
9
+ /* pixels */
10
+ "oooooooooooooooo",
11
+ "oo ooooooooo",
12
+ "o XXXXX oooooooo",
13
+ "o XXXXX oooooooo",
14
+ "o XXXXX oooooooo",
15
+ "oo ooooooooo",
16
+ "oooo.ooooooooooo",
17
+ "oooo.ooooooooooo",
18
+ "oooo.ooo oo",
19
+ "oooo.ooo XXXX oo",
20
+ "oooo.... oo",
21
+ "oooo.ooooooooooo",
22
+ "oooo.ooo oo",
23
+ "oooo.ooo XXXX oo",
24
+ "oooo.... oo",
25
+ "oooooooooooooooo"
26
+ };
@@ -0,0 +1,128 @@
1
+ module QDA::GUI
2
+ class DocumentImportProgressTracker < QDA::Indexer
3
+ PT_STYLE = Wx::PD_APP_MODAL|Wx::PD_AUTO_HIDE
4
+ def initialize(parent, title)
5
+ super()
6
+ @parent = parent
7
+ @doctitle = title
8
+ end
9
+
10
+ def prepare(content)
11
+ @progbar = Wx::ProgressDialog.new('Importing document',
12
+ "Reading document #{@doctitle}",
13
+ content.count($/),
14
+ @parent, PT_STYLE)
15
+ @progress = 0
16
+ end
17
+
18
+ def feed(line)
19
+ if ! @progbar.update(@progress += 1)
20
+ raise "Aborted document import"
21
+ end
22
+ super
23
+ end
24
+
25
+ def terminate()
26
+ @progbar.destroy()
27
+ end
28
+ end
29
+
30
+ class WordIndexSaveProgressTracker < QDA::Indexer
31
+ attr_reader :progbar
32
+ PT_STYLE = Wx::PD_APP_MODAL|Wx::PD_AUTO_HIDE
33
+ def initialize(count, parent, title)
34
+ super()
35
+ @progbar = Wx::ProgressDialog.new( 'Importing document',
36
+ "Saving indexes for #{title}",
37
+ count, parent, PT_STYLE)
38
+ @progress = 0
39
+ end
40
+
41
+ def next()
42
+ if ! @progbar.update(@progress += 1)
43
+ raise "Aborted document import"
44
+ end
45
+ end
46
+
47
+ def terminate()
48
+ @progbar.destroy()
49
+ end
50
+ end
51
+
52
+ class SearchDialog < Wx::Dialog
53
+ def initialize(parent)
54
+ super( parent, -1, 'Search', DEF_POS, Wx::Size.new(500,175) )
55
+
56
+ sizer = Wx::FlexGridSizer.new(2, 5)
57
+
58
+ # search text entry
59
+ sizer.add(Wx::StaticText.new(self, -1, 'Search for'),
60
+ 0, Wx::ALIGN_CENTRE_VERTICAL|Wx::ALIGN_LEFT|Wx::ALL, 4)
61
+ @term = Wx::TextCtrl.new(self, -1, '', DEF_POS, DEF_SIZE,
62
+ Wx::TE_PROCESS_ENTER)
63
+ evt_text_enter(@term.get_id) { | e | on_search(e) }
64
+ sizer.add(@term, 2, Wx::GROW|Wx::ALL|Wx::ADJUST_MINSIZE, 4)
65
+
66
+ # how much context to return
67
+ sizer.add(Wx::StaticText.new(self, -1, 'Expand results by '),
68
+ 0, Wx::ALIGN_CENTRE_VERTICAL|Wx::ALIGN_LEFT|Wx::ALL, 4)
69
+ mini_sizer = Wx::BoxSizer.new(Wx::HORIZONTAL)
70
+
71
+ @expand = Wx::SpinCtrl.new( self, -1, "")
72
+ @expand.set_range(0, 1000)
73
+ @expand.set_value(100)
74
+ mini_sizer.add(@expand, 0, Wx::ALL, 4)
75
+ mini_sizer.add(Wx::StaticText.new(self, -1, 'characters'),
76
+ 0, Wx::ALL, 6)
77
+ sizer.add(mini_sizer, 0)
78
+
79
+ # options
80
+ sizer.add(Wx::StaticText.new(self, -1, ''), 0, Wx::ALIGN_CENTRE, 4)
81
+ @case_sensi = Wx::CheckBox.new(self, -1, "Case sensitive?")
82
+ sizer.add(@case_sensi, 0, Wx::ALL, 4)
83
+
84
+ sizer.add(Wx::StaticText.new(self, -1, ''), 0, Wx::ALIGN_CENTRE, 4)
85
+ @whole_word = Wx::CheckBox.new(self, -1, "Whole words only?")
86
+ sizer.add(@whole_word, 0, Wx::ALL, 4)
87
+
88
+ # buttons
89
+ button = Wx::Button.new(self, -1, 'Search')
90
+ button.evt_button(button.get_id) { | e | on_search(e) }
91
+ sizer.add(button, 0, Wx::ALL, 4)
92
+
93
+ button = Wx::Button.new(self, -1, 'Cancel')
94
+ button.evt_button(button.get_id) { | e | end_modal(Wx::ID_CANCEL) }
95
+ sizer.add(button, 0, Wx::ALL|Wx::ALIGN_RIGHT, 4)
96
+
97
+ self.set_sizer(sizer)
98
+ # sizer.set_size_hints(self)
99
+ sizer.fit(self)
100
+ end
101
+
102
+ def on_search(e)
103
+ if term =~ /^\s*$/
104
+ Wx::MessageDialog.new(nil, Lang::NO_SEARCH_TERM_SPECIFIED,
105
+ Lang::NO_SEARCH_TERM_SPECIFIED,
106
+ Wx::OK|Wx::ICON_ERROR).show_modal()
107
+ return false
108
+ end
109
+ end_modal(Wx::ID_OK)
110
+ end
111
+
112
+ def term
113
+ @term.get_value
114
+ end
115
+
116
+ def case_sensitive
117
+ @case_sensi.is_checked
118
+ end
119
+
120
+ def whole_word
121
+ @whole_word.is_checked
122
+ end
123
+
124
+ def expand
125
+ @expand.get_value().to_i
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,25 @@
1
+ /* XPM */
2
+ static char *document[] = {
3
+ /* columns rows colors chars-per-pixel */
4
+ "16 16 3 1",
5
+ " c black",
6
+ ". c gray100",
7
+ "X c None",
8
+ /* pixels */
9
+ "XXXXXXXXXXXXXXXX",
10
+ "XX XXXXX",
11
+ "XX ........ XXXX",
12
+ "XX ......... XXX",
13
+ "XX . ... XX",
14
+ "XX .......... XX",
15
+ "XX . . XX",
16
+ "XX .......... XX",
17
+ "XX . . XX",
18
+ "XX .......... XX",
19
+ "XX . . XX",
20
+ "XX .......... XX",
21
+ "XX . . XX",
22
+ "XX .......... XX",
23
+ "XX XX",
24
+ "XXXXXXXXXXXXXXXX"
25
+ };
@@ -0,0 +1,52 @@
1
+ module QDA::GUI
2
+ class ErrorHandlerApp < Wx::App
3
+ attr_accessor :err
4
+
5
+ def on_init()
6
+ frame = Wx::Frame.new(nil, -1, 'Text')
7
+
8
+ panel = Wx::Panel.new(frame)
9
+ sizer = Wx::BoxSizer.new(Wx::VERTICAL)
10
+
11
+ @text_box = Wx::TextCtrl.new(panel, -1, @err.to_s,
12
+ Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE,
13
+ Wx::TE_MULTILINE|Wx::TE_RICH|Wx::TE_NOHIDESEL)
14
+ butt_panel = Wx::Panel.new(panel)
15
+ bott_sizer = Wx::BoxSizer.new(Wx::HORIZONTAL)
16
+
17
+ button = Wx::Button.new(butt_panel, -1, 'Save')
18
+ button.evt_button(button.get_id) { | e | on_font(e) }
19
+ bott_sizer.add(button, 1, Wx::ALL, 4)
20
+
21
+ button = Wx::Button.new(butt_panel, -1, 'Send')
22
+ button.evt_button(button.get_id) { | e | on_bold(e) }
23
+ bott_sizer.add(button, 1, Wx::ALL, 4)
24
+
25
+ button = Wx::Button.new(butt_panel, -1, 'Close')
26
+ button.evt_button(button.get_id) { | e | on_colour(e) }
27
+ bott_sizer.add(button, 1, Wx::ALL, 4)
28
+
29
+ butt_panel.set_sizer(bott_sizer)
30
+
31
+ sizer.add(@text_box, 1, Wx::GROW)
32
+ sizer.add(butt_panel, 0, Wx::GROW|Wx::ADJUST_MINSIZE|Wx::ALIGN_BOTTOM)
33
+ panel.set_sizer(sizer)
34
+
35
+
36
+ frame.set_client_size( Wx::Size.new(200,200) )
37
+ frame.show()
38
+ end
39
+
40
+ def on_font(e)
41
+ dialog = Wx::FontDialog.new()
42
+ case dialog.show_modal()
43
+ when Wx::ID_OK
44
+ font = dialog.get_font_data.get_chosen_font()
45
+ @text_box.set_font(font)
46
+ when Wx::ID_CANCEL
47
+ return
48
+ end
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,361 @@
1
+ require 'weft/wxgui/inspectors/textcontrols'
2
+
3
+ module QDA::GUI
4
+ class CategoryDropDown < Wx::ComboBox
5
+ include Subscriber
6
+
7
+ MAXIMUM_DROPDOWN_LENGTH = 7
8
+ attr_accessor :sticky
9
+
10
+ # +locked+ if true will prevent the dropdown from responding to
11
+ # global category focus events.
12
+ def initialize(app, parent, text_box = nil, locked = false)
13
+ super(parent, -1, '', Wx::DEFAULT_POSITION,
14
+ Wx::DEFAULT_SIZE, [])
15
+ @locked = locked
16
+ @client_data = {}
17
+ @text_box = text_box
18
+ @sticky = false
19
+
20
+ @app = app
21
+
22
+ evt_kill_focus() do | e |
23
+ find_and_add_categories()
24
+ e.skip()
25
+ end
26
+
27
+ evt_text_enter(self.get_id) do | e |
28
+ find_and_add_categories()
29
+ end
30
+
31
+ evt_combobox(self.get_id) do | e |
32
+ e.skip()
33
+ on_item_selected(e)
34
+ end
35
+
36
+ subscribe(:focus_category, :category_deleted, :category_changed)
37
+ if $wxapp.current_category
38
+ set_active_category($wxapp.current_category)
39
+ end
40
+ end
41
+
42
+ # is this dropdown responding to global :focus_category events?
43
+ def locked?
44
+ @locked ? true : false
45
+ end
46
+
47
+ # make this dropdown receive global :focus_category events
48
+ def lock
49
+ @locked = true
50
+ end
51
+
52
+ # prevent this dropdown responding to global :focus_category events
53
+ def unlock
54
+ @locked = false
55
+ end
56
+
57
+ # highlight text coded by the category on the way.
58
+ def set_selection(idx)
59
+ super(idx)
60
+ if @text_box && category = current_category
61
+ @text_box.highlight_codingtable(category.codes)
62
+ end
63
+ end
64
+
65
+ # highlight text coded by the newly-selected category
66
+ def on_item_selected(e)
67
+ if @text_box && category = current_category
68
+ @text_box.highlight_codingtable(category.codes)
69
+ end
70
+ end
71
+
72
+ # add the newly-focused category to this dropdown and highlight
73
+ # its text.
74
+ def receive_focus_category(cat)
75
+ set_active_category(cat) unless locked?
76
+ end
77
+
78
+ # if a category is deleted it should be removed from the list
79
+ def receive_category_deleted(cat)
80
+ (0 .. count - 1).each do | i |
81
+ delete(i) if get_client_data(i).dbid == cat.dbid
82
+ end
83
+ end
84
+
85
+ def receive_category_changed(cat)
86
+ (0 .. count - 1).each do | i |
87
+ if get_client_data(i).dbid == cat.dbid
88
+ # TODO set_string not implemented (wxr 0.6.0)
89
+ # set_string(i, cat.name)
90
+ # set_client_data(cat.name, cat)
91
+ prepend(cat) # will automatically delete old
92
+ end
93
+ end
94
+ end
95
+
96
+ def set_active_category(category)
97
+ # clear the first node unless it is sticky because it has been used
98
+ unless @sticky
99
+ delete(0)
100
+ end
101
+ # clear any remaining excess items
102
+ while count > MAXIMUM_DROPDOWN_LENGTH
103
+ delete(count - 1)
104
+ end
105
+
106
+ prepend(category)
107
+ @sticky = false
108
+ set_selection(0)
109
+ # currently disabled until 0.9.6
110
+
111
+ end
112
+
113
+ def prepend(category)
114
+ copy = [ category.name, category ]
115
+ while count > 0
116
+ this_text = get_string(0)
117
+ this_cat = @client_data[this_text]
118
+ unless this_cat.dbid == category.dbid
119
+ copy.push( this_text, @client_data[this_text] )
120
+ end
121
+ delete(0)
122
+ end
123
+
124
+ until copy.empty?
125
+ new_text, new_data = copy.shift, copy.shift
126
+ append(new_text, nil)
127
+ set_client_data(new_text, new_data)
128
+ end
129
+ set_selection(0)
130
+ end
131
+
132
+ # added for compatibility with set_client_data - temporarily
133
+ # removed in WxRuby 0.4.0, should remove when this is fixed
134
+ def append(text, category, *args )
135
+ super(text, nil, *args)
136
+ set_client_data(text, category )
137
+ end
138
+
139
+ # mimicking WxWidgets method, temp disabled in WxRuby
140
+ def set_client_data(text, client_data)
141
+ @client_data[text] = client_data
142
+ end
143
+
144
+ # mimicking ...
145
+ def get_client_data(index)
146
+ text = get_string(index)
147
+ @client_data[text]
148
+ end
149
+
150
+ def find_and_add_categories()
151
+ typed_text = get_value()
152
+ unless find_string( typed_text ) || typed_text.empty?
153
+ matches = @app.app.get_categories_by_path(typed_text)
154
+ if matches.empty?
155
+
156
+ elsif matches.length > 1
157
+
158
+ end
159
+ matches.each { | cat | prepend(cat) unless cat.parent.nil? }
160
+ set_selection( 0 )
161
+ end
162
+ end
163
+
164
+ def on_blur(e)
165
+ find_and_add_categories()
166
+ e.skip()
167
+ end
168
+
169
+ # missing in wxruby, but part of WxWidgets
170
+ # this version differs by returning nil rather than -1 on failure
171
+ def find_string(str)
172
+ ( 0 ... count ).each do | i |
173
+ return i if str == get_string(i)
174
+ end
175
+ return nil
176
+ end
177
+
178
+
179
+ # TODO - some visual cue to indicate that no category matched find-first
180
+ def set_broken(bool)
181
+
182
+ end
183
+
184
+ def set_warning(bool)
185
+
186
+ end
187
+ # returns the Category object associated with the currently
188
+ # selected item in the drop down.
189
+ def current_category
190
+ if curr_sel = get_selection()
191
+ if curr_sel.nil? || curr_sel == -1
192
+ return nil
193
+ end
194
+ return get_client_data( curr_sel )
195
+ end
196
+ end
197
+ end
198
+
199
+ class WorkAreaWindow < Wx::MDIChildFrame
200
+ # the default size for new windows of this type and
201
+ # subclasses. Expressed as a proportion of MDI client area width
202
+ # and MDI client area height.
203
+ W_WINDOW_DEF_SIZE = [ 0.6, 0.8 ]
204
+
205
+ def initialize(workarea, title, last_layout)
206
+ size = pos = nil
207
+ if last_layout
208
+ size = Wx::Size.new( last_layout[:w], last_layout[:h] )
209
+ pos = Wx::Point.new( last_layout[:x], last_layout[:y] )
210
+ else
211
+ proportions = self.class::W_WINDOW_DEF_SIZE
212
+ size = workarea.proportional_size(*proportions)
213
+ pos = Wx::DEFAULT_POSITION
214
+ end
215
+ super(workarea, -1, title, pos, size)
216
+ end
217
+
218
+ # returns a hash serialising the current shape and location of
219
+ # this window, so it can later be unthawed
220
+ def layout()
221
+ curr_size = get_size()
222
+ pos = get_position
223
+ return { :x => pos.x,
224
+ :y => pos.y,
225
+ :w => curr_size.width,
226
+ :h => curr_size.height }
227
+ end
228
+
229
+ def layout=(layout)
230
+ move( Wx::Point.new(layout[:x], layout[:y]) )
231
+ set_client_size( Wx::Size.new(layout[:w], layout[:h]) )
232
+ end
233
+
234
+ # is this the currently focused window within the MDI layout?
235
+ def active?()
236
+ self == parent.active_child
237
+ end
238
+ end
239
+
240
+ # a WorkArea Window with a notebook layout with a coding panel
241
+ # including a text display in the first pane. Documents, Categories
242
+ # and Queries are all displayed using this model
243
+ class InspectorWindow < WorkAreaWindow
244
+ if Wx::RUBY_PLATFORM == 'WXGTK'
245
+ # GTK uses a notebook to fake MDI windows, so if running under
246
+ # WXGTK, place the real notebook tabs on the right instead
247
+ INSPECTOR_NB_STYLE = [ Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE,
248
+ Wx::NB_RIGHT ]
249
+ else
250
+ INSPECTOR_NB_STYLE = []
251
+ end
252
+
253
+ def initialize(workarea, title, last_layout, &text_constructor)
254
+ super(workarea, title, last_layout)
255
+
256
+ @notebook = Wx::Notebook.new(self, -1, *INSPECTOR_NB_STYLE)
257
+ panel_1 = Wx::Panel.new(@notebook, -1)
258
+ sizer_1 = Wx::BoxSizer.new(Wx::VERTICAL)
259
+
260
+ @text_box = text_constructor.call(panel_1)
261
+ sizer_1.add(@text_box, 10, Wx::GROW|Wx::ALL, 4)
262
+
263
+ butt_panel = Wx::Panel.new(panel_1, -1)
264
+ bott_sizer = Wx::BoxSizer.new(Wx::HORIZONTAL)
265
+
266
+ @drop_down = CategoryDropDown.new(@app, butt_panel, @text_box)
267
+ bott_sizer.add(@drop_down, 3, Wx::ALL, 4)
268
+
269
+ button = Wx::Button.new(butt_panel, -1, 'Code')
270
+ button.evt_button(button.get_id) { | e | on_code(e) }
271
+ bott_sizer.add(button, 1, Wx::ALL, 4)
272
+
273
+ button = Wx::Button.new(butt_panel, -1, 'Uncode')
274
+ button.evt_button(button.get_id) { | e | on_uncode(e) }
275
+ bott_sizer.add(button, 1, Wx::ALL, 4)
276
+
277
+ # button = Wx::Button.new(butt_panel, -1, 'Note')
278
+ # button.evt_button(button.get_id) { | e | on_code(e) }
279
+ # bott_sizer.add(button, 1, Wx::ALL, 4, Wx::ALIGN_RIGHT)
280
+
281
+
282
+ butt_panel.sizer = bott_sizer
283
+ sizer_1.add(butt_panel, 0,
284
+ Wx::GROW|Wx::ADJUST_MINSIZE|Wx::ALIGN_BOTTOM)
285
+
286
+ panel_1.set_sizer( sizer_1 )
287
+ @notebook.add_page(panel_1, 'text')
288
+ evt_activate() { | e | on_activate(e) }
289
+ end
290
+
291
+ # (hopefully temporary) method -- when this window is closed,
292
+ # all widgets containsed within it that are subscribers to
293
+ # application events should also be unsubscribed so their notify
294
+ # method isn't later called - which causes a crash in wxruby 0.6.0
295
+ def associated_subscribers()
296
+ [ @drop_down ]
297
+ end
298
+
299
+ # this method should update the code combo box - this is done by
300
+ # the MDI Parent. But - the ActivateEvent class is not currently
301
+ # available in wxruby 0.6.0, so there's no way to distinguish an
302
+ # activate from a deactivate
303
+ def on_activate(e)
304
+ # e.methods.each { | m | p m }
305
+ # if e.get_active
306
+ # p "FOO"
307
+ # end
308
+ end
309
+
310
+ # code from the main text window
311
+ def on_code(e)
312
+ return unless category = get_current_category() # from drop-down
313
+
314
+ Wx::BusyCursor.busy do
315
+ codes = @text_box.selection_to_fragments()
316
+ codes.each { | c | category.code(c.docid, c.offset, c.length) }
317
+
318
+ $wxapp.app.save_category( category )
319
+ @drop_down.sticky = true
320
+ $wxapp.broadcast(:category_changed, category )
321
+ end
322
+ end
323
+
324
+ # uncode from the main text window
325
+ def on_uncode(e)
326
+ return unless category = get_current_category()
327
+ Wx::BusyCursor.busy do
328
+ codes = @text_box.selection_to_fragments()
329
+ codes.each { | c | category.uncode(c.docid, c.offset, c.length) }
330
+ $wxapp.app.save_category( category )
331
+ @drop_down.sticky = true
332
+ $wxapp.broadcast(:category_changed, category )
333
+ end
334
+ end
335
+
336
+ def refresh()
337
+
338
+ end
339
+
340
+ # the current category active in this window
341
+ def get_current_category()
342
+ if curr = @drop_down.current_category
343
+ return curr
344
+ else
345
+ return nil
346
+ end
347
+ end
348
+
349
+ # set the display font for use in this inspector
350
+ def set_display_font(font)
351
+ @text_box.set_font(font)
352
+ end
353
+ end
354
+
355
+ require 'weft/wxgui/inspectors/document.rb'
356
+ require 'weft/wxgui/inspectors/category.rb'
357
+ # require 'weft/wxgui/inspectors/imagedocument.rb'
358
+ require 'weft/wxgui/inspectors/search.rb'
359
+ require 'weft/wxgui/inspectors/script.rb'
360
+ require 'weft/wxgui/inspectors/codereview.rb'
361
+ end