view orpg/gametree/gametree.py @ 48:0aeee1992423 traipse_dev

This updates fixes three things. Branch names are now current to your udpate and updates take place before the program starts and minor error in update code (unremarked, removed '.')
author sirebral
date Thu, 06 Aug 2009 04:26:02 -0500
parents 4385a7d0efd1
children c54768cffbd4
line wrap: on
line source

# Copyright (C) 2000-2001 The OpenRPG Project
#
#        openrpg-dev@lists.sourceforge.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# --
#
# File: gametree.py
# Author: Chris Davis
# Maintainer:
# Version:
#   $Id: gametree.py,v 1.68 2007/12/07 20:39:48 digitalxero Exp $
#
# Description: The file contains code fore the game tree shell
#

__version__ = "$Id: gametree.py,v 1.68 2007/12/07 20:39:48 digitalxero Exp $"

from orpg.orpg_wx import *
from orpg.orpg_windows import *
from orpg.orpgCore import open_rpg
import orpg.dirpath
from nodehandlers import core
import orpg.gametree.nodehandlers.containers
import orpg.gametree.nodehandlers.forms
import orpg.gametree.nodehandlers.dnd3e
import orpg.gametree.nodehandlers.dnd35
import orpg.gametree.nodehandlers.chatmacro
import orpg.gametree.nodehandlers.map_miniature_nodehandler
import orpg.gametree.nodehandlers.minilib
import orpg.gametree.nodehandlers.rpg_grid
import orpg.gametree.nodehandlers.d20
import orpg.gametree.nodehandlers.StarWarsd20
import orpg.gametree.nodehandlers.voxchat
from gametree_version import GAMETREE_VERSION
import string
import urllib
import time
import os

STD_MENU_DELETE = wx.NewId()
STD_MENU_DESIGN = wx.NewId()
STD_MENU_USE = wx.NewId()
STD_MENU_PP = wx.NewId()
STD_MENU_RENAME = wx.NewId()
STD_MENU_SEND = wx.NewId()
STD_MENU_SAVE = wx.NewId()
STD_MENU_ICON = wx.NewId()
STD_MENU_CLONE = wx.NewId()
STD_MENU_ABOUT = wx.NewId()
STD_MENU_HTML = wx.NewId()
STD_MENU_EMAIL = wx.NewId()
STD_MENU_CHAT = wx.NewId()
STD_MENU_WHISPER = wx.NewId()
STD_MENU_WIZARD = wx.NewId()
STD_MENU_NODE_SUBMENU = wx.NewId()
STD_MENU_NODE_USEFUL = wx.NewId()
STD_MENU_NODE_USELESS = wx.NewId()
STD_MENU_NODE_INDIFFERENT = wx.NewId()
STD_MENU_MAP = wx.NewId()
TOP_IFILE = wx.NewId()
TOP_INSERT_URL = wx.NewId()
TOP_NEW_TREE = wx.NewId()
TOP_SAVE_TREE = wx.NewId()
TOP_SAVE_TREE_AS = wx.NewId()
TOP_TREE_PROP = wx.NewId()
TOP_FEATURES = wx.NewId()

