Class: MetaRuby::GUI::RubyConstantsItemModel
- Inherits:
-
Qt::AbstractItemModel
- Object
- Qt::AbstractItemModel
- MetaRuby::GUI::RubyConstantsItemModel
- Defined in:
- lib/metaruby/gui/ruby_constants_item_model.rb
Overview
A Qt item model that enumerates models stored in the Ruby constant hierarchy
The model exposes all registered constants for which #predicate returns true in a hierarchy, allowing the user to interact with it.
Discovery starts at Object
Defined Under Namespace
Classes: ModuleInfo, TypeInfo
Instance Attribute Summary collapse
-
#excludes ⇒ Set
readonly
Explicitely excluded objects.
-
#filtered_out_modules ⇒ Object
readonly
Set of objects that have been filtered out by #predicate.
-
#id_to_module ⇒ {Integer=>ModuleInfo}
readonly
Mapping from module ID to a module object.
-
#object_paths ⇒ {Object=>String}
readonly
List of paths for each of the discovered objects.
-
#predicate ⇒ #call
readonly
Predicate that filters objects in addition to #excludes.
-
#title ⇒ String
Name of the root item.
-
#type_info ⇒ {Class=>TypeInfo}
readonly
A list of expected object types.
Instance Method Summary collapse
-
#columnCount(parent) ⇒ Object
Reimplemented for Qt model interface.
-
#compute_full_name(info) ⇒ String
private
Lazily computes the full name of a discovered object.
-
#compute_keyword_string(info) ⇒ String
private
Lazily compute a comma-separated string that can be used to search for the given node.
-
#compute_path(info) ⇒ String
private
Lazily compute the path of a discovered object.
-
#data(index, role) ⇒ Object
Reimplemented for Qt model interface.
-
#discover_module(mod, stack = Array.new) ⇒ ModuleInfo
private
Discovers an object and its children.
-
#find_index_by_model(model) ⇒ Qt::ModelIndex?
Return the Qt::ModelIndex that represents a given object.
-
#find_index_by_path(*path) ⇒ Qt::ModelIndex?
Returns the Qt::ModelIndex that matches a given path.
-
#generate_paths(paths, info, current) ⇒ Object
private
Generate the path information, i.e.
-
#headerData(section, orientation, role) ⇒ Object
Reimplemented for Qt model interface.
-
#index(row, column, parent) ⇒ Object
Reimplemented for Qt model interface.
-
#info_from_index(index) ⇒ Object
Resolves a ModuleInfo from a Qt::ModelIndex.
-
#initialize(type_info = Hash.new, &predicate) ⇒ RubyConstantsItemModel
constructor
Initialize this model for objects of the given type.
-
#parent(child) ⇒ Object
Reimplemented for Qt model interface.
-
#reload ⇒ Object
Discovers or rediscovers the objects.
-
#root_info ⇒ Object
ModuleInfo for the root.
-
#rowCount(parent) ⇒ Object
Reimplemented for Qt model interface.
-
#update_module_type_info(info) ⇒ Object
private
Updates ModuleInfo#types so that it includes the type of its children.
Constructor Details
#initialize(type_info = Hash.new, &predicate) ⇒ RubyConstantsItemModel
Initialize this model for objects of the given type
67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 67 def initialize(type_info = Hash.new, &predicate) super() @predicate = predicate || proc { true } @type_info = type_info @title = "Model Browser" @excludes = [Qt].to_set @id_to_module = [] @filtered_out_modules = Set.new @object_paths = Hash.new end |
Instance Attribute Details
#excludes ⇒ Set (readonly)
Explicitely excluded objects
Set of objects that should be excluded from discovery, regardless of what #predicate would return from them.
Note that such objects are not discovered at all, meaning that if they contain objects that should have been discovered, they won’t be.
35 36 37 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 35 def excludes @excludes end |
#filtered_out_modules ⇒ Object (readonly)
Set of objects that have been filtered out by #predicate
51 52 53 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 51 def filtered_out_modules @filtered_out_modules end |
#id_to_module ⇒ {Integer=>ModuleInfo} (readonly)
Mapping from module ID to a module object
48 49 50 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 48 def id_to_module @id_to_module end |
#object_paths ⇒ {Object=>String} (readonly)
List of paths for each of the discovered objects
61 62 63 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 61 def object_paths @object_paths end |
#predicate ⇒ #call (readonly)
Predicate that filters objects in addition to #excludes
Only objects for which #call returns true and the constants that contain them are exposed by this model
23 24 25 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 23 def predicate @predicate end |
#title ⇒ String
Name of the root item
56 57 58 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 56 def title @title end |
#type_info ⇒ {Class=>TypeInfo} (readonly)
A list of expected object types
This is used to decide where a given object should be “attached” in the hierarchy. Matching types are stored in MetaRuby::GUI::RubyConstantsItemModel::ModuleInfo#types.
43 44 45 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 43 def type_info @type_info end |
Instance Method Details
#columnCount(parent) ⇒ Object
Reimplemented for Qt model interface
369 370 371 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 369 def columnCount(parent) return 1 end |
#compute_full_name(info) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Lazily computes the full name of a discovered object. It updates MetaRuby::GUI::RubyConstantsItemModel::ModuleInfo#full_name
224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 224 def compute_full_name(info) if name = info.full_name return name else full_name = [] current = info while current.parent full_name << current.name current = current.parent end info.full_name = full_name.reverse end end |
#compute_keyword_string(info) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Lazily compute a comma-separated string that can be used to search for the given node. The result is stored in MetaRuby::GUI::RubyConstantsItemModel::ModuleInfo#keyword_string
The returned string is of the form
type0[,type1...]:name0[,name1...]
305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 305 def compute_keyword_string(info) if keywords = info.keyword_string return keywords else types = info.types.map do |type| type_info[type].name end.sort.join(",") paths = [compute_path(info)] paths.concat info.children.map { |child| compute_keyword_string(child) } info.keyword_string = "#{types};#{paths.join(",")}" end end |
#compute_path(info) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Lazily compute the path of a discovered object. The result is stored in MetaRuby::GUI::RubyConstantsItemModel::ModuleInfo#path
245 246 247 248 249 250 251 252 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 245 def compute_path(info) if path = info.path return path else full_name = compute_full_name(info) info.path = ("/" + full_name.map(&:downcase).join("/")) end end |
#data(index, role) ⇒ Object
Reimplemented for Qt model interface
327 328 329 330 331 332 333 334 335 336 337 338 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 327 def data(index, role) if info = info_from_index(index) if role == Qt::DisplayRole return Qt::Variant.new(info.name) elsif role == Qt::EditRole return Qt::Variant.new(compute_full_name(info).join("/")) elsif role == Qt::UserRole return Qt::Variant.new(compute_keyword_string(info)) end end return Qt::Variant.new end |
#discover_module(mod, stack = Array.new) ⇒ ModuleInfo
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Discovers an object and its children
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 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 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 142 def discover_module(mod, stack = Array.new) return if excludes.include?(mod) stack.push mod children = [] mod_info = ModuleInfo.new(nil, nil, mod, nil, children, nil, Set.new) is_needed = (mod.kind_of?(Class) && mod == Object) || predicate.call(mod) if mod.respond_to?(:constants) children_modules = begin mod.constants rescue TypeError puts "cannot discover module #{mod}" [] end children_modules = children_modules.map do |child_name| next if !mod.const_defined?(child_name, false) # Ruby issues a warning when one tries to access Config # (it has been deprecated in favor of RbConfig). Ignore # it explicitly next if mod == Object && child_name == :Config next if mod.autoload?(child_name) child_mod = begin mod.const_get(child_name) rescue LoadError # Handle autoload errors end next if !child_mod next if filtered_out_modules.include?(child_mod) next if stack.include?(child_mod) [child_name.to_s, child_mod] end.compact.sort_by(&:first) children_modules.each do |child_name, child_mod| if info = discover_module(child_mod, stack) info.id = id_to_module.size info.name = child_name.to_s info.parent = mod_info info.row = children.size children << info id_to_module << info else filtered_out_modules << child_mod end end end if is_needed klass = if mod.respond_to?(:ancestors) then mod else mod.class end current_priority = nil klass.ancestors.each do |ancestor| if info = type_info[ancestor] current_priority ||= info.priority if current_priority < info.priority mod_info.types.clear mod_info.types << ancestor current_priority = info.priority elsif current_priority == info.priority mod_info.types << ancestor end end end end update_module_type_info(mod_info) if !children.empty? || is_needed mod_info end ensure stack.pop end |
#find_index_by_model(model) ⇒ Qt::ModelIndex?
Return the Qt::ModelIndex that represents a given object
268 269 270 271 272 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 268 def find_index_by_model(model) if info = id_to_module.find { |info| info.this == model } return create_index(info.row, 0, info.id) end end |
#find_index_by_path(*path) ⇒ Qt::ModelIndex?
Returns the Qt::ModelIndex that matches a given path
279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 279 def find_index_by_path(*path) current = id_to_module.last if path.first == current.name path.shift end path.each do |name| current = id_to_module.find do |info| info.name == name && info.parent == current end return if !current end create_index(current.row, 0, current.id) end |
#generate_paths(paths, info, current) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Generate the path information, i.e. per-object path string
111 112 113 114 115 116 117 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 111 def generate_paths(paths, info, current) info.children.each do |child| child_uri = current + '/' + child.name paths[child.this] = child_uri generate_paths(paths, child, child_uri) end end |
#headerData(section, orientation, role) ⇒ Object
Reimplemented for Qt model interface
319 320 321 322 323 324 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 319 def headerData(section, orientation, role) if role == Qt::DisplayRole && section == 0 Qt::Variant.new(title) else Qt::Variant.new end end |
#index(row, column, parent) ⇒ Object
Reimplemented for Qt model interface
341 342 343 344 345 346 347 348 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 341 def index(row, column, parent) if info = info_from_index(parent) if child_info = info.children[row] return create_index(row, column, child_info.id) end end Qt::ModelIndex.new end |
#info_from_index(index) ⇒ Object
Resolves a ModuleInfo from a Qt::ModelIndex
256 257 258 259 260 261 262 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 256 def info_from_index(index) if !index.valid? return id_to_module.last else id_to_module[index.internal_id >> 1] end end |
#parent(child) ⇒ Object
Reimplemented for Qt model interface
351 352 353 354 355 356 357 358 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 351 def parent(child) if info = info_from_index(child) if info.parent && info.parent != root_info return create_index(info.parent.row, 0, info.parent.id) end end Qt::ModelIndex.new end |
#reload ⇒ Object
Discovers or rediscovers the objects
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 80 def reload begin_reset_model @id_to_module = [] @filtered_out_modules = Set.new info = discover_module(Object) info.id = id_to_module.size info.name = title update_module_type_info(info) info.row = 0 id_to_module << info @object_paths = Hash.new generate_paths(object_paths, info, "") ensure end_reset_model end |
#root_info ⇒ Object
ModuleInfo for the root
99 100 101 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 99 def root_info id_to_module.last end |
#rowCount(parent) ⇒ Object
Reimplemented for Qt model interface
361 362 363 364 365 366 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 361 def rowCount(parent) if info = info_from_index(parent) info.children.size else 0 end end |
#update_module_type_info(info) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Updates MetaRuby::GUI::RubyConstantsItemModel::ModuleInfo#types so that it includes the type of its
children
125 126 127 128 129 130 131 132 133 |
# File 'lib/metaruby/gui/ruby_constants_item_model.rb', line 125 def update_module_type_info(info) types = info.types.to_set info.children.each do |child_info| types |= child_info.types.to_set end info.types = types.to_a.sort_by do |type| type_info[type].priority end.reverse end |