Tuesday, August 18, 2009

drag move charm #2

(continued from phosphorescence: drag move charm #1)

Why sample widget cannot be moved with grabbing top level widget? It's handled in DragMoveCharm#event_filter method. I had surveyed and debugged this method. Then I found it is caused by incorrect decision of inheritance. See the example code:
> /opt/ruby-1.9.1/bin/irb
irb(main):001:0> require 'Qt'
=> true
irb(main):002:0> Qt::Application.new([])
=> #<Qt::Application:0x00000000c00918 objectName="irb">
irb(main):003:0> label = Qt::Label.new
=> #<Qt::Label:0x00000000befc58 objectName="", x=0, y=0, width=640, height=480>
irb(main):004:0> Qt::Label.ancestors
=> [Qt::Label, Qt::Frame, Qt::Widget, Qt::Object, Qt::PaintDevice, Object, Kernel, BasicObject]
irb(main):005:0> Qt::Label.ancestors.collect do |ancestor_class|
irb(main):006:1* label.is_a? ancestor_class
irb(main):007:1> end
=> [true, false, false, false, false, true, true, true]

After QtRuby 2.0.3, class method Module.ancestors returns not only Ruby's super classes but also Qt's super classes because Qt::Base class overrides this method. But, other related methods don't. Object#is_a? and its alias Object#kind_of? aren't overrode.

If override? Let's try:
> /opt/ruby-1.9.1/bin/irb
irb(main):001:0> require 'Qt'
=> true
irb(main):002:0> module Qt
irb(main):003:1> class Base
irb(main):004:2> def is_a?(mod)
irb(main):005:3> super || self.class.ancestors.include?(mod)
irb(main):006:3> end
irb(main):007:2> end
irb(main):008:1> end
=> nil
irb(main):009:0> Qt::Application.new([])
=> #<Qt::Application:0x00000000ba5c98 objectName="irb">
irb(main):010:0> label = Qt::Label.new
=> #<Qt::Label:0x00000000b94c40 objectName="", x=0, y=0, width=640, height=480>
irb(main):011:0> Qt::Label.ancestors
=> [Qt::Label, Qt::Frame, Qt::Widget, Qt::Object, Qt::PaintDevice, Object, Kernel, BasicObject]
irb(main):012:0> Qt::Label.ancestors.collect do |ancestor_class|
irb(main):013:1* label.is_a? ancestor_class
irb(main):014:1> end
=> [true, true, true, true, true, true, true, true]

It looks like well. So adding below code to override is_a? and kind_of? before execution.
unless Qt::Base.instance_methods(false).include?(:is_a?)
module Qt
class Base
def is_a?(mod)
super || self.class.ancestors.include?(mod)
end
alias :kind_of? :is_a?
end
end
end


Finally, run and move with grabbing top level widget successfully. See widget class code is here, and execution code is here.

No comments:

Post a Comment