OSDN Git Service

Merge branch 'hotfix/singleton_with_db_accessor_generator_problem'
[amulettoolsmh4/main.git] / amulettool.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # お守りスキルのSeed特定ツールのコントロールクラス
5 # 2013/12/04 written by kei9
6
7 import threading
8 import time
9 import os.path
10 import sys
11 import pickle
12 import sqlite3
13
14 import wx
15
16 import view
17 import model
18 import convertcoding
19
20 SETTING_FILE = u"settings"
21 SETTING_THRESHOLD1 = u"threshold1"
22 SETTING_THRESHOLD2 = u"threshold2"
23 SETTING_SKILLS = u"skills"
24
25 def _get_base_dir():
26     u""" for pyinstaller 2.1 """
27     if getattr(sys, 'frozen', False):
28         # we are running in a |PyInstaller| bundle
29         basedir = sys._MEIPASS
30     else:
31         # we are running in a normal Python environment
32         #1basedir = os.path.dirname(__file__)
33         basedir = os.path.dirname(os.path.abspath(__file__))
34     return convertcoding.convert_unicode(basedir)
35
36
37 class AmuletToolController(wx.App):
38     u""" アプリケーションの制御クラス """
39     def OnInit(self):
40         self._read_settings()
41         self.frame_view = view.MainFrameView(os.path.join(_get_base_dir(), u"view", view.XRC_MAIN_FRAME))
42
43         self._init_events()
44
45         self.frame_view.Show()
46
47         self.frame_view.DisableNoteBook()
48
49         self._init_database()
50         self._init_notebook_seed1()
51         self._init_notebook_seed2()
52         self._init_notebook_skill1()
53         self._init_notebook_skill2()
54         self._init_notebook_setting()
55         self._init_notebook_simulator()
56         self._init_notebook_amulet()
57
58         self.frame_view.EnableNoteBook()
59         return True
60
61     def _init_events(self):
62         u"""イベント登録"""
63         frame = self.frame_view.frame
64
65         # menu event
66         frame.Bind(wx.EVT_MENU, self.OnClose, id=self.frame_view.ID_MENU_ITEM_EXIT)
67         frame.Bind(wx.EVT_MENU, self.OnAboutBox, id=self.frame_view.ID_MENU_ITEM_ABOUT)
68         frame.Bind(wx.EVT_MENU, self.OnMemoBox, id=self.frame_view.ID_MENU_MEMO)
69         frame.Bind(wx.EVT_CLOSE, self.CloseHandler)
70
71         # button event
72
73     def _init_database(self):
74         u""" DBの初期設定 """
75
76         if not os.path.exists(model.DB_FILE_NAME):
77             u""" DBが存在しない時は再生成する """
78             frame = self.frame_view.frame
79             try:
80                 generator = model.DataBaseGenerator(model.DB_FILE_NAME)
81                 #generator = model.DataBaseGenerator()
82
83                 dlg_view = view.GaugeDialogView(os.path.join(_get_base_dir(), u"view", view.XRC_GAUGE_DIALOG))
84                 def _loop():
85                     while t1.is_alive():
86                         dlg_view.gauge.Pulse()
87                         time.sleep(0.2)
88                     dlg_view.finish_generation()
89
90                 t1 = threading.Thread(target=generator.generate_db)
91                 t2 = threading.Thread(target=_loop)
92                 t1.start()
93                 t2.start()
94
95                 dlg_view.ShowModal()
96                 t1.join()
97                 t2.join()
98                 dlg_view.Destroy()
99             except sqlite3.Error as e:
100                 self._show_error_dialog(u"データベース生成中にエラーが発生しました")
101
102         # access to db
103         try:
104             self.db_accessor = model.DataBaseAccessor(model.DB_FILE_NAME)
105             #self.db_accessor = model.DataBaseAccessor(u"test.sqlite3")
106         except sqlite3.Error as e:
107             self._show_error_dialog(u"データベースが壊れています")
108
109         self._minmax_dict = self.db_accessor.get_minmax_dict()
110         self._amulet_names = self.db_accessor.get_id_sorted_amulet_names()
111         self._skill_names = self.db_accessor.get_id_sorted_skill_names()
112         #print self._minmax_dict
113
114     def _init_notebook_seed1(self):
115         u""" Seed1特定タブのviewの初期化 """
116         self.notebook_seed1_view = self.frame_view.notebook_seed1_view
117         self.notebook_seed1_view.bind_button_search(self.OnClickSeed1Search)
118         self.notebook_seed1_view.bind_button_clear(self.OnClickSeed1Clear)
119         self.notebook_seed1_view.bind_button_skill1(self.OnClickSkill1SearchFromSeed1)
120         self.notebook_seed1_view.set_skill1_button_enable(False)
121
122         u" 各種お守りの第1スキル選択のセット "
123         name2skill1s = {}
124         for name in self._amulet_names:
125             name2skill1s[name] = tuple([x for x in self._skill_names if x in self._minmax_dict[name][0]])
126         self.notebook_seed1_view.set_amuletname_skillnames_dict(self._amulet_names, name2skill1s)
127
128     def _init_notebook_seed2(self):
129         u""" Seed2特定タブのviewの初期化 """
130         self.notebook_seed2_view = self.frame_view.notebook_seed2_view
131         self.notebook_seed2_view.bind_button_search(self.OnClickSeed2Search)
132         self.notebook_seed2_view.bind_button_clear(self.OnClickSeed2Clear)
133         self.notebook_seed2_view.bind_button_skill2(self.OnClickSkill2SearchFromSeed2)
134
135         u" 各種お守りの第2スキル選択 "
136         for amu_key, amu_name in zip([view.KEY_AMULET1, view.KEY_AMULET2, view.KEY_AMULET3],
137                 [view.NAME_AMULET1, view.NAME_AMULET2, view.NAME_AMULET3]):
138             skill_names = [view.VAL_NO_SKILL] + [x for x in self._skill_names 
139                     if x in self._minmax_dict[amu_name][1]]
140             self.notebook_seed2_view.set_skill_names(amu_key, skill_names)
141         self.notebook_seed2_view.set_skill_selected_idx(0)
142
143     def _init_notebook_skill2(self):
144         u""" Seed2によるSkill2一覧タブのviewの初期化 """
145         self.notebook_skill2_view = self.frame_view.notebook_skill2_view
146         self.notebook_skill2_view.bind_button_search(self.OnClickSkill2Search)
147         self.notebook_skill2_view.bind_button_clear(self.OnClickSkill2Clear)
148
149     def _init_notebook_skill1(self):
150         u""" Seed1によるSkill1一覧タブのviewの初期化 """
151         self.notebook_skill1_view = self.frame_view.notebook_skill1_view
152         self.notebook_skill1_view.bind_button_search(self.OnClickSkill1Search)
153         self.notebook_skill1_view.bind_button_clear(self.OnClickSkill1Clear)
154
155     def _init_notebook_simulator(self):
156         u""" Seed1,Seed2による錬金シミュレータータブのviewの初期化 """
157         self.notebook_simulator_view = self.frame_view.notebook_simulator_view
158         self.notebook_simulator_view.bind_button_search(self.OnClickSimulatorSearch)
159         self.notebook_simulator_view.bind_button_clear(self.OnClickSimulatorClear)
160
161     def _update_notebook_amulet_seed2s(self):
162         u"""お守り検索タブのSeed2リストを更新する"""
163         pass
164
165     def _init_notebook_amulet(self):
166         u""" お守り検索タブの初期設定 """
167         self.notebook_amulet_view = self.frame_view.notebook_amulet_view
168         self.notebook_amulet_view.set_skillminmax_dict(self._skill_names, self._amulet_names, self._minmax_dict)
169         self.notebook_amulet_view.bind_button_search(self.OnClickAmuletSearch)
170         self.notebook_amulet_view.bind_button_clear(self.OnClickAmuletClear)
171         self.notebook_amulet_view.bind_button_simulate(self.OnClickSimulateFromAmulet)
172
173         self.notebook_amulet_view.set_selected_amulet(True, view.NAME_AMULET1)
174
175     def _init_notebook_setting(self):
176         u""" 設定タブの初期設定 """
177         self.notebook_setting_view = self.frame_view.notebook_setting_view
178         self.notebook_setting_view.bind_button_ok(self.OnClickSettingOK)
179         self.notebook_setting_view.bind_button_clear(self.OnClickSettingClear)
180         self.notebook_setting_view.set_skill_strings(self._skill_names)
181         self._update_notebook_setting()
182
183     def _update_notebook_setting(self):
184         u"""設定タブの値更新"""
185         self.notebook_setting_view.set_threshold(self._highlight_threshold1,
186                 self._highlight_threshold2)
187         self.notebook_setting_view.set_checked_strings(self._highlight_skills)
188
189     def _update_highlight(self):
190         u""" update highlight cells """
191         self.notebook_skill2_view.set_skill2_highlight(
192                 self._highlight_skills, self._highlight_threshold1, self._highlight_threshold2)
193         self.notebook_skill1_view.update_highlight(self._highlight_skills)
194
195     u""" Seed1 view's event"""
196     def OnClickSeed1Search(self, evt):
197         u""" search seed1s from selected skill1s """
198         alchemy_type = self.notebook_seed1_view.get_tenun_radio_key()
199         amu_skill_name_list = self.notebook_seed1_view.get_selected_amulets_and_names()
200         if alchemy_type == view.KEY_TENUN555:
201             alchemy_type = model.KEY_TENUN555
202         elif alchemy_type == view.KEY_TENUN888:
203             alchemy_type = model.KEY_TENUN888
204         else:
205             raise KeyError(u"key '{0}' not found in alchemy type".format(alchemy_type))
206         seed1s = self.db_accessor.select_seed1s(amu_skill_name_list, alchemy_type)
207         if len(seed1s) == 0:
208             self.notebook_seed1_view.set_text_result(u"条件に一致するSeed1は見つかりません")
209             self.notebook_seed1_view.set_skill1_button_enable(False)
210         elif len(seed1s) == 1:
211             seed1 = [x for x in seed1s][0]
212             no, table_no, result_num = self.db_accessor.select_table_nos_from_seed1(seed1, alchemy_type)
213             self.notebook_seed1_view.set_text_result_by_seed1(seed1, table_no, no)
214             self.notebook_seed1_view.set_skill1_button_enable(True)
215         else:
216             self.notebook_seed1_view.set_text_result(
217                     u"Seed1は{0}件あります。条件を絞ってください".format(len(seed1s)))
218             self.notebook_seed1_view.set_skill1_button_enable(False)
219
220     def OnClickSeed1Clear(self, evt):
221         u""" clear seed1s from selected skill1s """
222         self.notebook_seed1_view.clear_combobox()
223         self.notebook_seed1_view.clear_text_result()
224
225     def OnClickSkill1SearchFromSeed1(self, evt):
226         u""" change page to skill1 search from seed1"""
227         seed1 = self.notebook_seed1_view.get_result_seed1()
228         alchemy_type = self.notebook_seed1_view.get_tenun_radio_key()
229         if seed1 is not None:
230             self.notebook_skill1_view.set_seed1_value(seed1)
231             self.notebook_skill1_view.set_tenun_radio_key(alchemy_type)
232             self.frame_view.note_book.SetSelection(view.SKILL1_SEARCH_PAGE)
233             self.OnClickSkill1Search(evt)
234
235     u""" Seed2 view's event """
236     def OnClickSeed2Search(self, evt):
237         u""" search seed2s from selected skill2s """
238         amu2skills_dict = {}
239         for amu_key, amu_name in zip([view.KEY_AMULET1, view.KEY_AMULET2, view.KEY_AMULET3], 
240                 [view.NAME_AMULET1, view.NAME_AMULET2, view.NAME_AMULET3]):
241             names = self.notebook_seed2_view.get_selected_skill_names(amu_key)
242             amu2skills_dict[amu_name] = [name if name in self._skill_names else None for name in names]
243         seed_sets = self.db_accessor.select_seed2s(amu2skills_dict)
244         self.notebook_seed2_view.set_result_text(u"""Seedの候補は{0}個です。""".format(len(seed_sets)))
245
246         if len(seed_sets) > 0:
247             self.notebook_seed2_view.set_seed_lists([u"{0}".format(seed) for seed in sorted(seed_sets)])
248             self.notebook_seed2_view.set_skill2_button_enable(True)
249         else:
250             self.notebook_seed2_view.clear_seed_list()
251             self.notebook_seed2_view.set_skill2_button_enable(False)
252
253     def OnClickSeed2Clear(self, evt):
254         u""" reset seed2 search settings of combo box"""
255         self.notebook_seed2_view.set_skill_selected_idx(0)
256         self.notebook_seed2_view.clear_seed_list()
257         self.notebook_seed2_view.set_result_text(u"")
258         self.notebook_seed2_view.set_skill2_button_enable(False)
259
260     def OnClickSkill2SearchFromSeed2(self, evt):
261         u""" change page to skill2 search from seed2"""
262         seed2 = self.notebook_seed2_view.get_selected_seed2()
263         if seed2 is not None:
264             self.notebook_skill2_view.set_seed2_value(seed2)
265             self.frame_view.note_book.SetSelection(view.SKILL2_SEARCH_PAGE)
266             self.OnClickSkill2Search(evt)
267
268     u""" Skill1 search from Seed1's event """
269     def OnClickSkill1Search(self, evt):
270         u""" skill1 search from seed1"""
271         seed1 = self.notebook_skill1_view.get_seed1_value()
272         alchemy_type = self.notebook_skill1_view.get_tenun_radio_key()
273         if seed1 is not None:
274             try:
275                 no, table_no, result_num = self.db_accessor.select_table_nos_from_seed1(seed1, alchemy_type)
276                 self.notebook_skill1_view.set_text_result_by_seed1(seed1, table_no, no)
277                 # list of (no, seed1)
278                 near_num = view.NEAR_SEED1_NUMBERS
279                 no_seed1_dict = self.db_accessor.select_near_seed1s_from_table_no(
280                         no, table_no, near_num, near_num, alchemy_type)
281
282                 # no -> (seed1, result_num, amu_names, skill_names)
283                 self.notebook_skill1_view.set_no2seed1s_dict(no_seed1_dict, no)
284                 self.notebook_skill1_view.update_highlight(self._highlight_skills)
285             except KeyError, e:
286                 self._show_message_dialog(message=u"指定されたSeed値は存在しません")
287         else:
288             self._show_message_dialog(message=u"Seed値には数字を入力してください")
289
290     def OnClickSkill1Clear(self, evt):
291         u""" clear skills from seed """
292         self.notebook_skill1_view.clear_skill1_grid()
293         self.notebook_skill1_view.clear_highlight()
294         self.notebook_skill1_view.clear_result_text()
295
296     u""" Skill2 search from Seed2's event """
297     def OnClickSkill2Search(self, evt):
298         u""" skill search from seed2"""
299         seed2 = self.notebook_skill2_view.get_seed2_value()
300         if seed2 is not None:
301             table_no, no, skill_dict, th1s, th2s = self.db_accessor.select_names_from_seed2(seed2)
302             try:
303                 for amu_key, amu_name in zip([view.KEY_AMULET1, view.KEY_AMULET2, view.KEY_AMULET3], 
304                         [view.NAME_AMULET1, view.NAME_AMULET2, view.NAME_AMULET3]):
305                     skill_names = skill_dict[amu_name]
306                     self.notebook_skill2_view.set_skill2_by_col_key(amu_key, skill_names)
307                 th_vals = [u"{0}".format(x) for x in th1s]
308                 self.notebook_skill2_view.set_skill2_by_col_key(view.KEY_THRESHOLD1, th_vals)
309                 th_vals = [u"{0}".format(x) for x in th2s]
310                 self.notebook_skill2_view.set_skill2_by_col_key(view.KEY_THRESHOLD2, th_vals)
311                 #inishie
312                 skill_name, th1, th2 = self.db_accessor.select_inishie_skill2_from_seed2(seed2)
313                 self.notebook_skill2_view.set_inishie(skill_name, th1, th2)
314                 # explanation
315                 self.notebook_skill2_view.set_result_text(
316                         u"SEED2: {2}, 通し番号: {1}, テーブルNo: {0}".format(table_no, no, seed2))
317             except KeyError, e:
318                 self._show_message_dialog(message=u"指定されたSeed値は存在しません")
319             finally:
320                 self._update_highlight()
321
322         else:
323             self._show_message_dialog(message=u"Seed値には数字を入力してください")
324
325     def OnClickSkill2Clear(self, evt):
326         u""" clear skills from seed """
327         self.notebook_skill2_view.clear_skill2_grid()
328         self.notebook_skill2_view.clear_skill2_highlight()
329         self.notebook_skill2_view.clear_result_text()
330         self.notebook_skill2_view.clear_inishie()
331
332     u""" Alchemy Simulator's event """
333     def OnClickSimulatorSearch(self, evt):
334         u""" alchemy simulation from seed1, seed2"""
335         seeds = self.notebook_simulator_view.get_seed_values()
336         alchemy_type = self.notebook_simulator_view.get_tenun_radio_key()
337         if seeds is not None:
338             seed1, seed2 = seeds
339             #try:
340             result = self.db_accessor.simulate_nazo(seed1, seed2)
341             self.notebook_simulator_view.set_values(view.KEY_NAZO, *result)
342             result = self.db_accessor.simulate_komyou(seed1, seed2)
343             self.notebook_simulator_view.set_values(view.KEY_KOMYOU, *result)
344             result = self.db_accessor.simulate_inishie(seed1, seed2)
345             self.notebook_simulator_view.set_values(view.KEY_INISHIE, *result)
346             result = self.db_accessor.simulate_tenun(seed1, seed2, alchemy_type)
347             self.notebook_simulator_view.set_tenun_values(result)
348             #except KeyError, e:
349             #   self._show_message_dialog(message=u"指定されたSeed値は存在しません")
350             #finally:
351             self.notebook_simulator_view.update_highlight(self._highlight_skills)
352         else:
353             self._show_message_dialog(message=u"Seed値には数字を入力してください")
354
355     def OnClickSimulatorClear(self, evt):
356         u""" clear simulator form """
357         self.notebook_simulator_view.clear_seed_values()
358         self.notebook_simulator_view.clear_grid()
359         self.notebook_simulator_view.clear_highlight()
360
361     u""" amulet search event """
362     def OnClickAmuletSearch(self, evt):
363         u""" search seeds from amulet condition """
364         search_type = self.notebook_amulet_view.get_selected_search_type()
365         skill1_name, skill2_name = self.notebook_amulet_view.get_skill_names()
366         skill1_val, skill2_val = self.notebook_amulet_view.get_skill_values()
367         slot_num = self.notebook_amulet_view.get_slot_value()
368         amulet_name = self.notebook_amulet_view.get_selected_amulet()
369         if search_type == view.SEARCH_TYPE_SEED2:
370             suff_val, threshold, th1_seed2s, th2_seed2s = self.db_accessor.simple_select_seed2s_from_names(
371                     amulet_name, skill1_name, skill1_val, skill2_name, skill2_val, slot_num)
372             self.notebook_amulet_view.set_result_only_seed2(suff_val, threshold, th1_seed2s, th2_seed2s)
373         elif search_type == view.SEARCH_TYPE_FIXED_SEED2:
374             seed2 = self.notebook_amulet_view.get_fixed_seed2()
375             suff_val = self.db_accessor.get_sufficient_value(amulet_name, skill1_name, skill2_name, skill1_val, skill2_val)
376             threshold = self.db_accessor.select_threshold_from_sufficient(amulet_name, suff_val)[slot_num-1]
377             if seed2 is not None and skill2_name in self._skill_names:
378                 seed1s_555, seed1s_888 = self.db_accessor.select_seed1s_from_fixed_seed2(seed2,
379                         amulet_name, skill1_name, skill1_val, skill2_name, skill2_val, slot_num)
380                 self.notebook_amulet_view.set_result_fixed_seed2(suff_val, threshold, seed2, seed1s_555, seed1s_888)
381             elif seed2 is None:
382                 self._show_message_dialog(message=u"Seed2には数字を入力して下さい")
383             else:
384                 self._show_message_dialog(message=u"第2スキルに何らかのスキルを指定してください")
385         elif search_type == view.SEARCH_TYPE_SEED1_SEED2:
386             u"""
387             suff_val = self.db_accessor.get_sufficient_value(amulet_name, skill1_name, skill2_name,
388                     skill1_val, skill2_val)
389             if suff_val > 15:
390                 result_dict = self.db_accessor.select_seed1s_from_names(amulet_name, 
391                         skill1_name, skill1_val, skill2_name, skill2_val, slot_num)
392                 self.notebook_amulet_view.set_result_seeds(suff_val, result_dict)
393             else:
394                 self._show_message_dialog(message=u"指定されたお守りの充足値が低いため、結果を表示しきれません")
395             """
396             pass
397
398     def OnClickAmuletClear(self, evt):
399         u""" clear amulet conditions """
400         self.notebook_amulet_view.clear_grid()
401         self.notebook_amulet_view.clear_input_values()
402
403     def OnClickSimulateFromAmulet(self, evt):
404         u""" change page to skill search from amulet"""
405         values = self.notebook_amulet_view.get_selected_seeds()
406         if values is not None:
407             seed1, seed2 = values
408             self.notebook_simulator_view.set_seed_values(seed1, seed2)
409             self.frame_view.note_book.SetSelection(view.ALCHEMY_SIMULATE_PAGE)
410             if seed1 is not None and seed2 is not None:
411                 tenun = self.notebook_amulet_view.get_selected_tenun_type()
412                 self.notebook_simulator_view.set_tenun_radio_key(tenun)
413                 self.OnClickSimulatorSearch(evt)
414         else:
415             self._show_message_dialog(message=u"有効な行を選択してください")
416
417     u""" settings' event """
418     def OnClickSettingOK(self, evt):
419         u""" get settings of setting tab """
420         (self._highlight_threshold1, 
421                 self._highlight_threshold2) = self.frame_view.notebook_setting_view.get_threshold()
422         self._highlight_skills = set([x for x in self.frame_view.notebook_setting_view.get_checked_strings()
423                 if x in self._skill_names])
424         self._update_highlight()
425
426     def OnClickSettingClear(self, evt):
427         u""" reset settings of setting tab """
428         self._highlight_threshold1 = view.HIGHLIGHT_THRESHOLD1
429         self._highlight_threshold2 = view.HIGHLIGHT_THRESHOLD2
430         self._highlight_skills = set()
431         self._update_notebook_setting()
432         self._update_highlight()
433
434     def _show_error_dialog(self, message=u"予期せぬエラーが発生しました", caption=u"エラー"):
435         u""" エラーダイアログを表示し、
436         OKボタンが押されたらアプリケーションを終了する
437         """
438         dlg = wx.MessageDialog(self.frame_view.frame, 
439             message,
440             caption, wx.OK | wx.ICON_ERROR)
441         dlg.ShowModal()
442         dlg.Destroy()
443         wx.Exit()
444
445     def _show_message_dialog(self, message, caption=u"メッセージ"):
446         u""" メッセージダイアログを表示する
447         """
448         dlg = wx.MessageDialog(self.frame_view.frame, 
449             message,
450             caption, wx.OK | wx.ICON_INFORMATION)
451         dlg.ShowModal()
452         dlg.Destroy()
453
454     def CloseHandler(self, evt):
455         dlg = wx.MessageDialog(parent = self.frame_view.frame,
456                 message = u"終了します。よろしいですか?", 
457                 caption = u"終了確認", 
458                 style = wx.YES_NO)
459         result = dlg.ShowModal()
460         dlg.Destroy()
461         if result == wx.ID_YES:
462             self._write_settings()
463             wx.Exit()
464
465     def OnClose(self, evt):
466         self.frame_view.Close()
467
468     def OnAboutBox(self, evt):
469         info = self.frame_view.GetAboutInfo()
470         wx.AboutBox(info)
471
472     def OnMemoBox(self, evt):
473         dlg_view = view.MemoDialogView(os.path.join(_get_base_dir(), u"view", view.XRC_MEMO_DIALOG))
474         dlg_view.Show()
475
476     def _write_settings(self):
477         with open(SETTING_FILE, mode="w") as f:
478             data = {SETTING_THRESHOLD1:self._highlight_threshold1, 
479                     SETTING_THRESHOLD2:self._highlight_threshold2, 
480                     SETTING_SKILLS:self._highlight_skills}
481             pickle.dump(data, f)
482
483     def _read_settings(self):
484         if os.path.exists(SETTING_FILE):
485             with open(SETTING_FILE, mode="r") as f:
486                 try:
487                     data = pickle.load(f)
488                     self._highlight_threshold1 = data[SETTING_THRESHOLD1] 
489                     self._highlight_threshold2 = data[SETTING_THRESHOLD2] 
490                     self._highlight_skills = data[SETTING_SKILLS]
491                 except EOFError, e:
492                     self._highlight_threshold1 = view.HIGHLIGHT_THRESHOLD1
493                     self._highlight_threshold2 = view.HIGHLIGHT_THRESHOLD2
494                     self._highlight_skills = set()
495         else:
496             self._highlight_threshold1 = view.HIGHLIGHT_THRESHOLD1
497             self._highlight_threshold2 = view.HIGHLIGHT_THRESHOLD2
498             self._highlight_skills = set()
499
500 if __name__ == "__main__":
501     app = AmuletToolController(False)
502     app.MainLoop()
503