weft-qda 0.9.6 → 0.9.8

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 (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,54 +1,91 @@
1
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
2
+ class StageProgressDialog < Wx::ProgressDialog
3
+ PT_STYLE = Wx::PD_APP_MODAL|Wx::PD_AUTO_HIDE|Wx::PD_CAN_ABORT
4
+
5
+ FIXED_PROGRESS = 200
6
+ def initialize(parent, title, msg)
7
+ super(title, msg, FIXED_PROGRESS, parent, PT_STYLE)
8
+ @progress = 0.0
9
+ @step = FIXED_PROGRESS.to_f / 10.0
16
10
  end
17
11
 
18
- def feed(line)
19
- if ! @progbar.update(@progress += 1)
20
- raise "Aborted document import"
12
+ def step(msg = nil)
13
+ @progress = @progress + @step
14
+ result = msg ? update(@progress.to_i, msg) :
15
+ update(@progress.to_i)
16
+ if not result
17
+ Kernel.raise UserAbortedException.new('Document import cancelled')
21
18
  end
22
- super
23
19
  end
24
-
25
- def terminate()
26
- @progbar.destroy()
20
+
21
+ def retarget(new_target)
22
+ remaining = FIXED_PROGRESS - @progress
23
+ @step = remaining / new_target.to_f
24
+ end
25
+
26
+ def finish()
27
+ update(@progress = FIXED_PROGRESS)
27
28
  end
28
29
  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
30
+
31
+ # A simple class for displaying helpful info.
32
+ class InformationDialog < Wx::MessageDialog
33
+ INFO_DIALOG_FLAGS = Wx::OK|Wx::ICON_INFORMATION
34
+ def self.display(title, message)
35
+ new(nil, message, title, INFO_DIALOG_FLAGS).show_modal()
39
36
  end
40
-
41
- def next()
42
- if ! @progbar.update(@progress += 1)
43
- raise "Aborted document import"
44
- end
37
+ end
38
+
39
+ class ErrorDialog < Wx::MessageDialog
40
+ ERR_DIALOG_FLAGS = Wx::OK|Wx::ICON_ERROR
41
+ def self.display(title, message)
42
+ new(nil, message, title, ERR_DIALOG_FLAGS).show_modal()
45
43
  end
46
-
47
- def terminate()
48
- @progbar.destroy()
44
+ end
45
+
46
+ # A simple class for seeking warnings of risky requests.
47
+ class WarningDialog < Wx::MessageDialog
48
+ WARN_DIALOG_FLAGS = Wx::NO_DEFAULT|Wx::OK|Wx::CANCEL|Wx::ICON_EXCLAMATION
49
+ def self.display(title, message)
50
+ new(nil, message, title, WARN_DIALOG_FLAGS).show_modal()
49
51
  end
50
52
  end
51
-
53
+
54
+ class ConfirmDialog < Wx::MessageDialog
55
+ CONFIRM_DIALOG_FLAGS = Wx::NO_DEFAULT|Wx::YES|Wx::NO|Wx::ICON_EXCLAMATION
56
+ def self.display(title, message)
57
+ new(nil, message, title, CONFIRM_DIALOG_FLAGS).show_modal()
58
+ end
59
+ end
60
+
61
+ class SuppressibleConfirmDialog < ConfirmDialog
62
+ def self.suppress_conf()
63
+ conf = Wx::ConfigBase.get()
64
+ conf.path = '/SuppressWarnings'
65
+ conf
66
+ end
67
+
68
+ def self.suppressed?(key)
69
+ suppress_conf.read_bool(key, false)
70
+ end
71
+
72
+ def self.suppress(key)
73
+ suppress_conf.write(key, true)
74
+ end
75
+
76
+ def self.release(key)
77
+ suppress_conf.write(key, false)
78
+ end
79
+
80
+ def self.display(key, title, message)
81
+ if suppressed?(key)
82
+ return Wx::ID_YES
83
+ else
84
+ return super(title, message)
85
+ end
86
+ end
87
+ end
88
+
52
89
  class SearchDialog < Wx::Dialog
53
90
  def initialize(parent)
54
91
  super( parent, -1, 'Search', DEF_POS, Wx::Size.new(500,175) )
@@ -70,7 +107,7 @@ module QDA::GUI
70
107
 
71
108
  @expand = Wx::SpinCtrl.new( self, -1, "")
72
109
  @expand.set_range(0, 1000)
73
- @expand.set_value(100)
110
+ @expand.set_value(200)
74
111
  mini_sizer.add(@expand, 0, Wx::ALL, 4)
75
112
  mini_sizer.add(Wx::StaticText.new(self, -1, 'characters'),
76
113
  0, Wx::ALL, 6)
@@ -125,4 +162,70 @@ module QDA::GUI
125
162
  @expand.get_value().to_i
126
163
  end
127
164
  end
165
+
166
+ class ImportFileDialog < Wx::FileDialog
167
+ def initialize(parent, import_class)
168
+ @import_class = import_class
169
+ imports = QDA::Filters::import_filters[import_class]
170
+ wildcard = imports.map { | filt | '%s (*.%s)|*.%s' %
171
+ [ filt::DESCRIPTION,
172
+ filt::EXTENSIONS,
173
+ filt::EXTENSIONS ] }.join('|')
174
+ super(parent, Lang::IMPORT_DOC_DIALOGUE_TITLE,
175
+ "", "", wildcard, Wx::MULTIPLE)
176
+ end
177
+
178
+ # return each selected file in turn into a block, passing in +path+ and
179
+ # +filename+
180
+ def each_with_path
181
+ get_paths.each_with_index do | fpath, i |
182
+ yield fpath, get_filenames[i]
183
+ end
184
+ end
185
+
186
+ def filter()
187
+ QDA::Filters::import_filters[@import_class][filter_index]
188
+ end
189
+ end
190
+
191
+
192
+ class ExportFileDialog < Wx::FileDialog
193
+ def initialize(parent, export_obj)
194
+ @obj = export_obj
195
+ exports = QDA::Filters::export_filters[@obj.class]
196
+ wildcard = exports.map { | filt | '%s (*.%s)|*.%s' %
197
+ [ filt::DESCRIPTION,
198
+ filt::EXTENSION,
199
+ filt::EXTENSION ] }.join('|')
200
+ super(parent, Lang::EXPORT_DOC_DIALOGUE_TITLE,
201
+ "", "", wildcard, Wx::SAVE|Wx::OVERWRITE_PROMPT)
202
+ set_filename( exports[0].def_name(export_obj) )
203
+ end
204
+
205
+ def filter()
206
+ QDA::Filters::export_filters[@obj.class][filter_index]
207
+ end
208
+ end
209
+
210
+
211
+ class ScriptFileDialog < Wx::FileDialog
212
+ def initialize(parent, saving = false)
213
+ if saving
214
+ style = Wx::SAVE|Wx::OVERWRITE_PROMPT
215
+ title = 'Save a Script to a Ruby File'
216
+ else
217
+ style = Wx::OPEN
218
+ title = 'Import a Script from a Ruby File'
219
+ end
220
+ super(parent, title, "", "", 'Ruby files (*.rb)|*.rb', style)
221
+ end
222
+ end
223
+
224
+ class ScriptOutputFileDialog < Wx::FileDialog
225
+ def initialize(parent)
226
+ style = Wx::SAVE|Wx::OVERWRITE_PROMPT
227
+ super(parent, 'Save Script Output to a File',
228
+ "", "", 'Output files (*.txt)|*.txt', style)
229
+ end
230
+ end
128
231
  end
@@ -1,52 +1,132 @@
1
+ require 'net/http'
2
+ require 'rbconfig'
3
+ require 'uri'
4
+
1
5
  module QDA::GUI
2
- class ErrorHandlerApp < Wx::App
6
+ # A dialog that shows if Weft QDA encounters an unhandled exception.
7
+ # Gathers information about the error, and offers to send it over HTTP
8
+ # to a crash report CGI.
9
+ class CrashReportDialog < Wx::Dialog
3
10
  attr_accessor :err
11
+ attr_reader :panel
12
+ private :panel
13
+
14
+ def initialize(parent, exception)
15
+ super(nil, -1, Lang::CRASH_REPORT_TITLE)
16
+ @err = exception
4
17
 
5
- def on_init()
6
- frame = Wx::Frame.new(nil, -1, 'Text')
7
-
8
- panel = Wx::Panel.new(frame)
18
+ @panel = Wx::Panel.new(self)
9
19
  sizer = Wx::BoxSizer.new(Wx::VERTICAL)
20
+ text = Wx::StaticText.new(panel, -1, Lang::CRASH_REPORT_MESSAGE)
21
+ sizer.add(text, 0, Wx::ALL, 8)
22
+ sizer.add( construct_crash_report_form , 1, Wx::GROW|Wx::ALL, 5)
23
+ sizer.add( construct_send_buttons, 0,
24
+ Wx::GROW|Wx::ADJUST_MINSIZE|Wx::ALIGN_BOTTOM, 8)
25
+
26
+ panel.set_sizer(sizer)
27
+ self.client_size = Wx::Size.new(400, 500)
28
+ end
29
+
30
+ def self.display(*args)
31
+ new(*args).show_modal()
32
+ end
33
+
34
+ def rs2exe
35
+ if defined? ::RUBYSCRIPT2EXE_EEEEXE
36
+ return ::RUBYSCRIPT2EXE_EEEEXE
37
+ else
38
+ return ''
39
+ end
40
+ end
41
+
42
+ def crash_details()
43
+ @crash ||= { 'when' => Time.now.to_s(),
44
+ 'os' => Config::CONFIG['target_os'],
45
+ 'config' => Config::CONFIG['build'],
46
+ 'ruby_version' => [ Config::CONFIG['MAJOR'],
47
+ Config::CONFIG['MINOR'],
48
+ Config::CONFIG['TEENY'] ].join('.'),
49
+ 'rs2exe' => rs2exe,
50
+ 'backtrace' => ( [ err.inspect ] +
51
+ err.backtrace ).join("\n") }
52
+ end
53
+
54
+ def crash_details_string
55
+ %w[when os config ruby_version rs2exe backtrace].inject('') do | str, key |
56
+ str << "#{key}: #{crash_details[key]}\n"
57
+ end
58
+ end
59
+
60
+
61
+ def encoded_crash_details()
62
+ str = crash_details.keys.inject('') do | str, key |
63
+ str << URI.encode(key) << '=' << URI.encode(crash_details[key]) << '&'
64
+ end
65
+ str << URI.encode('email') << '=' << URI.encode(@email_box.value) << '&'
66
+ str << URI.encode('info') << '=' << URI.encode(@info_box.value)
67
+ end
68
+
69
+
70
+ def on_dont_send()
71
+ end_modal(Wx::ID_CANCEL)
72
+ end
73
+
74
+ #
75
+ def on_send()
76
+ disable()
77
+ Wx::BusyCursor.busy do
78
+ # see weft/wxgui/constants.rb for CRASH_REPORT_URL
79
+ Net::HTTP.start(CRASH_REPORT_URL.host, 80) do | http |
80
+ response = http.post(CRASH_REPORT_URL.path, encoded_crash_details)
81
+ if response.code != '204'
82
+ ErrorDialog.display( Lang::FAILED_CRASH_SEND_TITLE,
83
+ Lang::FAILED_CRASH_SEND_MESSAGE %
84
+ response.inspect )
85
+ end
86
+ end
87
+ end
88
+ end_modal(Wx::ID_OK)
89
+ end
90
+
91
+ def construct_crash_report_form()
92
+ report_box = Wx::StaticBox.new(panel, -1, Lang::CRASH_REPORT)
93
+ report_box_sizer = Wx::StaticBoxSizer.new(report_box, Wx::VERTICAL)
94
+
95
+ email_label = Wx::StaticText.new(panel, -1, Lang::CRASH_REPORT_EMAIL)
96
+ report_box_sizer.add(email_label, 0, Wx::ALL, 3)
97
+ @email_box = Wx::TextCtrl.new(panel, -1, '')
98
+ report_box_sizer.add(@email_box, 0, Wx::ALL|Wx::GROW, 3)
99
+
100
+ info_label = Wx::StaticText.new(panel, -1, Lang::CRASH_REPORT_INFO)
101
+ report_box_sizer.add(info_label, 0, Wx::ALL, 3)
102
+ @info_box = Wx::TextCtrl.new(panel, -1, '')
103
+ report_box_sizer.add(@info_box, 0, Wx::ALL|Wx::GROW, 3)
10
104
 
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)
105
+ data_label = Wx::StaticText.new(panel, -1, Lang::CRASH_REPORT_DATA)
106
+ report_box_sizer.add(data_label, 0, Wx::ALL, 2)
107
+
108
+ @text_box = Wx::TextCtrl.new(panel, -1, crash_details_string(),
109
+ DEF_POS, DEF_SIZE,
110
+ Wx::TE_MULTILINE|Wx::TE_RICH|
111
+ Wx::TE_NOHIDESEL|Wx::TE_READONLY )
112
+ report_box_sizer.add(@text_box, 1, Wx::ALL|Wx::GROW, 3)
113
+ return report_box_sizer
114
+ end
115
+
116
+
117
+ def construct_send_buttons()
14
118
  butt_panel = Wx::Panel.new(panel)
