weft-qda 0.9.6 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/lib/weft.rb +16 -1
  2. data/lib/weft/WEFT-VERSION-STRING.rb +1 -1
  3. data/lib/weft/application.rb +17 -74
  4. data/lib/weft/backend.rb +6 -32
  5. data/lib/weft/backend/sqlite.rb +222 -164
  6. data/lib/weft/backend/sqlite/category_tree.rb +52 -48
  7. data/lib/weft/backend/sqlite/database.rb +57 -0
  8. data/lib/weft/backend/sqlite/upgradeable.rb +7 -0
  9. data/lib/weft/broadcaster.rb +90 -0
  10. data/lib/weft/category.rb +139 -47
  11. data/lib/weft/codereview.rb +160 -0
  12. data/lib/weft/coding.rb +74 -23
  13. data/lib/weft/document.rb +23 -10
  14. data/lib/weft/exceptions.rb +10 -0
  15. data/lib/weft/filters.rb +47 -224
  16. data/lib/weft/filters/indexers.rb +137 -0
  17. data/lib/weft/filters/input.rb +118 -0
  18. data/lib/weft/filters/output.rb +101 -0
  19. data/lib/weft/filters/templates.rb +80 -0
  20. data/lib/weft/filters/win32backtick.rb +246 -0
  21. data/lib/weft/query.rb +169 -0
  22. data/lib/weft/wxgui.rb +349 -294
  23. data/lib/weft/wxgui/constants.rb +43 -0
  24. data/lib/weft/wxgui/controls.rb +6 -0
  25. data/lib/weft/wxgui/controls/category_dropdown.rb +192 -0
  26. data/lib/weft/wxgui/controls/category_tree.rb +314 -0
  27. data/lib/weft/wxgui/controls/document_list.rb +97 -0
  28. data/lib/weft/wxgui/controls/multitype_control.rb +37 -0
  29. data/lib/weft/wxgui/{inspectors → controls}/textcontrols.rb +235 -64
  30. data/lib/weft/wxgui/dialogs.rb +144 -41
  31. data/lib/weft/wxgui/error_handler.rb +116 -36
  32. data/lib/weft/wxgui/exceptions.rb +7 -0
  33. data/lib/weft/wxgui/inspectors.rb +61 -208
  34. data/lib/weft/wxgui/inspectors/category.rb +19 -16
  35. data/lib/weft/wxgui/inspectors/codereview.rb +90 -132
  36. data/lib/weft/wxgui/inspectors/document.rb +12 -8
  37. data/lib/weft/wxgui/inspectors/imagedocument.rb +56 -56
  38. data/lib/weft/wxgui/inspectors/query.rb +284 -0
  39. data/lib/weft/wxgui/inspectors/script.rb +147 -23
  40. data/lib/weft/wxgui/lang/en.rb +69 -0
  41. data/lib/weft/wxgui/sidebar.rb +90 -432
  42. data/lib/weft/wxgui/utilities.rb +70 -91
  43. data/lib/weft/wxgui/workarea.rb +150 -43
  44. data/share/icons/category.ico +0 -0
  45. data/share/icons/category.xpm +109 -0
  46. data/share/icons/codereview.ico +0 -0
  47. data/share/icons/codereview.xpm +54 -0
  48. data/share/icons/d_and_c.xpm +126 -0
  49. data/share/icons/document.ico +0 -0
  50. data/share/icons/document.xpm +70 -0
  51. data/share/icons/project.ico +0 -0
  52. data/share/icons/query.ico +0 -0
  53. data/share/icons/query.xpm +56 -0
  54. data/{lib/weft/wxgui → share/icons}/search.xpm +0 -0
  55. data/share/icons/weft.ico +0 -0
  56. data/share/icons/weft.xpm +62 -0
  57. data/share/icons/weft16.ico +0 -0
  58. data/share/icons/weft32.ico +0 -0
  59. data/share/templates/category_plain.html +18 -0
  60. data/share/templates/codereview_plain.html +18 -0
  61. data/share/templates/document_plain.html +13 -0
  62. data/share/templates/document_plain.txt +7 -0
  63. data/test/001-document.rb +55 -36
  64. data/test/002-category.rb +81 -6
  65. data/test/003-code.rb +8 -4
  66. data/test/004-application.rb +13 -34
  67. data/test/005-query_review.rb +139 -0
  68. data/test/006-filters.rb +54 -42
  69. data/test/007-output_filters.rb +113 -0
  70. data/test/009a-backend_sqlite_basic.rb +95 -24
  71. data/test/009b-backend_sqlite_complex.rb +43 -62
  72. data/test/009c_backend_sqlite_bench.rb +5 -10
  73. data/test/053-doc_inspector.rb +46 -0
  74. data/test/055-query_window.rb +50 -0
  75. data/test/all-tests.rb +1 -0
  76. data/test/test-common.rb +19 -0
  77. data/test/testdata/empty.qdp +0 -0
  78. data/test/testdata/simple with space.pdf +0 -0
  79. data/test/testdata/simple.pdf +0 -0
  80. data/weft-qda.rb +40 -7
  81. metadata +74 -14
  82. data/lib/weft/wxgui/category.xpm +0 -26
  83. data/lib/weft/wxgui/document.xpm +0 -25
  84. data/lib/weft/wxgui/inspectors/search.rb +0 -265
  85. data/lib/weft/wxgui/mondrian.xpm +0 -44
  86. data/lib/weft/wxgui/weft16.xpm +0 -31
