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,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