15
119
  bott_sizer = Wx::BoxSizer.new(Wx::HORIZONTAL)
16
120
 
17
- button = Wx::Button.new(butt_panel, -1, 'Save')
18
- button.evt_button(button.get_id) { | e | on_font(e) }
121
+ button = Wx::Button.new(butt_panel, -1, "Don't Send")
122
+ button.evt_button(button.get_id) { | e | on_dont_send() }
19
123
  bott_sizer.add(button, 1, Wx::ALL, 4)
20
124
 
21
125
  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) }
126
+ button.evt_button(button.get_id) { on_send }
27
127
  bott_sizer.add(button, 1, Wx::ALL, 4)
28
-
29
128
  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
129
+ return butt_panel
49
130
  end
50
131
  end
51
-
52
132
  end
@@ -0,0 +1,7 @@
1
+ module QDA::GUI
2
+ class GUIException < StandardError
3
+ end
4
+
5
+ class UserAbortedException < GUIException
6
+ end
7
+ end
@@ -1,208 +1,36 @@
1
- require 'weft/wxgui/inspectors/textcontrols'
2
-
3
1
  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
2
+ class MDIWorkAreaWindow < Wx::MDIChildFrame
3
+ def initialize(workarea, *args)
4
+ super(workarea, -1, *args)
50
5
  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
