OSDN Git Service

change skill2 table to wx.Grid and implement auto column size of Grid
[amulettoolsmh4/main.git] / amulettool.py
index d145fa3..b95ae2c 100644 (file)
@@ -1,3 +1,4 @@
+#!/usr/bin/python
 # -*- coding: utf-8 -*-
 
 # お守りスキルのSeed特定ツールのコントロールクラス
@@ -6,23 +7,49 @@
 import threading
 import time
 import os.path
+import sys
+import pickle
+import sqlite3
 
 import wx
 
 import view
 import model
+import convertcoding
+
+SETTING_FILE = u"settings"
+SETTING_THRESHOLD1 = u"threshold1"
+SETTING_THRESHOLD2 = u"threshold2"
+SETTING_SKILLS = u"skills"
+
+def _get_base_dir():
+    u""" for pyinstaller 2.1 """
+    if getattr(sys, 'frozen', False):
+        # we are running in a |PyInstaller| bundle
+        basedir = sys._MEIPASS
+    else:
+        # we are running in a normal Python environment
+        #1basedir = os.path.dirname(__file__)
+        basedir = os.path.dirname(os.path.abspath(__file__))
+    return convertcoding.convert_unicode(basedir)
 
 
 class AmuletToolController(wx.App):
     u""" アプリケーションの制御クラス """
     def OnInit(self):
-        self.frame_view = view.MainFrameView("view")
-        
+        self._read_settings()
+        self.frame_view = view.MainFrameView(os.path.join(_get_base_dir(), u"view", view.XRC_MAIN_FRAME))
+
         self._init_events()
 
         self.frame_view.Show()
 
+        self.frame_view.DisableNoteBook()
+
         self._init_database()
+        self._set_views()
+
+        self.frame_view.EnableNoteBook()
         return True
 
     def _init_events(self):
@@ -32,6 +59,28 @@ class AmuletToolController(wx.App):
         # menu event
         frame.Bind(wx.EVT_MENU, self.OnClose, id=self.frame_view.ID_MENU_ITEM_EXIT)
         frame.Bind(wx.EVT_MENU, self.OnAboutBox, id=self.frame_view.ID_MENU_ITEM_ABOUT)
+        frame.Bind(wx.EVT_CLOSE, self.CloseHandler)
+
+        # button event
+        frame.Bind(wx.EVT_BUTTON, self.OnClickSeedSearch, id=self.frame_view.ID_BUTTON_SEED_SEARCH)
+        frame.Bind(wx.EVT_BUTTON, self.OnClickSeedClear, id=self.frame_view.ID_BUTTON_SEED_CLEAR)
+        frame.Bind(wx.EVT_BUTTON, self.OnClickSkillSearchFromSeed, id=self.frame_view.ID_BUTTON_SKILL_FROM_SEED_SEARCH)
+        frame.Bind(wx.EVT_BUTTON, self.OnClickSkillSearch, id=self.frame_view.ID_BUTTON_SKILL_SEARCH)
+        frame.Bind(wx.EVT_BUTTON, self.OnClickSkillClear, id=self.frame_view.ID_BUTTON_SKILL_CLEAR)
+        frame.Bind(wx.EVT_BUTTON, self.OnClickAmuletSearch, id=self.frame_view.ID_BUTTON_AMULET_SEARCH_SEARCH)
+        frame.Bind(wx.EVT_BUTTON, self.OnClickAmuletClear, id=self.frame_view.ID_BUTTON_AMULET_SEARCH_CLEAR)
+        frame.Bind(wx.EVT_BUTTON, self.OnClickSkillSearchFromAmulet, id=self.frame_view.ID_BUTTON_AMULET_SEARCH_SKILL)
+        frame.Bind(wx.EVT_BUTTON, self.OnClickSettingOK, id=self.frame_view.ID_BUTTON_SETTING_OK)
+        frame.Bind(wx.EVT_BUTTON, self.OnClickSettingClear, id=self.frame_view.ID_BUTTON_SETTING_CLEAR)
+
+        # radio button event
+        frame.Bind(wx.EVT_RADIOBUTTON, self.OnClickAmuletRadio, id=self.frame_view.ID_RADIO_BUTTON_AMULET1)
+        frame.Bind(wx.EVT_RADIOBUTTON, self.OnClickAmuletRadio, id=self.frame_view.ID_RADIO_BUTTON_AMULET2)
+        frame.Bind(wx.EVT_RADIOBUTTON, self.OnClickAmuletRadio, id=self.frame_view.ID_RADIO_BUTTON_AMULET3)
+
+        # combo box event
+        frame.Bind(wx.EVT_COMBOBOX, self.OnClickAmuletCombo, id=self.frame_view.ID_COMBO_BOX_AMULET_SEARCH_SKILL1)
+        frame.Bind(wx.EVT_COMBOBOX, self.OnClickAmuletCombo, id=self.frame_view.ID_COMBO_BOX_AMULET_SEARCH_SKILL2)
 
     def _init_database(self):
         u""" DBの初期設定 """