@@ -1,26 +0,0 @@
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
- };
@@ -1,25 +0,0 @@
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
- };
@@ -1,265 +0,0 @@
1
- module QDA::GUI
2
- # a window that allows the entry of criteria (category
3
- # intersections and unions, text search, document attributes), and
4
- # interactively presents the text meeting the criteria, and to save
5
- # the results as a permanent category (memo describing the rules
6
- # used to produce the codes.
7
- class QueryWindow < InspectorWindow
8
- include Subscriber
9
-
10
- # obj is a simple object with a +dbid+ representing a project
11
- # unique identifier for this query
12
- def initialize(obj, app, workarea, layout)
13
- @app = app
14
- @query = obj # currently a pretty much empty object
15
-
16
- super(workarea, "Query #{@query.dbid}", layout) do | parent |
17
- @text_box = CompositeText.new(parent, '', 0, @app)
18
- end
19
- set_icon( app.fetch_icon("search.xpm") )
20
- construct_query_panel
21
- @notebook.selection = 1
22
- subscribe()
23
- # evt_set_focus() { | e | p "focussed #{e.event_object}"; e.skip() }
24
- end
25
-
26
- def associated_subscribers()
27
- super << @objects.grep(CategoryDropDown)
28
- end
29
-
30
- # runs a query using the currently selected query options
31
- def get_results()
32
- begin
33
- # remember the last query we did
34
- @last_query = get_query_string
35
- @last_results = @app.app.do_query( *get_query_arguments )
36
- rescue Exception => err
37
- Wx::MessageDialog.new(nil, err.to_s,
38
- "Error running query",
39
- Wx::OK|Wx::ICON_EXCLAMATION).show_modal()
40
- return
41
- end
42
- return @last_results
43
- end
44
-
45
- def get_target_argument(offset, as_string = false)
46
- return nil unless @objects[offset].is_shown
47
- if @rules[offset].value == 'IS CODED BY'
48
- if @objects[offset].current_category
49
- category = @objects[offset].current_category
50
- return as_string ? category.name : category.dbid
51
- else
52
- # use fail rather than raise as it gets interp as a method...
53
- fail RuntimeError.new("No category value set for CODED BY")
54
- end
55
- elsif @rules[offset].value == 'CONTAINS WORD'
56
- str = @objects[offset].get_value
57
- if str.empty?
58
- fail RuntimeError.new("No text search set for CONTAINS WORD")
59
- else
60
- return str
61
- end
62
- end
63
- end
64
-
65
- def get_query_arguments()
66
- return @rules[0].value, get_target_argument(0),
67
- @ops[0].value,
68
- @rules[1].value, get_target_argument(1)
69
- end
70
-
71
- # TODO
72
- # returns a stringified representation of the query. The only
73
- # reason this is here at the moment is because the underlying
74
- # query code parser doesn't accept string literal paths or names
75
- # for categories- only database ids. This should be remedied, so
76
- # the string passed to query and this are the same.
77
- def get_query_string(join_char = " ")
78
- begin
79
- query_parts = [ @rules[0].value, get_target_argument(0, true) ]
80
- # add on the second bit if used
81
- # TODO - this is barbaric - this whole thing needs tidying
82
- # and being made more extensible n = many
83
- if @ops[0].value != ''
84
- query_parts += [ @ops[0].value,
85
- @rules[1].value, get_target_argument(1, true) ]
86
- end
87
- return query_parts.join(join_char)
88
- rescue Exception => err
89
- return ''
90
- end
91
- end
92
-
93
- # run the query, display the results, view them
94
- def on_view(e)
95
- Wx::BusyCursor.busy do
96
- results = get_results()
97
- return unless results
98
- @text_box.populate( results )
99
- if curr_category = @drop_down.current_category()
100
- @text_box.highlight_codingtable(curr_category.codes)
101
- end
102
- end
103
- @notebook.selection = 0
104
- end
105
-
106
- def on_save_results(e)
107
- # check for saved results
108
- unless @last_results and ! @last_query.empty? and
109
- @last_query == get_query_string()
110
- Wx::BusyCursor.busy do
111
- results = get_results()
112
- return unless results
113
- @text_box.populate(results)
114
- end
115
- end
116
-
117
- q_string = get_query_string
118
- title = "'#{q_string[0, 30]}...' (query results)"
119
- search_parent = @app.app.get_root_category('SEARCHES')
120
- query_cat = Category.new( title, search_parent )
121
- query_cat.codetable = @last_results
122
- query_cat.memo = get_query_string("\n")
123
- $wxapp.app.save_category(query_cat)
124
- $wxapp.broadcast(:category_added, query_cat)
125
- end
126
-
127
- def on_focus_dropdown(e)
128
- # p "focussed #{e.event_object}"
129
- # e.skip()
130
- end
131
-
132
- def on_blur_dropdown(e)
133
- # p "blurred #{e.event_object}"
134
- # p active?
135
- # e.skip()
136
- end
137
-
138
- def construct_query_panel()
139
- panel2 = Wx::Panel.new(@notebook, -1)
140
- sizer2 = Wx::BoxSizer.new(Wx::VERTICAL)
141
- sizer2.add( Wx::StaticText.new(panel2, -1, 'Find text that:'),
142
- 0, Wx::ALL|Wx::ADJUST_MINSIZE, 4 )
143
-
144
- # criteria consist of rules ('is coded by', 'text matches'),
145
- # targets ('category "Foo"', 'text "Bar"') and may be joined by
146
- # ops ('AND', 'OR')
147
-
148
- @rules = []
149
- @objects = []
150
- @ops = []
151
-
152
- @crit_panel = Wx::Panel.new(panel2, -1)
153
- @crit_sizer = Wx::BoxSizer.new(Wx::VERTICAL)
154
-
155
- add_criterion(true)
156
- add_criterion(false)
157
-
158
-
159
- @ops[0].evt_combobox(@ops[0].get_id) do | e |
160
- operator = @ops[0].get_string_selection
161
- if operator != ""
162
- @rules[1].show(true)
163
- @objects[1].show(true)
164
- else
165
- @rules[1].hide()
166
- @objects[1].hide()
167
- end
168
- end
169
- @rules[1].hide()
170
- @objects[1].hide()
171
-
172
- @crit_panel.set_sizer(@crit_sizer)
173
- sizer2.add(@crit_panel, 1, Wx::GROW|Wx::ALL|Wx::ADJUST_MINSIZE, 4 )
174
-
175
- butt_panel = Wx::Panel.new(panel2, -1)
176
- bott_sizer = Wx::BoxSizer.new(Wx::HORIZONTAL)
177
-
178
- button = Wx::Button.new(butt_panel, -1, 'View')
179
- button.evt_button(button.get_id) { | e | on_view(e) }
180
- bott_sizer.add(button, 1, Wx::ALL, 4)
181
-
182
- button = Wx::Button.new(butt_panel, -1, 'Save Results')
183
- button.evt_button(button.get_id) { | e | on_save_results(e) }
184
- bott_sizer.add(button, 1, Wx::ALL, 4)
185
-
186
- butt_panel.set_sizer(bott_sizer)
187
- sizer2.add(butt_panel, 0,
188
- Wx::GROW|Wx::ADJUST_MINSIZE|Wx::ALIGN_BOTTOM)
189
- @notebook.add_page(panel2, 'query')
190
- panel2.set_sizer_and_fit(sizer2)
191
- # sizer2.set_size_hints(panel2)
192
- end
193
-
194
- def add_criterion(with_bool = false)
195
- row_sizer = Wx::BoxSizer.new(Wx::HORIZONTAL)
196
- row_n = @rules.length
197
-
198
- type_op1 = Wx::ComboBox.new(@crit_panel, -1, '', Wx::DEFAULT_POSITION,
199
- Wx::DEFAULT_SIZE, [],
200
- Wx::CB_READONLY|Wx::CB_DROPDOWN)
201
- type_op1.append('IS CODED BY')
202
- type_op1.append('CONTAINS WORD')
203
-
204
- type_op1.selection = 0
205
- row_sizer.add( type_op1, 1, Wx::GROW|Wx::ALL)
206
- @rules.push( type_op1 )
207
-
208
- op2_placeholder = Wx::BoxSizer.new(Wx::VERTICAL)
209
- type_op2 = CategoryDropDown.new(@app, @crit_panel, nil, true)
210
- # TODO - allow currently highlighted category dropdown to
211
- # receive global focus_category events
212
- # type_op2.evt_set_focus() { | e | on_focus_dropdown(e) }
213
- # type_op2.evt_kill_focus() { | e | on_blur_dropdown(e) }
214
-
215
- op2_placeholder.add(type_op2, 1,
216
- Wx:: GROW|Wx::ALL)
217
-
218
- type_op2_a = Wx::TextCtrl.new(@crit_panel, -1, '')
219
- type_op2_a.hide()
220
- row_sizer.add( op2_placeholder, 1, Wx::ADJUST_MINSIZE)
221
-
222
- @objects.push( type_op2 )
223
-
224
-
225
- # switch inputs
226
- evt_combobox(type_op1.get_id) do | e |
227
- function = type_op1.get_string_selection()
228
- if function == "IS CODED BY" and not type_op2.shown?
229
- type_op2_a.hide()
230
- op2_placeholder.remove(type_op2_a)
231
-
232
- op2_placeholder.add(type_op2, 1,
233
- Wx::GROW|Wx::ADJUST_MINSIZE|Wx::ALL)
234
- type_op2.show()
235
- op2_placeholder.layout()
236
- @objects[row_n] = type_op2
237
- elsif function == "CONTAINS WORD" and not type_op2_a.shown?
238
- type_op2.hide()
239
- op2_placeholder.remove(type_op2)
240
- op2_placeholder.add(type_op2_a, 1,
241
- Wx:: GROW|Wx::ADJUST_MINSIZE|Wx::ALL)
242
- type_op2_a.show()
243
- op2_placeholder.layout()
244
- @objects[row_n] = type_op2_a
245
- end
246
- end
247
-
248
- type_op3 = Wx::ComboBox.new(@crit_panel, -1, '', Wx::DEFAULT_POSITION,
249
- Wx::DEFAULT_SIZE, [],
250
- Wx::CB_READONLY|Wx::CB_DROPDOWN)
251
- type_op3.append('')
252
- type_op3.append('AND')
253
- type_op3.append('AND NOT')
254
- type_op3.append('OR')
255
- type_op3.selection = 0
256
-
257
- row_sizer.add( type_op3, 1, Wx::GROW|Wx::ALL, 2)
258
- @ops.push( type_op3 )
259
- unless with_bool
260
- type_op3.hide()
261
- end
262
- @crit_sizer.add( row_sizer, 0, Wx::GROW|Wx::ALL|Wx::ALIGN_TOP )
263
- end
264
- end
265
- end
@@ -1,44 +0,0 @@
1
- /* XPM */
2
- static char *mondrian_xpm[] = {
3
- /* columns rows colors chars-per-pixel */
4
- "32 32 6 1",
5
- " c Black",
6
- ". c Blue",
7
- "X c #00bf00",
8
- "o c Red",
9
- "O c Yellow",
10
- "+ c Gray100",
11
- /* pixels */
12
- " ",
13
- " oooooo +++++++++++++++++++++++ ",
14
- " oooooo +++++++++++++++++++++++ ",
15
- " oooooo +++++++++++++++++++++++ ",
16
- " oooooo +++++++++++++++++++++++ ",
17
- " oooooo +++++++++++++++++++++++ ",
18
- " oooooo +++++++++++++++++++++++ ",
19
- " oooooo +++++++++++++++++++++++ ",
20
- " ",
21
- " ++++++ ++++++++++++++++++ .... ",
22
- " ++++++ ++++++++++++++++++ .... ",
23
- " ++++++ ++++++++++++++++++ .... ",
24
- " ++++++ ++++++++++++++++++ .... ",
25
- " ++++++ ++++++++++++++++++ .... ",
26
- " ++++++ ++++++++++++++++++ ",
27
- " ++++++ ++++++++++++++++++ ++++ ",
28
- " ++++++ ++++++++++++++++++ ++++ ",
29
- " ++++++ ++++++++++++++++++ ++++ ",
30
- " ++++++ ++++++++++++++++++ ++++ ",
31
- " ++++++ ++++++++++++++++++ ++++ ",
32
- " ++++++ ++++++++++++++++++ ++++ ",
33
- " ++++++ ++++++++++++++++++ ++++ ",
34
- " ++++++ ++++++++++++++++++ ++++ ",
35
- " ++++++ ++++++++++++++++++ ++++ ",
36
- " ++++++ ++++ ",
37
- " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
38
- " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
39
- " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
40
- " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
41
- " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
42
- " ++++++ OOOOOOOOOOOO XXXXX ++++ ",
43
- " "
44
- };
@@ -1,31 +0,0 @@
1
- /* XPM */
2
- static char *weft16[] = {
3
- /* columns rows colors chars-per-pixel */
4
- "16 16 9 1",
5
- " c #400000",
6
- ". c #CCCC00",
7
- "X c #E9E991",
8
- "o c #999900",
9
- "O c gray100",
10
- "+ c black",
11
- "@ c black",
12
- "# c black",
13
- "$ c None",
14
- /* pixels */
15
- "$$$$$ $$$ $$$$",
16
- "$$$$ XX $ XX $$$",
17
- "$$$$ .XX XX. $$$",
18
- "$$ $ .XX o $ $$",
19
- "$ XX $ .XX $ X $",
20
- "$ XX. o .X. XX. ",
21
- "$$ . XXo . XX. $",
22
- "$$$ XX. $ XX. $$",
23
- "$$ XX. o XX. o $",
24
- "$ XX. o.X . o.X ",
25
- " XX. $ XXX $ X $",
26
- " X. $ o XXX $ $$",
27
- "$ $ XXo XXX $$$",
28
- "$$$ XX. $ XX $$$",
29
- "$$$ X. $$$ $$$$",
30
- "$$$$ $$$$$$$$$$"
31
- };