Class: QDA::GUI::CategoryTree

Inherits:
Wx::TreeCtrl
  • Object
show all
Includes:
HashLikeItemData, Subscriber
Defined in:
lib/weft/wxgui/controls/category_tree.rb

Overview

the category tree list for the side panel

Constant Summary collapse

CATEGORY_TREE_STYLE =
Wx::TR_HIDE_ROOT|Wx::TR_HAS_BUTTONS|
Wx::TR_LINES_AT_ROOT|Wx::TR_EDIT_LABELS

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Subscriber

#notify, #subscribe

Methods included from HashLikeItemData

#data, #index

Methods included from ItemData

#get_item_data, #set_item_data, #value_to_ident

Constructor Details

#initialize(weft_client, parent, locked = false) ⇒ CategoryTree

a locked control is one that is not editable, and does not affect the selection of categories in other widgetes.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/weft/wxgui/controls/category_tree.rb', line 14

def initialize(weft_client, parent, locked = false)
  @client = weft_client
  @locked = locked
  # a hash whose keys are the dbids which are expanded
  @expanded = {}
  super(parent, -1, Wx::DEFAULT_POSITION, Wx::DEFAULT_SIZE,
        CATEGORY_TREE_STYLE)
  my_id = self.get_id()
  evt_tree_item_activated(my_id) { | e | on_item_activated(e) }

  if ! @locked
    evt_tree_sel_changed(my_id) { | e | on_item_selected(e) }
    evt_tree_end_drag(my_id) { | e | on_drag_end(e) }
    evt_tree_begin_drag(my_id) { | e | on_drag_begin(e) }
    evt_tree_begin_label_edit(my_id) { | e | on_edit_label_begin(e) }
    evt_tree_end_label_edit(my_id) { | e | on_edit_label_end(e) }
    evt_tree_key_down(my_id) { | e | on_key_down(e) }
    evt_tree_item_expanded(my_id) { | e | on_item_expanded(e) }
    evt_tree_item_collapsed(my_id) { | e | on_item_collapsed(e) }
  end

  subscribe(@client, :category_deleted, :category_changed, :category_added)
end

Instance Attribute Details

#root_idObject (readonly)

Returns the value of attribute root_id.



10
11
12
# File 'lib/weft/wxgui/controls/category_tree.rb', line 10

def root_id
  @root_id
end

Instance Method Details

#append_item(parent, text, data = nil) ⇒ Object

for faked-up item data



39
40
41
42
43
44
# File 'lib/weft/wxgui/controls/category_tree.rb', line 39

def append_item(parent, text, data = nil)
  id = super(parent, text, -1, -1)
  set_item_data(id, data)
  set_item_bold(id) if parent == @root_id
  id
end

#append_recursively(parent, children) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/weft/wxgui/controls/category_tree.rb', line 89

def append_recursively(parent, children)
  children.each do | child_cat |
    name = child_cat.name.empty? ? 'DEFAULT' : child_cat.name

    id = append_item(parent, name, child_cat )
    # remember this for later use
    @search_id = id if name == 'SEARCHES' 
    @codes_id  = id if name == 'CATEGORIES' or name == 'CODES'

    append_recursively(id, child_cat.children)
  end
end

#delete(id) ⇒ Object

for faked-up item data



54
55
56
57
58
59
60
61
62
# File 'lib/weft/wxgui/controls/category_tree.rb', line 54

def delete(id)
  super(id)
  del_cat = data.delete(id)
  if del_cat.parent && old_parent_id = value_to_ident(del_cat.parent)
    set_item_data( old_parent_id, 
                   @client.app.get_category(del_cat.parent.dbid) )
  end        
  return nil
end

#delete_selectionObject



294
295
296
# File 'lib/weft/wxgui/controls/category_tree.rb', line 294

def delete_selection()
  @client.on_delete_category()
end

#dont_move(from) ⇒ Object



183
184
185
# File 'lib/weft/wxgui/controls/category_tree.rb', line 183

def dont_move(from)
  select_item(from) if from != 0
end

#expand_items(catids) ⇒ Object

Opens the category nodes corresponding to the category ids in catids



79
80
81
82
83
84
85
86
87
# File 'lib/weft/wxgui/controls/category_tree.rb', line 79

def expand_items(catids)
  catids.keys.each do | catid |
    if itemid = value_to_ident(catid) 
      # this is done here to prevent it being seen as a change by evt handler
      @expanded[catid] = true
      expand( itemid )
    end 
  end
end

#expanded_itemsObject

returns an array of category ids NOT USED?



74
75
76
# File 'lib/weft/wxgui/controls/category_tree.rb', line 74

def expanded_items()
  @expanded.keys
end