@@ -39,32 +88,365 @@ class AmuletToolController(wx.App):
         if not os.path.exists(model.DB_FILE_NAME):
             u""" DBが存在しない時は再生成する """
             frame = self.frame_view.frame
-            generator = model.DataBaseGenerator(model.DB_FILE_NAME)
-            #generator = model.DataBaseGenerator()
-
-            dlg_view = view.GaugeDialogView("view")
-            def _loop():
-                while t1.is_alive():
-                    dlg_view.gauge.Pulse()
-                    time.sleep(0.2)
-                dlg_view.finish_generation()
-
-            t1 = threading.Thread(target=generator.generate_db)
-            t2 = threading.Thread(target=_loop)
-            t1.start()
-            t2.start()
-
-            dlg_view.ShowModal()
-            t1.join()
-            t2.join()
-            dlg_view.Destroy()
+            try:
+                generator = model.DataBaseGenerator(model.DB_FILE_NAME)
+                #generator = model.DataBaseGenerator()
+
+                dlg_view = view.GaugeDialogView(os.path.join(_get_base_dir(), u"view", view.XRC_GAUGE_DIALOG))
+                def _loop():
+                    while t1.is_alive():
+                        dlg_view.gauge.Pulse()
+                        time.sleep(0.2)
+                    dlg_view.finish_generation()
+
+                t1 = threading.Thread(target=generator.generate_db)
+                t2 = threading.Thread(target=_loop)
+                t1.start()
+                t2.start()
+
+                dlg_view.ShowModal()
+                t1.join()
+                t2.join()
+                dlg_view.Destroy()
+            except sqlite3.Error as e:
+                self._show_error_dialog(u"データベース生成中にエラーが発生しました")
 
         # access to db
