実行可能アクティビティ図アプリ

 そういえば、JRubyがでたときに、試用のために、でJUDE APIをたたいて、アクティビティ図を実行するアプリってのを作ったんだった。アクティビティ図の分岐をそのままボタンに換えて、対話的に実行します。

 SWTでつくったらぜんぜんRubyらしくないでやんの。GUIJava側にもってくるのははじめいいかもと思ったが、これをみるかぎりかなり苦しかった。SWT触ったのさえ初めてだったから、ノウハウがないせいかもしれないけど。

 前のコードなので動くかどうか不明・・・とりあえずはっときます。

# main.rb
# 2007/06/11
#

require 'java'
require  'main_form'
require  'start_form'


module Jude
  include_package "com.change_vision.jude.api.inf.project"
  include_package "com.change_vision.jude.api.inf.model"
end

class JudeActivityDiagram
  attr_reader :ac_node_list
  
  def initialize(file_name = 'JudeSampleProject.jude')
    include_class 'java.lang.System' 
    
    prjAccessor = Jude::ProjectAccessorFactory.getProjectAccessor
    prjAccessor.open(file_name)
    
    dgms = prjAccessor.getProject.getDiagrams
    @ac_node_list = {}  
    dgms.each{|dgm|
      if dgm.java_kind_of?(Jude::IActivityDiagram)
        activity = dgm.getActivity
        activityNodes = activity.getActivityNodes 
        activityNodes.each{|node|
          @ac_node_list[node.getId] = node
        }
      end
    }
  end 
  
end


st_form = StartForm.new
st_form.show
# main_form.rb
# 2007/06/21
#

require 'java'

module SWTJava
  include_package 'org.eclipse.swt'
  include_package 'org.eclipse.swt.layout'
  include_package 'org.eclipse.swt.widgets'
  include_package 'org.eclipse.swt.events'
end

module JudeObject
  def set_jude_obj(jude_obj)
    @jude_obj = jude_obj
  end
  def get_jude_obj(jude_obj)
    @jude_obj
  end
end

 class ButtonClickEvent < SWTJava::SelectionAdapter
    attr_writer :main_form, :flow
    def widgetSelected(e)
      next_action = @flow.getTarget
      @main_form.set_node(next_action)
    end
 end

  class FinishButtonClickEvent < SWTJava::SelectionAdapter
    attr_writer :main_form
    def widgetSelected(e)
      shell = e.getSource.getShell
      shell.dispose        
    end
 end
 
class MainForm
  def initialize(main_shell = nil)
      @main_shell = main_shell
      if @main_shell
        @shell = SWTJava::Shell.new(@main_shell)        
      else
        SWTJava::Display.setAppName "Executable Activity Diagram"
        @display = SWTJava::Display.new
        @shell = SWTJava::Shell.new(@display)
      end
      @shell.setSize(1000, 1000)

      layout = SWTJava::GridLayout.new()
      layout.numColumns = 1
      layout.marginHeight = 20
      layout.marginWidth = 20
      layout.verticalSpacing = 20

      @shell.setLayout layout
      @shell.setText "Executable Activity Diagram"
      
      @textbox = SWTJava::Text.new(@shell, SWTJava::SWT::MULTI || SWTJava::SWT::READONLY)
      @textbox.extend JudeObject
      @textbox.setText("てすとてすと")  
   end
   
   def show()
      @shell.pack
      @shell.open
      unless @main_shell
        until @shell.isDisposed do
          @display.sleep unless @display.readAndDispatch
        end
        @display.dispose
      end
   end
   
   def set_node(node)    
     set_message(node)
     flows = node.getOutgoings
     if node.getOutgoings.size == 1 
       next_node = node.getOutgoings[0].getTarget
       if defined? next_node.getName && ( next_node.getName == "" || next_node.getName =~ /(デシジョンノード|マージノード|合流)/ )
         flows = next_node.getOutgoings
       end     
     end
     set_next_button(flows)
     @shell.pack
   end
   
   def set_message(node)
     @textbox.set_jude_obj(node)
     if node.java_kind_of?(Jude::IControlNode) && node.isInitialNode
         @textbox.setText("開始します")
     elsif node.java_kind_of?(Jude::IControlNode) && node.isFinalNode
         @textbox.setText("ここで終了です")
     else
        if defined? node.getName && node.getName != ""
          @textbox.setText("#{node.getName}")
        end
     end
   end
   
   def set_next_button(flows)
      if @buttons
        @buttons.each_value{|button| 
          button.dispose
        }
      end
      @buttons = {}

      if flows.size == 0
        button = SWTJava::Button.new(@shell, SWTJava::SWT::PUSH)
        button.setText("終了")        
        btn_click = FinishButtonClickEvent.new()
        btn_click.main_form = self
        button.addSelectionListener(btn_click)
        @buttons[0] = button
      else
        flows.each{ |flow|
          button = SWTJava::Button.new(@shell, SWTJava::SWT::PUSH)
          button.extend JudeObject
          if flow.getAction != "" && flow.getGuard != ""
            button.setText("アクション:#{flow.getAction}[条件:#{flow.getGuard}]")
          elsif flow.getAction != ""
            button.setText("アクション:#{flow.getAction}")            
          elsif flow.getGuard != ""
            button.setText("条件:#{flow.getGuard}")
          else
            button.setText("次へ進む")        
          end
          button.set_jude_obj(flow)
          btn_click = ButtonClickEvent.new()
          btn_click.main_form = self
          btn_click.flow = flow
          button.addSelectionListener(btn_click)
          @buttons[flow.getId] = button
        }
      end
   end
  