#get_current_categoryObject Also known as: selected_category

get the currently active category



103
104
105
106
107
108
109
110
111
# File 'lib/weft/wxgui/controls/category_tree.rb', line 103

def get_current_category()
  if curr_sel = get_selection()
    return nil if curr_sel == 0
    category = get_item_data( curr_sel )
    return nil if category.nil? # important for GTK
    return nil if category.parent.nil? # don't return root nodes
    category
  end
end

#move(from, to) ⇒ Object

moves the item identifed by the tree id from to be the last child of the category with the tree id to



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/weft/wxgui/controls/category_tree.rb', line 190

def move(from, to)
  return dont_move(from) unless from and to
  return dont_move(from) if from == 0 or to == 0
  return dont_move(from) if from == to 

  movee = get_item_data( from )
  destination = get_item_data( to )
  # if for some reason these tree ids didn't correspond to categories...
  return dont_move(from) unless movee and destination

  # ensure that the relevant categories are fully loaded inc codes
  movee = @client.app.get_category( movee.dbid )
  # include children
  destination = @client.app.get_category( destination.dbid, true )

  # don't move root nodes
  return dont_move(from) if not movee.parent
  # ignore if no move - target is same as current parent
  return dont_move(from) if movee.parent == destination
  # don't attach to descendants
  return dont_move(from) if destination.is_descendant_of?(movee)
  # complain if a child with this name already attached to parent
  if destination[movee.name]
    ErrorDialog.display( Lang::DUPLICATE_CATEGORY_NAME_TITLE, 
                         Lang::DUPLICATE_CATEGORY_NAME_WARNING )
    return dont_move(from)
  end
  
  Wx::BusyCursor.busy do
    movee.parent = destination
    @client.app.save_category( movee )
  end
end

#move_item(from, to) ⇒ Object

Moves the tree item identified by from so that it is attached the parent identified by new_parent. Does nothing if that is already the location of the node.



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/weft/wxgui/controls/category_tree.rb', line 227

def move_item(from, to)
  # don't alter if unchanged
  from_parent = get_item_parent(from)
  return from if from_parent == to

  # remember expanded-or-collapsed state
  reexpand = expanded?(from_parent)

  # create a new tree item under the new parent
  new_child = append_item(to, get_item_text(from),
  get_item_data(from))

  # recursively move all children underneath to the new node
  child = get_first_child(from)[0]
  while child != 0
    move_item(child, new_child)
    child = get_first_child(from)[0]
  end

  # restore my visibility settings
  expand(to) if reexpand
  delete( from )
  
  new_child
end

#on_create_itemObject

when we’re asked to add an item. This will be attached to the currently selected category in the tree, or the default ‘CATEGORIES’ category if no item is selected



256
257
258
# File 'lib/weft/wxgui/controls/category_tree.rb', line 256

def on_create_item()
  @client.on_add_category()
end

#on_drag_begin(evt) ⇒ Object



167
168
169
170
# File 'lib/weft/wxgui/controls/category_tree.rb', line 167

def on_drag_begin(evt)
  @drag_subject = evt.item
  evt.allow()
end

#on_drag_end(evt) ⇒ Object

relocates or merges the coding of the draggee to the drag target



173
174
175
176
177
178
179
180
181
# File 'lib/weft/wxgui/controls/category_tree.rb', line 173

def on_drag_end(evt)
  @drag_target = evt.item
  # control_down is a property of a mouse event, so this doesn't work
  # p "CONTROL IS DOWN" if evt.control_down
  move(@drag_subject, @drag_target)

  @drag_subject = nil
  @drag_target  = nil
end

#on_edit_label_begin(evt) ⇒ Object



129
130
131
132
133
# File 'lib/weft/wxgui/controls/category_tree.rb', line 129

def on_edit_label_begin(evt)
  # TODO - this should really talk to the underlying category,
  # rather than just assuming bold = locked
  evt.veto() if bold?(evt.item)
end

#on_edit_label_end(evt) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/weft/wxgui/controls/category_tree.rb', line 135

def on_edit_label_end(evt)
  new_text = evt.label
  if new_text == ""
    evt.veto()
    return
  end

  old_text = get_item_text( evt.item )
  # don't bother saving if the text isn't changed
  return if old_text == new_text
  c_cdata  = get_item_data( evt.item )
  category = @client.app.get_category( c_cdata.dbid )
  Wx::BusyCursor.busy do
    begin
      category.name = new_text
      @client.app.save_category( category)
    rescue QDA::BadNameError
      category.name = old_text
      ErrorDialog.display( Lang::BAD_CATEGORY_NAME_TITLE, 
                           Lang::BAD_CATEGORY_NAME_WARNING )
      evt.veto()
    rescue QDA::NotUniqueNameError
      category.name = old_text
      ErrorDialog.display( Lang::DUPLICATE_CATEGORY_NAME_TITLE, 
                           Lang::DUPLICATE_CATEGORY_NAME_WARNING )
      evt.veto()
    end
  end
  
  set_item_data(evt.item, category )