-        db_accessor = model.DataBaseAccessor(model.DB_FILE_NAME)
+        try:
+            self.db_accessor = model.DataBaseAccessor(model.DB_FILE_NAME)
+        except sqlite3.Error as e:
+            self._show_error_dialog(u"データベースが壊れています")
+
+        # get dictionaries
+        (self._skill_id2name_dict, 
+            self._skill_name2id_dict,
+            self._amulet_id2name_dict, 
+            self._amulet_name2id_dict,
+            self._amulet_id2skill1_id_dict,
+            self._amulet_id2skill2_id_dict) = self.db_accessor.get_dicts()
+
+
+    def _set_views(self):
+        u""" GUIにDBの各種値をセットする """
+        self._set_combo_views()
+        self._set_spin_views()
+        self._set_check_list_views()
+
+    def _set_combo_views(self):
+        u""" ComboBoxの値をセットする """
+        combo_dict = self.frame_view.combo_box_skill_dict
+
+        u" 各種お守りの第2スキル選択 "
+        for amu_key, amu_name in zip([view.KEY_AMULET1, view.KEY_AMULET2, view.KEY_AMULET3], 
+                [view.NAME_AMULET1, view.NAME_AMULET2, view.NAME_AMULET3]):
+            amu_id = self._amulet_name2id_dict[amu_name]
+            skill_ids = self._amulet_id2skill2_id_dict[amu_id]
+            skill_names = [view.VAL_NO_SKILL] + [self._skill_id2name_dict[x] for x in skill_ids]
+            for combo in combo_dict[amu_key]:
+               combo.SetItems(skill_names)
+               combo.SetSelection(0)
+
+        # amulet search
+        amu_id = self._amulet_name2id_dict[view.NAME_AMULET1]
+        self._set_skill_list_from_amulet(amu_id)
+        self.frame_view.amulet2radio_button_dict[view.NAME_AMULET1].SetValue(True)
+
+    def _set_skill_list_from_amulet(self, amulet_id):
+        u""" お守り種類の選択が変わった時の動作 """
+
+        for i, (combo, skill_dict) in enumerate(zip(
+                [self.frame_view.combo_box_amulet_search_skill1, 
+                    self.frame_view.combo_box_amulet_search_skill2], 
+                [self._amulet_id2skill1_id_dict, self._amulet_id2skill2_id_dict]
+                )):
+            skill_ids = skill_dict[amulet_id]
+            skill_names = [self._skill_id2name_dict[_id] for _id in skill_ids]
+            if i == 0:
+                combo.SetItems(skill_names)
+                skill1_selected = skill_ids[0]
+            elif i == 1:
+                combo.SetItems([view.VAL_NO_SKILL] + skill_names)
+            else:
+                raise NotImplementedError(u"this iteration must be conducted only twice!")
+            combo.SetSelection(0)   # combo1 = skill1, combo2 = No Skill
+        self._set_spin_range(amulet_id, skill1_selected, None)
+
+    def _set_spin_views(self):
+        u""" Spin Ctrlの最大最小をセット"""
+        min1, max1, min2, max2 = self.db_accessor.get_skill_minmax()
+        self.frame_view.spin_ctrl_amulet_search_slot_num.SetRange(view.SLOT_MIN, view.SLOT_MAX)
+        self.frame_view.spin_ctrl_highlight1.SetRange(view.THRESHOLD1_MIN, view.THRESHOLD1_MAX)
+        self.frame_view.spin_ctrl_highlight2.SetRange(view.THRESHOLD2_MIN, view.THRESHOLD2_MAX)
+        self.frame_view.spin_ctrl_highlight1.SetValue(self._highlight_threshold1)
+        self.frame_view.spin_ctrl_highlight2.SetValue(self._highlight_threshold2)
+
+    def _set_check_list_views(self):
+        u""" CheckListBoxの値のセット """
+        checklist = self.frame_view.check_list_box_highlight_skill
+        checklist.SetItems(self._skill_name2id_dict.keys())
+        checklist.SetCheckedStrings([self._skill_id2name_dict[x] for x in self._highlight_skills])
+
+    def _set_spin_range(self, amulet_id, skill1_id, skill2_id):
+        u""" スキルに応じてSpinCtrlの最大最小をセットする """
+        if skill2_id is None:
+            minmax_dict = self.db_accessor.select_minmax_from_skill_ids(amulet_id, [skill1_id])
+            min1, max1 = minmax_dict[skill1_id][0], minmax_dict[skill1_id][1]
+            min2, max2 = 0, 0
+        else:
+            minmax_dict = self.db_accessor.select_minmax_from_skill_ids(amulet_id, [skill1_id, skill2_id])
+            min1, max1 = minmax_dict[skill1_id][0], minmax_dict[skill1_id][1]
+            min2, max2 = minmax_dict[skill2_id][2], minmax_dict[skill2_id][3]
+        self.frame_view.spin_ctrl_amulet_search_skill1_val.SetRange(min1, max1)
+        self.frame_view.spin_ctrl_amulet_search_skill2_val.SetRange(min2, max2)
 
