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/lang/en.rb
CHANGED
@@ -5,6 +5,17 @@ module QDA::GUI::Lang
|
|
5
5
|
FILE_ALREADY_EXISTS = "A project file with this name already exists. If you continue, all data in it will be lost. Are you sure?"
|
6
6
|
SIDEBAR_TITLE = "Documents & Categories"
|
7
7
|
SEARCH_RESULTS = "search results"
|
8
|
+
|
9
|
+
OPEN_PROJECT_ERROR_TITLE = "Cannot open project"
|
10
|
+
IMPORT_DOC_DIALOGUE_TITLE = "Import a Document From File"
|
11
|
+
EXPORT_DOC_DIALOGUE_TITLE = "Export to File"
|
12
|
+
|
13
|
+
REVERT_WARNING_TITLE = "Really revert project?"
|
14
|
+
REVERT_WARNING_MESSAGE =
|
15
|
+
"Are you sure you want to revert the project to its last saved state?
|
16
|
+
|
17
|
+
This will undo all changes made since the project was last saved"
|
18
|
+
|
8
19
|
REINDEX_DOCS_WARNING =
|
9
20
|
"This will reindex all previously imported documents, which will take
|
10
21
|
some time. You only need to do this once if:
|
@@ -15,7 +26,40 @@ Otherwise there is no need to run this command.
|
|
15
26
|
Are you sure you wish to proceed and reindex all documents? "
|
16
27
|
|
17
28
|
REINDEX_DOCS_WARNING_TITLE = "Reindex all documents?"
|
29
|
+
NO_EXPORT_FILTER_TITLE = "No export filter available"
|
30
|
+
NO_EXPORT_FILTER_WARNING =
|
31
|
+
"Sorry, there are no export filters available to output a %s"
|
32
|
+
DUPLICATE_CATEGORY_NAME_TITLE = "Duplicate category name"
|
33
|
+
DUPLICATE_CATEGORY_NAME_WARNING =
|
34
|
+
"A category with the same name already exists at this position.
|
35
|
+
|
36
|
+
Either choose a different name, or attach the category elsewhere in the tree."
|
37
|
+
|
38
|
+
BAD_CATEGORY_NAME_TITLE = "Bad Category Name"
|
39
|
+
BAD_CATEGORY_NAME_WARNING =
|
40
|
+
"A category may not have the character '/' at the beginning or end
|
41
|
+
of its name.
|
42
|
+
|
43
|
+
Please choose a different name and try again."
|
44
|
+
|
45
|
+
DELETE_DOCUMENT_TITLE= "Confirm document deletion"
|
46
|
+
DELETE_DOCUMENT_WARNING =
|
47
|
+
"The document '%s' will permanently deleted, along with its memo and
|
48
|
+
any coding applied to it.
|
49
|
+
|
50
|
+
Are you sure you want to proceed?"
|
51
|
+
|
52
|
+
DELETE_CATEGORY_TITLE= "Confirm category deletion"
|
53
|
+
DELETE_CATEGORY_WARNING =
|
54
|
+
"The category '%s' will permanently deleted, along with its memo and
|
55
|
+
any coding associated with it.
|
18
56
|
|
57
|
+
Are you sure you want to proceed?"
|
58
|
+
|
59
|
+
NO_COPYING_ERROR_TEXT =
|
60
|
+
"The author or publisher of this PDF document has locked it to
|
61
|
+
prevent copying and extraction of its text. It is not possible to
|
62
|
+
import this document."
|
19
63
|
NO_SEARCH_TERM_SPECIFIED = "No search term specified"
|
20
64
|
DOC_PANEL_TITLE = 'Documents'
|
21
65
|
IMPORT_DOC_BUTTON = 'Import...'
|
@@ -28,6 +72,31 @@ Are you sure you wish to proceed and reindex all documents? "
|
|
28
72
|
HELP_ABOUT_MESSAGE = "Thank you for trying Weft QDA
|
29
73
|
Version '#{::WEFT_VERSION}'\n\n-- qda@pressure.to"
|
30
74
|
|
75
|
+
|
76
|
+
CRASH_REPORT_TITLE = 'Weft QDA Crash reporting'
|
77
|
+
CRASH_REPORT_MESSAGE =
|
78
|
+
"The program has encountered an error and has to close. Any unsaved
|
79
|
+
work has been lost. Sorry for the inconvenience.
|
80
|
+
|
81
|
+
Weft QDA has gathered information about this error that can be used
|
82
|
+
to improve the software. This does not include any personal information
|
83
|
+
about you. It may occasionally include small sections of project data;
|
84
|
+
you can preview the full contents of the error report below.
|
85
|
+
|
86
|
+
To submit the error report and exit, click 'Send'. To exit without sending
|
87
|
+
any information, click 'Don't Send'."
|
88
|
+
|
89
|
+
CRASH_REPORT = 'Crash report'
|
90
|
+
CRASH_REPORT_EMAIL = 'Email (optional)'
|
91
|
+
CRASH_REPORT_INFO = 'Further information about the crash (optional)'
|
92
|
+
CRASH_REPORT_DATA = 'Crash information'
|
93
|
+
|
94
|
+
FAILED_CRASH_SEND_TITLE = 'Failed to send crash report'
|
95
|
+
FAILED_CRASH_SEND_MESSAGE =
|
96
|
+
'It was not possible to send the error report at this time.
|
97
|
+
|
98
|
+
%s'
|
99
|
+
|
31
100
|
if RUBY_PLATFORM =~ /mswin/
|
32
101
|
HELP_HELP_MESSAGE = <<HELP
|
33
102
|
Help files are installed with Weft QDA.
|
data/lib/weft/wxgui/sidebar.rb
CHANGED
@@ -1,449 +1,40 @@
|
|
1
1
|
module QDA::GUI
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
include ItemData
|
8
|
-
include Subscriber
|
9
|
-
|
10
|
-
attr_reader :root_id
|
11
|
-
|
12
|
-
# a +locked+ control is one that is not editable, and does not
|
13
|
-
# affect the selection of categories in other widgetes.
|
14
|
-
def initialize(app, parent, locked = false)
|
15
|
-
@app = app
|
16
|
-
@locked = locked
|
17
|
-
super(parent, -1, Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE,
|
18
|
-
CATEGORY_TREE_STYLE)
|
19
|
-
my_id = self.get_id()
|
20
|
-
evt_tree_item_activated(my_id) { | e | on_item_activated(e) }
|
21
|
-
|
22
|
-
if ! @locked
|
23
|
-
evt_tree_sel_changed(my_id) { | e | on_item_selected(e) }
|
24
|
-
evt_tree_end_drag(my_id) { | e | on_drag_end(e) }
|
25
|
-
evt_tree_begin_drag(my_id) { | e | on_drag_begin(e) }
|
26
|
-
evt_tree_begin_label_edit(my_id) { | e | on_edit_label_begin(e) }
|
27
|
-
evt_tree_end_label_edit(my_id) { | e | on_edit_label_end(e) }
|
28
|
-
evt_tree_key_down(my_id) { | e | on_key_down(e) }
|
29
|
-
end
|
30
|
-
|
31
|
-
subscribe(:category_deleted, :category_changed, :category_added)
|
32
|
-
end
|
33
|
-
|
34
|
-
# for faked-up item data
|
35
|
-
def append_item(parent, text, data = nil)
|
36
|
-
id = super(parent, text, -1, -1)
|
37
|
-
set_item_data(id, data)
|
38
|
-
set_item_bold(id) if parent == @root_id
|
39
|
-
id
|
40
|
-
end
|
41
|
-
|
42
|
-
# for faked-up item data
|
43
|
-
def prepend_item(parent, text, img = -1, sel_img = -1, data = nil)
|
44
|
-
id = super(parent, text, img, sel_img)
|
45
|
-
set_item_data(id, data)
|
46
|
-
return id
|
47
|
-
end
|
48
|
-
|
49
|
-
# for faked-up item data
|
50
|
-
def delete(id)
|
51
|
-
super(id)
|
52
|
-
@data_table.delete(id)
|
53
|
-
return nil
|
54
|
-
end
|
55
|
-
|
56
|
-
def populate(children)
|
57
|
-
# the root isn't shown, so the top level of +children+ is what
|
58
|
-
# appears at the base of the tree.
|
59
|
-
@root_id = add_root('ROOT')
|
60
|
-
append_recursively(@root_id, children)
|
61
|
-
refresh()
|
62
|
-
end
|
63
|
-
|
64
|
-
def append_recursively(parent, children)
|
65
|
-
children.each do | child_cat |
|
66
|
-
name = child_cat.name.empty? ? 'DEFAULT' : child_cat.name
|
67
|
-
|
68
|
-
id = append_item(parent, name, child_cat )
|
69
|
-
# remember this for later use
|
70
|
-
@search_id = id if name == 'SEARCHES'
|
71
|
-
@codes_id = id if name == 'CATEGORIES' or name == 'CODES'
|
72
|
-
|
73
|
-
append_recursively(id, child_cat.children)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# get the currently active category
|
78
|
-
def get_current_category()
|
79
|
-
if curr_sel = get_selection()
|
80
|
-
return nil if curr_sel == 0
|
81
|
-
category = get_item_data( curr_sel )
|
82
|
-
return nil if category.nil? # important for GTK
|
83
|
-
return nil if category.parent.nil? # don't return root nodes
|
84
|
-
category
|
85
|
-
end
|
86
|
-
end
|
87
|
-
alias :selected_category :get_current_category
|
88
|
-
|
89
|
-
|
90
|
-
def on_edit_label_begin(evt)
|
91
|
-
# TODO - this should really talk to the underlying category,
|
92
|
-
# rather than just assuming bold = locked
|
93
|
-
evt.veto() if bold?(evt.item)
|
94
|
-
end
|
95
|
-
|
96
|
-
def on_edit_label_end(evt)
|
97
|
-
new_text = evt.label
|
98
|
-
if new_text == ""
|
99
|
-
evt.veto()
|
100
|
-
return
|
101
|
-
end
|
102
|
-
|
103
|
-
old_text = get_item_text( evt.item )
|
104
|
-
# don't bother saving if the text isn't changed
|
105
|
-
return if old_text == new_text
|
106
|
-
|
107
|
-
Wx::BusyCursor.busy do
|
108
|
-
c_cdata = get_item_data( evt.item )
|
109
|
-
category = @app.app.get_category( c_cdata.dbid )
|
110
|
-
category.name = new_text
|
111
|
-
@app.app.save_category( category)
|
112
|
-
set_item_data(evt.item, category )
|
113
|
-
$wxapp.broadcast(:category_changed, category)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def on_drag_begin(evt)
|
118
|
-
@drag_subject = evt.item
|
119
|
-
evt.allow()
|
120
|
-
end
|
121
|
-
|
122
|
-
# relocates or merges the coding of the draggee to the drag target
|
123
|
-
def on_drag_end(evt)
|
124
|
-
@drag_target = evt.item
|
125
|
-
# control_down is a property of a mouse event, so this doesn't work
|
126
|
-
# p "CONTROL IS DOWN" if evt.control_down
|
127
|
-
move_item(@drag_subject, @drag_target)
|
128
|
-
|
129
|
-
@drag_subject = nil
|
130
|
-
@drag_target = nil
|
131
|
-
end
|
132
|
-
|
133
|
-
def dont_move(from)
|
134
|
-
select_item(from) if from != 0
|
135
|
-
end
|
136
|
-
# moves the item identifed by +from+ to be the last child of
|
137
|
-
# +to+
|
138
|
-
def move_item(from, to)
|
139
|
-
return dont_move(from) unless from and to
|
140
|
-
return dont_move(from) if from == 0 or to == 0
|
141
|
-
return dont_move(from) if from == to
|
142
|
-
|
143
|
-
movee = get_item_data( from )
|
144
|
-
destination = get_item_data( to )
|
145
|
-
# don't move root nodes
|
146
|
-
return dont_move(from) if not movee.parent
|
147
|
-
# ignore if no move
|
148
|
-
return dont_move(from) if movee.parent == destination
|
149
|
-
# don't attach to descendants
|
150
|
-
return dont_move(from) if @app.app.is_descendant?(movee, destination)
|
151
|
-
|
152
|
-
shift_nodes = Proc.new do | node, parent |
|
153
|
-
c_text = get_item_text( node )
|
154
|
-
category = get_item_data( node )
|
155
|
-
new_parent = get_item_data( parent )
|
156
|
-
|
157
|
-
# TODO - make expanded persist
|
158
|
-
# c_expand = is_expanded( node )
|
159
|
-
category.parent = new_parent
|
160
|
-
new_child = append_item(parent, c_text, category)
|
161
|
-
child = get_first_child(node)[0]
|
162
|
-
while child != 0
|
163
|
-
shift_nodes.call(child, new_child)
|
164
|
-
child = get_first_child(node)[0]
|
165
|
-
end
|
166
|
-
delete( node )
|
167
|
-
new_child
|
168
|
-
end
|
169
|
-
Wx::BusyCursor.busy do
|
170
|
-
new_cat = shift_nodes.call(from, to)
|
171
|
-
@app.app.save_category( get_item_data(new_cat) )
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
# when we're asked to add an item. This will be attached to the
|
176
|
-
# currently selected category in the tree, or the default 'CATEGORIES'
|
177
|
-
# category if no item is selected
|
178
|
-
def on_create_item()
|
179
|
-
# attach to currently selected
|
180
|
-
parent_item = get_selection()
|
181
|
-
# or default to 'CATEGORIES'
|
182
|
-
if parent_item.nil? || parent_item == 0
|
183
|
-
parent_item = @codes_id
|
184
|
-
end
|
185
|
-
|
186
|
-
dialog = Wx::TextEntryDialog.new(@app.sidebar, "Add Category\n",
|
187
|
-
"Enter the new category name",
|
188
|
-
"", Wx::OK | Wx::CANCEL)
|
189
|
-
|
190
|
-
if dialog.show_modal() == Wx::ID_OK
|
191
|
-
parent = get_item_data(parent_item)
|
192
|
-
cat = QDA::Category.new( dialog.get_value(), parent )
|
193
|
-
@app.app.save_category(cat)
|
194
|
-
$wxapp.broadcast(:category_added, cat)
|
195
|
-
|
196
|
-
expand(parent_item)
|
197
|
-
id = value_to_ident(cat)
|
198
|
-
select_item(id)
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
def valid_selection(event)
|
203
|
-
item_id = event.get_item()
|
204
|
-
return false if item_id.nil? or item_id == 0
|
205
|
-
return false if is_bold(item_id)
|
206
|
-
get_item_data(item_id)
|
207
|
-
end
|
208
|
-
|
209
|
-
def on_item_selected(event)
|
210
|
-
category = valid_selection(event) or return()
|
211
|
-
@app.current_category = category
|
212
|
-
end
|
213
|
-
|
214
|
-
def on_item_activated(event)
|
215
|
-
item_id = event.get_item()
|
216
|
-
category = get_item_data(item_id)
|
217
|
-
return nil if category.parent.nil?
|
218
|
-
Wx::BusyCursor.busy() do
|
219
|
-
category = @app.app.get_category(category.dbid, 1)
|
220
|
-
if category != nil
|
221
|
-
@app.on_category_open(category)
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def delete_item(itemid)
|
227
|
-
Wx::BusyCursor.busy() do
|
228
|
-
return false if is_bold(itemid)
|
229
|
-
cat = get_item_data(itemid)
|
230
|
-
if cat
|
231
|
-
# delete_category is recursive and so several categories may be
|
232
|
-
# removed, and each is broadcast separately
|
233
|
-
dels = @app.app.delete_category(cat)
|
234
|
-
dels.each do | deletion |
|
235
|
-
$wxapp.broadcast(:category_deleted, deletion)
|
236
|
-
end
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
def on_key_down(evt)
|
242
|
-
sel = get_selection()
|
243
|
-
case evt.key_code()
|
244
|
-
when 127 # DEL
|
245
|
-
delete_item(sel)
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
def receive_category_deleted(cat)
|
250
|
-
# may not include this item if it's a partial subtree
|
251
|
-
if tree_id = value_to_ident(cat)
|
252
|
-
delete( value_to_ident(cat) )
|
253
|
-
@data_table.delete(cat)
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
def receive_category_changed(cat)
|
258
|
-
# may not include this item if it's a partial subtree
|
259
|
-
if tree_id = value_to_ident(cat)
|
260
|
-
set_item_data( value_to_ident(cat), cat)
|
261
|
-
set_item_text( value_to_ident(cat), cat.name)
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
def receive_category_added(cat)
|
266
|
-
if cat.parent.nil?
|
267
|
-
p_id = @root_id
|
268
|
-
else
|
269
|
-
p_id = value_to_ident(cat.parent)
|
270
|
-
end
|
271
|
-
append_item( p_id, cat.name, cat) if p_id
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
class DocumentList < Wx::ListBox
|
276
|
-
include ItemData
|
277
|
-
include Subscriber
|
278
|
-
|
279
|
-
def initialize(app, *args)
|
280
|
-
@app = app
|
281
|
-
super(*args)
|
282
|
-
evt_left_dclick() { | event | on_double_click(event) }
|
283
|
-
evt_key_down() { | e | on_key_down(e) }
|
284
|
-
|
285
|
-
subscribe(:document_added, :document_deleted, :document_changed)
|
2
|
+
class DocumentsAndCategories < Wx::SplitterWindow
|
3
|
+
def initialize(parent, weft_client)
|
4
|
+
@client = weft_client
|
5
|
+
@app = @client.app
|
6
|
+
super(parent, -1, DEF_POS, DEF_SIZE, Wx::SP_3DSASH)
|
286
7
|
|
287
|
-
|
288
|
-
|
289
|
-
# @menu.append(1234, 'Foo')
|
290
|
-
# @menu.append(1235, 'Bar')
|
291
|
-
end
|
292
|
-
|
293
|
-
# add the document to the end of the list.
|
294
|
-
def append(doc)
|
295
|
-
set_item_data(count, doc)
|
296
|
-
super(doc.title)
|
297
|
-
end
|
298
|
-
|
299
|
-
# needs to rejig the datatable to reflect the fact that all items
|
300
|
-
# below the deleted item have been deleted, and the datatable maps
|
301
|
-
# positions in the list to document values. Urgh. TODO - would be
|
302
|
-
# easier if data_table was an Array under the hood - but it is
|
303
|
-
# currently shared with TreeList data which is more Hash-ish.
|
304
|
-
def delete(item)
|
305
|
-
super(item)
|
306
|
-
@data_table.delete(item)
|
307
|
-
@data_table.keys.find_all { | k | k > item }.sort.each do | k |
|
308
|
-
set_item_data(k - 1, get_item_data(k) )
|
309
|
-
@data_table.delete(k)
|
310
|
-
end
|
311
|
-
# p @data_table
|
312
|
-
end
|
313
|
-
|
314
|
-
|
315
|
-
def on_context_menu(e)
|
316
|
-
popup_menu_xy(@menu, e.get_x, e.get_y)
|
317
|
-
end
|
318
|
-
|
319
|
-
def on_double_click(e)
|
320
|
-
if string_selection != ''
|
321
|
-
@app.on_document_open( selected_document() )
|
322
|
-
else
|
323
|
-
@app.import_document()
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
def selected_document()
|
328
|
-
sel = get_selection()
|
329
|
-
return nil unless sel and sel != -1
|
330
|
-
get_item_data( sel )
|
331
|
-
end
|
332
|
-
|
333
|
-
def receive_document_deleted(doc)
|
334
|
-
0.upto(count - 1) do | i |
|
335
|
-
if get_item_data(i).dbid == doc.dbid
|
336
|
-
delete(i)
|
337
|
-
return true
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
def receive_document_changed(doc)
|
343
|
-
set_string( value_to_ident(doc), doc.title )
|
344
|
-
end
|
345
|
-
|
346
|
-
def receive_document_added(doc)
|
347
|
-
append(doc)
|
348
|
-
end
|
349
|
-
|
350
|
-
def on_key_down(evt)
|
351
|
-
sel = get_selection()
|
352
|
-
return if sel == -1
|
353
|
-
case evt.key_code()
|
354
|
-
when 127 # DEL
|
355
|
-
doc = get_item_data(sel)
|
356
|
-
@app.app.delete_document( doc.dbid )
|
357
|
-
$wxapp.broadcast(:document_deleted, doc)
|
358
|
-
else
|
359
|
-
evt.skip()
|
360
|
-
end
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
|
-
class SideBar < Wx::Frame
|
365
|
-
attr_reader :tree_list
|
366
|
-
|
367
|
-
def initialize(parent, app)
|
368
|
-
super(parent, -1, Lang::SIDEBAR_TITLE,
|
369
|
-
Wx::Point.new(0, 0),
|
370
|
-
parent.proportional_size(0.3, 0.995) )
|
371
|
-
@app = app
|
372
|
-
self.construct()
|
373
|
-
|
374
|
-
conf = Wx::ConfigBase::get()
|
375
|
-
conf.path = "/SideFrame"
|
376
|
-
x = conf.read_int("x", 0)
|
377
|
-
y = conf.read_int("y", 0)
|
378
|
-
w = conf.read_int("w", 200)
|
379
|
-
h = conf.read_int("h", 400)
|
380
|
-
split = conf.read_int("split", 200)
|
381
|
-
split = 200 if split.zero? # otherwise "Documents" are invisible
|
382
|
-
move( Wx::Point.new(x, y) )
|
383
|
-
set_size( Wx::Size.new(w, h) )
|
384
|
-
@splitter.set_sash_position(split)
|
385
|
-
|
386
|
-
|
387
|
-
evt_close() { | e | on_close(e) }
|
388
|
-
end
|
389
|
-
|
390
|
-
def on_close(e)
|
391
|
-
if shown?
|
392
|
-
@app.on_toggle_dandc(e)
|
393
|
-
end
|
394
|
-
e.veto() # don't actually destroy the window
|
395
|
-
end
|
396
|
-
|
397
|
-
# save layout to Config so window is same position next time
|
398
|
-
def remember_size()
|
399
|
-
conf = Wx::ConfigBase::get()
|
400
|
-
# global window size settings
|
401
|
-
if conf
|
402
|
-
size = get_size()
|
403
|
-
pos = get_position
|
404
|
-
conf.path = '/SideFrame'
|
405
|
-
conf.write("x", pos.x)
|
406
|
-
conf.write("y", pos.y)
|
407
|
-
conf.write("w", size.width)
|
408
|
-
conf.write("h", size.height)
|
409
|
-
conf.write("split", @splitter.sash_position)
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
def construct()
|
414
|
-
# build the sidebar - should go in sidebar.rb
|
415
|
-
@splitter = Wx::SplitterWindow.new(self, -1,
|
416
|
-
Wx::DEFAULT_POSITION,
|
417
|
-
Wx::DEFAULT_SIZE,Wx::SP_3DSASH)
|
418
|
-
|
419
|
-
panel_docs = Wx::Panel.new(@splitter)
|
8
|
+
minimum_pane_size = 75
|
9
|
+
panel_docs = Wx::Panel.new(self)
|
420
10
|
panel_docs_sizer = Wx::BoxSizer.new(Wx::VERTICAL)
|
421
11
|
|
422
12
|
doc_label = Wx::StaticBox.new(panel_docs, -1, Lang::DOC_PANEL_TITLE)
|
423
13
|
doc_box_sizer = Wx::StaticBoxSizer.new(doc_label, Wx::VERTICAL)
|
424
14
|
|
425
15
|
# Document List
|
426
|
-
@doc_list = DocumentList.new(@
|
16
|
+
@doc_list = DocumentList.new(@client, panel_docs)
|
427
17
|
doc_box_sizer.add(@doc_list, 1, Wx::GROW|Wx::ALL|Wx::ADJUST_MINSIZE, 4)
|
428
18
|
|
429
19
|
# Buttons Below Document List
|
430
20
|
butt_panel = Wx::Panel.new(panel_docs)
|
431
21
|
butt_sizer = Wx::BoxSizer.new(Wx::HORIZONTAL)
|
432
22
|
|
433
|
-
|
434
|
-
|
435
|
-
|
23
|
+
@view_doc_button = Wx::Button.new(butt_panel, -1,
|
24
|
+
Lang::VIEW_DOC_BUTTON )
|
25
|
+
@view_doc_button.evt_button(@view_doc_button.get_id) do | e |
|
436
26
|
if @doc_list.selected_document
|
437
|
-
@
|
27
|
+
@client.on_document_open( @doc_list.selected_document )
|
438
28
|
end
|
439
29
|
end
|
440
|
-
|
30
|
+
|
31
|
+
@view_doc_button.disable()
|
441
32
|
evt_listbox( @doc_list.get_id ) { | e | @view_doc_button.enable(true) }
|
442
33
|
|
443
|
-
butt_sizer.add(
|
34
|
+
butt_sizer.add(@view_doc_button, 0, Wx::ALL|Wx::ALIGN_LEFT, 4)
|
444
35
|
|
445
36
|
button = Wx::Button.new(butt_panel, -1, Lang::IMPORT_DOC_BUTTON)
|
446
|
-
button.evt_button(button.get_id) { | e | @
|
37
|
+
button.evt_button(button.get_id) { | e | @client.on_import_document(e) }
|
447
38
|
butt_sizer.add(button, 0, Wx::ALL|Wx::ALIGN_RIGHT, 4)
|
448
39
|
|
449
40
|
butt_panel.set_sizer(butt_sizer)
|
@@ -452,13 +43,13 @@ module QDA::GUI
|
|
452
43
|
panel_docs.set_sizer(panel_docs_sizer)
|
453
44
|
|
454
45
|
# Category Tree
|
455
|
-
panel_cats = Wx::Panel.new(
|
46
|
+
panel_cats = Wx::Panel.new(self)
|
456
47
|
panel_cats_sizer = Wx::BoxSizer.new(Wx::VERTICAL)
|
457
48
|
|
458
49
|
cats_label = Wx::StaticBox.new(panel_cats, -1, Lang::CAT_PANEL_TITLE)
|
459
50
|
cats_box_sizer = Wx::StaticBoxSizer.new(cats_label, Wx::VERTICAL)
|
460
51
|
|
461
|
-
@tree_list = CategoryTree.new(@
|
52
|
+
@tree_list = CategoryTree.new(@client, panel_cats, false)
|
462
53
|
cats_box_sizer.add(@tree_list, 3, Wx::GROW|Wx::ALL, 4)
|
463
54
|
|
464
55
|
# Buttons below Category Tree
|
@@ -468,13 +59,13 @@ module QDA::GUI
|
|
468
59
|
button = Wx::Button.new(butt_panel, -1, Lang::VIEW_CAT_BUTTON)
|
469
60
|
button.evt_button(button.get_id) do | e |
|
470
61
|
if @tree_list.selected_category
|
471
|
-
@
|
62
|
+
@client.on_category_open( @tree_list.selected_category )
|
472
63
|
end
|
473
64
|
end
|
474
65
|
button.disable()
|
475
66
|
@view_cat_button = button
|
476
67
|
evt_tree_sel_changing( @tree_list.get_id ) do | e |
|
477
|
-
@tree_list.valid_selection(e) ?
|
68
|
+
@tree_list.valid_selection?(e) ?
|
478
69
|
@view_cat_button.enable(true) : @view_cat_button.disable()
|
479
70
|
end
|
480
71
|
butt_sizer.add(button, 0, Wx::ALL|Wx::ALIGN_RIGHT, 4)
|
@@ -489,10 +80,77 @@ module QDA::GUI
|
|
489
80
|
panel_cats.set_sizer(panel_cats_sizer)
|
490
81
|
|
491
82
|
|
492
|
-
@app.
|
493
|
-
@tree_list.populate( @app.
|
83
|
+
@app.each_doc { | d | @doc_list.append_item(d) }
|
84
|
+
@tree_list.populate( @app.get_all_categories() )
|
85
|
+
if opened = @app.get_preference('TreeLayout')
|
86
|
+
@tree_list.expand_items(opened)
|
87
|
+
end
|
88
|
+
|
89
|
+
split_horizontally(panel_docs, panel_cats, 200)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class SideBar < Wx::Frame
|
94
|
+
attr_reader :tree_list, :doc_list
|
95
|
+
|
96
|
+
def initialize(parent, weft_client)
|
97
|
+
super(parent, -1, Lang::SIDEBAR_TITLE,
|
98
|
+
Wx::Point.new(0, 0),
|
99
|
+
parent.proportional_size(0.3, 0.995) )
|
100
|
+
@client = weft_client
|
101
|
+
self.icon = @client.fetch_icon('project')
|
102
|
+
@splitter = DocumentsAndCategories.new(self, @client)
|
103
|
+
|
104
|
+
conf = Wx::ConfigBase::get()
|
105
|
+
conf.path = "/SideFrame"
|
106
|
+
x = conf.read_int("x", -1)
|
107
|
+
x = DEF_POS.x if x < 0
|
108
|
+
y = conf.read_int("y", -1)
|
109
|
+
y = DEF_POS.y if y < 0
|
110
|
+
w = conf.read_int("w", -1)
|
111
|
+
w = ( DEF_SIZE.width / 2 ) if w < 160
|
112
|
+
h = conf.read_int("h", -1)
|
113
|
+
h = DEF_SIZE.height if h < 160
|
114
|
+
max = conf.read_bool("max", false)
|
115
|
+
|
116
|
+
if max
|
117
|
+
maximize(true)
|
118
|
+
else
|
119
|
+
move( Wx::Point.new(x, y) )
|
120
|
+
set_size( Wx::Size.new(w, h) )
|
121
|
+
end
|
122
|
+
|
123
|
+
split = conf.read_int("split", 200)
|
124
|
+
# sometimes weirdly ends up with negative value
|
125
|
+
split = client_size.height / 2 if split <= 0
|
126
|
+
@splitter.set_sash_position(split)
|
494
127
|
|
495
|
-
|
128
|
+
evt_close() { | e | on_close(e) }
|
129
|
+
end
|
130
|
+
|
131
|
+
def on_close(e)
|
132
|
+
if shown?
|
133
|
+
@client.on_toggle_dandc(e)
|
134
|
+
end
|
135
|
+
e.veto() # don't actually destroy the window
|
496
136
|
end
|
137
|
+
|
138
|
+
# save layout to Config so window is same position next time
|
139
|
+
def remember_size()
|
140
|
+
conf = Wx::ConfigBase::get()
|
141
|
+
# global window size settings
|
142
|
+
if conf
|
143
|
+
size = get_size()
|
144
|
+
pos = get_position()
|
145
|
+
conf.path = '/SideFrame'
|
146
|
+
conf.write("x", pos.x)
|
147
|
+
conf.write("y", pos.y)
|
148
|
+
conf.write("w", size.width)
|
149
|
+
conf.write("h", size.height)
|
150
|
+
conf.write("split", @splitter.sash_position)
|
151
|
+
conf.write("max", maximized?)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
497
155
|
end
|
498
156
|
end
|