#!/usr/bin/env ruby
#
# This file is gererated by ruby-glade-create-template 1.1.3.
#

require 'gconf2'
require 'rexml/document'
require 'optparse'
require 'tmpdir'

require 'remastering/remastertool_const'

require 'remastering/glade/remastertoolGlade'
require 'remastering/remastertool_init'
require 'remastering/remastertool_package'
require 'remastering/remastertool_makepackage'
require 'remastering/remastertool_file'
require 'remastering/remastertool_fixed'
require 'remastering/remastertool_distribution'
require 'remastering/remastertool_test'
require 'remastering/remastertool_procedure'
require 'remastering/remastertool_utility'

class Remastertool < RemastertoolGlade
  include GetText

  attr :glade

    PROG_PATH = "remastertool.glade"

	bindtextdomain(PROG_NAME, nil, nil, "UTF-8")

	DISPLAY_NAME = _("Remastering tool")
	PLUGIN_XML = "XML"						# XMLプラグインの名前
	SAVE_FORMAT = _("File type:")			# 手順ファイル保存ダイアログのコンボボックスのラベル

	# Gconf アクセスキー
	CONF_KEY_USE_PROXY = "/apps/remasteringtool/network/useProxy"
	CONF_KEY_HTTP_PROXY = "/apps/remasteringtool/network/httpProxy"
	CONF_KEY_FTP_PROXY = "/apps/remasteringtool/network/ftpProxy"
	CONF_KEY_DNS_SERVERS = "/apps/remasteringtool/network/DNSServers"
	CONF_KEY_INSTALL_TERM = "/apps/remasteringtool/install/terminal"
	CONF_KEY_SAVE_FUNC = "/apps/remasteringtool/save/function"
	CONF_KEY_VIEW_TOOLBAR = "/apps/remasteringtool/view/viewToolbar"
	CONF_KEY_VIEW_SIDEBAR = "/apps/remasteringtool/view/viewSidebar"
	CONF_KEY_VIEW_MESSAGEBAR = "/apps/remasteringtool/view/viewMessagebar"

	# オプション画面表示機能名
	OPTION_SAVE_FUNCS = [ [ "Initialize", _("Initialize"),  IDX_PANE_INIT ],
		[ "Package" , _("Package install/uninstall") , IDX_PANE_PACKAGE ],
		[ "File", _("File exchange"), IDX_PANE_FILE ],
		[ "Fixed", _("Fixed processing"), IDX_PANE_FIXED ],
		[ "Distribution", _("Make distribution"), IDX_PANE_DIST ] ]

	# 画面表示リテラル
	ABOUT_NAME_LITERAL = _("About %s plugin")
	OPTION_NAME_LITERAL = _("Setting %s plugin")

	# メッセージ定義
	MSG_ERR_NOGLADE = _("Cannot find glade files\nPlease check installation environment.\n")
	MSG_QUE_OPEN = _("Remastering procedure is changed.\n Is the change saved?")
	MSG_ERR_NO_PLUGIN = _("Cannot find %s plugin.\nPlease check installation environment.\n")
	TITLE_DIALOG_MENU_OPEN = _("Choose a remastering procedure file")
	TITLE_DIALOG_MENU_SAVE = _("Store remastering procedure to file")
	TITLE_DIALOG_SELECT_TERM = _("Choose a terminal command")
	TITLE_DIALOG_SELECT_LOGDIR = _("Choose a log output directory")
	TITLE_DIALOG_EXPORT = _("Store remastering environment archive file")
	TITLE_DIALOG_IMPORT = _("Choose remastering environment archive file")
	MSG_WARN_NOTERMINAL = _("Please sepcify a terminal command")
	MSG_WARN_NOLOGDIR = _("Please sepcify a log directory")
	MSG_ERR_EXPORT_ENV = _("Failed to export remastering environment(%s).")
	MSG_ERR_IMPORT_ENV = _("Failed to import remastering environment(%d).")
	MSG_WAIT_EXPORT = _("The exporting file is made an archive.")
	MSG_WAIT_IMPORT = _("The archive is extracted.")

	# 仮想マシンテストツールコマンド名
	CMD_RVMTOOL = "rvmtool"

	# リマスタリング手順ファイルの拡張子
	RMTOOL_EXT = ".rpml"

	# kpackageコマンド
	CMD_KPACKAGE = "kpackage"

	# リマスタリング環境アーカイブ作成／展開コマンド
	CMD_ARCHIVE_ENV = "tar -C %s -cf %s . && gzip -c %s > %s"
	CMD_EXTRACT_ENV = "gzip -dc %s > %s && tar -C %s -xf %s"

	# アーカイブファイル内のリマスタリング手順ファイル名
	RPML_IN_ARCHIVE = "procedure.rpml"

    #=== 初期化処理
    #
    #リマスタリングツールの#初期化を行う。
    #
    def initialize(procedure_file)
		# インスタンス変数の初期化
		@imageDir = ""		# イメージファイル格納ディレクトリ
		@pane = Hash.new	# 右ペイン画面のWidget格納用ハッシュ
		@pane_objs = Array.new	# 右ペイン画面のWidget格納用配列
		@options = Hash.new	# オプション情報ハッシュ
		@selectedFunc = nil	# 現在表示中の右ペイン

		@remasterFile	= nil
		@remasterFile_fmt = nil
		@importPath = ""	# importファイル展開ディレクトリ

		# gladeファイルディレクトリの取得
		glade_dir = RTUtility.get_glade_dir(PROG_PATH)
		if glade_dir == nil
			STDERR.puts MSG_ERR_NOGLADE
			exit 1
		end

		# glade-2でウインドウを作成
		super(File.join(glade_dir, PROG_PATH), nil, PROG_NAME, nil, GladeXML::FILE)

		# リマスタリングツールのオプション情報の読み込み&反映
		read_option
		apply_option

		# ユーティリティクラスに自インスタンス、メインウインドウインスタンスを設定する
		mainWindow = @glade["mainWindow"]
		RTUtility.setObjs(self, mainWindow)

		# プラグインをロードする
		RTUtility.load_plugin

		# プラグインのロードチェック
		# 全プラグインが少なくとも１つ上ロードされていることをチェック
		begin
			raise PLUGIN_TYPE_OS if RTUtility.get_os_plugins.empty?
			raise PLUGIN_TYPE_MEDIA if RTUtility.get_media_plugins.empty?
			raise PLUGIN_TYPE_PACKAGE if RTUtility.get_package_plugins.empty?
			raise PLUGIN_TYPE_TEST if RTUtility.get_test_plugins.empty?
			raise PLUGIN_TYPE_EMULATOR if RTUtility.get_emulator_plugins.empty?
			raise PLUGIN_TYPE_EXPORT if RTUtility.get_export_plugins.empty?
			raise PLUGIN_XML unless RTUtility.get_export_plugins[PLUGIN_XML]
		rescue
			RTUtility.unload_plugin
			raise sprintf(MSG_ERR_NO_PLUGIN, $!.to_s)
		end

		# メニューの初期化
		init_menu
	
		# リマスタリングツールのサイドバーにより切り替わる右ペインのインスタンスを作成
		init_pane glade_dir

		# リマスタリングツール本体のオプションダイアログを初期化
		init_dialog_option

		# メッセージ領域のフォントを設定  ★★★オプション情報で設定かな★★★
		style = Gtk::Style.new
		style.font_desc = Pango::FontDescription.new("Sans 12")
		@glade["textview_msg"].style = style

		# サイドバーボタン(初期設定完了以降に使用可能になるボタン)を非活性化する
		enable_sidebar_button false

		# リマスタリング環境を初期状態に設定する。
		init_environ

		# 起動オプションでリマスタリング手順ファイルが指定されている場合は手順ファイルを読み込む
		unless procedure_file.empty?
			if openProcedureFile(procedure_file)
				@remasterFile = procedure_file
				@remasterFile_fmt = PLUGIN_XML
			end
		end
	end


	#
	# Get resolv.conf contents
	#
	def get_resolv_conf
		resolvconf = ""
		@options[CONF_KEY_DNS_SERVERS].split(",").each {|server|
			resolvconf << "nameserver " + server + "\n"
		}
		resolvconf
	end

    #=== サイドバーボタンの設定
    #
    #リマスタリングツールの状態によりenbale/disableがトグルするサイドバーボタン
	#の状態を設定する。
	#
	#enable:: サイドの状態。 true=活生化、false=非活性化
	#復帰値:: なし
	#
	def enable_sidebar_button(enable)
		@glade["sideToggleButton_package"].set_sensitive enable
		@glade["sideToggleButton_file"].set_sensitive enable
		@glade["sideToggleButton_distribution"].set_sensitive enable
		@glade["sideToggleButton_fixed"].set_sensitive enable
		@glade["sideToggleButton_test"].set_sensitive enable
		@glade["sideToggleButton_settest"].set_sensitive enable
		@glade["sideToggleButton_list"].set_sensitive enable

		unless enable
			# 初期状態にもどした場合、は初期設定ボタンを凹状態にする
			@glade["sideToggleButton_init"].set_active(true)
		end

		# [File]-[Import]メニューの設定
		@glade["Import_rpml"].set_sensitive !enable
	end

    #=== メッセージバーへのメッセージ表示
    #
    #指定されたメッセージをメッセージバーに追加する。。
	#
	#msg:: 表示メッセージの内容
	#復帰値:: なし
	#
	def addMessage(msg)
		@glade["textview_msg"].buffer.insert(@glade["textview_msg"].buffer.end_iter, msg)
		@glade["textview_msg"].buffer.place_cursor(@glade["textview_msg"].buffer.end_iter)
		@glade["scrolledwindow_message"].vadjustment.value = @glade["scrolledwindow_message"].vadjustment.upper
	end

	#=== OSイメージの再作成が必要であることを通知
	#
	#ファイル操作、パッケージのインストール／アンインストールによりOSイメージ
	#の再作成が必要であることを通知する。
	#この呼び出しにより、ディストリビューション作成画面の「OSイメージの作成」、「プロファイリング」、
	#「メディアの作成」の各手順が身実行状態になる。
	#
	#復帰値:: なし
	#
	def need_osimage_remake
		@pane_objs[IDX_PANE_DIST].need_osimage_remake
	end

    #=== パッケージインストールコマンド実行用ターミナルの取得
    #
    #パッケージインストールコマンドを実行するためのターミナルコマンド文字列を取得する。
    #
    #復帰値::ターミナルコマンド文字列
	#
	def get_terminal_cmd
		@options[CONF_KEY_INSTALL_TERM]
	end

    #=== リマスタリング環境のインポート
    #
    #リマスタリング環境をリマスタリング環境ファイルから復元する。
	#importメソッドでは利用者が指定したリマスタリング環境ファイルを
	#各画面、各プラグインに反映する処理を実施する。
    #
    #復帰値::なし
    #
	def import
		RTUtility.get_logger.debug("import: import dir: " + @importPath)
		# importファイル展開ディレクトリ格納変数の内容が空の場合、何もしない
		return if @importPath.empty?

		# 右ペインの各機能に対して、import指示を発行する。
		@pane_objs.each{|obj| return unless obj.import(@importPath) }

		# 全プラグインに対して、expoer指示を発行する。
		RTUtility.get_plugins.each_value {|hash|
			hash.each { |key, val| return unless val.import(File.join(@importPath, key)) }
		}
		RTUtility.get_logger.debug("import: delete import dir")
		FileUtils.rm_rf(@importPath)
		@importPath = ""
	end

