Module: Qt

Defined in:
lib/qt_connect/qt_compat.rb,
lib/qt_connect/qt_sugar.rb,
lib/qt_connect/qt_jbindings.rb,
lib/qt_connect/qt_jbindings.rb

Overview

Author: Cees Zeelenberg ([email protected])

Copyright:  (c) 2010-2012 by Cees Zeelenberg
License:    This program is free software; you can redistribute it and/or modify  
            it under the terms of the GNU Lesser General Public License as published
            by the Free Software Foundation; either version 2 of the License, or 
            (at your option) any later version.                       *

This software extends the basic qt_jbindings API with functionality to
improve compatibility with the existing QtRuby API:
- same shorthand notations for Enums
- patches to classes where the API is slightly different to support
  both interfaces (ongoing work)
- support for the QtRuby signals/slot interface in addition
  to the QtJambi signals interface
- implementations of Qt::Variant and Qt::ModelIndex to allow single source
  maintenance for QtRuby and QtJRuby

Defined Under Namespace

Modules: Internal Classes: Boolean, MetaObject, ModelIndex, RubySignalAction, Signal

Constant Summary collapse

WidgetType =

compat QtRuby4 (fails for WindowType)

WindowType::Widget
DialogType =

WindowType=WindowType::Window

WindowType::Dialog
SheetType =
WindowType::Sheet
DrawerType =
WindowType::Drawer
PopupType =
WindowType::Popup
ToolType =
WindowType::Tool
ToolTipType =
WindowType::ToolTip
SplashScreenType =
WindowType::SplashScreen
DesktopType =
WindowType::Desktop
SubWindowType =
WindowType::SubWindow
AlignTrailing =

Internal

AlignRight
AlignLeading =
AlignLeft
@@activated =

qtclass # => Java::ComTrolltechQtCore::QPoint (Class) JRuby exposes Java classes fields as Ruby instance methods, class methods or constants. there is a problem with the implementation of Signals in Jambi in that there is a (public) Java field and (private) Java methods with the same name (e.g. clicked) we want to access the field, but get the method. The logic here defines a new method which acesses the field this is done for the Qt class being activated PLUS all Qt signal emitting classes for which this class may return instances (e.g. Qt::WebPage also activates Qt::WebFrame because Qt::WebPage.mainPage returns an instance of Qt::WebFrame which is a signalemitter)

{}

Class Method Summary collapse

Class Method Details

.const_missing(name) ⇒ Object

come here on missing constant in the Qt namespace if the missing name maps to an existing QtJambi class, equate the missing constant to that class and

  • make Signal fields accessable to Ruby methods

  • define a ‘new’ classmethod with optional iterator block initialization

  • define ‘shorthand’ constants to be compatible with qtbindings (optional, require ‘qt_compat.rb’ )

  • monkeypatch the underlying class with extensions defined in Qt::Internal (optional, require ‘qt_compat.rb’ )



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/qt_connect/qt_jbindings.rb', line 240

def const_missing(name)
  qtclass = QtJambi.const_get("Q#{name}") rescue qtclass = QtJambi.const_get("Qt#{name}") rescue qtclass = QtJambi.const_get("#{name}")
  qtclass.class_eval do        if self.class==Class # no constructor for modules
      class << self
        def new(*args,&block)
          instance=self.allocate
          instance.send(:initialize,*args)
          if block_given?
            if block.arity == -1 || block.arity == 0
              instance.instance_eval(&block)
            elsif block.arity == 1
              block.call(instance)
            else
              raise ArgumentError, "Wrong number of arguments to block(#{block.arity} ; should be 1 or 0)"
            end
          end
          return instance
        end
      end
    end
  #Ruby extensions for a class are stored in Qt::Internal as Procs with the same name as the class
  #the signature for each extension is logged in Qt::Internal::RUBY_extensions (for documentation only)
  #see examples in qt_compat.rb
  if Qt::Internal.const_defined?(name)
    puts "include extension #{name}" if $VERB
    self.class_eval(&Qt::Internal.const_get(name))
  end

end
const_set(name, qtclass)
Qt.create_constants(qtclass,"Qt::#{name}") if Qt.respond_to? :create_constants
Qt.setup_qt_signals(qtclass)
return qtclass
end

.create_constants(qtclass, qtname) ⇒ Object

‘create_constants’ is called whenever new Module or Class is activated qtclass Java::ComTrollTechQtGui::QDockWidget (Class) qtname Qt::Dockwidget (String)



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/qt_connect/qt_compat.rb', line 50

def self.create_constants(qtclass,qtname)
  qtclass.class_eval{
    constants.dup.each{ |c|
      embedded_class=eval("#{qtclass.name}::#{c}")
      next unless embedded_class.respond_to?(:java_class)
      ancestors=(embedded_class.respond_to?(:ancestors)) ? embedded_class.ancestors : []
      if ancestors.include? java.lang.Enum
        embedded_class.values.to_ary.each{ |s|
          symbol=s.toString
          next if Qt::Internal::DONT_ABBREVIATE["#{qtname}::#{c}::#{symbol}"]
          next if symbol=~/\A[^A-Z].*\Z/
          next if const_defined?(symbol)
          qtclass.class_eval("#{symbol}=#{qtclass.name}::#{c}::#{symbol}") rescue next
        }
      else
        #could be class with public static final int field(s)
        fields=embedded_class.java_class.fields rescue next
        fields.each{ |field|
          next unless field.static? && field.final? && field.public? && (field.value_type=="int")
          symbol=field.name
          value=Java.java_to_ruby(field.static_value)
          qtclass.class_eval("#{symbol}=#{value}") rescue next
        }
      end
    }
  }
end

.method_missing(method, *args) ⇒ Object

deal with Qt::blue etc.



94
95
96
97
98
# File 'lib/qt_connect/qt_compat.rb', line 94

def Qt.method_missing(method,*args)
  return Color.send(method) if Color.respond_to?(method)
  return Color.new(*args).rgba if method==:qRgba
  super(*args)
end

.setup_qt_signals(qtclass) ⇒ Object



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/qt_connect/qt_jbindings.rb', line 286

def Qt.setup_qt_signals(qtclass)
return if @@activated[qtclass.java_class.name]
org.jruby.javasupport.JavaClass.getMethods(qtclass).to_a.
  map{ |jm| returnclass=jm.getReturnType}.
  select{ |jc| jc.getClasses.to_a.include? QtJambi::ABSTRACTSIGNAL}.
  map{ |jc| jc.getName}.
  uniq.
  delete_if{ |jn| @@activated[jn]}.
  each { |klassname| klass=eval(klassname)
    klass.class_eval do
      next if @@activated[java_class.name]
      java_class.fields.each do |field|
        next unless field.type.superclass==QtJambi::ABSTRACTSIGNAL
        puts "     #{java_class.name} fieldname: #{field.name} fieldtype: #{field.type.to_s}" if $VERB
        uscore_name = if (field.name =~ /\A[A-Z]+\z/)
          field.name.downcase
        else
          field.name.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').tr("-","_").downcase
        end
        self.class_eval %Q[
          def #{field.name}(*args, &block)
            #puts '===> #{klass.name}.#{field.name} <=> #{field.type.to_s} -1-'
            return self.java_class.field(:#{field.name}).value(self)
          end
          #{(uscore_name==field.name) ? '' : "alias :#{uscore_name} :#{field.name}"}
        ]
      end
      @@activated[java_class.name]=true
    end
    
  }
  #@@activated[qtclass.java_class.name]=true
end