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.
- 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/utilities.rb
CHANGED
@@ -1,126 +1,105 @@
|
|
1
|
+
# temporary hack to turn c++ style set_foo(), get_foo() and is_foo()
|
2
|
+
# accessors into ruby style foo=() foo() and foo?()
|
3
|
+
wx_classes = Wx::constants.collect { | c | Wx::const_get(c) }.grep(Class)
|
4
|
+
wx_classes.each do | klass |
|
5
|
+
klass.instance_methods.grep(/^([gs]et|evt|is)_/).each do | meth |
|
6
|
+
case meth
|
7
|
+
when /^get_(\w+)$/
|
8
|
+
klass.class_eval("alias :#{$1} :#{meth}")
|
9
|
+
when /^set_(\w+)$/
|
10
|
+
klass.class_eval("alias :#{$1}= :#{meth}")
|
11
|
+
when /^is_(\w+)$/
|
12
|
+
klass.class_eval("alias :#{$1}? :#{meth}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Wx::NORMAL_CURSOR = Wx::Cursor.new(Wx::CURSOR_ARROW)
|
18
|
+
Wx::BUSY_CURSOR = Wx::Cursor.new(Wx::CURSOR_WAIT)
|
19
|
+
|
1
20
|
module QDA::GUI
|
2
21
|
# ItemData - allows widgets to store information about assocations
|
3
22
|
# with underlying project objects such as categories and documents.
|
4
23
|
module ItemData
|
5
24
|
# for faked-up item data
|
6
25
|
def get_item_data(id)
|
7
|
-
|
26
|
+
data[id]
|
8
27
|
end
|
9
28
|
alias :get_client_data :get_item_data
|
10
29
|
|
11
30
|
# for faked-up item data
|
12
|
-
def set_item_data(id,
|
13
|
-
|
14
|
-
@data_table[id] = data
|
15
|
-
return nil
|
31
|
+
def set_item_data(id, data_obj)
|
32
|
+
data[id] = data_obj
|
16
33
|
end
|
17
34
|
alias :set_client_data :set_item_data
|
18
|
-
|
35
|
+
|
19
36
|
# returns the key associated with the value +value+
|
20
37
|
def value_to_ident(value)
|
21
38
|
return nil if value.nil?
|
22
|
-
|
39
|
+
if value.nil?
|
40
|
+
return nil
|
41
|
+
elsif value.respond_to?(:dbid)
|
42
|
+
the_id = value.dbid
|
43
|
+
elsif value.kind_of?(Fixnum)
|
44
|
+
the_id = value
|
45
|
+
else
|
23
46
|
Kernel.raise "Cannot search for invalid value #{value.inspect}"
|
24
47
|
end
|
25
|
-
|
26
|
-
return k if val.dbid == value.dbid
|
27
|
-
end
|
28
|
-
return nil
|
48
|
+
return index(the_id)
|
29
49
|
end
|
30
50
|
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
module Broadcaster
|
37
|
-
SUBSCRIBABLE_EVENTS = [ :document_added, :document_changed,
|
38
|
-
:document_deleted, :category_added, :category_changed,
|
39
|
-
:category_deleted, :focus_category, :savestate_changed ]
|
40
|
-
|
41
|
-
# intended to be module private variables to managed which widgets
|
42
|
-
# are subscribing to which events
|
43
|
-
attr_accessor :bc__subscribers, :bc__subscriptions
|
44
|
-
|
45
|
-
# broadcast an event to all subscribers to event of type
|
46
|
-
# +event_type+, optionally including +content+
|
47
|
-
def broadcast(event_type, content = nil)
|
48
|
-
for subscriber in bc__subscriptions[event_type]
|
49
|
-
subscriber.notify(event_type, content)
|
50
|
-
end
|
51
|
+
|
52
|
+
module ListLikeItemData
|
53
|
+
include ItemData
|
54
|
+
def data()
|
55
|
+
@data_table ||= Array.new()
|
51
56
|
end
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
events.each do | e |
|
57
|
-
bc__subscriptions[e].push(subscriber)
|
58
|
-
end
|
59
|
-
subscriber.evt_close do | e |
|
60
|
-
delete_subscriber(subscriber)
|
61
|
-
e.skip()
|
57
|
+
|
58
|
+
def delete_item_data(the_data)
|
59
|
+
if i = value_to_ident(the_data)
|
60
|
+
data.delete_at(i)
|
62
61
|
end
|
63
62
|
end
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
subscriber.associated_subscribers.each do | child |
|
69
|
-
delete_subscriber(child)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
bc__subscribers.delete(subscriber)
|
73
|
-
bc__subscriptions.each_value do | subscriber_set |
|
74
|
-
subscriber_set.delete(subscriber)
|
75
|
-
end
|
63
|
+
|
64
|
+
def unshift_item_data(the_data)
|
65
|
+
delete_item_data(the_data)
|
66
|
+
data.unshift(the_data)
|
76
67
|
end
|
77
68
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
obj.reset_subscriptions()
|
69
|
+
def push_item_data(the_data)
|
70
|
+
delete_item_data(the_data)
|
71
|
+
data.push(the_data)
|
82
72
|
end
|
83
|
-
|
84
|
-
def
|
85
|
-
|
86
|
-
|
87
|
-
raise "Cannot subscribe to unknown event #{ev}"
|
73
|
+
|
74
|
+
def index(the_id)
|
75
|
+
data.each_with_index do | val, i |
|
76
|
+
return i if val.dbid == the_id
|
88
77
|
end
|
89
|
-
|
78
|
+
return nil
|
90
79
|
end
|
91
80
|
end
|
92
81
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
module Subscriber
|
98
|
-
# receive notification that an event of type +ev+ has been called,
|
99
|
-
# optionally passing +content+ for additional information about the
|
100
|
-
# object the event concerned.
|
101
|
-
def notify(ev, content = nil)
|
102
|
-
receiver = "receive_#{ev}".intern
|
103
|
-
if respond_to?(receiver)
|
104
|
-
send(receiver, content)
|
105
|
-
else
|
106
|
-
warn "#{self} received unhandled event #{ev}"
|
107
|
-
end
|
82
|
+
module HashLikeItemData
|
83
|
+
include ItemData
|
84
|
+
def data()
|
85
|
+
@data_table ||= Hash.new()
|
108
86
|
end
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
# For every event type to which a subscriber subscribes, it should
|
116
|
-
# implement a corresponding receive_xxx method, where xxx is the
|
117
|
-
# name of the event type. To act upon category changes, the
|
118
|
-
# subscriber should implement +receive_category_changed+
|
119
|
-
def subscribe(*events)
|
120
|
-
$wxapp.add_subscriber(self, *events)
|
87
|
+
|
88
|
+
def index(the_id)
|
89
|
+
data.each do | k, val |
|
90
|
+
return k if val.dbid == the_id
|
91
|
+
end
|
92
|
+
return nil
|
121
93
|
end
|
122
94
|
end
|
123
|
-
|
95
|
+
|
96
|
+
class LabelledVSizer < Wx::StaticBoxSizer
|
97
|
+
def initialize(sized_object, label)
|
98
|
+
static_box = Wx::StaticBox.new(sized_object, -1, label)
|
99
|
+
super(static_box, Wx::VERTICAL)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
124
103
|
# extension to Wx::Colour
|
125
104
|
class Wx::Colour
|
126
105
|
# Create a new colour by mixing +self_parts+ of +self+ with
|
data/lib/weft/wxgui/workarea.rb
CHANGED
@@ -1,27 +1,28 @@
|
|
1
1
|
module QDA::GUI
|
2
2
|
# The main application window, where docuemnts, categories, searches
|
3
3
|
# etc are displayed. Only one instance per application.
|
4
|
-
|
5
|
-
include Subscriber
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
restore_size()
|
13
|
-
subscribe(:savestate_changed)
|
14
|
-
end
|
15
|
-
|
4
|
+
module InspectorWindowManager
|
5
|
+
include QDA::Subscriber
|
6
|
+
|
7
|
+
# This sets the last-focussed child. However, when later requesting info
|
8
|
+
# on the currently active window, MDI reports the active_child() call,
|
9
|
+
# whereas the @active_child variable is read by MultiframeWindowManager
|
10
|
+
# - in MDI there is a foremost window which may not have received focus.
|
11
|
+
attr_writer :active_child
|
16
12
|
# Resizes the workarea to the state when the application was last used
|
17
13
|
def restore_size()
|
18
14
|
conf = Wx::ConfigBase::get()
|
19
15
|
conf.path = "/MainFrame"
|
20
|
-
x = conf.read_int("x",
|
21
|
-
y = conf.read_int("y",
|
22
|
-
w = conf.read_int("w",
|
23
|
-
h = conf.read_int("h",
|
16
|
+
x = conf.read_int( "x", -1 )
|
17
|
+
y = conf.read_int( "y", -1 )
|
18
|
+
w = conf.read_int( "w", -1 )
|
19
|
+
h = conf.read_int( "h", -1 )
|
24
20
|
max = conf.read_bool("max", false)
|
21
|
+
|
22
|
+
x = DEF_POS.x if x < 0
|
23
|
+
y = DEF_POS.y if y < 0
|
24
|
+
w = DEF_SIZE.width if w < 200
|
25
|
+
h = DEF_SIZE.height if h < 200
|
25
26
|
|
26
27
|
if max
|
27
28
|
maximize(true)
|
@@ -32,6 +33,9 @@ module QDA::GUI
|
|
32
33
|
end
|
33
34
|
|
34
35
|
# save layout to Config so window is same position next time
|
36
|
+
|
37
|
+
|
38
|
+
|
35
39
|
def remember_size()
|
36
40
|
conf = Wx::ConfigBase::get()
|
37
41
|
# global window size settings
|
@@ -70,7 +74,7 @@ module QDA::GUI
|
|
70
74
|
else
|
71
75
|
w_i = window_ident(bound_obj)
|
72
76
|
last_layout = restore_layout( w_i )
|
73
|
-
win = klass.new( bound_obj, @
|
77
|
+
win = klass.new( bound_obj, @client, self, last_layout )
|
74
78
|
@window_map[w_i] = win
|
75
79
|
|
76
80
|
# set up a hook to clean up when this window is closed later
|
@@ -127,7 +131,7 @@ module QDA::GUI
|
|
127
131
|
# remember how the windows were arranged
|
128
132
|
def remember_layouts()
|
129
133
|
# project specific settings
|
130
|
-
if
|
134
|
+
if self.app
|
131
135
|
@window_map.each do | key, window |
|
132
136
|
remember_layout(key, window, true) unless key.nil?
|
133
137
|
end
|
@@ -135,64 +139,167 @@ module QDA::GUI
|
|
135
139
|
end
|
136
140
|
|
137
141
|
def remember_layout(window_id, window, open = false)
|
138
|
-
if
|
139
|
-
layouts =
|
142
|
+
if self.app
|
143
|
+
layouts = app.get_preference('Layouts') || {}
|
140
144
|
layouts[window_id] = window.layout
|
141
145
|
layouts[window_id][:open] = open
|
142
|
-
|
146
|
+
app.save_preference('Layouts', layouts)
|
143
147
|
end
|
144
148
|
end
|
145
149
|
|
146
150
|
def restore_layout(window_id)
|
147
|
-
if
|
148
|
-
layouts =
|
151
|
+
if self.app
|
152
|
+
layouts = app.get_preference('Layouts') || {}
|
149
153
|
return layouts[window_id]
|
150
154
|
end
|
151
155
|
end
|
152
156
|
|
153
157
|
def restore_layouts()
|
154
|
-
if
|
155
|
-
layouts =
|
158
|
+
if self.app
|
159
|
+
layouts = app.get_preference('Layouts')
|
156
160
|
return unless layouts
|
157
161
|
# get all previously open windows
|
158
162
|
open = layouts.find_all { | x | x[1][:open] }
|
159
163
|
open.each do | ident, layout |
|
160
164
|
if ident =~ /^Document(\w+)$/
|
161
|
-
|
165
|
+
@client.on_document_open($1)
|
162
166
|
elsif ident =~ /^Category(\w+)/ and
|
163
|
-
cat =
|
164
|
-
|
167
|
+
cat = app.get_category($1, true)
|
168
|
+
@client.on_category_open(cat)
|
165
169
|
end
|
166
170
|
end
|
167
171
|
end
|
168
172
|
end
|
169
173
|
|
170
|
-
def set_display_font(font)
|
171
|
-
# super(font)
|
172
|
-
@window_map.values.each do | child |
|
173
|
-
child.set_display_font(font) if child.respond_to?(:set_display_font)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
174
|
def close_all()
|
178
175
|
@window_map.values.each { | child | child.close() }
|
176
|
+
close_d_and_c()
|
179
177
|
end
|
180
178
|
|
181
|
-
def
|
182
|
-
|
183
|
-
|
184
|
-
|
179
|
+
def notify(ev, content = nil)
|
180
|
+
case ev
|
181
|
+
when :focus_category
|
182
|
+
return # ignore
|
183
|
+
when :ended
|
184
|
+
title = 'Weft QDA'
|
185
|
+
when :saved, :started
|
186
|
+
title = 'Weft QDA'
|
187
|
+
if self.app.dbfile
|
185
188
|
title << " - #{app.dbfile}"
|
186
189
|
else
|
187
190
|
title << " - [New Project]"
|
188
191
|
end
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
+
else
|
193
|
+
title = get_title()
|
194
|
+
title << '*' if title[-1,1] != '*'
|
195
|
+
end
|
196
|
+
set_title(title)
|
197
|
+
end
|
198
|
+
|
199
|
+
def app()
|
200
|
+
@client.app
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
class MDIWorkArea < Wx::MDIParentFrame
|
206
|
+
include InspectorWindowManager
|
207
|
+
def initialize(weft_client)
|
208
|
+
@client = weft_client
|
209
|
+
@window_map = {}
|
210
|
+
super(nil, -1, "Weft QDA")
|
211
|
+
restore_size()
|
212
|
+
subscribe(@client, :all)
|
213
|
+
end
|
214
|
+
|
215
|
+
def d_and_c()
|
216
|
+
@sidebar
|
217
|
+
end
|
218
|
+
|
219
|
+
# display the listings of documents and categories
|
220
|
+
def show_d_and_c()
|
221
|
+
if not @sidebar
|
222
|
+
# see sidebar.rb
|
223
|
+
@sidebar = SideBar.new( self, @client )
|
192
224
|
end
|
193
|
-
|
225
|
+
@sidebar.show()
|
226
|
+
end
|
227
|
+
|
228
|
+
def hide_d_and_c()
|
229
|
+
@sidebar.hide() if @sidebar
|
230
|
+
end
|
231
|
+
|
232
|
+
def close_d_and_c()
|
233
|
+
return if not @sidebar
|
234
|
+
@sidebar.remember_size()
|
235
|
+
@sidebar.close()
|
236
|
+
@sidebar = nil
|
237
|
+
end
|
238
|
+
|
239
|
+
def d_and_c_visible?()
|
240
|
+
@sidebar.shown?
|
241
|
+
end
|
242
|
+
|
243
|
+
def hide_all()
|
244
|
+
hide_d_and_c()
|
245
|
+
self.hide()
|
194
246
|
end
|
195
247
|
end
|
248
|
+
|
249
|
+
# presentation of main window as a standalone window, launching inspector
|
250
|
+
# windows as separate frames
|
251
|
+
class MultiFrameWorkArea < Wx::Frame
|
252
|
+
include InspectorWindowManager
|
253
|
+
|
254
|
+
attr_reader :d_and_c, :active_child
|
255
|
+
|
256
|
+
def initialize(weft_client)
|
257
|
+
@client = weft_client
|
258
|
+
@window_map = {}
|
259
|
+
super(nil, -1, "Weft QDA")
|
260
|
+
restore_size()
|
261
|
+
set_sizer( @sizer = Wx::BoxSizer.new(Wx::VERTICAL) )
|
262
|
+
subscribe(@client, :all)
|
263
|
+
end
|
264
|
+
|
265
|
+
def show_d_and_c()
|
266
|
+
if not @d_and_c
|
267
|
+
@d_and_c ||= DocumentsAndCategories.new(self, @client)
|
268
|
+
conf = Wx::ConfigBase::get()
|
269
|
+
conf.path = "/SideFrame"
|
270
|
+
split = conf.read_int("split", 200)
|
271
|
+
# sometimes weirdly ends up with negative value
|
272
|
+
split = client_size.height / 2 if split <= 0
|
273
|
+
@d_and_c.set_sash_position(split)
|
274
|
+
@sizer.add(@d_and_c, 1, Wx::GROW|Wx::ALL, 0)
|
275
|
+
@sizer.layout()
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def hide_d_and_c()
|
280
|
+
# do nothing
|
281
|
+
end
|
282
|
+
|
283
|
+
def close_d_and_c()
|
284
|
+
@sizer.remove(@d_and_c)
|
285
|
+
@d_and_c.destroy()
|
286
|
+
@d_and_c = nil
|
287
|
+
end
|
288
|
+
|
289
|
+
def hide_all()
|
290
|
+
@window_map.each { | w | w.hide() }
|
291
|
+
self.hide()
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
|
297
|
+
if WINDOW_MODE == :MDI
|
298
|
+
WorkArea = MDIWorkArea
|
299
|
+
else
|
300
|
+
WorkArea = MultiFrameWorkArea
|
301
|
+
end
|
302
|
+
|
196
303
|
|
197
304
|
class EasyMenu < Wx::Menu
|
198
305
|
def EasyMenu.next_base()
|