private

    #=== 右ペインのインスタンス初期化
    #
    #リマスタリングツールの右ペインに表示するクラスのインスタンスを作成する。
    #
    #dir:: gladeファイルの格納ディレクトリ
    #
	def init_pane(dir)
		@glade["functionHbox"].hide
		@pane_objs.push Remastertool_Init.new(dir, PROG_NAME)
		@pane[@glade["sideToggleButton_init"]] = @pane_objs.last.getBox(@glade["functionHbox"])
		@pane_objs.push RemastertoolPackage.new(dir, PROG_NAME)
		@pane[@glade["sideToggleButton_package"]] = @pane_objs.last.getBox(@glade["functionHbox"])
		@pane_objs.push RemastertoolMakePackage.new(dir, PROG_NAME, @pane_objs[IDX_PANE_PACKAGE])
		@pane[@glade["sideToggleButton_newPackage"]] = @pane_objs.last.getBox(@glade["functionHbox"])
		@pane_objs.push RemastertoolFile.new(dir, PROG_NAME)
		@pane[@glade["sideToggleButton_file"]] = @pane_objs.last.getBox(@glade["functionHbox"])
		@pane_objs.push RemastertoolFixed.new(dir, PROG_NAME)
		@pane[@glade["sideToggleButton_fixed"]] = @pane_objs.last.getBox(@glade["functionHbox"])
		@pane_objs.push RemastertoolDistribution.new(dir, PROG_NAME, @pane_objs[IDX_PANE_FILE], @pane_objs[IDX_PANE_PACKAGE], @pane_objs[IDX_PANE_FIXED])
		@pane[@glade["sideToggleButton_distribution"]] = @pane_objs.last.getBox(@glade["functionHbox"])
		@pane_objs.push RemastertoolTest.new(dir, PROG_NAME)
		@pane[@glade["sideToggleButton_settest"]] = @pane[@glade["sideToggleButton_test"]] = @pane_objs.last.getBox(@glade["functionHbox"])
		@pane_objs.push RemastertoolProcedure.new(dir, PROG_NAME)
		@pane[@glade["sideToggleButton_list"]] = @pane_objs.last.getBox(@glade["functionHbox"])
		@pane_objs.last.set_pane_objs(@pane_objs)	# 手順編集画面にペインの一覧を通知

		@pane.each_value {|val| val.hide }
		@glade["functionHbox"].show
	end

	#=== オプション設定の読み込み
	#
	#GConfを使用し、以下の設定を読み込む
	#  ・DNS server
	#  ・Proxy server使用有無
	#  ・HTTP/FTP Proxy
	#  ・Tool bar表示有無
	#  ・Side bar表示有無
	#  ・Message bar表示有無
	#
	#復帰値:: なし
	#
	def read_option
		gconf = GConf::Client.default

		# DNS server Setting
		@options[CONF_KEY_DNS_SERVERS] = gconf[CONF_KEY_DNS_SERVERS] ? gconf[CONF_KEY_DNS_SERVERS] : ""

		# Proxy Setting
		if gconf[CONF_KEY_USE_PROXY] != nil
			@options[CONF_KEY_USE_PROXY] = gconf[CONF_KEY_USE_PROXY]
		else
			@options[CONF_KEY_USE_PROXY] = (ENV["http_proxy"] != nil || ENV["ftp_proxy"] != nil)
		end
		if gconf[CONF_KEY_HTTP_PROXY]
			@options[CONF_KEY_HTTP_PROXY] = gconf[CONF_KEY_HTTP_PROXY]
		else
			@options[CONF_KEY_HTTP_PROXY] = ENV["http_proxy"] ? ENV["http_proxy"] : ""
		end
		if gconf[CONF_KEY_FTP_PROXY]
			@options[CONF_KEY_FTP_PROXY] = gconf[CONF_KEY_FTP_PROXY]
		else
			@options[CONF_KEY_FTP_PROXY] = ENV["ftp_proxy"] ? ENV["ftp_proxy"] : ""
		end

		# terminal command for execution of package install command
		if gconf[CONF_KEY_INSTALL_TERM]
			@options[CONF_KEY_INSTALL_TERM] = gconf[CONF_KEY_INSTALL_TERM]
		else
			@options[CONF_KEY_INSTALL_TERM] = "xterm -e %s"
		end

		# log setting
		RTUtility.set_logger

		# save setting
		gconf.all_entries(CONF_KEY_SAVE_FUNC).each{|entry|
			@options[entry.key] = entry.value
		}

		# Tool/Side/Message bar表示有無
		@options[CONF_KEY_VIEW_TOOLBAR] = gconf[CONF_KEY_VIEW_TOOLBAR] ? gconf[CONF_KEY_VIEW_TOOLBAR] : true
		@options[CONF_KEY_VIEW_SIDEBAR] = gconf[CONF_KEY_VIEW_SIDEBAR] ? gconf[CONF_KEY_VIEW_SIDEBAR] : true
		@options[CONF_KEY_VIEW_MESSAGEBAR] = gconf[CONF_KEY_VIEW_MESSAGEBAR] ? gconf[CONF_KEY_VIEW_MESSAGEBAR] : true

		hash
	end

	#=== オプション設定の反映
	#
	#パラメタのHashに格納されたオプション情報を環境に反映する
	#  ・HTTP/FTP Proxy
	#
	#復帰値:: なし
	#
	def apply_option
		# 環境変数 http_proxy, ftp_proxyの反映
		# Update environment variables
		if @options[CONF_KEY_HTTP_PROXY].empty? || ! @options[CONF_KEY_USE_PROXY]
			ENV.delete("http_proxy")
		else
			ENV["http_proxy"] = @options[CONF_KEY_HTTP_PROXY]
		end
		if @options[CONF_KEY_FTP_PROXY].empty? || ! @options[CONF_KEY_USE_PROXY]
			ENV.delete("ftp_proxy")
		else
			ENV["ftp_proxy"] = @options[CONF_KEY_FTP_PROXY]
		end

		# 表示メニューのチェックをプラグイン状態の設定と表示の設定
		@glade["menu_view_toolbar"].active = @options[CONF_KEY_VIEW_TOOLBAR]
		on_menu_view_toolbar_activate @glade["menu_view_toolbar"]
		@glade["menu_view_message"].active = @options[CONF_KEY_VIEW_MESSAGEBAR]
		on_menu_view_message_activate @glade["menu_view_message"]
		@glade["menu_view_sidebar"].active = @options[CONF_KEY_VIEW_SIDEBAR]
		on_menu_view_sidebar_activate @glade["menu_view_sidebar"]
	end

    #=== リマスタリングツールのメニューの初期設定
    #
    #リマスタリングツールのメニューの初期設定を行う。
    #
	def init_menu
		@menu_option = RTUtility.create_menu_option(@glade["menu_option_menu"])	# プラグインのオプションメニューの作成
		@menu_help = RTUtility.create_menu_help(@glade["menu_help_menu"])	# プラグインのヘルプメニューの作成
	end

	#=== [File]-[New]メニューのイベントハンドラ
	#
	#メニューの[File]-[New]が選択されたときに呼び出され、リマスタリング環境の
	#さらの状態に戻す。
	#このとき、既にリマスタリング手順を更新していた場合、メッセージダイアログを
	#表示して、現在のリマスタリング手順の保存先の要否を確認する。
	#
	#widget:: [File]-[New]メニューのWidget
	#復帰値:: なし
	#
	def on_new_activate(widget)
		# リマスタリング手順が更新されている場合、現在のリマスタリング手順を保存する
		case need_save?
		when Gtk::Dialog::RESPONSE_YES:
			#保存が成功しなかった場合(キャンセルされた場合も含む)環境の初期化を行わない
			return false unless on_save_activate(@glade["save"])
		when Gtk::Dialog::RESPONSE_CANCEL:
			# 操作キャンセル時は何もしない
			return
		end

		# 環境の初期化
		init_environ
	end

	#=== リマスタリング環境の初期化
	#
	#新たなリマスタリング作業を開始するためにリマスタリング環境を初期状態に戻す。
	#
	#復帰値:: なし
	#
	def init_environ
		# 各ペインの環境初期化メソッドを呼び出し、リマスタリング環境を初期状態に戻す。
		@pane_objs.each{|obj| obj.init_environ }

		# 各プラグインの環境初期化メソッドを呼び出し、リマスタリング環境を初期状態に戻す。
		RTUtility.get_plugins.each_value{|hash|
			hash.each_value { |obj| obj.init_environ }
		}

		# 初期表示ペイン(初期設定画面)の表示
		@glade["sideToggleButton_init"].set_active(true)

		@remasterFile	= nil
		@remasterFile_fmt = nil
		unless @importPath.empty?
			RTUtility.get_logger.debug("init_environ: delete import dir")
			FileUtils.rm_rf(@importPath)
			@importPath = ""	# importファイル展開ディレクトリ
		end
	end

	#=== [File]-[Open]メニューのイベントハンドラ
	#
	#メニューの[File]-[Open]が選択されたときにファイル選択ダイアログを開き、
	#リマスタリング手順ファイルの指定を行う。
	#指定された手順ファイルは手順ファイル適用処理を呼びだし、読み込みを行う。
	#
	#widget:: [File]-[Open]メニューのWidget
	#復帰値:: なし
	#
	def on_open_activate(widget)
		# リマスタリング手順が更新されている場合、現在のリマスタリング手順を保存する
		case need_save?
		when Gtk::Dialog::RESPONSE_YES:
			#保存が成功しなかった場合(キャンセルされた場合も含む)環境の初期化を行わない
			return false unless on_save_activate(@glade["save"])
		when Gtk::Dialog::RESPONSE_CANCEL:
			# 操作キャンセル時は何もしない
			return
		end

		# ファイル選択ダイアログの作成
		dialog = Gtk::FileChooserDialog.new(TITLE_DIALOG_MENU_OPEN,
							@glade["mainWindow"],
							Gtk::FileChooser::ACTION_OPEN,
							nil,
							[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
							[Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_OK])
		begin
			dialog.current_folder = Pathname.new(File.dirname(@remasterFile)).realpath
		rescue
		end
	
		filter = Gtk::FileFilter.new
 		type = RTUtility.get_export_plugins[PLUGIN_XML].get_file_type
		filter.name = type[0] + " (*." + type[1] + ")"
		filter.add_pattern("*." + type[1])
		dialog.add_filter(filter)

		if dialog.run == Gtk::Dialog::RESPONSE_OK
			# [OK]ボタンで終了した場合、XMLプラグインの手順ファイルの読み込み処理を呼び出す。
			# 正常終了の場合、リマスタリング手順ファイル名を保持しているインスタンス変数
			# を更新する。
			if openProcedureFile(dialog.filename)
				@remasterFile = dialog.filename
				@remasterFile_fmt = PLUGIN_XML
			end
		end
		dialog.destroy
	end

	#=== リマスタリング手順ファイルの保存確認
	#
	#現在のリマスタリング手順をファイルに保存していない場合、保存するか確認する。
	#
	#file:: リマスタリング手順ファイル
	#復帰値:: Gtk::Dialog::RESPONSE_YES=保存する,
	#        Gtk::Dialog::RESPONSE_NO=保存しない(保存不要)
	#        Gtk::Dialog::RESPONSE_CANCEL=操作をキャンセル
	#
	def need_save?
		# 各ペインの変更確認メソッドを呼び出し、リマスタリング手順の変更の有無を確認する。
		modified = false
		@pane_objs.each{|obj|
			modified = obj.isModified?
			break if modified
		}

		unless modified
			# 各プラグインの変更確認メソッドを呼び出し、リマスタリング手順の変更の有無を確認する。
			catch :loop_end do
				RTUtility.get_plugins.each_value{|hash|
					hash.each_value { |obj|
						modified = obj.isModified?
						throw :loop_end if modified
					}
				}
			end
		end
		if modified
			# 既に初期設定が完了している場合、これまでの手順を保存するか確認する。
			msgDialog = Gtk::MessageDialog.new(@glade["mainWindow"],
							Gtk::Dialog::MODAL, Gtk::MessageDialog::QUESTION,
							Gtk::MessageDialog::BUTTONS_NONE,
							MSG_QUE_OPEN)
			msgDialog.add_button(Gtk::Stock::YES, Gtk::Dialog::RESPONSE_YES)
			msgDialog.add_button(Gtk::Stock::NO, Gtk::Dialog::RESPONSE_NO)
			msgDialog.add_button(Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL)
			response = msgDialog.run
			msgDialog.destroy
			response = Gtk::Dialog::RESPONSE_CANCEL if response == Gtk::Dialog::RESPONSE_DELETE_EVENT
			return response
		end
		Gtk::Dialog::RESPONSE_NO
	end

	#=== リマスタリング手順ファイルの読み込み
	#
	#XMLプラグインのファイル名ロードメソッドを呼び出し、手順ファイルの読み込みを行う。
	#
	#file:: リマスタリング手順ファイル
	#復帰値:: true=正常終了, false=異常終了(読み込みでエラー発生)
	#
	def openProcedureFile(file)
 		xml = RTUtility.get_export_plugins[PLUGIN_XML].read_procedure(file)
		return false unless xml
		return true unless xml.root

		init_environ # 環境を初期化してからXMLの適用を開始する

		# XMLドキュメントを右ペインの各機能に渡し、ファイル内の手順を復元する。
		@pane_objs.each{|obj| obj.init_environ; obj.load_xml xml.root }

		# XMLドキュメントを全プラグインに渡し、ファイル内の手順を復元する。
		RTUtility.get_plugins.each_value {|hash|
			hash.each_value { |val| val.load_xml xml.root }
		}
		true
	end

	#=== [File]-[Save]メニューのイベントハンドラ
	#
	#メニューの[File]-[Save]が選択されたときに呼び出され、[File]-[Open]で選択したファイル
	#またはツール起動時にしているした手順ファイルに現在のリマスタリング手順を上書き保存する、
	#新規にリマスタリング手順を作成している場合は、[File]-[Save as]のイベントハンドラを
	#呼びだし、リマスタリング手順ファイルの指定を行う。
	#
	#widget:: [File]-[Save]メニューのWidget
	#復帰値:: true=保存成功、fasle=保存失敗
	#
	def on_save_activate(widget)
		if @remasterFile == nil
			on_save_as_activate(widget)
		else
			saveProcedureFile(@remasterFile, @remasterFile_fmt)
		end
	end

	#=== [File]-[Save as]メニューのイベントハンドラ
	#
	#メニューの[File]-[Save as]が選択されたときに呼び出され、ファイル選択ダイアログを表示し
	#リマスタリング手順を保存するファイルの指定を行う。
	#このとき、既に存在するファイルが指定された場合、メッセージダイアログを表示して上書の
	#可否を確認する。
	#
	#widget:: [File]-[Save as]メニューのWidget
	#復帰値:: true=保存成功、fasle=保存失敗
	#
	def on_save_as_activate(widget)
		# ファイルの保存先/形式を設定するファイル選択ダイアログを表示する
		dialog = Gtk::FileChooserDialog.new(TITLE_DIALOG_MENU_SAVE,
							@glade["mainWindow"],
							Gtk::FileChooser::ACTION_SAVE,
							nil,
							[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
							[Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_OK])
		dialog.do_overwrite_confirmation = true

		# ファイルフィルタの設定
		filter_hash = Hash.new
		RTUtility.get_export_plugins.each{ |key, value|
			type = value.get_file_type
			filter = Gtk::FileFilter.new
			filter.name = type[0] + " (*." + type[1] + ")"
			filter.add_pattern("*." + type[1])
			dialog.add_filter(filter)
			if key == @remasterFile_fmt || (@remasterFile_fmt == nil && key == PLUGIN_XML)
				dialog.filter = filter
			end
			filter_hash[filter] = key
		}

		begin
			path = Pathname.new(@remasterFile).realpath
			dialog.current_folder = File.dirname(path)
			dialog.filename = path
		rescue
		end

		# 指定されたファイルにリマスタリング手順を保存する(OKボタンをクリックした場合のみ)。
		ret = false
		begin
			break if dialog.run != Gtk::Dialog::RESPONSE_OK
			ret = saveProcedureFile(dialog.filename, filter_hash[dialog.filter])
			if ret
				@remasterFile = dialog.filename
				@remasterFile_fmt = filter_hash[dialog.filter]
				break
			end
			dialog.show
		end while true

		dialog.destroy
		ret
	end

	#=== リマスタリング手順ファイルの保存
	#
	#XMLプラグインにより、リマスタリング手順をXML化する。
	#XML化したリマスタリング手順を保存形式に対応するプラグインのファイルセーブメソッドを呼び出し、
	#手順ファイルの保存を行う。
	#
	#file:: リマスタリング手順ファイル
	#format:: リマスタリング手順ファイルの保存形式
	#復帰値:: true=正常終了, false=異常終了(保存で失敗)
	#
	def saveProcedureFile(file, format = PLUGIN_XML)
		RTUtility.get_logger.debug "saveProcedureFile: file=" + file +", fmt=" + format.to_s
		# XMLプラグインでXMLドキュメントを作成する
		xml = create_xml(format == PLUGIN_XML ? 0 : 1)

		# エクスポートプラグインによりリマスタリング手順をファイルに保存する
		if RTUtility.get_export_plugins[format] &&
			RTUtility.get_export_plugins[format].write_procedure(file, xml)
			RTUtility.get_logger.debug "saveProcedureFile: write_procedure method return true"
			if format == PLUGIN_XML
				# XMLドキュメントの保存に成功したので、全ペイン、全プラグインに変更フラグを
				# 落とすように通知する。
				@pane_objs.each{|obj| obj.fix_procedure }
				RTUtility.get_plugins.each_value {|hash|
					hash.each_value { |val|	val.fix_procedure }
				}
			end
			return true
		end
		false
	end

	#=== リマスタリング手順の作成(XML形式)
	#
	#リマスタリングツール本体の各ペイン、および、全プラグインからXML形式のリマスタリング
	#手順を取得して結合する。
	#
	#localize:: ローカライゼーション(0:非ローカライゼーション化XMLを作成, 1:ローカライゼーション化XMLを作成)
	#復帰値:: リマスタリング手順(REXML::Document)
	#
	def create_xml(localize = 0)
		RTUtility.get_logger.debug "create_xml: localize=" + localize.to_s
		# XMLヘッダの作成
		doc = REXML::Document.new
		doc.add REXML::XMLDecl.new("1.0", "UTF-8")
		doc.add_element(REXML::Element.new(XML_ROOT))

		OPTION_SAVE_FUNCS.each{|ary|
			if @options[File.join(CONF_KEY_SAVE_FUNC, ary[0])] != false
				element = @pane_objs[ary[2]].make_xml localize
				doc.root.add_element(element) if element
			end
		}

		# 各プラグインのXML手順作成処理を呼び出し、リマスタリング手順をXML化する。
		RTUtility.get_plugins.each_value{|hash|
			hash.each_value { |obj|
				if @options[File.join(CONF_KEY_SAVE_FUNC, obj.class.to_s)] != false
					element = obj.make_xml localize
					doc.root.add_element(element) if element
				end
			}
		}
		doc
	end

	#=== [File]-[Import]メニューのイベントハンドラ
	#
	#メニューの[File]-[Import]が選択されたときに呼び出され、リマスタリングツールの作業
	#環境を単一ファイルにアーカイブ化されたファイルから環境の復元を行う。
	#
	#widget:: [File]-[Import]メニューのWidget
	#復帰値:: なし
	#
	def on_Import_rpml_activate(widget)
		# ファイル選択ダイアログでexport先のファイルを指定する。
		dialog = Gtk::FileChooserDialog.new(TITLE_DIALOG_EXPORT,
							@glade["mainWindow"],
							Gtk::FileChooser::ACTION_OPEN,
							nil,
							[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
							[Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_OK])

		env_file = ""
		env_file_work = ""
		if dialog.run == Gtk::Dialog::RESPONSE_OK
			env_file = dialog.filename
			env_file_work = env_file + ".incomplete"
		end
		dialog.destroy
		return if env_file.empty?	# OK 以外でファイル選択ダイアログを終了したら何もしない

		# importの作業用dirを作成
		import_dir = File.join(Dir.tmpdir, "remaster_import_" + $$.to_s)
		begin
			FileUtils.rm_rf(import_dir)
			FileUtils.mkdir_p(import_dir)

			# アーカイブの内容をimportディレクトリに展開する
			status = RTUtility.exec_workOS_command(
				sprintf(CMD_EXTRACT_ENV, env_file, env_file_work, import_dir, env_file_work),
				nil, nil, nil, @glade["mainWindow"], MSG_WAIT_IMPORT)
			raise sprintf(MSG_ERR_IMPORT_ENV, status.to_s) unless status == 0
	
			# リマスタリング手順ファイルを抽出し、読み込みを行う
			return unless openProcedureFile(File.join(import_dir, RPML_IN_ARCHIVE))

			# リマスタリング環境が初期設定済の場合はimportPathを設定しない
			@importPath = import_dir unless RTUtility.isInitialized?
			RTUtility.get_logger.debug "on_Import_rpml_activate: import dir = " + @importPath

		rescue
			# 警告メッセージを表示する
			dlg = Gtk::MessageDialog.new(@glade["mainWindow"], Gtk::Dialog::MODAL,
					Gtk::MessageDialog::ERROR, Gtk::MessageDialog::BUTTONS_OK, $!.to_s)
			dlg.run
			dlg.destroy
			FileUtils.rm_f(env_file)

		ensure
			FileUtils.rm_rf(env_file + ".incomplete")
		end
	end

	#=== [File]-[Export]メニューのイベントハンドラ
	#
	#メニューの[File]-[Export]が選択されたときに呼び出され、リマスタリングツールの作業
	#環境を単一ファイルにアーカイブ化する。
	#
	#widget:: [File]-[Export]メニューのWidget
	#復帰値:: なし
	#
	def on_export_rpml_activate(widget)
		# ファイル選択ダイアログでexport先のファイルを指定する。
		dialog = Gtk::FileChooserDialog.new(TITLE_DIALOG_EXPORT,
							@glade["mainWindow"],
							Gtk::FileChooser::ACTION_SAVE,
							nil,
							[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
							[Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_OK])
		dialog.do_overwrite_confirmation = true

		env_file = ""
		env_file_work = ""
		if dialog.run == Gtk::Dialog::RESPONSE_OK
			env_file = dialog.filename
			env_file_work = env_file + ".incomplete"
		end
		dialog.destroy
		return if env_file.empty?	# OK 以外でファイル選択ダイアログを終了したら何もしない

		# exportの作業用dirを作成
		export_dir = File.join(Dir.tmpdir, "remaster_export_" + $$.to_s)
		begin
			FileUtils.rm_rf(export_dir)
			FileUtils.mkdir_p(export_dir)
			FileUtils.mkdir_p(File.dirname(env_file))
	
			if RTUtility.isInitialized?
				# 右ペインの各機能に対して、export指示を発行する。
				@pane_objs.each{|obj| return unless obj.export(export_dir) }
		
				# 全プラグインに対して、export指示を発行する。
				RTUtility.get_plugins.each_value {|hash|
					hash.each { |key, val| return unless val.export(File.join(export_dir, key)) }
				}
			end

			# リマスタリング手順ファイルを作成し、エクスポートディレクトリに格納する
			return unless RTUtility.get_export_plugins[PLUGIN_XML].write_procedure(
				File.join(export_dir, RPML_IN_ARCHIVE), create_xml)

			# exportディレクトリの内容をアーカイブ化する
			status = RTUtility.exec_workOS_command(
				sprintf(CMD_ARCHIVE_ENV, export_dir, env_file_work, env_file_work, env_file),
				nil, nil, nil, @glade["mainWindow"], MSG_WAIT_EXPORT)
			raise sprintf(MSG_ERR_EXPORT_ENV, status.to_s) unless status == 0

		rescue
			# 警告メッセージを表示する
			dlg = Gtk::MessageDialog.new(@glade["mainWindow"], Gtk::Dialog::MODAL,
					Gtk::MessageDialog::ERROR, Gtk::MessageDialog::BUTTONS_OK, $!.to_s)
			dlg.run
			dlg.destroy
			FileUtils.rm_f(env_file)

		ensure
			FileUtils.rm_rf([export_dir, env_file + ".incomplete"])
		end
	end

	#=== [File]-[Quit]メニューのイベントハンドラ
	#
	#メニューの[File]-[Quit]が選択されたときに呼び出され、リマスタリングツールを終了する。
	#このとき、既に初期設定が完了している場合、メッセージダイアログを表示してリマスタリング
	#手順を保存するか確認する。
	#保存する場合は[File]-[Save]メニューのハンドラを呼び出しファイルの保存を行う。
	#
	#widget:: [File]-[Quit]メニューのWidget
	#復帰値:: ツール終了の可否(true=終了, false=終了しない)
	#
	def on_quit_activate(widget)
		case need_save?
		when Gtk::Dialog::RESPONSE_YES:
			#保存が成功しなかった場合(キャンセルされた場合も含む)環境の初期化を行わない
			return true unless on_save_activate(@glade["save"])
		when Gtk::Dialog::RESPONSE_CANCEL:
			# 操作キャンセル時は何もしない
			return true
		end

		# importファイルの展開した資源を削除
		unless @importPath.empty?
			RTUtility.get_logger.debug("on_quit_activate: delete import dir")
			FileUtils.rm_rf(@importPath)
			@importPath = ""
		end

		#  オプション情報の書き込み
		gconf = GConf::Client.default
		@options.each{|key,value| gconf[key] = value }

		# プラグインの終了処理
		RTUtility.unload_plugin

#		@pane.each_value{|val| @glade["functionHbox"].remove(val) if val.parent}
#		@pane.clear
#		@pane_objs.clear
#		@pane = @pane_objs = @selectedFunc = nil

		# mainループの終了
		Gtk.main_quit
		false
	end

	#=== [View]-[Toolbar]メニューのイベントハンドラ
	#
	#メニューの[View]-[Toolbar]が選択されたときに呼び出され、サイドバーの表示のON/OFF
	#を切り替える。
	#
	#widget:: [View]-[Toolbar]メニューのWidget
	#復帰値:: なし
	#
	def on_menu_view_toolbar_activate(widget)
		if widget.active?
			@glade["toolBar"].show
		else
			@glade["toolBar"].hide
		end
	end

	#=== [View]-[Sidebar]メニューのイベントハンドラ
	#
	#メニューの[View]-[Sidebar]が選択されたときに呼び出され、サイドバーの表示
	#のON/OFFを切り替える。
	#
	#widget:: [View]-[Sidebar]メニューのWidget
	#復帰値:: なし
	#
	def on_menu_view_sidebar_activate(widget)
		if widget.active?
			@glade["sideFrame"].show
		else
			@glade["sideFrame"].hide
		end
	end

	#=== [View]-[Meesagebar]メニューのイベントハンドラ
	#
	#メニューの[View]-[Meesagebar]が選択されたときに呼び出され、メッセージ表示域
	#の表示のON/OFFを切り替える。
	#
	#widget:: [View]-[Meesagebar]メニューのWidget
	#復帰値:: なし
	#
	def on_menu_view_message_activate(widget)
		if widget.active?
			@glade["scrolledwindow_message"].show
		else
			@glade["scrolledwindow_message"].hide
		end
	end

	#=== [View]-[Refresh]メニューのイベントハンドラ
	#
	#メニューの[View]-[Refresh]が選択されたときに呼び出され、表示いきの更新を行う。
	#
	#widget:: [View]-[Refresh]メニューのWidget
	#復帰値:: なし
	#
	def on_menu_view_refresh_activate(widget)
		pos = 0
		case @selectedFunc
			when @glade["sideToggleButton_init"]		then pos = IDX_PANE_INIT
			when @glade["sideToggleButton_package"]		then pos = IDX_PANE_PACKAGE
			when @glade["sideToggleButton_newPackage"]	then pos = IDX_PANE_MAKEPKG
			when @glade["sideToggleButton_file"]		then pos = IDX_PANE_FILE
			when @glade["sideToggleButton_distribution"]	then pos = IDX_PANE_DIST
			when @glade["sideToggleButton_settest"]		then pos = IDX_PANE_TEST
			when @glade["sideToggleButton_list"]		then pos = IDX_PANE_LIST
			when @glade["sideToggleButton_fixed"]		then pos = IDX_PANE_FIXED
		end
		@pane_objs[pos].refresh
	end

	#=== [Option]-[Setting of remasteringtool]メニューのイベントハンドラ
	#
	#メニューの[Option]-[Setting of remasteringtool]が選択されたときに呼び出され、
	#オプションダイアログの表示を行う。
	#
	#widget:: [Option]-[Setting of remasteringtool]メニューのWidget
	#復帰値:: なし
	#
	def on_remastering_tool_setting_activate(widget)
		@glade["optiondialog"].set_transient_for(@glade["mainWindow"])
		@glade["optiondialog"].run
	end

	#=== [Help]-[About]メニューのイベントハンドラ
	#
	#メニューの[Help]-[About]が選択されたときに呼び出され、
	#オプションダイアログの表示を行う。
	#
	#widget:: [Help]-[About]メニューのWidget
	#復帰値:: なし
	#
	def on_about_activate(widget)
		RTUtility.show_about(DISPLAY_NAME, PROG_VERSION, SSL_COPYRIGHT, SSL_LICENSE)
	end

	#===ツールバー [New]のイベントハンドラ
	#
	#ツールバーの[New]が選択されたときに呼び出される。
	#メニュー[File]-[New]のハンドラを呼び出し、同じ動作を実施する。
	#
	#widget:: ツールバー [New]のWidget
	#復帰値:: なし
	#
	def on_toolbutton_New_clicked(widget)
		on_new_activate(widget)
	end

	#===ツールバー [Open]のイベントハンドラ
	#
	#ツールバーの[Open]が選択されたときに呼び出される。
	#メニュー[File]-[Open]のハンドラを呼び出し、同じ動作を実施する。
	#
	#widget:: ツールバー [Open]のWidget
	#復帰値:: なし
	#
	def on_toolbutton_Open_clicked(widget)
		on_open_activate(widget)
	end

	#===ツールバー [Save]のイベントハンドラ
	#
	#ツールバーの[Save]が選択されたときに呼び出される。
	#メニュー[File]-[Save]のハンドラを呼び出し、同じ動作を実施する。
	#
	#widget:: ツールバー [Save]のWidget
	#復帰値:: なし
	#
	def on_toolbutton_Save_clicked(widget)
		on_save_activate(widget)
	end

	#=== [x]ボタンクリック持のイベントハンドラ
	#
	#[x]ボタンクリック時に[File]-[Quit]メニューのハンドラを呼び出し、終了処理を行う。
	#
	#widget:: リマスタリングツールのWidget
	#arg0:: 未使用
	#復帰値:: なし
	#
    def on_mainWindow_delete_event(widget, arg0)
		on_quit_activate(@glade["quit"])
    end

	#===サイドバーボタンクリック時のイベントハンドラ
	#
	#サイドバーのボタン([手順の入れ替え]、[仮想マシンテストツールの起動]以外)がクリック
	#されたときに呼び出される。
	#クリックされたサイドバーボタンに対応した機能の画面を右ペインに表示する。
	#
	#widget:: クリックしたサイドバーボタンのWidget
	#復帰値:: なし
	#
	def on_sideToggleButton_clicked(widget)
		if widget.active?
			# ボタンが押された状態になった場合、これまで押されていたボタン
			# の選択を解除する。
			oldSelect = @selectedFunc
			@selectedFunc = widget
			if(oldSelect and oldSelect != widget)
				oldSelect.set_active(false)
			end
	
		else
			widget.set_active(true) if @selectedFunc == widget
			return
		end
		# 右ペイン表示の切り替え
		change_pane(widget)
	end

public
	#===右ペイン表示の切り替え
	#
	#サイドバーのボタン([手順の入れ替え]、[仮想マシンテストツールの起動]以外)がクリック
	#されたときに呼び出される。
	#クリックされたサイドバーボタンに対応した機能の画面を右ペインに表示する。
	#
	#widget:: クリックしたサイドバーボタンのWidget(nilの場合[初期設定]ボタンとみなす)
	#復帰値:: なし
	#
	def change_pane(button)
		button = @glade["sideToggleButton_init"] unless button
		return unless @pane[button]

		# いままで表示していたペインを隠す
		@pane.each_value { |pane| pane.hide }

		# クリックしたボタンに対応した右ペインを表示する。
		@pane[button].show
		
		# テスト設定/結果表示のペインではテスト項目設定ペインの表示/非表示の設定を行う。
		case button
		when @glade["sideToggleButton_test"]
			@pane_objs[IDX_PANE_TEST].show_setting_pane false
		when @glade["sideToggleButton_settest"]
 			@pane_objs[IDX_PANE_TEST].show_setting_pane true
		end
	end

private
	#===サイドバー [仮想マシンテストツールの起動]ボタンクリック時のイベントハンドラ
	#
	#サイドバーのボタン[仮想マシンテストツールの起動]がクリックされたときに
	#呼び出される。
	#子プロセスとして仮想マシンテストツールを起動する。起動後はツールの終了を待たずに
	#制御を戻す。
	#
	#widget::  [仮想マシンテストツールの起動]ボタンのWidget
	#復帰値:: なし
	#
	def on_sideButton_vmtool_clicked(widget)
		# 子プロセスとして仮想マシンテストツールを起動する
		cmd = CMD_RVMTOOL
		cmd << " -e " + @pane_objs[IDX_PANE_DIST].get_emulator
		unless RTUtility.get_media_plugins[@pane_objs[IDX_PANE_DIST].get_media].get_output_image.empty?
			cmd << " -f " + RTUtility.get_media_plugins[@pane_objs[IDX_PANE_DIST].get_media].get_output_image
		end
		fork { exec(cmd) }
	end


	########################################
	# Option dialog
	########################################

    #=== オプションダイアログの初期化
    #
    #オプションダイアログ中の部品を初期化する。
    #
    #復帰値::なし
    #
	def init_dialog_option
		# DNSサーバリストにStringのカラムを作成する
		column = Gtk::TreeViewColumn.new("dummy", Gtk::CellRendererText.new, :text => 0)
		@glade["treeview_dns"].append_column(column)
		model = Gtk::ListStore.new(String)
		@glade["treeview_dns"].set_model(model)

		# 保存対象機能リストにcheckbox + Stringのカラムを作成する
		@save_chkbox_render = Gtk::CellRendererToggle.new
		@save_chkbox_render.activatable = true
		@save_chkbox_render.signal_connect("toggled"){ |widget, path_str|
			path = Gtk::TreePath.new(path_str)
			iter = @glade["treeview_save_function"].model.get_iter(path)
			iter[0] = ! iter[0]
		}
		@glade["treeview_save_function"].append_column(Gtk::TreeViewColumn.new("dummy", @save_chkbox_render, :active => 0))
		@glade["treeview_save_function"].append_column(Gtk::TreeViewColumn.new("dummy", Gtk::CellRendererText.new, :text => 1))
		@glade["treeview_save_function"].append_column(Gtk::TreeViewColumn.new("dummy", Gtk::CellRendererText.new, :text => 2))
		@glade["treeview_save_function"].get_column(2).visible = false
		@glade["treeview_save_function"].set_model(Gtk::ListStore.new(TrueClass, String, String))
	end

	#=== オプションダイアログ表示時のイベントハンドラ
	#
	#オプションダイアログ表示時に表示毎に設定が必要な部品の初期化を実施する
	#
	#widget:: オプションダイアログのWidget
	#復帰値:: なし
	#
	def on_optiondialog_map(widget)
		@glade["entry_dns"].text = ""

		# DNS server Setting
		@glade["treeview_dns"].model.clear	# delete all data
		@options[CONF_KEY_DNS_SERVERS].split(",").each {|server|
			iter = @glade["treeview_dns"].model.append
			iter[0] = server
		}

		# Proxy Setting
		@glade["entry_proxy_http"].set_text( @options[CONF_KEY_HTTP_PROXY] )
		@glade["entry_proxy_ftp"].set_text( @options[CONF_KEY_FTP_PROXY] )
		@glade["checkbutton_proxy"].set_active( @options[CONF_KEY_USE_PROXY] )
		on_checkbutton_proxy_button_press_event(@glade["checkbutton_proxy"])

		# terminal setting
		@glade["entry_term"].set_text( @options[CONF_KEY_INSTALL_TERM] )

		# log setting
		@glade["entry_log_dir"].text, @glade["combobox_log_level"].active  = RTUtility.get_log_option

		# save setting
		@glade["treeview_save_function"].model.clear	# delete all data
		OPTION_SAVE_FUNCS.each{|funcs|
			iter = @glade["treeview_save_function"].model.append
			key = File.join(CONF_KEY_SAVE_FUNC, funcs[0])
			iter[0] = ((@options[key] != nil) ? @options[key] : true)
			iter[1] = funcs[1]
			iter[2] = key
		}
		RTUtility.get_plugins.each_value {|hash|
			hash.each { |plugin_name, plugin_obj|
				iter = @glade["treeview_save_function"].model.append
				key = File.join(CONF_KEY_SAVE_FUNC, (plugin_obj.class.to_s))
				iter[0] = (@options[key] != nil) ? @options[key] : true
				iter[1] = plugin_name
				iter[2] = key
			}
		}
	end

	#=== [x]ボタンクリック持のイベントハンドラ
	#
	#[x]ボタンクリック時にキャンセルボタンのハンドラを呼び出し、キャンセルボタンと同じ動作を実現する。
	#
	#widget:: オプションダイアログのWidget
	#arg0:: 未使用
	#復帰値:: なし
	#
	def on_optiondialog_delete_event(widget, arg0)
 	   on_cancelbutton_clicked(widget)
	end

	#=== [キャンセル]ボタンクリック時のイベントハンドラ
	#
	#[キャンセル]ボタンクリック時にオプションダイアログを閉じる。
	#
	#widget:: キャンセルボタンのWidget
	#復帰値:: なし
	#
	def on_cancelbutton_clicked(widget)
		@glade["optiondialog"].hide
	end

	#=== [OK]ボタンクリック時のイベントハンドラ
	#
	#[OK]ボタンクリック時にオプション情報を保存してからダイアログを閉じる。
	#
	#widget:: OKボタンのWidget
	#復帰値:: なし
	#
	def on_okbutton_clicked(widget)
		# check input value
		begin
			if @glade["entry_term"].text.strip.empty?
				@glade["notebook_option"].page = 1; raise MSG_WARN_NOTERMINAL
			end
			if @glade["entry_log_dir"].text.strip.empty?
				@glade["notebook_option"].page = 2; raise MSG_WARN_NOLOGDIR
			end

		rescue
			# 警告メッセージを表示する
			dlg = Gtk::MessageDialog.new(@glade["optiondialog"], Gtk::Dialog::MODAL,
					Gtk::MessageDialog::WARNING, Gtk::MessageDialog::BUTTONS_OK, $!.to_s)
			dlg.run
			dlg.destroy
			return
		end

		gconf = GConf::Client.default
		###############
		# Network tab
		###############
		# DNS Server
		servers = Array.new
		@glade["treeview_dns"].model.each {|model, path, iter| servers.push(iter.get_value(0)) }
		@options[CONF_KEY_DNS_SERVERS] = servers.join(",")

		# Proxy Server
		# Update environment variables
		@options[CONF_KEY_HTTP_PROXY] = @glade["entry_proxy_http"].text.strip
		@options[CONF_KEY_FTP_PROXY] = @glade["entry_proxy_ftp"].text.strip
		@options[CONF_KEY_USE_PROXY] = @glade["checkbutton_proxy"].active?

		###############
		# install tab
		###############
		# terminal setting
		@options[CONF_KEY_INSTALL_TERM] = @glade["entry_term"].text.strip

		###############
		# log tab
		###############
		# log setting
		RTUtility.set_logger(@glade["entry_log_dir"].text.strip, @glade["combobox_log_level"].active)

		###############
		# save tab
		###############
		# save function
		iter = @glade["treeview_save_function"].model.iter_first
		if iter
			begin
				# 非表示の第3カラムにオプションのキー名が格納してある
				@options[iter[2]] = iter[0]
			end while iter.next!
		end

		apply_option

		@options.each{|key,value| gconf[key] = value }

		@glade["optiondialog"].hide
	end


	#=== [追加]ボタンクリック時のイベントハンドラ
	#
	#指定のDNSサーバをリストに追加する。
	#
	#widget:: [追加]チェックボックスのWidget
	#復帰値:: なし
	#
	def on_button_add_clicked(widget)
		return if @glade["entry_dns"].text.strip.empty?
		RTUtility.add_list(@glade["treeview_dns"], [@glade["entry_dns"].text.strip])
	end

	#
	# Event Handler: [Convert] button click event
	#
	def on_button_update_clicked(widget)
#		@glade["treeview_dns"].selection.selected.set_value(@glade["entry_dns"].text.strip)
		if @glade["treeview_dns"].selection.selected
			@glade["treeview_dns"].selection.selected[0] = @glade["entry_dns"].text.strip
		end
	end

	#=== [削除]ボタンクリック時のイベントハンドラ
	#
	#リストで選択中のDNSサーバをリストから削除する。
	#
	#widget:: [削除]チェックボックスのWidget
	#復帰値:: なし
	#
	def on_button_del_clicked(widget)
		RTUtility.del_list(@glade["treeview_dns"])
	end

	#=== [プロキシサーバを使用する]チェックボックスクリック時のイベントハンドラ
	#
	#チェックボックスがチェック状態にときにプロキシサーバ入力域を活生化し、未チェック持
	#に非活性化する。
	#
	#widget:: [プロキシサーバを使用する]チェックボックスのWidget
	#復帰値:: なし
	#
	def on_checkbutton_proxy_button_press_event(widget)
		@glade["table_proxy"].sensitive = widget.active?
	end

	#=== [kpackagepを起動]ボタンクリック時のイベントハンドラ
	#
	#kpackageコマンドをバックグラウンドジョブとして起動する
	#
	#widget:: [kpackagepを起動]ボタンのWidget
	#復帰値:: なし
	#
	def on_button_option_kpkg_clicked(widget)
		fork { exec(CMD_KPACKAGE) }
	end

	#=== [参照]（ターミナルコマンド）ボタンクリック時のイベントハンドラ
	#
	#[参照]（ターミナルコマンド）クリック時にファイル選択ダイアログを起動してターミナル
	#コマンドを選択する。
	#
	#widget:: [参照]（ターミナルコマンド）ボタンのWidget
	#復帰値:: なし
	#
	def on_button_term_browse_clicked(widget)
		# ファイル選択ダイアログの作成
		dialog = Gtk::FileChooserDialog.new(TITLE_DIALOG_SELECT_TERM,
							@glade["optiondialog"],
							Gtk::FileChooser::ACTION_OPEN,
							nil,
							[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
							[Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_OK])
		dialog.current_folder = "/usr/bin"
		if dialog.run == Gtk::Dialog::RESPONSE_OK
			# [OK]ボタンで終了した場合、ターミナルコマンドを入力域に設定する。
			@glade["entry_term"].text = dialog.filename
		end
		dialog.destroy
	end

	#=== [参照]（ログ出力先）ボタンクリック時のイベントハンドラ
	#
	#[参照]（ログ出力先）クリック時にファイル選択ダイアログを起動してログ出力先
	#ディレクトリを選択する。
	#
	#widget:: [参照]（ログ出力先）ボタンのWidget
	#復帰値:: なし
	#
	def on_button_logdir_browse_clicked(widget)
		# ファイル選択ダイアログの作成
		dialog = Gtk::FileChooserDialog.new(TITLE_DIALOG_SELECT_LOGDIR,
							@glade["optiondialog"],
							Gtk::FileChooser::ACTION_SELECT_FOLDER,
							nil,
							[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
							[Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_OK])
		dialog.current_folder = "/var/log"
		if dialog.run == Gtk::Dialog::RESPONSE_OK
			# [OK]ボタンで終了した場合、ログディレクトリを入力域に設定する。
			@glade["entry_log_dir"].text = dialog.filename
		end
		dialog.destroy
	end

end

# Main program
if __FILE__ == $0

	#===リマスタリングツールのオプション解析
	#
	#リマスタリングツールのオプション解析を行う。
	#
	#復帰値:: OSイメージファイルとエミュレータソフトを格納した配列( [os_image, emulator] )
	#
	def parse_option
		procedure_file = ""
	
		# オプション解析準備
		opt = OptionParser.new
		opt.version = PROG_VERSION
		opt.program_name = PROG_HELP_NAME
		opt.summary_width = 15
		opt.banner = "Usage: " + $0 + " [options] [remaster_file]"
		opt.on("-v", ": print version") {|v| puts opt.ver; exit 0 }
		opt.on("-h", ": print this help") {|v| puts opt.help; puts "    remaster_file   : read the remaster_file to the remastering procedure file"; exit 0 }

		# オプション解析
		begin
			opt.permute!(ARGV)
		rescue
			# オプションエラー
			puts $!.to_s
			exit 1
		end

		# リマスタリング手順ファイル名の取り出し
		procedure_file = ARGV.shift if ARGV.size > 0
		procedure_file
	end

	MSG_ERR_NO_ROOT = _("Please execute as root user")

	#===実行ユーザのチェック
	#
	#リマスタリングツールを起動したユーザがrootかチェックする。
	#root以外が起動した場合、メッセージを表示後終了する。
	#
	#復帰値:: なし
	#
	def check_user
		if Process.uid != 0
			puts MSG_ERR_NO_ROOT
			exit 1
		end
	end

	#===メイン処理
	#
	#仮想マシンテストツールのメイン処理
	#
	#復帰値:: 0=正常終了、1=異常終了
	#

	# root user check
	check_user

	# オプション解析
	procedure_file = parse_option

	Gtk.init

	begin
		tool = Remastertool.new procedure_file
	rescue
		puts $!.to_s
		exit 1
	end

	Gtk.main
	exit!
end