end

#on_item_activated(event) ⇒ Object



268
269
270
271
272
273
274
275
276
277
278
# File 'lib/weft/wxgui/controls/category_tree.rb', line 268

def on_item_activated(event)
  item_id  = event.get_item()
  category =  get_item_data(item_id)
  return nil if category.parent.nil?
  Wx::BusyCursor.busy() do 
    category = @client.app.get_category(category.dbid, true)
    if category != nil
      @client.on_category_open(category)
    end
  end
end

#on_item_collapsed(evt) ⇒ Object



122
123
124
125
126
127
# File 'lib/weft/wxgui/controls/category_tree.rb', line 122

def on_item_collapsed(evt)
  cat = get_item_data(evt.item)
  return unless cat
  @expanded.delete(cat.dbid)
  @client.app.save_preference('TreeLayout', @expanded)
end

#on_item_expanded(evt) ⇒ Object



114
115
116
117
118
119
120
# File 'lib/weft/wxgui/controls/category_tree.rb', line 114

def on_item_expanded(evt)
  cat = get_item_data(evt.item)
  return unless cat
  return if @expanded[cat.dbid] # prevents futile re-saving if already open
  @expanded[cat.dbid] = true
  @client.app.save_preference('TreeLayout', @expanded)
end

#on_item_selected(event) ⇒ Object



260
261
262
263
264
265
266
# File 'lib/weft/wxgui/controls/category_tree.rb', line 260

def on_item_selected(event)
  if valid_selection?(event)
    @client.current_category = get_item_data( event.get_item )
  else
    @client.current_category = nil
  end
end

#on_key_down(evt) ⇒ Object



298
299
300
301
302
303
# File 'lib/weft/wxgui/controls/category_tree.rb', line 298

def on_key_down(evt)
  case evt.key_code()
  when 127 # DEL
    delete_selection()
  end
end

#populate(children) ⇒ Object



64
65
66
67
68
69
70
# File 'lib/weft/wxgui/controls/category_tree.rb', line 64

def populate(children)
  # the root isn't shown, so the top level of +children+ is what
  # appears at the base of the tree.
  @root_id = add_root('ROOT')
  append_recursively(@root_id, children)
  refresh()
end

#prepend_item(parent, text, img = -1,, sel_img = -1,, data = nil) ⇒ Object

for faked-up item data



47
48
49
50
51
# File 'lib/weft/wxgui/controls/category_tree.rb', line 47

def prepend_item(parent, text, img = -1, sel_img = -1, data = nil)
  id = super(parent, text, img, sel_img)
  set_item_data(id, data)
  return id
end

#receive_category_added(cat) ⇒ Object



322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/weft/wxgui/controls/category_tree.rb', line 322

def receive_category_added(cat)
  if cat.parent.nil? 
    p_id = @root_id
  else
    p_id = value_to_ident(cat.parent)
  end
  return if not p_id
  append_item( p_id, cat.name, cat)
  expand(p_id)
  id = value_to_ident(cat)
  select_item(id)
end

#receive_category_changed(cat) ⇒ Object



312
313
314
315
316
317
318
319
320
# File 'lib/weft/wxgui/controls/category_tree.rb', line 312

def receive_category_changed(cat)
  # may not include this item if it's a partial subtree
  if tree_id = value_to_ident(cat)
    # it's maybe moved
    tree_id = move_item(tree_id, value_to_ident(cat.parent) )
    set_item_text( tree_id, cat.name)
    set_item_data( tree_id, cat)
  end
end

#receive_category_deleted(cat) ⇒ Object



305
306
307
308
309
310
# File 'lib/weft/wxgui/controls/category_tree.rb', line 305

def receive_category_deleted(cat)
  # may not include this item if it's a partial subtree
  if tree_id = value_to_ident(cat)
    delete( tree_id )
  end
end

#valid_selection?(event) ⇒ Boolean

Returns:

  • (Boolean)


280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/weft/wxgui/controls/category_tree.rb', line 280

def valid_selection?( event )
  # wxruby varies across platforms in how it indicates "no item
  # selected" - on windows, get_selection returns 0, on Linux, a
  # weird large integer id. Returning nil is the "correct" future behaviour
  item_id = event.get_item()
  if item_id.nil? or item_id == 0 or is_bold(item_id)
    return false
  elsif not get_item_data( item_id )
    return false
  else
    return true
  end
end