6
+ end
7
+
8
+ class StandaloneWorkAreaWindow < Wx::Frame
9
+ def initialize(workarea, *args)
10
+ super(nil, -1, *args)
63
11
  end
64
12
 
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?
13
+ #
14
+ def activate()
15
+ # TODO - raise() doesn't seem to work on GTK
16
+ shown? ? raise() : show()
76
17
  end
18
+ end
77
19
 
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
20
+ if WINDOW_MODE == :MDI
21
+ WorkAreaWindowBaseClass = MDIWorkAreaWindow
22
+ else
23
+ WorkAreaWindowBaseClass = StandaloneWorkAreaWindow
197
24
  end
198
25
 
199
- class WorkAreaWindow < Wx::MDIChildFrame
26
+ class WorkAreaWindow < WorkAreaWindowBaseClass
200
27
  # the default size for new windows of this type and
201
28
  # subclasses. Expressed as a proportion of MDI client area width
202
29
  # and MDI client area height.
203
30
  W_WINDOW_DEF_SIZE = [ 0.6, 0.8 ]
204
31
 
205
32
  def initialize(workarea, title, last_layout)
33
+ @workarea = workarea
206
34
  size = pos = nil
207
35
  if last_layout
208
36
  size = Wx::Size.new( last_layout[:w], last_layout[:h] )