end
# start_form.rb
# 2007/06/21
#

require 'java'
require 'main_form'

 class FileOpenButtonClickEvent < SWTJava::SelectionAdapter
    attr_writer :form
    def widgetSelected(e)
      shell = e.getSource.getShell
      openDialog = SWTJava::FileDialog.new(shell,SWTJava::SWT::OPEN);
      openFile = openDialog.open();
      @form.textbox.setText(openFile)
    end
 end

  class OkButtonClickEvent < SWTJava::SelectionAdapter
    attr_writer :form
    def widgetSelected(e)
        shell = e.getSource.getShell
        filepath = @form.textbox.getText

        main_form = MainForm.new(shell)
        acDgm = JudeActivityDiagram.new(filepath)

        #スタートポイントを探して、セット
        acDgm.ac_node_list.each_value{|node|
          if node.java_kind_of?(Jude::IControlNode)
            if node.isInitialNode
              main_form.set_node(node)    
              break
            end
          end
        }

         main_form.show

    end
 end
 
class StartForm
  attr_reader :textbox, :ref_button, :ok_button
  
  def initialize()
      SWTJava::Display.setAppName "Executable Activity Diagram"

      @display = SWTJava::Display.new
      @shell = SWTJava::Shell.new(@display)
      @shell.setSize(2000, 1000)

      layout = SWTJava::GridLayout.new()
      layout.numColumns = 2
      layout.makeColumnsEqualWidth = false

      @shell.setLayout layout
      @shell.setText "Executable Activity Diagram"
      
      #ファイルパス
      grid_data1 = SWTJava::GridData.new(SWTJava::GridData::FILL_HORIZONTAL)
      grid_data1.widthHint = 400
      @textbox = SWTJava::Text.new(@shell, SWTJava::SWT::SINGLE)
      @textbox.setText("")
      @textbox.setLayoutData(grid_data1)
      
      #参照ボタン
      grid_data2 = SWTJava::GridData.new(SWTJava::GridData::HORIZONTAL_ALIGN_END)
      grid_data2.heightHint = 20      
      @ref_button = SWTJava::Button.new(@shell, SWTJava::SWT::PUSH)
      @ref_button.setText("参照")    
      ref_btn_click = FileOpenButtonClickEvent.new
      ref_btn_click.form = self
      @ref_button.addSelectionListener(ref_btn_click)
      @ref_button.setLayoutData(grid_data2)
      
      #okボタン
      grid_data3 = SWTJava::GridData.new(SWTJava::GridData::HORIZONTAL_ALIGN_END)
      grid_data3.horizontalSpan = 2
      grid_data3.heightHint = 20      
      grid_data3.widthHint = 60
      @ok_button = SWTJava::Button.new(@shell, SWTJava::SWT::PUSH)
      @ok_button.setText("OK") 
      ok_btn_click = OkButtonClickEvent.new
      ok_btn_click.form = self
      @ok_button.addSelectionListener(ok_btn_click)
      @ok_button.setLayoutData(grid_data3)
      
   end

    def show()    
      @shell.pack
      @shell.open
      until @shell.isDisposed do
        @display.sleep unless @display.readAndDispatch
      end    
      @display.dispose
   end
 end