class game_tree(wx.TreeCtrl):
    def __init__(self, parent, id):
        wx.TreeCtrl.__init__(self,parent,id,  wx.DefaultPosition, wx.DefaultSize,style=wx.TR_EDIT_LABELS | wx.TR_HAS_BUTTONS)
        self.log = open_rpg.get_component('log')
        self.log.log("Enter game_tree", ORPG_DEBUG)
        self.validate = open_rpg.get_component('validate')
        self.xml = open_rpg.get_component('xml')
        self.settings = open_rpg.get_component('settings')
        self.session = open_rpg.get_component('session')
        self.chat = open_rpg.get_component('chat')
        self.mainframe = open_rpg.get_component('frame')
        self.build_img_list()
        self.build_std_menu()
        self.nodehandlers = {}
        self.nodes = {}
        self.init_nodehandlers()
        self.Bind(wx.EVT_LEFT_DCLICK, self.on_ldclick)
        self.Bind(wx.EVT_RIGHT_DOWN, self.on_rclick)
        self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.on_drag, id=id)
        self.Bind(wx.EVT_LEFT_UP, self.on_left_up)
        self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
        self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.on_label_change, id=self.GetId())
        self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.on_label_begin, id=self.GetId())
        self.Bind(wx.EVT_CHAR, self.on_char)
        self.Bind(wx.EVT_KEY_UP, self.on_key_up)
        self.id = 1
        self.dragging = False
        self.root_dir = orpg.dirpath.dir_struct["home"]
        self.last_save_dir = orpg.dirpath.dir_struct["user"]

        #Create tree from default if it does not exist
        self.validate.config_file("tree.xml","default_tree.xml")
        open_rpg.add_component("tree", self)
        #build tree
        self.root = self.AddRoot("Game Tree",self.icons['gear'])
        self.was_labeling = 0
        self.rename_flag = 0
        self.image_cache = {}
        self.log.log("Exit game_tree", ORPG_DEBUG)

    def add_nodehandler(self, nodehandler, nodeclass):
        self.log.log("Enter game_tree->add_nodehandler(self, nodehandler, nodeclass)", ORPG_DEBUG)
        if not self.nodehandlers.has_key(nodehandler):
            self.nodehandlers[nodehandler] = nodeclass
        else:
            self.log.log("Nodehandler for " + nodehandler + " already exists!", ORPG_DEBUG, True)
        self.log.log("Exit game_tree->add_nodehandler(self, nodehandler, nodeclass)", ORPG_DEBUG)

    def remove_nodehandler(self, nodehandler):
        self.log.log("Enter game_tree->remove_nodehandler(self, nodehandler)", ORPG_DEBUG)
        if self.nodehandlers.has_key(nodehandler):
            del self.nodehandlers[nodehandler]
        else:
            self.log.log("No nodehandler for " + nodehandler + " exists!", ORPG_DEBUG, True)
        self.log.log("Exit game_tree->remove_nodehandler(self, nodehandler)", ORPG_DEBUG)

    def init_nodehandlers(self):
        self.log.log("Enter game_tree->init_nodehandlers(self)", ORPG_DEBUG)
        self.add_nodehandler('group_handler', orpg.gametree.nodehandlers.containers.group_handler)
        self.add_nodehandler('tabber_handler', orpg.gametree.nodehandlers.containers.tabber_handler)
        self.add_nodehandler('splitter_handler', orpg.gametree.nodehandlers.containers.splitter_handler)
        self.add_nodehandler('form_handler', orpg.gametree.nodehandlers.forms.form_handler)
        self.add_nodehandler('textctrl_handler', orpg.gametree.nodehandlers.forms.textctrl_handler)
        self.add_nodehandler('listbox_handler', orpg.gametree.nodehandlers.forms.listbox_handler)
        self.add_nodehandler('link_handler', orpg.gametree.nodehandlers.forms.link_handler)
        self.add_nodehandler('webimg_handler', orpg.gametree.nodehandlers.forms.webimg_handler)
        self.add_nodehandler('dnd3echar_handler', orpg.gametree.nodehandlers.dnd3e.dnd3echar_handler)
        self.add_nodehandler('dnd35char_handler', orpg.gametree.nodehandlers.dnd35.dnd35char_handler)
        self.add_nodehandler('macro_handler', orpg.gametree.nodehandlers.chatmacro.macro_handler)
        self.add_nodehandler('map_miniature_handler', orpg.gametree.nodehandlers.map_miniature_nodehandler.map_miniature_handler)
        self.add_nodehandler('minilib_handler', orpg.gametree.nodehandlers.minilib.minilib_handler)
        self.add_nodehandler('mini_handler', orpg.gametree.nodehandlers.minilib.mini_handler)
        self.add_nodehandler('rpg_grid_handler', orpg.gametree.nodehandlers.rpg_grid.rpg_grid_handler)
        self.add_nodehandler('d20char_handler', orpg.gametree.nodehandlers.d20.d20char_handler)
        self.add_nodehandler('SWd20char_handler', orpg.gametree.nodehandlers.StarWarsd20.SWd20char_handler)
        self.add_nodehandler('voxchat_handler', orpg.gametree.nodehandlers.voxchat.voxchat_handler)
        self.add_nodehandler('file_loader', core.file_loader)
        self.add_nodehandler('node_loader', core.node_loader)
        self.add_nodehandler('url_loader', core.url_loader)
        self.add_nodehandler('min_map', core.min_map)
        self.log.log("Exit game_tree->init_nodehandlers(self)", ORPG_DEBUG)

    #   event = wxKeyEvent
    #   set to be called by wxWindows by EVT_CHAR macro in __init__
    def on_key_up(self, evt):
        self.log.log("Enter game_tree->on_key_up(self, evt)", ORPG_DEBUG)
        key_code = evt.GetKeyCode()
        if self.dragging and (key_code == wx.WXK_SHIFT):
            curSelection = self.GetSelection()
            cur = wx.StockCursor(wx.CURSOR_ARROW)
            self.SetCursor(cur)
            self.dragging = False
            obj = self.GetPyData(curSelection)
            self.SelectItem(curSelection)
            if(isinstance(obj,core.node_handler)):
                obj.on_drop(evt)
                self.drag_obj = None
        evt.Skip()
        self.log.log("Exit game_tree->on_key_up(self, evt)", ORPG_DEBUG)

    def on_char(self, evt):
        self.log.log("Enter game_tree->on_char(self, evt)", ORPG_DEBUG)
        key_code = evt.GetKeyCode()
        curSelection = self.GetSelection()                            #  Get the current selection
        if evt.ShiftDown() and ((key_code == wx.WXK_UP) or (key_code == wx.WXK_DOWN)) and not self.dragging:
            curSelection = self.GetSelection()
            obj = self.GetPyData(curSelection)
            self.SelectItem(curSelection)
            if(isinstance(obj,core.node_handler)):
                self.dragging = True
                cur = wx.StockCursor(wx.CURSOR_HAND)
                self.SetCursor(cur)
                self.drag_obj = obj
        elif key_code == wx.WXK_LEFT:
            self.Collapse(curSelection)

        elif key_code == wx.WXK_DELETE:                          #  Handle the delete key
            if curSelection:
                nextSelect = self.GetItemParent(curSelection)
                self.on_del(evt)
                try:
                    if self.GetItemText(nextSelect) != "":
                        self.SelectItem(nextSelect)
                except:
                    pass
        elif key_code == wx.WXK_F2:
            self.rename_flag = 1
            self.EditLabel(curSelection)
        evt.Skip()
        self.log.log("Exit game_tree->on_char(self, evt)", ORPG_DEBUG)

    ## locate_valid_tree
    ## GUI based dialogs to locate/fix missing treefile issues --Snowdog 3/05
    def locate_valid_tree(self, error, msg, dir, filename):
        """prompts the user to locate a new tree file or create a new one"""
        self.log.log("Enter game_tree->locate_valid_tree(self, error, msg, dir, filename)", ORPG_DEBUG)
        response = wx.MessageDialog(self, msg, error, wx.YES|wx.NO|wx.ICON_ERROR)
        if response == wx.YES:
            file = None
            filetypes = "Gametree (*.xml)|*.xml|All files (*.*)|*.*"
            dlg = wx.FileDialog(self, "Locate Gametree file", dir, filename, filetypes,wx.OPEN | wx.CHANGE_DIR)
            if dlg.ShowModal() == wx.ID_OK: file = dlg.GetPath()
            dlg.Destroy()
            if not file: self.load_tree(error=1)
            else: self.load_tree(file)
            self.log.log("Exit game_tree->locate_valid_tree(self, error, msg, dir, filename)", ORPG_DEBUG)
            return
        else:
            self.validate.config_file("tree.xml","default_tree.xml")
            self.load_tree(error=1)
            self.log.log("Exit game_tree->locate_valid_tree(self, error, msg, dir, filename)", ORPG_DEBUG)
            return

    def load_tree(self, filename=orpg.dirpath.dir_struct["user"]+'tree.xml', error=0):
        self.log.log("Enter game_tree->load_tree(self, filename, error)", ORPG_DEBUG)
        self.settings.set_setting("gametree", filename)
        tmp = None
        xml_dom = None
        xml_doc = None
        try:
            self.log.log("Reading Gametree file: " + filename + "...", ORPG_INFO, True)
            tmp = open(filename,"r")
            xml_doc = self.xml.parseXml(tmp.read())
            tmp.close()
            if xml_doc == None:
                pass
            else:
                xml_dom = xml_doc._get_documentElement()
            self.log.log("done.", ORPG_INFO, True)

        except IOError:
            emsg = "Gametree Missing!\n"+filename+" cannot be found.\n\n"\
                   "Would you like to locate it?\n"\
                   "(Selecting 'No' will cause a new default gametree to be generated)"
            fn = filename[ ((filename.rfind(os.sep))+len(os.sep)):]
            self.locate_valid_tree("Gametree Error", emsg, orpg.dirpath.dir_struct["user"], fn)
            self.log.log(emsg, ORPG_GENERAL)
            self.log.log("Exit game_tree->load_tree(self, filename, error)", ORPG_DEBUG)
            return

        if not xml_dom:
            os.rename(filename,filename+".corrupt")
            fn = filename[ ((filename.rfind(os.sep))+len(os.sep)):]
            emsg = "Your gametree is being regenerated.\n\n"\
                   "To salvage a recent version of your gametree\n"\
                   "exit OpenRPG and copy the lastgood.xml file in\n"\
                   "your myfiles directory to "+fn+ "\n"\
                   "in your myfiles directory.\n\n"\
                   "lastgood.xml WILL BE OVERWRITTEN NEXT TIME YOU RUN OPENRPG.\n\n"\
                   "Would you like to select a different gametree file to use?\n"\
                   "(Selecting 'No' will cause a new default gametree to be generated)"
            self.locate_valid_tree("Corrupt Gametree!", emsg, orpg.dirpath.dir_struct["user"], fn)
            self.log.log(emsg, ORPG_GENERAL)
            self.log.log("Exit game_tree->load_tree(self, filename, error)", ORPG_DEBUG)
            return

        if xml_dom._get_tagName() != "gametree":
            fn = filename[ ((filename.rfind(os.sep))+len(os.sep)):]
            emsg = fn+" does not appear to be a valid gametree file.\n\n"\
                   "Would you like to select a different gametree file to use?\n"\
                   "(Selecting 'No' will cause a new default gametree to be generated)"
            self.locate_valid_tree("Invalid Gametree!", emsg, orpg.dirpath.dir_struct["user"], fn)
            self.log.log(emsg, ORPG_DEBUG)
            self.log.log("Exit game_tree->load_tree(self, filename, error)", ORPG_DEBUG)
            return

        # get gametree version - we could write conversion code here!
        self.master_dom = xml_dom
        self.log.log("Master Dom Set", ORPG_DEBUG)

        try:
            version = self.master_dom.getAttribute("version")
            # see if we should load the gametree
            loadfeatures = int(self.settings.get_setting("LoadGameTreeFeatures"))
            if loadfeatures:
                xml_dom = self.xml.parseXml(open(orpg.dirpath.dir_struct["template"]+"feature.xml","r").read())
                xml_dom = xml_dom._get_documentElement()
                xml_dom = self.master_dom.appendChild(xml_dom)
                self.settings.set_setting("LoadGameTreeFeatures","0")

            ## load tree
            self.log.log("Features loaded (if required)", ORPG_DEBUG)
            self.CollapseAndReset(self.root)
            children = self.master_dom._get_childNodes()
            self.log.log("Parsing Gametree Nodes ", ORPG_INFO, True)
            for c in children:
                print '.',
                self.load_xml(c,self.root)
            self.log.log("done", ORPG_INFO, True)
            self.Expand(self.root)
            self.SetPyData(self.root,self.master_dom)
            if error != 1:
                infile = open(filename, "rb")
                outfile = open(orpg.dirpath.dir_struct["user"]+"lastgood.xml", "wb")
                outfile.write(infile.read())
            else:
                self.log.log("Not overwriting lastgood.xml file.", ORPG_INFO, True)

        except Exception, e:
            self.log.log(traceback.format_exc(), ORPG_GENERAL)
            wx.MessageBox("Corrupt Tree!\nYour game tree is being regenerated. To\nsalvage a recent version of your gametree\nexit OpenRPG and copy the lastgood.xml\nfile in your myfiles directory\nto "+filename+ "\nin your myfiles directory.\nlastgood.xml WILL BE OVERWRITTEN NEXT TIME YOU RUN OPENRPG.")
            os.rename(filename,filename+".corrupt")
            self.validate.config_file("tree.xml","default_tree.xml")
            self.load_tree(error=1)
        self.log.log("Exit game_tree->load_tree(self, filename, error)", ORPG_DEBUG)

    def build_std_menu(self, obj=None):
        self.log.log("Enter game_tree->build_std_menu(self, obj)", ORPG_DEBUG)

        # build useful menu
        useful_menu = wx.Menu()
        useful_menu.Append(STD_MENU_NODE_USEFUL,"Use&ful")
        useful_menu.Append(STD_MENU_NODE_USELESS,"Use&less")
        useful_menu.Append(STD_MENU_NODE_INDIFFERENT,"&Indifferent")
        # build standard menu
        self.std_menu = wx.Menu()
        self.std_menu.SetTitle("game tree")
        self.std_menu.Append(STD_MENU_USE,"&Use")
        self.std_menu.Append(STD_MENU_DESIGN,"&Design")
        self.std_menu.Append(STD_MENU_PP,"&Pretty Print")
        self.std_menu.AppendSeparator()
        self.std_menu.Append(STD_MENU_SEND,"Send To Player")
        self.std_menu.Append(STD_MENU_MAP,"Send To Map")
        self.std_menu.Append(STD_MENU_CHAT,"Send To Chat")
        self.std_menu.Append(STD_MENU_WHISPER,"Whisper To Player")
        self.std_menu.AppendSeparator()
        self.std_menu.Append(STD_MENU_ICON,"Change &Icon")
        self.std_menu.Append(STD_MENU_DELETE,"D&elete")
        self.std_menu.Append(STD_MENU_CLONE,"&Clone")
        self.std_menu.AppendMenu(STD_MENU_NODE_SUBMENU,"Node &Usefulness",useful_menu)
        self.std_menu.AppendSeparator()
        self.std_menu.Append(STD_MENU_SAVE,"&Save Node")
        self.std_menu.Append(STD_MENU_HTML,"E&xport as HTML")
        self.std_menu.AppendSeparator()
        self.std_menu.Append(STD_MENU_ABOUT,"&About")
        self.Bind(wx.EVT_MENU, self.on_send_to, id=STD_MENU_SEND)
        self.Bind(wx.EVT_MENU, self.indifferent, id=STD_MENU_NODE_INDIFFERENT)
        self.Bind(wx.EVT_MENU, self.useful, id=STD_MENU_NODE_USEFUL)
        self.Bind(wx.EVT_MENU, self.useless, id=STD_MENU_NODE_USELESS)
        self.Bind(wx.EVT_MENU, self.on_del, id=STD_MENU_DELETE)
        self.Bind(wx.EVT_MENU, self.on_send_to_map, id=STD_MENU_MAP)
        self.Bind(wx.EVT_MENU, self.on_node_design, id=STD_MENU_DESIGN)
        self.Bind(wx.EVT_MENU, self.on_node_use, id=STD_MENU_USE)
        self.Bind(wx.EVT_MENU, self.on_node_pp, id=STD_MENU_PP)
        self.Bind(wx.EVT_MENU, self.on_save, id=STD_MENU_SAVE)
        self.Bind(wx.EVT_MENU, self.on_icon, id=STD_MENU_ICON)
        self.Bind(wx.EVT_MENU, self.on_clone, id=STD_MENU_CLONE)
        self.Bind(wx.EVT_MENU, self.on_about, id=STD_MENU_ABOUT)
        self.Bind(wx.EVT_MENU, self.on_send_to_chat, id=STD_MENU_CHAT)
        self.Bind(wx.EVT_MENU, self.on_whisper_to, id=STD_MENU_WHISPER)
        self.Bind(wx.EVT_MENU, self.on_export_html, id=STD_MENU_HTML)
        self.top_menu = wx.Menu()
        self.top_menu.SetTitle("game tree")
        self.top_menu.Append(TOP_IFILE,"&Insert File")
        self.top_menu.Append(TOP_INSERT_URL,"Insert &URL")
        self.top_menu.Append(TOP_FEATURES, "Insert &Features Node")
        self.top_menu.Append(TOP_NEW_TREE, "&Load New Tree")
        self.top_menu.Append(TOP_SAVE_TREE,"&Save Tree")
        self.top_menu.Append(TOP_SAVE_TREE_AS,"Save Tree &As...")
        self.top_menu.Append(TOP_TREE_PROP,"&Tree Properties")
        self.Bind(wx.EVT_MENU, self.on_insert_file, id=TOP_IFILE)
        self.Bind(wx.EVT_MENU, self.on_insert_url, id=TOP_INSERT_URL)
        self.Bind(wx.EVT_MENU, self.on_save_tree_as, id=TOP_SAVE_TREE_AS)
        self.Bind(wx.EVT_MENU, self.on_save_tree, id=TOP_SAVE_TREE)
        self.Bind(wx.EVT_MENU, self.on_load_new_tree, id=TOP_NEW_TREE)
        self.Bind(wx.EVT_MENU, self.on_tree_prop, id=TOP_TREE_PROP)
        self.Bind(wx.EVT_MENU, self.on_insert_features, id=TOP_FEATURES)
        self.log.log("Exit game_tree->build_std_menu(self, obj)", ORPG_DEBUG)

    def do_std_menu(self, evt, obj):
        self.log.log("Enter game_tree->do_std_menu(self, evt, obj)", ORPG_DEBUG)
        try:
            self.std_menu.Enable(STD_MENU_MAP, obj.checkToMapMenu())
        except:
            self.std_menu.Enable(STD_MENU_MAP, obj.map_aware())
        self.std_menu.Enable(STD_MENU_CLONE, obj.can_clone())
        self.PopupMenu(self.std_menu)
        self.log.log("Exit game_tree->do_std_menu(self, evt, obj)", ORPG_DEBUG)

    def strip_html(self, player):
        self.log.log("Enter game_tree->strip_html(self, player)", ORPG_DEBUG)
        ret_string = ""
        x = 0
        in_tag = 0
        for x in xrange(len(player[0])) :
            if player[0][x] == "<" or player[0][x] == ">" or in_tag == 1 :
                if player[0][x] == "<" :
                    in_tag = 1
                elif player[0][x] == ">" :
                    in_tag = 0
                else :
                    pass
            else :
                ret_string = ret_string + player[0][x]
        self.log.log(ret_string, ORPG_DEBUG)
        self.log.log("Exit game_tree->strip_html(self, player)", ORPG_DEBUG)
        return ret_string

    def on_receive_data(self, data, player):
        self.log.log("Enter game_tree->on_receive_data(self, data, player)", ORPG_DEBUG)
        beg = string.find(data,"<tree>")
        end = string.rfind(data,"</tree>")
        data = data[6:end]
        self.insert_xml(data)
        self.log.log("Exit game_tree->on_receive_data(self, data, player)", ORPG_DEBUG)

    def on_send_to_chat(self, evt):
        self.log.log("Enter game_tree->on_send_to_chat(self, evt)", ORPG_DEBUG)
        item = self.GetSelection()
        obj = self.GetPyData(item)
        obj.on_send_to_chat(evt)
        self.log.log("Exit game_tree->on_send_to_chat(self, evt)", ORPG_DEBUG)

    def on_whisper_to(self, evt):
        self.log.log("Enter game_tree->on_whisper_to(self, evt)", ORPG_DEBUG)
        players = self.session.get_players()
        opts = []
        myid = self.session.get_id()
        me = None
        for p in players:
            if p[2] != myid:
                opts.append("("+p[2]+") " + self.strip_html(p))
            else:
                me = p
        if len(opts):
            players.remove(me)
        if len(opts):
            dlg = orpgMultiCheckBoxDlg( self.GetParent(),opts,"Select Players:","Whisper To",[] )
            if dlg.ShowModal() == wx.ID_OK:
                item = self.GetSelection()
                obj = self.GetPyData(item)
                selections = dlg.get_selections()
                if len(selections) == len(opts):
                    self.chat.ParsePost(obj.tohtml(),True,True)
                else:
                    player_ids = []
                    for s in selections:
                        player_ids.append(players[s][2])
                    self.chat.whisper_to_players(obj.tohtml(),player_ids)
        self.log.log("Exit game_tree->on_whisper_to(self, evt)", ORPG_DEBUG)

    def on_export_html(self, evt):
        self.log.log("Enter game_tree->on_export_html(self, evt)", ORPG_DEBUG)
        f = wx.FileDialog(self,"Select a file", self.last_save_dir,"","HTML (*.html)|*.html",wx.SAVE)
        if f.ShowModal() == wx.ID_OK:
            item = self.GetSelection()
            obj = self.GetPyData(item)
            type = f.GetFilterIndex()
            file = open(f.GetPath(),"w")
            data = "<html><head><title>"+obj.master_dom.getAttribute("name")+"</title></head>"
            data += "<body bgcolor=\"#FFFFFF\" >"+obj.tohtml()+"</body></html>"
            for tag in ("</tr>","</td>","</th>","</table>","</html>","</body>"):
                data = data.replace(tag,tag+"\n")
            file.write(data)
            file.close()
            self.last_save_dir, throwaway = os.path.split( f.GetPath() )
        f.Destroy()
        os.chdir(self.root_dir)
        self.log.log("Exit game_tree->on_export_html(self, evt)", ORPG_DEBUG)

    def indifferent(self, evt):
        self.log.log("Enter game_tree->indifferent(self, evt)", ORPG_DEBUG)
        item = self.GetSelection()
        obj = self.GetPyData(item)
        obj.usefulness("indifferent")
        self.log.log("Exit game_tree->indifferent(self, evt)", ORPG_DEBUG)

    def useful(self, evt):
        self.log.log("Enter game_tree->useful(self, evt)", ORPG_DEBUG)
        item = self.GetSelection()
        obj = self.GetPyData(item)
        obj.usefulness("useful")
        self.log.log("Exit game_tree->useful(self, evt)", ORPG_DEBUG)

    def useless(self, evt):
        self.log.log("Enter game_tree->useless(self, evt)", ORPG_DEBUG)
        item = self.GetSelection()
        obj = self.GetPyData(item)
        obj.usefulness("useless")
        self.log.log("Exit game_tree->useless(self, evt)", ORPG_DEBUG)

    def on_email(self,evt):
        pass

    def on_send_to(self, evt):
        self.log.log("Enter game_tree->on_send_to(self, evt)", ORPG_DEBUG)
        players = self.session.get_players()
        opts = []
        myid = self.session.get_id()
        me = None
        for p in players:
            if p[2] != myid:
                opts.append("("+p[2]+") " + self.strip_html(p))
            else:
                me = p
        if len(opts):
            players.remove(me)
            dlg = orpgMultiCheckBoxDlg( None, opts, "Select Players:", "Send To", [] )
            if dlg.ShowModal() == wx.ID_OK:
                item = self.GetSelection()
                obj = self.GetPyData(item)
                xmldata = "<tree>" + self.xml.toxml(obj) + "</tree>"
                selections = dlg.get_selections()
                if len(selections) == len(opts):
                    self.session.send(xmldata)
                else:
                    for s in selections:
                        self.session.send(xmldata,players[s][2])
            dlg.Destroy()
        self.log.log("Exit game_tree->on_send_to(self, evt)", ORPG_DEBUG)

    def on_icon(self, evt):
        self.log.log("Enter game_tree->on_icon(self, evt)", ORPG_DEBUG)
        icons = self.icons.keys()
        icons.sort()
        dlg = wx.SingleChoiceDialog(self,"Choose Icon?","Change Icon",icons)
        if dlg.ShowModal() == wx.ID_OK:
            key = dlg.GetStringSelection()
            item = self.GetSelection()
            obj = self.GetPyData(item)
            obj.change_icon(key)
        dlg.Destroy()
        self.log.log("Exit game_tree->on_icon(self, evt)", ORPG_DEBUG)

    def on_wizard(self, evt):
        self.log.log("Enter game_tree->on_wizard(self, evt)", ORPG_DEBUG)
        item = self.GetSelection()
        obj = self.GetPyData(item)
        name = "New " + obj.master_dom.getAttribute("name")
        icon = obj.master_dom.getAttribute("icon")
        xml_data = "<nodehandler name=\""+name+"\" icon=\"" + icon + "\" module=\"core\" class=\"node_loader\" >"
        xml_data += self.xml.toxml(obj)
        xml_data += "</nodehandler>"
        self.insert_xml(xml_data)
        self.log.log(xml_data, ORPG_DEBUG)
        self.log.log("Exit game_tree->on_wizard(self, evt)", ORPG_DEBUG)

    def on_clone(self, evt):
        self.log.log("Enter game_tree->on_clone(self, evt)", ORPG_DEBUG)
        item = self.GetSelection()
        obj = self.GetPyData(item)
        if obj.can_clone():
            parent_node = self.GetItemParent(item)
            prev_sib = self.GetPrevSibling(item)
            if not prev_sib.IsOk():
                prev_sib = parent_node
            xml_dom = self.xml.parseXml(self.xml.toxml(obj))
            xml_dom = xml_dom._get_firstChild()
            parent = obj.master_dom._get_parentNode()
            xml_dom = parent.insertBefore(xml_dom, obj.master_dom)
            self.load_xml(xml_dom, parent_node, prev_sib)
        self.log.log("Exit game_tree->on_clone(self, evt)", ORPG_DEBUG)

    def on_save(self, evt):
        """save node to a xml file"""
        self.log.log("Enter game_tree->on_save(self, evt)", ORPG_DEBUG)
        item = self.GetSelection()
        obj = self.GetPyData(item)
        obj.on_save(evt)
        os.chdir(self.root_dir)
        self.log.log("Exit game_tree->on_save(self, evt)", ORPG_DEBUG)

    def on_save_tree_as(self, evt):
        self.log.log("Enter game_tree->on_save_tree_as(self, evt)", ORPG_DEBUG)
        f = wx.FileDialog(self,"Select a file", self.last_save_dir,"","*.xml",wx.SAVE)
        if f.ShowModal() == wx.ID_OK:
            self.save_tree(f.GetPath())
            self.last_save_dir, throwaway = os.path.split( f.GetPath() )
        f.Destroy()
        os.chdir(self.root_dir)
        self.log.log("Exit game_tree->on_save_tree_as(self, evt)", ORPG_DEBUG)

    def on_save_tree(self, evt=None):
        self.log.log("Enter game_tree->on_save_tree(self, evt)", ORPG_DEBUG)
        filename = self.settings.get_setting("gametree")
        self.save_tree(filename)
        self.log.log("Exit game_tree->on_save_tree(self, evt)", ORPG_DEBUG)

    def save_tree(self, filename=orpg.dirpath.dir_struct["user"]+'tree.xml'):
        self.log.log("Enter game_tree->save_tree(self, filename)", ORPG_DEBUG)
        self.master_dom.setAttribute("version",GAMETREE_VERSION)
        self.settings.set_setting("gametree",filename)
        file = open(filename,"w")
        file.write(self.xml.toxml(self.master_dom,1))
        file.close()
        self.log.log("Exit game_tree->save_tree(self, filename)", ORPG_DEBUG)

    def on_load_new_tree(self, evt):
        self.log.log("Enter game_tree->on_load_new_tree(self, evt)", ORPG_DEBUG)
        f = wx.FileDialog(self,"Select a file", self.last_save_dir,"","*.xml",wx.OPEN)
        if f.ShowModal() == wx.ID_OK:
            self.load_tree(f.GetPath())
            self.last_save_dir, throwaway = os.path.split( f.GetPath() )
        f.Destroy()
        os.chdir(self.root_dir)
        self.log.log("Exit game_tree->on_load_new_tree(self, evt)", ORPG_DEBUG)

    def on_insert_file(self, evt):
        """loads xml file into the tree"""
        self.log.log("Enter game_tree->on_insert_file(self, evt)", ORPG_DEBUG)
        if self.last_save_dir == ".":
            self.last_save_dir = orpg.dirpath.dir_struct["user"]
        f = wx.FileDialog(self,"Select a file", self.last_save_dir,"","*.xml",wx.OPEN)
        if f.ShowModal() == wx.ID_OK:
            self.insert_xml(open(f.GetPath(),"r").read())
            self.last_save_dir, throwaway = os.path.split( f.GetPath() )
        f.Destroy()
        os.chdir(self.root_dir)
        self.log.log("Exit game_tree->on_insert_file(self, evt)", ORPG_DEBUG)

    def on_insert_url(self, evt):
        """loads xml url into the tree"""
        self.log.log("Enter game_tree->on_insert_url(self, evt)", ORPG_DEBUG)
        dlg = wx.TextEntryDialog(self,"URL?","Insert URL", "http://")
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetValue()
            file = urllib.urlopen(path)
            self.insert_xml(file.read())
        dlg.Destroy()
        self.log.log("Exit game_tree->on_insert_url(self, evt)", ORPG_DEBUG)

    def on_insert_features(self, evt):
        self.log.log("Enter game_tree->on_insert_features(self, evt)", ORPG_DEBUG)
        self.insert_xml(open(orpg.dirpath.dir_struct["template"]+"feature.xml","r").read())
        self.log.log("Exit game_tree->on_insert_features(self, evt)", ORPG_DEBUG)

    def on_tree_prop(self, evt):
        self.log.log("Enter game_tree->on_tree_prop(self, evt)", ORPG_DEBUG)
        dlg = gametree_prop_dlg(self, self.settings)
        if dlg.ShowModal() == wx.ID_OK:
            pass
        dlg.Destroy()
        self.log.log("Exit game_tree->on_tree_prop(self, evt)", ORPG_DEBUG)

    def on_node_design(self, evt):
        self.log.log("Enter game_tree->on_node_design(self, evt)", ORPG_DEBUG)

        item = self.GetSelection()
        obj = self.GetPyData(item)
        obj.on_design(evt)

        self.log.log("Exit game_tree->on_node_design(self, evt)", ORPG_DEBUG)

    def on_node_use(self, evt):
        self.log.log("Enter game_tree->on_node_use(self, evt)", ORPG_DEBUG)

        item = self.GetSelection()
        obj = self.GetPyData(item)
        obj.on_use(evt)

        self.log.log("Exit game_tree->on_node_use(self, evt)", ORPG_DEBUG)

    def on_node_pp(self, evt):
        self.log.log("Enter game_tree->on_node_pp(self, evt)", ORPG_DEBUG)

        item = self.GetSelection()
        obj = self.GetPyData(item)
        obj.on_html_view(evt)

        self.log.log("Exit game_tree->on_node_pp(self, evt)", ORPG_DEBUG)

    def on_del(self, evt):
        self.log.log("Enter game_tree->on_del(self, evt)", ORPG_DEBUG)
        status_value = "none"
        try:
            item = self.GetSelection()
            if item:
                obj = self.GetPyData(item)
                parent_obj = obj
                try:
                    status_value = parent_obj.master_dom.getAttribute('status')
                    name = parent_obj.master_dom.getAttribute('name')
                except:
                    status_value = "none"
                parent_obj = parent_obj.master_dom._get_parentNode()
                while status_value!="useful" and status_value!="useless":
                    try:
                        status_value = parent_obj.getAttribute('status')
                        name = parent_obj.getAttribute('name')
                        if status_value == "useless":
                            break
                        elif status_value == "useful":
                            break
                    except:
                        status_value = "none"
                    try:
                        parent_obj = parent_obj._get_parentNode()
                    except:
                        break
                if status_value == "useful":
                    dlg = wx.MessageDialog(self, `name` + "  And everything beneath it are considered useful.  \n\nAre you sure you want to delete this item?",'Important Item',wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
                    if dlg.ShowModal() == wx.ID_YES:
                        obj.delete()
                else:
                    obj.delete()
        except:
            if self.GetSelection() == self.GetRootItem():
                msg = wx.MessageDialog(None,"You can't delete the root item.","Delete Error",wx.OK)
            else:
                msg = wx.MessageDialog(None,"Unknown error deleting node.","Delete Error",wx.OK)
            msg.ShowModal()
            msg.Destroy()

        self.log.log("Exit game_tree->on_del(self, evt)", ORPG_DEBUG)

    def on_about(self, evt):
        self.log.log("Enter game_tree->on_about(self, evt)", ORPG_DEBUG)

        item = self.GetSelection()
        obj = self.GetPyData(item)
        about = MyAboutBox(self,obj.about())
        about.ShowModal()
        about.Destroy()

        self.log.log("Exit game_tree->on_about(self, evt)", ORPG_DEBUG)

    def on_send_to_map(self, evt):
        self.log.log("Enter game_tree->on_send_to_map(self, evt)", ORPG_DEBUG)

        item = self.GetSelection()
        obj = self.GetPyData(item)
        if hasattr(obj,"on_send_to_map"):
            obj.on_send_to_map(evt)

        self.log.log("Exit game_tree->on_send_to_map(self, evt)", ORPG_DEBUG)

    def insert_xml(self, txt):
        self.log.log("Enter game_tree->insert_xml(self, txt)", ORPG_DEBUG)
        #Updated to allow safe merging of gametree files
        #without leaving an unusable and undeletable node.
        #                               -- Snowdog 8/03
        xml_dom = self.xml.parseXml(txt)
        if xml_dom == None:
            wx.MessageBox("Import Failed: Invalid or missing node data")
            self.log.log("Import Failed: Invalid or missing node data", ORPG_DEBUG)
            self.log.log("Exit game_tree->insert_xml(self, txt)", ORPG_DEBUG)
            return
        xml_temp = xml_dom._get_documentElement()

        if not xml_temp:
            wx.MessageBox("Error Importing Node or Tree")
            self.log.log("Error Importing Node or Tree", ORPG_DEBUG)
            self.log.log("Exit game_tree->insert_xml(self, txt)", ORPG_DEBUG)
            return

        if xml_temp._get_tagName() == "gametree":
            children = xml_temp._get_childNodes()
            for c in children:
                self.load_xml(c, self.root)
            self.log.log("Exit game_tree->insert_xml(self, txt)", ORPG_DEBUG)
            return

        if not xml_dom:
            wx.MessageBox("XML Error")
            self.log.log("XML Error", ORPG_DEBUG)
            self.log.log("Exit game_tree->insert_xml(self, txt)", ORPG_DEBUG)
            return

        xml_dom = xml_dom._get_firstChild()
        child = self.master_dom._get_firstChild()
        xml_dom = self.master_dom.insertBefore(xml_dom,child)
        self.load_xml(xml_dom,self.root,self.root)
        self.log.log("Exit game_tree->insert_xml(self, txt)", ORPG_DEBUG)

    def build_img_list(self):
        """make image list"""
        self.log.log("Enter game_tree->build_img_list(self)", ORPG_DEBUG)
        helper = img_helper()
        self.icons = { }
        self._imageList= wx.ImageList(16,16,False)
        man = open(orpg.dirpath.dir_struct["icon"]+"icons.xml","r")
        xml_dom = self.xml.parseXml(man.read())
        man.close()
        xml_dom = xml_dom._get_documentElement()
        node_list = xml_dom._get_childNodes()
        for n in node_list:
            key = n.getAttribute("name")
            path = orpg.dirpath.dir_struct["icon"] + n.getAttribute("file")
            img = helper.load_file(path)
            self.icons[key] = self._imageList.Add(img)
        self.SetImageList(self._imageList)
        self.log.log("Exit game_tree->build_img_list(self)", ORPG_DEBUG)

    def load_xml(self, xml_dom, parent_node, prev_node=None):
        self.log.log("Enter game_tree->load_xml(self, xml_dom, parent_node, prev_node)", ORPG_DEBUG)
        #add the first tree node
        i = 0
        text = xml_dom.getAttribute("name")
        icon = xml_dom.getAttribute("icon")
        if self.icons.has_key(icon):
            i = self.icons[icon]
        name = xml_dom._get_nodeName()
        self.log.log("Text, icon and name set\n" + text + "\n" + icon + "\n" + name, ORPG_DEBUG)
        if prev_node:
            if prev_node == parent_node:
                new_tree_node = self.PrependItem(parent_node, text, i, i)
            else:
                new_tree_node = self.InsertItem(parent_node,prev_node, text, i, i)
        else:
            new_tree_node = self.AppendItem(parent_node, text, i, i)

        self.log.log("Node Added to tree", ORPG_DEBUG)
        #create a nodehandler or continue loading xml into tree
        if name == "nodehandler":
            #wx.BeginBusyCursor()
            self.log.log("We have a Nodehandler", ORPG_DEBUG)
            try:
                py_class = xml_dom.getAttribute("class")
                self.log.log("nodehandler class: " + py_class, ORPG_DEBUG)
                if not self.nodehandlers.has_key(py_class):
                    raise Exception, "Unknown Nodehandler for " + py_class
                self.nodes[self.id] = self.nodehandlers[py_class](xml_dom, new_tree_node)
                self.SetPyData(new_tree_node, self.nodes[self.id])
                self.log.log("Node Data set", ORPG_DEBUG)
                bmp = self.nodes[self.id].get_scaled_bitmap(16,16)
                if bmp:
                    self.cached_load_of_image(bmp,new_tree_node,)
                self.log.log("Node Icon loaded", ORPG_DEBUG)
                self.id = self.id + 1
            except Exception, er:
                self.log.log(traceback.format_exc(), ORPG_GENERAL)
                #self.log.log("Error Info: " + xml_dom.getAttribute("class") + "\n" + str(er), "Tree Node Load Error", ORPG_GENERAL, True) # Arbitrary fix! TaS. (gametree should thread in the future.)
		self.log.log("Error Info: " + xml_dom.getAttribute("class") + "\n" + str(er), ORPG_GENERAL, True)
                self.Delete(new_tree_node)
                parent = xml_dom._get_parentNode()
                parent.removeChild(xml_dom)
            #wx.EndBusyCursor()
        self.log.log("Exit game_tree->load_xml(self, xml_dom, parent_node, prev_node)", ORPG_DEBUG)
        return new_tree_node

    def cached_load_of_image(self, bmp_in, new_tree_node):
        self.log.log("Enter game_tree->cached_load_of_image(self, bmp_in, new_tree_node)", ORPG_DEBUG)
        image_list = self.GetImageList()
        img = wx.ImageFromBitmap(bmp_in)
        img_data = img.GetData()
        image_index = None
        for key in self.image_cache.keys():
            if self.image_cache[key] == str(img_data):
                image_index = key
                break

        if image_index is None:
            image_index = image_list.Add(bmp_in)
            self.image_cache[image_index] = img_data
        self.SetItemImage(new_tree_node,image_index)
        self.SetItemImage(new_tree_node,image_index, wx.TreeItemIcon_Selected)
        self.log.log("Exit game_tree->cached_load_of_image(self, bmp_in, new_tree_node)", ORPG_DEBUG)
        return image_index


    def on_rclick(self, evt):
        self.log.log("Enter game_tree->on_rclick(self, evt)", ORPG_DEBUG)
        pt = evt.GetPosition()
        (item, flag) = self.HitTest(pt)
        if item.IsOk():
            obj = self.GetPyData(item)
            self.SelectItem(item)
            if(isinstance(obj,core.node_handler)):
                obj.on_rclick(evt)
            else:
                self.PopupMenu(self.top_menu)
        else:
            self.PopupMenu(self.top_menu,pt)
        self.log.log("Exit game_tree->on_rclick(self, evt)", ORPG_DEBUG)

    def on_ldclick(self, evt):
        self.log.log("Enter game_tree->on_ldclick(self, evt)", ORPG_DEBUG)
        self.rename_flag = 0
        pt = evt.GetPosition()
        (item, flag) = self.HitTest(pt)
        if item.IsOk():
            obj = self.GetPyData(item)
            self.SelectItem(item)
            if(isinstance(obj,core.node_handler)):
                if not obj.on_ldclick(evt):
                    action = self.settings.get_setting("treedclick")
                    if action == "use":
                        obj.on_use(evt)
                    elif action == "design":
                        obj.on_design(evt)
                    elif action == "print":
                        obj.on_html_view(evt)
                    elif action == "chat":
                        self.on_send_to_chat(evt)
        self.log.log("Exit game_tree->on_ldclick(self, evt)", ORPG_DEBUG)

    def on_left_down(self, evt):
        self.log.log("Enter game_tree->on_left_down(self, evt)", ORPG_DEBUG)
        pt = evt.GetPosition()
        (item, flag) = self.HitTest(pt)
        if item.IsOk() and self.was_labeling:
            self.SelectItem(item)
            self.rename_flag = 0
            self.was_labeling = 0
        elif (flag & wx.TREE_HITTEST_ONITEMLABEL) == wx.TREE_HITTEST_ONITEMLABEL and self.IsSelected(item):
            #  this next if tests to ensure that the mouse up occurred over a label, and not the icon
            self.rename_flag = 1
        else:
            self.SelectItem(item)
        evt.Skip()
        self.log.log("Exit game_tree->on_left_down(self, evt)", ORPG_DEBUG)

    def on_left_up(self, evt):
        self.log.log("Enter game_tree->on_left_up(self, evt)", ORPG_DEBUG)
        if self.dragging:
            cur = wx.StockCursor(wx.CURSOR_ARROW)
            self.SetCursor(cur)
            self.dragging = False
            pt = evt.GetPosition()
            (item, flag) = self.HitTest(pt)
            if item.IsOk():
                obj = self.GetPyData(item)
                self.SelectItem(item)
                if(isinstance(obj,core.node_handler)):
                    obj.on_drop(evt)
                    self.drag_obj = None
        self.log.log("Exit game_tree->on_left_up(self, evt)", ORPG_DEBUG)

    def on_label_change(self, evt):
        self.log.log("Enter game_tree->on_label_change(self, evt)", ORPG_DEBUG)
        item = evt.GetItem()
        txt = evt.GetLabel()
        self.was_labeling = 0
        self.rename_flag = 0
        if txt != "":
            obj = self.GetPyData(item)
            obj.master_dom.setAttribute('name',txt)
        else:
            evt.Veto()
        self.log.log("Exit game_tree->on_label_change(self, evt)", ORPG_DEBUG)

    def on_label_begin(self, evt):
        self.log.log("Enter game_tree->on_label_begin(self, evt)", ORPG_DEBUG)
        if not self.rename_flag:
            evt.Veto()
        else:
            self.was_labeling = 1
            item = evt.GetItem()
            if item == self.GetRootItem():
                evt.Veto()
        self.log.log("Exit game_tree->on_label_begin(self, evt)", ORPG_DEBUG)

    def on_drag(self, evt):
        self.log.log("Enter game_tree->on_drag(self, evt)", ORPG_DEBUG)
        self.rename_flag = 0
        item = self.GetSelection()
        obj = self.GetPyData(item)
        self.SelectItem(item)
        if(isinstance(obj,core.node_handler) and obj.drag):
            self.dragging = True
            cur = wx.StockCursor(wx.CURSOR_HAND)
            self.SetCursor(cur)
            self.drag_obj = obj
        self.log.log("Exit game_tree->on_drag(self, evt)", ORPG_DEBUG)

    def is_parent_node(self, node, compare_node):
        self.log.log("Enter game_tree->is_parent_node(self, node, compare_node)", ORPG_DEBUG)

        parent_node = self.GetItemParent(node)
        if compare_node == parent_node:

            self.log.log("parent node", ORPG_DEBUG)
            self.log.log("Exit game_tree->is_parent_node(self, node, compare_node)", ORPG_DEBUG)
            return 1
        elif parent_node == self.root:

            self.log.log("not parent", ORPG_DEBUG)
            self.log.log("Exit game_tree->is_parent_node(self, node, compare_node)", ORPG_DEBUG)
            return 0
        else:

            self.log.log("Exit game_tree->is_parent_node(self, node, compare_node)", ORPG_DEBUG)
            return self.is_parent_node(parent_node, compare_node)

CTRL_TREE_FILE = wx.NewId()
CTRL_YES = wx.NewId()
CTRL_NO = wx.NewId()
CTRL_USE = wx.NewId()
CTRL_DESIGN = wx.NewId()
CTRL_CHAT = wx.NewId()
CTRL_PRINT = wx.NewId()

class gametree_prop_dlg(wx.Dialog):
    def __init__(self, parent, settings):
        wx.Dialog.__init__(self, parent, wx.ID_ANY, "Game Tree Properties")
        self.settings  = settings

        #sizers
        sizers = {}
        sizers['but'] = wx.BoxSizer(wx.HORIZONTAL)
        sizers['main'] = wx.BoxSizer(wx.VERTICAL)

        #box sizers
        box_sizers = {}
        box_sizers["save"] = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, "Save On Exit"), wx.HORIZONTAL)
        box_sizers["file"] = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, "Tree File"), wx.HORIZONTAL)
        box_sizers["dclick"] = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, "Double Click Action"), wx.HORIZONTAL)
        self.ctrls = {  CTRL_TREE_FILE : FileBrowseButtonWithHistory(self, wx.ID_ANY,  labelText="" ) ,
                        CTRL_YES : wx.RadioButton(self, CTRL_YES, "Yes", style=wx.RB_GROUP),
                        CTRL_NO : wx.RadioButton(self, CTRL_NO, "No"),
                        CTRL_USE : wx.RadioButton(self, CTRL_USE, "Use", style=wx.RB_GROUP),
                        CTRL_DESIGN : wx.RadioButton(self, CTRL_DESIGN, "Desgin"),
                        CTRL_CHAT : wx.RadioButton(self, CTRL_CHAT, "Chat"),
                        CTRL_PRINT : wx.RadioButton(self, CTRL_PRINT, "Pretty Print")
                        }
        self.ctrls[CTRL_TREE_FILE].SetValue(settings.get_setting("gametree"))
        opt = settings.get_setting("SaveGameTreeOnExit")
        self.ctrls[CTRL_YES].SetValue(opt=="1")
        self.ctrls[CTRL_NO].SetValue(opt=="0")
        opt = settings.get_setting("treedclick")
        self.ctrls[CTRL_DESIGN].SetValue(opt=="design")
        self.ctrls[CTRL_USE].SetValue(opt=="use")
        self.ctrls[CTRL_CHAT].SetValue(opt=="chat")
        self.ctrls[CTRL_PRINT].SetValue(opt=="print")
        box_sizers['save'].Add(self.ctrls[CTRL_YES],0, wx.EXPAND)
        box_sizers['save'].Add(wx.Size(10,10))
        box_sizers['save'].Add(self.ctrls[CTRL_NO],0, wx.EXPAND)
        box_sizers['file'].Add(self.ctrls[CTRL_TREE_FILE], 0, wx.EXPAND)
        box_sizers['dclick'].Add(self.ctrls[CTRL_USE],0, wx.EXPAND)
        box_sizers['dclick'].Add(wx.Size(10,10))
        box_sizers['dclick'].Add(self.ctrls[CTRL_DESIGN],0, wx.EXPAND)
        box_sizers['dclick'].Add(wx.Size(10,10))
        box_sizers['dclick'].Add(self.ctrls[CTRL_CHAT],0, wx.EXPAND)
        box_sizers['dclick'].Add(wx.Size(10,10))
        box_sizers['dclick'].Add(self.ctrls[CTRL_PRINT],0, wx.EXPAND)

        # buttons
        sizers['but'].Add(wx.Button(self, wx.ID_OK, "Apply"), 1, wx.EXPAND)
        sizers['but'].Add(wx.Size(10,10))
        sizers['but'].Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), 1, wx.EXPAND)
        sizers['main'].Add(box_sizers['save'], 1, wx.EXPAND)
        sizers['main'].Add(box_sizers['file'], 1, wx.EXPAND)
        sizers['main'].Add(box_sizers['dclick'], 1, wx.EXPAND)
        sizers['main'].Add(sizers['but'], 0, wx.EXPAND|wx.ALIGN_BOTTOM )

        #sizers['main'].SetDimension(10,10,csize[0]-20,csize[1]-20)
        self.SetSizer(sizers['main'])
        self.SetAutoLayout(True)
        self.Fit()
        self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK)

    def on_ok(self,evt):
        self.settings.set_setting("gametree",self.ctrls[CTRL_TREE_FILE].GetValue())
        self.settings.set_setting("SaveGameTreeOnExit",str(self.ctrls[CTRL_YES].GetValue()))
        if self.ctrls[CTRL_USE].GetValue():
            self.settings.set_setting("treedclick","use")
        elif self.ctrls[CTRL_DESIGN].GetValue():
            self.settings.set_setting("treedclick","design")
        elif self.ctrls[CTRL_PRINT].GetValue():
            self.settings.set_setting("treedclick","print")
        elif self.ctrls[CTRL_CHAT].GetValue():
            self.settings.set_setting("treedclick","chat")
        self.EndModal(wx.ID_OK)