@@ -212,9 +40,15 @@ module QDA::GUI
212
40
  size = workarea.proportional_size(*proportions)
213
41
  pos = Wx::DEFAULT_POSITION
214
42
  end
215
- super(workarea, -1, title, pos, size)
43
+ super(workarea, title, pos, size)
44
+ evt_set_focus() { | e | on_focus() }
216
45
  end
217
46
 
47
+ #
48
+ def on_focus()
49
+ @workarea.active_child = self
50
+ end
51
+
218
52
  # returns a hash serialising the current shape and location of
219
53
  # this window, so it can later be unthawed
220
54
  def layout()
@@ -239,17 +73,19 @@ module QDA::GUI
239
73
 
240
74
  # a WorkArea Window with a notebook layout with a coding panel
241
75
  # including a text display in the first pane. Documents, Categories
242
- # and Queries are all displayed using this model
76
+ # and Queries are all displayed using this model.
243
77
  class InspectorWindow < WorkAreaWindow
244
- if Wx::RUBY_PLATFORM == 'WXGTK'
78
+ if Wx::RUBY_PLATFORM == 'WXGTK' and WINDOW_MODE == :MDI
245
79
  # GTK uses a notebook to fake MDI windows, so if running under
246
- # WXGTK, place the real notebook tabs on the right instead
80
+ # WXGTK and using MDI mode, place the real notebook tabs on the
81
+ # right instead. Note that this combo (GTK+MDI) is not recommended
247
82
  INSPECTOR_NB_STYLE = [ Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE,
248
83
  Wx::NB_RIGHT ]
249
84
  else
250
85
  INSPECTOR_NB_STYLE = []
251
86
  end
252
-
87
+ attr_reader :client
88
+
253
89
  def initialize(workarea, title, last_layout, &text_constructor)
254
90
  super(workarea, title, last_layout)
255
91
 
@@ -258,22 +94,29 @@ module QDA::GUI
258
94
  sizer_1 = Wx::BoxSizer.new(Wx::VERTICAL)
259
95
 
260
96
  @text_box = text_constructor.call(panel_1)
97
+ @text_box.evt_key_down { | e | on_key_down(e) }
261
98
  sizer_1.add(@text_box, 10, Wx::GROW|Wx::ALL, 4)
