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.
- data/lib/weft.rb +16 -1
- data/lib/weft/WEFT-VERSION-STRING.rb +1 -1
- data/lib/weft/application.rb +17 -74
- data/lib/weft/backend.rb +6 -32
- data/lib/weft/backend/sqlite.rb +222 -164
- data/lib/weft/backend/sqlite/category_tree.rb +52 -48
- data/lib/weft/backend/sqlite/database.rb +57 -0
- data/lib/weft/backend/sqlite/upgradeable.rb +7 -0
- data/lib/weft/broadcaster.rb +90 -0
- data/lib/weft/category.rb +139 -47
- data/lib/weft/codereview.rb +160 -0
- data/lib/weft/coding.rb +74 -23
- data/lib/weft/document.rb +23 -10
- data/lib/weft/exceptions.rb +10 -0
- data/lib/weft/filters.rb +47 -224
- data/lib/weft/filters/indexers.rb +137 -0
- data/lib/weft/filters/input.rb +118 -0
- data/lib/weft/filters/output.rb +101 -0
- data/lib/weft/filters/templates.rb +80 -0
- data/lib/weft/filters/win32backtick.rb +246 -0
- data/lib/weft/query.rb +169 -0
- data/lib/weft/wxgui.rb +349 -294
- data/lib/weft/wxgui/constants.rb +43 -0
- data/lib/weft/wxgui/controls.rb +6 -0
- data/lib/weft/wxgui/controls/category_dropdown.rb +192 -0
- data/lib/weft/wxgui/controls/category_tree.rb +314 -0
- data/lib/weft/wxgui/controls/document_list.rb +97 -0
- data/lib/weft/wxgui/controls/multitype_control.rb +37 -0
- data/lib/weft/wxgui/{inspectors → controls}/textcontrols.rb +235 -64
- data/lib/weft/wxgui/dialogs.rb +144 -41
- data/lib/weft/wxgui/error_handler.rb +116 -36
- data/lib/weft/wxgui/exceptions.rb +7 -0
- data/lib/weft/wxgui/inspectors.rb +61 -208
- data/lib/weft/wxgui/inspectors/category.rb +19 -16
- data/lib/weft/wxgui/inspectors/codereview.rb +90 -132
- data/lib/weft/wxgui/inspectors/document.rb +12 -8
- data/lib/weft/wxgui/inspectors/imagedocument.rb +56 -56
- data/lib/weft/wxgui/inspectors/query.rb +284 -0
- data/lib/weft/wxgui/inspectors/script.rb +147 -23
- data/lib/weft/wxgui/lang/en.rb +69 -0
- data/lib/weft/wxgui/sidebar.rb +90 -432
- data/lib/weft/wxgui/utilities.rb +70 -91
- data/lib/weft/wxgui/workarea.rb +150 -43
- data/share/icons/category.ico +0 -0
- data/share/icons/category.xpm +109 -0
- data/share/icons/codereview.ico +0 -0
- data/share/icons/codereview.xpm +54 -0
- data/share/icons/d_and_c.xpm +126 -0
- data/share/icons/document.ico +0 -0
- data/share/icons/document.xpm +70 -0
- data/share/icons/project.ico +0 -0
- data/share/icons/query.ico +0 -0
- data/share/icons/query.xpm +56 -0
- data/{lib/weft/wxgui → share/icons}/search.xpm +0 -0
- data/share/icons/weft.ico +0 -0
- data/share/icons/weft.xpm +62 -0
- data/share/icons/weft16.ico +0 -0
- data/share/icons/weft32.ico +0 -0
- data/share/templates/category_plain.html +18 -0
- data/share/templates/codereview_plain.html +18 -0
- data/share/templates/document_plain.html +13 -0
- data/share/templates/document_plain.txt +7 -0
- data/test/001-document.rb +55 -36
- data/test/002-category.rb +81 -6
- data/test/003-code.rb +8 -4
- data/test/004-application.rb +13 -34
- data/test/005-query_review.rb +139 -0
- data/test/006-filters.rb +54 -42
- data/test/007-output_filters.rb +113 -0
- data/test/009a-backend_sqlite_basic.rb +95 -24
- data/test/009b-backend_sqlite_complex.rb +43 -62
- data/test/009c_backend_sqlite_bench.rb +5 -10
- data/test/053-doc_inspector.rb +46 -0
- data/test/055-query_window.rb +50 -0
- data/test/all-tests.rb +1 -0
- data/test/test-common.rb +19 -0
- data/test/testdata/empty.qdp +0 -0
- data/test/testdata/simple with space.pdf +0 -0
- data/test/testdata/simple.pdf +0 -0
- data/weft-qda.rb +40 -7
- metadata +74 -14
- data/lib/weft/wxgui/category.xpm +0 -26
- data/lib/weft/wxgui/document.xpm +0 -25
- data/lib/weft/wxgui/inspectors/search.rb +0 -265
- data/lib/weft/wxgui/mondrian.xpm +0 -44
- data/lib/weft/wxgui/weft16.xpm +0 -31
data/lib/weft/wxgui/dialogs.rb
CHANGED
@@ -1,54 +1,91 @@
|
|
1
1
|
module QDA::GUI
|
2
|
-
class
|
3
|
-
PT_STYLE = Wx::PD_APP_MODAL|Wx::PD_AUTO_HIDE
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
19
|
-
|
20
|
-
|
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
|
26
|
-
@
|
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
|
31
|
-
|
32
|
-
|
33
|
-
def
|
34
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
48
|
-
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
12
|
-
|
13
|
-
|
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, '
|
18
|
-
button.evt_button(button.get_id) { | 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) {
|
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
|
@@ -1,208 +1,36 @@
|
|
1
|
-
require 'weft/wxgui/inspectors/textcontrols'
|
2
|
-
|
3
1
|
module QDA::GUI
|
4
|
-
class
|
5
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
#
|
66
|
-
def
|
67
|
-
|
68
|
-
|
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
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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 <
|
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,
|
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
|
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(
|
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, '
|
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, '
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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/
|
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
|