require 'Qt'
require 'rexml/document'

# raise is over writed by Qt::Widget, we need a new name
alias :myraise :raise

class QtUi
  def add_object name, w
    return if name == ""
    (class << self; self; end).class_eval do 
      attr_reader name.to_sym
    end
    instance_variable_set("@#{name}", w)
  end
  def get_object name
    instance_variable_get("@#{name}")
  end
end

module RbQt_UiSupport
  def setup_ui ui_path
    @ui = QtUi.new
    @posted_task = []
    doc = REXML::Document.new File.new(ui_path)
    doc.elements["ui"].elements.each do |e|
      case e.name
      when "class"
        @ui.add_object e.text, self
      when "widget"
        _setup_widget self, e
      when "resources"
        # do nothing
      when "connections"
        _setup_connections e
      when "tabstops"
        _setup_tabstops e
      else
        myraise "Unknown node: #{e.inspect}"
      end
    end
    @posted_task.each do |block|
      block.call
    end
    @posted_task = nil
    Qt::MetaObject.connectSlotsByName(self)
  end
  def ui
    @ui
  end
  def post_task &block
    @posted_task << block
  end

  protected
  def _create_qt_object name, *argv
    kls_name = Qt::Internal.normalize_classname(name)
    kls = Qt::Internal.classes[kls_name]
    if not kls
      myraise "Cannot found class named #{e.attributes["class"]}"
    end
    kls.new *argv
  end
  def _create_widget e, parent
    subw = _create_qt_object e.attributes["class"], parent
    subw_name = e.attributes["name"]
    subw.objectName = subw_name
    @ui.add_object subw_name, subw
    subw
  end
  def _create_layout e, parent_layout, parent_widget
    if parent_layout
      layout = _create_qt_object e.attributes["class"]
    else
      layout = _create_qt_object e.attributes["class"], parent_widget
    end
    @ui.add_object e.attributes["name"], layout
    layout
  end
  def _create_spacer re
    name = re.attributes["name"]
    orient = Qt::Horizontal
    width = 20
    height = 20
    policy = Qt::SizePolicy::Minimum
    re.elements.each do |e|
      case e.name + "-" + e.attributes["name"]
      when "property-orientation"
        orient = _string_to_enum e.elements["enum"].text
      when "property-sizeHint"
        width = e.elements["size/width"].text.to_i
        height = e.elements["size/height"].text.to_i
      when "property-sizeType"
        policy = _string_to_enum e.elements["enum"].text
      else
        myraise "Cannot found class named #{e.attributes["class"]}"
      end
    end
    if orient == Qt::Horizontal
      Qt::SpacerItem.new width, height, policy, Qt::SizePolicy::Ignored
    else
      Qt::SpacerItem.new width, height, Qt::SizePolicy::Ignored, policy
    end
  end
  def _string_to_enum str
    case str 
    when "Qt::Horizontal"
      Qt::Horizontal
    when "Qt::Vertical"
      Qt::Vertical
    when "QSizePolicy::Fixed"
      Qt::SizePolicy::Fixed
    when "QSizePolicy::Minimum"
      Qt::SizePolicy::Minimum
    when "QSizePolicy::Maximum"
      Qt::SizePolicy::Maximum
    when "QSizePolicy::Preferred"
      Qt::SizePolicy::Preferred
    when "QSizePolicy::MinimumExpanding"
      Qt::SizePolicy::MinimumExpanding
    when "QSizePolicy::Expanding"
      Qt::SizePolicy::Expanding
    when "QSizePolicy::Ignored"
      Qt::SizePolicy::Ignored
    else
      myraise "Cannot parse enum: #{str}"
    end
  end
  def _setup_widget w, re
    re.elements.each do |e|
      case e.name 
      when "property"
        _setup_property w, e
      when "widget"
        subw = _create_widget e, w
        _setup_widget subw, e
      when "layout"
        subl = _create_layout e, nil, w
        _setup_layout w, subl, e
      when "zorder"
        ui.get_object(e.text).raise
      else
        myraise "Unknown node: #{e.inspect}"
      end
    end
  end
  def _setup_property w, re
    val = nil
    re.elements.each do |e|
      case e.name
      when "rect"
        x = e.elements["x"].text.to_i
        y = e.elements["y"].text.to_i
        width = e.elements["width"].text.to_i
        height = e.elements["height"].text.to_i
        val = Qt::Rect.new(x, y, width, height)
      when "string"
        val = e.text
      when "number"
        val = e.text.to_i
      when "enum"
        val = _string_to_enum e.text
      when "cstring"
        post_task do
          val = ui.get_object e.text
          w.send("#{re.attributes["name"]}=", val)
        end
        return
      else
        myraise "Unknown node: #{e.inspect}"
      end
    end
    w.send("#{re.attributes["name"]}=", val)
  end
  def _setup_layout widget, layout, re
    re.elements.each do |e|
      case e.name
      when "item"
        e.elements.each do |sube|
          case sube.name 
          when "widget"
            subw = _create_widget sube, widget
            _setup_widget subw, sube
            layout.addWidget subw
          when "layout"
            subl = _create_layout sube, layout, widget
            _setup_layout widget, subl, sube
            layout.addLayout subl
          when "spacer"
            spacer = _create_spacer sube
            layout.addSpacerItem spacer
          else
            myraise "Unknown node: #{sube.inspect}"
          end
        end
      else
        myraise "Unknown node: #{e.inspect}"
      end
    end
  end
  def _setup_connections re
    re.elements.each do |e|
      case e.name
      when "connection"
        sender = e.elements["sender"].text
        signal = e.elements["signal"].text
        receiver = e.elements["receiver"].text
        slot = e.elements["slot"].text
        connect(@ui.get_object(sender), SIGNAL(signal), @ui.get_object(receiver), SLOT(slot))
      else
        myraise "Unknown node: #{e.inspect}"
      end
    end
  end
  def _setup_tabstops re
    a = []
    re.elements.each do |e|
      if e.name != "tabstop"
        myraise "Unknown node: #{e.inspect}"
      end
      a << ui.get_object(e.text)
    end
    a.each.with_index do |w, idx|
      wn = a[idx + 1]
      break unless wn
      setTabOrder w, wn
    end
  end
end

module Qt
  class Widget
    include RbQt_UiSupport
  end
end
#kso_plugin 673A2CBD844026EA20F6720D0781B9130F5F00C31E1C9CBCB5E4D631A60A0CBF978BCB6A73B2815F71A2062CAD7E97ADCF0D6D057AC0547DABD130E90F66D216

#A0352DDD2F01682FF67CB2F2A592970DCC7C6D59B7B578E3D21C645C8516FB225CCEAB82BAF143353384D37E28D669140B20F5B6155649A323A8F341659E7CBE