262
99
 
263
100
  butt_panel = Wx::Panel.new(panel_1, -1)
264
101
  bott_sizer = Wx::BoxSizer.new(Wx::HORIZONTAL)
265
102
 
266
- @drop_down = CategoryDropDown.new(@app, butt_panel, @text_box)
103
+ @drop_down = CategoryDropDown.new(client, butt_panel, @text_box)
267
104
  bott_sizer.add(@drop_down, 3, Wx::ALL, 4)
268
105
 
269
- button = Wx::Button.new(butt_panel, -1, 'Code')
106
+ button = Wx::Button.new(butt_panel, -1, 'Mark')
270
107
  button.evt_button(button.get_id) { | e | on_code(e) }
271
108
  bott_sizer.add(button, 1, Wx::ALL, 4)
272
109
 
273
- button = Wx::Button.new(butt_panel, -1, 'Uncode')
110
+ button = Wx::Button.new(butt_panel, -1, 'Unmark')
274
111
  button.evt_button(button.get_id) { | e | on_uncode(e) }
275
112
  bott_sizer.add(button, 1, Wx::ALL, 4)
276
-
113
+
114
+ if @text_box.respond_to?(:start_find)
115
+ button = Wx::Button.new(butt_panel, -1, 'Find')
116
+ button.evt_button(button.get_id) { @text_box.start_find(self) }
117
+ bott_sizer.add(button, 1, Wx::ALL, 4)
118
+ end
119
+
277
120
  # button = Wx::Button.new(butt_panel, -1, 'Note')
278
121
  # button.evt_button(button.get_id) { | e | on_code(e) }
279
122
  # bott_sizer.add(button, 1, Wx::ALL, 4, Wx::ALIGN_RIGHT)
@@ -286,6 +129,7 @@ module QDA::GUI
286
129
  panel_1.set_sizer( sizer_1 )
287
130
  @notebook.add_page(panel_1, 'text')
288
131
  evt_activate() { | e | on_activate(e) }
132
+ subscribe(client, :text_font_changed)
289
133
  end
290
134
 
291
135
  # (hopefully temporary) method -- when this window is closed,
@@ -315,9 +159,8 @@ module QDA::GUI
315
159
  codes = @text_box.selection_to_fragments()
316
160
  codes.each { | c | category.code(c.docid, c.offset, c.length) }
317
161
 
318
- $wxapp.app.save_category( category )
162
+ @client.app.save_category( category )
319
163
  @drop_down.sticky = true
320
- $wxapp.broadcast(:category_changed, category )
321
164
  end
322
165
  end
323
166
 
@@ -327,14 +170,24 @@ module QDA::GUI
327
170
  Wx::BusyCursor.busy do
328
171
  codes = @text_box.selection_to_fragments()
329
172
  codes.each { | c | category.uncode(c.docid, c.offset, c.length) }
330
- $wxapp.app.save_category( category )
173
+ @client.app.save_category( category )
331
174
  @drop_down.sticky = true
332
- $wxapp.broadcast(:category_changed, category )
333
175
  end
334
176
  end
335
177
 
336
- def refresh()
337
-
178
+ # implements keyboard shortcuts for this window - these are activated by
179
+ # interaction with the text-box.
180
+ # currently, CTRL-k is mapped to "Code" and CTRL-l is mapped to "Uncode"
181
+ def on_key_down(evt)
182
+ return unless evt.control_down()
183
+ case evt.key_code()
184
+ when 70 # "f"
185
+ @text_box.start_find(self) if @text_box.respond_to?(:start_find)
186
+ when 77 # "m"
187
+ on_code(evt)
188
+ when 44 # ","
189
+ on_uncode(evt)
190
+ end
338
191
  end
339
192
 
340
193
  # the current category active in this window
@@ -347,7 +200,7 @@ module QDA::GUI
347
200
  end
348
201
 
349
202
  # set the display font for use in this inspector
350
- def set_display_font(font)
203
+ def receive_text_font_changed(font)
351
204
  @text_box.set_font(font)
352
205
  end
353
206
  end
@@ -355,7 +208,7 @@ module QDA::GUI
355
208
  require 'weft/wxgui/inspectors/document.rb'
356
209
  require 'weft/wxgui/inspectors/category.rb'
357
210
  # require 'weft/wxgui/inspectors/imagedocument.rb'
358
- require 'weft/wxgui/inspectors/search.rb'
211
+ require 'weft/wxgui/inspectors/query.rb'
359
212
  require 'weft/wxgui/inspectors/script.rb'
360
213
  require 'weft/wxgui/inspectors/codereview.rb'
361
214
  end