+    def OnClickSeedSearch(self, evt):
+        u""" search seeds from selected skills """
+        amu_id2skill_id_list_dict = {}
+        for amu_key, amu_name in zip([view.KEY_AMULET1, view.KEY_AMULET2, view.KEY_AMULET3], 
+                [view.NAME_AMULET1, view.NAME_AMULET2, view.NAME_AMULET3]):
+            amu_id = self._amulet_name2id_dict[amu_name]
+            ls = []
+            for combo in self.frame_view.combo_box_skill_dict[amu_key]:
+                name = combo.GetStringSelection()
+                if name not in self._skill_name2id_dict:
+                    ls.append(None)
+                else:
+                    ls.append(self._skill_name2id_dict[name])
+            amu_id2skill_id_list_dict[amu_id] = ls
+        seed_sets = self.db_accessor.select_seeds(amu_id2skill_id_list_dict)
+        self.frame_view.text_ctrl_seed_result.SetValue(u"""Seedの候補は{0}個です。""".format(len(seed_sets)))
 
+        if len(seed_sets) > 0:
+            self.frame_view.list_box_seed.SetItems([u"{0}".format(seed) for seed in seed_sets])
+            self.frame_view.list_box_seed.SetSelection(0)
+            self.frame_view.button_skill_from_seed_search.Enable()
+        else:
+            self.frame_view.list_box_seed.Clear()
 
 
+    def OnClickSeedClear(self, evt):
+        u""" reset seed search settings of combo box"""
+        combo_dict = self.frame_view.combo_box_skill_dict
+        for amu_key in [view.KEY_AMULET1, view.KEY_AMULET2, view.KEY_AMULET3]:
+            for combo in combo_dict[amu_key]:
+                combo.SetSelection(0)
+        self.frame_view.text_ctrl_seed_result.SetValue(u"")
+        self.frame_view.button_skill_from_seed_search.Disable()
+        self.frame_view.list_box_seed.Clear()
+
+    def OnClickSkillSearchFromSeed(self, evt):
+        u""" change page to skill search from seed"""
+        seed = self.frame_view.list_box_seed.GetStringSelection()
+        if seed.isdigit():
+            self.frame_view.text_ctrl_seed_select.SetValue(seed)
+            self.frame_view.note_book.SetSelection(view.SKILL_SEARCH_PAGE)
+            self.OnClickSkillSearch(evt)
+
+    def OnClickSkillSearch(self, evt):
+        u""" skill search from seed"""
+        seed = self.frame_view.text_ctrl_seed_select.GetValue()
+        if seed.isdigit():
+            seed = int(seed)
+            skill_dict, threshold1_dict = self.db_accessor.select_skills_from_seeds([seed])
+            grid = self.frame_view.skill2_grid
+            try:
+                for amu_key, amu_name in zip([view.KEY_AMULET1, view.KEY_AMULET2, view.KEY_AMULET3], 
+                    [view.NAME_AMULET1, view.NAME_AMULET2, view.NAME_AMULET3]):
+                    amu_id = self._amulet_name2id_dict[amu_name]
+                    amu_col = view.DICT_SKILL2_GRID_COL[amu_key]
+                    for row, skill_id in enumerate(skill_dict[amu_id][seed]):
+                        grid.SetCellValue(row, amu_col, self._skill_id2name_dict[skill_id])
+                th1_col = view.DICT_SKILL2_GRID_COL[view.KEY_THRESHOLD1]
+                for row, threshold1 in enumerate(threshold1_dict[seed]):
+                    grid.SetCellValue(row, th1_col, u"{0}".format(threshold1))
+                self._update_highlight()
+
+            except KeyError, e:
+                self._show_message_dialog(message=u"指定されたSeed値は存在しません")
+        else:
+            self._show_message_dialog(message=u"Seed値には数字を入力してください")
+
+    def OnClickSkillClear(self, evt):
+        u""" clear skills from seed """
+
+        grid = self.frame_view.skill2_grid
+        for row in range(view.NUM_SKILL2_GRID_ROW):
+            for col in range(view.NUM_SKILL2_GRID_COL):
+                grid.SetCellValue(row, col, "")
+        self.frame_view.list_box_seed_skill_amulet_prospect.Clear() 
+        self._update_highlight()
+
+    def OnClickAmuletRadio(self, evt):
+        u""" switch skill lists by amulet id """
+        btn_id = evt.GetId()
+        if btn_id == self.frame_view.ID_RADIO_BUTTON_AMULET1:
+            amu_id = self._amulet_name2id_dict[view.NAME_AMULET1]
+        elif btn_id == self.frame_view.ID_RADIO_BUTTON_AMULET2:
+            amu_id = self._amulet_name2id_dict[view.NAME_AMULET2]
+        elif btn_id == self.frame_view.ID_RADIO_BUTTON_AMULET3:
+            amu_id = self._amulet_name2id_dict[view.NAME_AMULET3]
+        else:
+            return
+        self._set_skill_list_from_amulet(amu_id)
+
+    def OnClickAmuletCombo(self, evt):
+        u""" switch skill minmax by amulet id and skill_id"""
+        skill1_name = self.frame_view.combo_box_amulet_search_skill1.GetStringSelection()
+        skill2_name = self.frame_view.combo_box_amulet_search_skill2.GetStringSelection()
+        skill1_id = self._skill_name2id_dict[skill1_name]
+        if skill2_name in self._skill_name2id_dict:
+            skill2_id = self._skill_name2id_dict[skill2_name]
+        else:
+            skill2_id = None
+        if self.frame_view.amulet2radio_button_dict[view.NAME_AMULET1].GetValue():
+            amu_id = self._amulet_name2id_dict[view.NAME_AMULET1]
+        elif self.frame_view.amulet2radio_button_dict[view.NAME_AMULET2].GetValue():
+            amu_id = self._amulet_name2id_dict[view.NAME_AMULET2]
+        elif self.frame_view.amulet2radio_button_dict[view.NAME_AMULET3].GetValue():
+            amu_id = self._amulet_name2id_dict[view.NAME_AMULET3]
+        else:
+            raise IndexError(u"amulet id is unknown")
+        self._set_spin_range(amu_id, skill1_id, skill2_id)
+
+    def OnClickAmuletSearch(self, evt):
+        u""" search seeds from amulet condition """
+        skill1_name = self.frame_view.combo_box_amulet_search_skill1.GetStringSelection()
+        skill2_name = self.frame_view.combo_box_amulet_search_skill2.GetStringSelection()
+        skill1_val = self.frame_view.spin_ctrl_amulet_search_skill1_val.GetValue()
+        skill2_val = self.frame_view.spin_ctrl_amulet_search_skill2_val.GetValue()
+        slot_val = self.frame_view.spin_ctrl_amulet_search_slot_num.GetValue()
+        if self.frame_view.amulet2radio_button_dict[view.NAME_AMULET1].GetValue():
+            amu_id = self._amulet_name2id_dict[view.NAME_AMULET1]
+        elif self.frame_view.amulet2radio_button_dict[view.NAME_AMULET2].GetValue():
+            amu_id = self._amulet_name2id_dict[view.NAME_AMULET2]
+        elif self.frame_view.amulet2radio_button_dict[view.NAME_AMULET3].GetValue():
+            amu_id = self._amulet_name2id_dict[view.NAME_AMULET3]
+        else:
+            raise IndexError(u"amulet id is unknown")
+
+        list_box = self.frame_view.list_box_amulet_search_seeds
+        if skill1_name == skill2_name:
+            self._show_message_dialog(message=u"異なるスキルを選択してください")
+        elif skill1_val == 0:
+            self._show_message_dialog(message=u"第1スキルの値には0以外を指定してください")
+        else:
+            skill1_id = self._skill_name2id_dict[skill1_name]
+            if skill2_name in self._skill_name2id_dict:
+                skill2_id = self._skill_name2id_dict[skill2_name]
+            else:
+                skill2_id = None # for skill2 is 0
+            suff_dict = {}
+            tup = self.db_accessor.get_sufficient_value(
+                amu_id, skill1_id, skill2_id, skill1_val, skill2_val)
+            if tup is not None:
+                suff_val = tup[0]
+                seeds_set = self.db_accessor.select_seeds_from_sufficient_val(amu_id, suff_val, slot_val, skill2_id)
+                if len(seeds_set) > 0:
+                    self.frame_view.text_ctrl_amulet_search_result.SetValue(
+                        u"{0}個のSeedで出現するお守りです".format(len(seeds_set)))
+                    list_box.SetItems([u"{0}".format(seed) for seed in seeds_set])
+                    list_box.SetSelection(0)
+                    self.frame_view.button_amulet_search_skill.Enable()
+                else:
+                    self.frame_view.text_ctrl_amulet_search_result.SetValue(
+                        u"指定されたお守りは見つかりませんでした")
+                    self.frame_view.button_amulet_search_skill.Disable()
+                    list_box.Clear()
+            else:
+                self.frame_view.text_ctrl_amulet_search_result.SetValue(
+                    u"エラー。充足値が計算できません")
+                self.frame_view.button_amulet_search_skill.Disable()
+                list_box.Clear()
+
+    def OnClickAmuletClear(self, evt):
+        u""" clear amulet conditions """
+        amu_id = self._amulet_name2id_dict[view.NAME_AMULET1]
+        self._set_skill_list_from_amulet(amu_id)
+        self.frame_view.amulet2radio_button_dict[view.NAME_AMULET1].SetValue(True)
+        self.frame_view.button_amulet_search_skill.Disable()
+        self.frame_view.text_ctrl_amulet_search_result.SetValue(u"")
+        self.frame_view.list_box_amulet_search_seeds.Clear()
+
+    def OnClickSkillSearchFromAmulet(self, evt):
+        u""" change page to skill search from amulet"""
+        seed = self.frame_view.list_box_amulet_search_seeds.GetStringSelection()
+        if seed.isdigit():
+            self.frame_view.text_ctrl_seed_select.SetValue(seed)
+            self.frame_view.note_book.SetSelection(view.SKILL_SEARCH_PAGE)
+            self.OnClickSkillSearch(evt)
+
+    def OnClickSettingOK(self, evt):
+        u""" get settings of setting tab """
+        self._highlight_threshold1 = self.frame_view.spin_ctrl_highlight1.GetValue()
+        self._highlight_threshold2 = self.frame_view.spin_ctrl_highlight2.GetValue()
+        self._highlight_skills = set([self._skill_name2id_dict[x] for x in 
+                self.frame_view.check_list_box_highlight_skill.GetCheckedStrings()
+                if x in self._skill_name2id_dict])
+        self._update_highlight()
+
+    def OnClickSettingClear(self, evt):
+        u""" reset settings of setting tab """
+        self._highlight_threshold1 = view.HIGHLIGHT_THRESHOLD1
+        self._highlight_threshold2 = view.HIGHLIGHT_THRESHOLD2
+        self.frame_view.spin_ctrl_highlight1.SetValue(view.HIGHLIGHT_THRESHOLD1)
+        self.frame_view.spin_ctrl_highlight2.SetValue(view.HIGHLIGHT_THRESHOLD2)
+        self._highlight_skills = set()
+        for idx in self.frame_view.check_list_box_highlight_skill.GetChecked():
+            self.frame_view.check_list_box_highlight_skill.Check(idx, False)
+        self._update_highlight()
+
+    def _update_highlight(self):
+        u""" update highlight cells """
+        grid = self.frame_view.skill2_grid
+        for key in [view.KEY_AMULET1, view.KEY_AMULET2, view.KEY_AMULET3]:
+            col = view.DICT_SKILL2_GRID_COL[key]
+            for row in range(view.NUM_SKILL2_GRID_ROW):
+                val = grid.GetCellValue(row, col)
+                if (val in self._skill_name2id_dict and
+                        self._skill_name2id_dict[val] in self._highlight_skills):
+                    grid.SetCellBackgroundColour(row, col, "Yellow")
+                else:
+                    grid.SetCellBackgroundColour(row, col, wx.NullColor)
+        col = view.DICT_SKILL2_GRID_COL[view.KEY_THRESHOLD1]
+        for row in range(view.NUM_SKILL2_GRID_ROW):
+            val = grid.GetCellValue(row, col)
+            if val.isdigit() and int(val) >= self._highlight_threshold1:
+                grid.SetCellBackgroundColour(row, col, "Yellow")
+            else:
+                grid.SetCellBackgroundColour(row, col, wx.NullColor)
+
+
+    def _show_error_dialog(self, message=u"予期せぬエラーが発生しました", caption=u"エラー"):
+        u""" エラーダイアログを表示し、
+        OKボタンが押されたらアプリケーションを終了する
+        """
+        dlg = wx.MessageDialog(self.frame_view.frame, 
+            message,
+            caption, wx.OK | wx.ICON_ERROR)
+        dlg.ShowModal()
+        dlg.Destroy()
+        wx.Exit()
+    
+    def _show_message_dialog(self, message, caption=u"メッセージ"):
+        u""" メッセージダイアログを表示する
+        """
+        dlg = wx.MessageDialog(self.frame_view.frame, 
+            message,
+            caption, wx.OK | wx.ICON_INFORMATION)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    def CloseHandler(self, evt):
+        dlg = wx.MessageDialog(parent = self.frame_view.frame,
+                message = u"終了します。よろしいですか?", 
+                caption = u"終了確認", 
+                style = wx.YES_NO)
+        result = dlg.ShowModal()
+        dlg.Destroy()
+        if result == wx.ID_YES:
+            self._write_settings()
+            wx.Exit()
+
     def OnClose(self, evt):
         self.frame_view.Close()
 
