diff --git a/core/plugin/extract/extract.rb b/core/plugin/extract/extract.rb
index 788bb515..44c37b3e 100644
--- a/core/plugin/extract/extract.rb
+++ b/core/plugin/extract/extract.rb
@@ -91,9 +91,11 @@ def extract_tabs
                                    true } })))
     Plugin.create :extract do
       add_tab_observer = on_extract_tab_create(&tablist.method(:add_record))
+      update_tab_observer = on_extract_tab_update(&tablist.method(:update_record))
       delete_tab_observer = on_extract_tab_delete(&tablist.method(:remove_record))
       tablist.ssc(:destroy) do
         detach add_tab_observer
+        detach update_tab_observer
         detach delete_tab_observer end end
   end
 
diff --git a/core/plugin/extract/extract_tab_list.rb b/core/plugin/extract/extract_tab_list.rb
index 88d6ef38..de611242 100644
--- a/core/plugin/extract/extract_tab_list.rb
+++ b/core/plugin/extract/extract_tab_list.rb
@@ -7,35 +7,74 @@ module Plugin::Extract
 =end
 
 class Plugin::Extract::ExtractTabList < ::Gtk::TreeView
-  ITER_NAME = 0
-  ITER_ID   = 1
+  ICON_SIZE = 16
+
+  COL_ICON  = 0
+  COL_NAME  = 1
+  COL_ID    = 2
+  COL_SOUND = 3
+  COL_POPUP = 4
 
   def initialize(plugin)
     type_strict plugin => Plugin
     @plugin = plugin
-    super(Gtk::ListStore.new(String, Numeric))
-
-    append_column Gtk::TreeViewColumn.new(plugin._("名前"), Gtk::CellRendererText.new, text: ITER_NAME)
-
-    extract_tabs.each(&method(:add_record)) end
+    super(Gtk::ListStore.new(
+      GdkPixbuf::Pixbuf, # icon
+      String,            # name
+      Numeric,           # id
+      GdkPixbuf::Pixbuf, # sound
+      GdkPixbuf::Pixbuf  # popup
+    ))
+
+    append_column Gtk::TreeViewColumn.new(
+      '',
+      Gtk::CellRendererPixbuf.new,
+      pixbuf: COL_ICON
+    )
+    append_column Gtk::TreeViewColumn.new(
+      plugin._('名前'),
+      Gtk::CellRendererText.new,
+      text: COL_NAME
+    ).tap { |col| col.expand = true }
+    append_column Gtk::TreeViewColumn.new(
+      '',
+      Gtk::CellRendererPixbuf.new,
+      pixbuf: COL_SOUND
+    )
+    append_column Gtk::TreeViewColumn.new(
+      '',
+      Gtk::CellRendererPixbuf.new,
+      pixbuf: COL_POPUP
+    )
+
+    extract_tabs.each(&method(:add_record))
+    register_signal_handlers
+  end
 
   # 現在選択されている抽出タブのIDを返す
   # ==== Return
   # 選択されている項目のID。何も選択されていない場合はnil
   def selected_id
     selected_iter = selection.selected
-    selected_iter[ITER_ID] if selected_iter end
+    selected_iter[COL_ID] if selected_iter end
 
   # レコードを追加する
   # ==== Args
   # [record] 追加するレコード(Hash)
-  # ==== Return
-  # self
   def add_record(record)
     iter = model.append
-    iter[Plugin::Extract::ExtractTabList::ITER_NAME] = record[:name]
-    iter[Plugin::Extract::ExtractTabList::ITER_ID] = record[:id]
-    self end
+    setup_iter iter, record
+  end
+
+  # レコードをもとにリストビューを更新する
+  # ==== Args
+  # [record] 更新されたレコード(Hash)
+  def update_record(record)
+    update_iter = model.to_enum
+                       .map { |_, _, iter| iter }
+                       .find { |iter| iter[COL_ID] == record[:id] }
+    setup_iter update_iter, record if update_iter
+  end
 
   # 抽出タブをリストから削除する
   # ==== Args
@@ -43,12 +82,24 @@ def add_record(record)
   # ==== Return
   # self
   def remove_record(record_id)
-    remove_iter = model.to_enum(:each).map{|_,_,iter|iter}.find{|iter| record_id == iter[ITER_ID] }
+    remove_iter = model.to_enum(:each).map{|_,_,iter|iter}.find{|iter| record_id == iter[COL_ID] }
     model.remove(remove_iter) if remove_iter
     self end
 
   private
 
+  def register_signal_handlers
+    # 項目をダブルクリックして設定を開く
+    ssc(:button_press_event) do |_, ev|
+      next if ev.event_type != Gdk::Event::BUTTON2_PRESS
+      id = selected_id
+      if id
+        Plugin.call(:extract_open_edit_dialog, id)
+        true
+      end
+    end
+  end
+
 # ==== utility
 
   # レコードの配列を返す
@@ -57,19 +108,53 @@ def remove_record(record_id)
   def extract_tabs
     UserConfig[:extract_tabs] || [] end
 
+  # イテレータにレコードの内容をコピーする
+  # ==== Args
+  # [iter] TreeIter
+  # [record] 参照するレコード (Hash)
+  def setup_iter(iter, record)
+    size = { width: ICON_SIZE, height: ICON_SIZE }
+    set_icon = lambda { |col, photo|
+      iter[col] = photo.load_pixbuf(**size) do |pb|
+        iter[col] = pb unless destroyed?
+      end
+    }
+
+    iter[COL_NAME] = record[:name]
+    iter[COL_ID] = record[:id]
+    if record[:icon]
+      photo = Enumerator.new do |y|
+        Plugin.filtering :photo_filter, record[:icon], y
+      end.first
+      set_icon.call COL_ICON, photo
+    end
+    if record[:sound].to_s.empty?
+      # FIXME: 適当なアイコンを標準スキンに入れる
+      set_icon.call COL_SOUND, Skin['speaker-x.png']
+    else
+      set_icon.call COL_SOUND, Skin['speaker-l.png']
+    end
+    if record[:popup]
+      # FIXME: 適当なアイコンを標準スキンに入れる
+      set_icon.call COL_POPUP, Skin['popup.png']
+    else
+      set_icon.call COL_POPUP, Skin['no-popup.png']
+    end
+  end
+
   # def on_created(iter)
   #   Plugin.call(:extract_tab_create,
-  #               name: iter[ITER_NAME],
+  #               name: iter[COL_NAME],
   #               sexp: iter[ITER_SEXP],
   #               sources: iter[ITER_SOURCE],
-  #               id: iter[ITER_ID] = gen_uniq_id) end
+  #               id: iter[COL_ID] = gen_uniq_id) end
 
   # def on_updated(iter)
   #   Plugin.call(:extract_tab_update,
-  #               name: iter[ITER_NAME],
+  #               name: iter[COL_NAME],
   #               sexp: iter[ITER_SEXP],
   #               sources: iter[ITER_SOURCE],
-  #               id: iter[ITER_ID]) end
+  #               id: iter[COL_ID]) end
 
   def gen_uniq_id(uniq_id = Time.now.to_i)
     if extract_tabs.any?{ |x| x[:id] == uniq_id }
