diff orpg/gametree/gametree.py @ 0:4385a7d0efd1 grumpy-goblin

Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author sirebral
date Tue, 14 Jul 2009 16:41:58 -0500
parents
children c54768cffbd4
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orpg/gametree/gametree.py	Tue Jul 14 16:41:58 2009 -0500
@@ -0,0 +1,1073 @@
+# 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)