@@ -72,6 +454,31 @@ class AmuletToolController(wx.App):
         info = self.frame_view.GetAboutInfo()
         wx.AboutBox(info)
 
+    def _write_settings(self):
+        with open(SETTING_FILE, mode="w") as f:
+            data = {SETTING_THRESHOLD1:self._highlight_threshold1, 
+                    SETTING_THRESHOLD2:self._highlight_threshold2, 
+                    SETTING_SKILLS:self._highlight_skills}
+            pickle.dump(data, f)
+
+    def _read_settings(self):
+        if os.path.exists(SETTING_FILE):
+            with open(SETTING_FILE, mode="r") as f:
+                try:
+                    data = pickle.load(f)
+                    self._highlight_threshold1 = data[SETTING_THRESHOLD1] 
+                    self._highlight_threshold2 = data[SETTING_THRESHOLD2] 
+                    self._highlight_skills = data[SETTING_SKILLS]
+                except EOFError, e:
+                    self._highlight_threshold1 = view.HIGHLIGHT_THRESHOLD1
+                    self._highlight_threshold2 = view.HIGHLIGHT_THRESHOLD2
+                    self._highlight_skills = set()
+        else:
+            self._highlight_threshold1 = view.HIGHLIGHT_THRESHOLD1
+            self._highlight_threshold2 = view.HIGHLIGHT_THRESHOLD2
+            self._highlight_skills = set()
+
 if __name__ == "__main__":
     app = AmuletToolController(False)
     app.MainLoop()
+