[Winopenrpg-developer] openrpg1/orpg/tools __init__.py,NONE,1.1 autoupdate.py,NONE,1.1 config_files.
Status: Inactive
Brought to you by:
digitalxero
|
From: Digital X. <dig...@us...> - 2006-01-26 17:33:28
|
Update of /cvsroot/winopenrpg/openrpg1/orpg/tools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30930/orpg/tools Added Files: __init__.py autoupdate.py config_files.py config_update.py inputValidator.py orpg_settings.py orpg_sound.py orpg_update.py passtool.py predTextCtrl.py rgbhex.py scriptkit.py server_probe.py toolBars.py Log Message: Initial commit of OpenRPG++ python --- NEW FILE: orpg_sound.py --- from orpg.orpg_windows import * if wxPlatform == '__WXMSW__': import winsound class orpg_sound: def __init__(self,unix_player=None): self.unix_player = unix_player def play(self,sound_file): if not sound_file: return if wxPlatform == '__WXMSW__': self.play_windows(sound_file) elif wxPlatform == '__WXGTK__': self.play_unix(sound_file) def play_windows(self,sound_file): print sound_file winsound.PlaySound(sound_file, winsound.SND_FILENAME) def play_unix(self,sound_file): if self.unix_player: os.system(self.unix_player + " " + sound_file + " &") --- NEW FILE: server_probe.py --- #!/usr/bin/env python # Copyright (C) 2000-2001 The OpenRPG Project # # ope...@li... # # 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: server_probe.py # Author: Chris Davis # Maintainer: # Version: # $Id: server_probe.py,v 1.1 2006/01/26 17:33:16 digitalxero Exp $ # # Description: This is a periodic maintenance script for removing # Unresponsive servers from the meta list. # from threading import Event from orpg.networking import mplay_client from orpg.networking import meta_server_lib import time class server_probe: def __init__(self): self.evts = { } self.evts['on_receive'] = self.on_receive self.evts['on_mplay_event'] = self.on_mplay_event self.evts['on_group_event'] = self.on_group_event self.evts['on_player_event'] = self.on_player_event self.evts['on_status_event'] = self.on_status_event self.session = mplay_client.mplay_client("Server Probe",self.evts) self.removed=0 self.ok =0 self.lock = Event() def probe_servers(self): names = [] addresses = [] node_list = None try: xml_dom = meta_server_lib.get_server_list(); node_list = xml_dom.getElementsByTagName('server') for n in node_list: address = n.getAttribute('address') name = n.getAttribute( 'name' ) id = n.getAttribute('id') if address not in addresses and name not in names: names.append( name ) addresses.append( address ) self.probe_server(address,id) else: # If we are here, we found a duplicate print "Duplicate entry, \"" + name + "\", is being removed." self.removed = self.removed + 1 meta_server_lib.remove_server(id) except: print "An exception has occured. Attempting to ignore it..." print "\n\nServers probe done " if node_list != None: print "Total Servers:" + str(len(node_list)) print "servers removed: " + str(self.removed) print "servers ok: " + str(self.ok) def probe_server(self,address,id): print "trying server: " + address if address == "asdfasdf": # replace with address of server to force from list print "Forced removal of server!!!!!!!!!!" meta_server_lib.remove_server(id) else: if self.session.connect(address): self.lock.wait( timeout=20 ) self.session.start_disconnect() while self.session.is_connected(): time.sleep( 1 ) self.session.check_my_status() print "server: " + address + " ok\n" self.ok = self.ok + 1 print "disconnected from valid server." else: print "**********>failed connnection!" print "**********>removng server " + address + "\n" self.removed = self.removed + 1 meta_server_lib.remove_server(id) ## meta_server_lib.post_failed_connection( id ) while self.session.is_connected(): time.sleep(1) def on_receive( self, evt, data ): """Not used """ self.lock.set() def on_mplay_event( self, evt ): """Not used """ self.lock.set() def on_group_event( self, evt ): """Not used """ self.lock.set() def on_player_event( self, evt ): """Disconnects from the server if a 'new player' event is generated. """ self.lock.set() def on_status_event( self, evt ): """Not used """ self.lock.set() if __name__ == "__main__": probe = server_probe() probe.probe_servers() --- NEW FILE: orpg_settings.py --- # Copyright (C) 2000-2001 The OpenRPG Project # # ope...@li... # # 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: orpg_settings.py # Author: Chris Davis # Maintainer: # Version: # $Id: orpg_settings.py,v 1.1 2006/01/26 17:33:16 digitalxero Exp $ # # Description: classes for orpg settings # from orpg.orpg_windows import * import orpg.dirpath import config_files import config_update from orpg.orpg_xml import * from rgbhex import * import sys import os class settings_grid(wxGrid): """grid for gen info""" def __init__(self, parent, setobj, settings, openrpg = None): wxGrid.__init__(self, parent, -1, style=wxSUNKEN_BORDER| wxWANTS_CHARS) self.openrpg = openrpg self.setting_data = [] EVT_SIZE(self, self.on_size) EVT_GRID_CELL_CHANGE(self, self.on_cell_change) EVT_GRID_CELL_LEFT_CLICK(self, self.on_left_click) self.CreateGrid(len(settings),3) self.SetRowLabelSize(0) self.SetColLabelValue(0,"Setting") self.SetColLabelValue(1,"Value") self.SetColLabelValue(2,"Available Options") for i in range(len(settings)): self.SetCellValue(i,0,settings[i]) value = setobj.get_setting(settings[i]) self.SetCellValue(i,1,value) if value and value[0] == '#': self.SetCellBackgroundColour(i,1,value) options = setobj.get_options(settings[i]) self.SetCellValue(i,2,options) self.setobj = setobj def on_left_click(self,evt): row = evt.GetRow() col = evt.GetCol() if col == 2: return elif col == 0: name = self.GetCellValue(row,0) str = self.setobj.get_help(name) msg = wxMessageBox(str,name) return setting = self.GetCellValue(row,0) value = self.GetCellValue(row,1) if value and value[0] == '#': hexcolor = RGBHex().do_hex_color_dlg(self) if hexcolor: self.setobj.set_setting(setting,hexcolor) self.SetCellBackgroundColour(row,1,hexcolor) self.Refresh() else: evt.Skip() def on_cell_change(self,evt): row = evt.GetRow() col = evt.GetCol() if col <> 1: return setting = self.GetCellValue(row,0) value = self.GetCellValue(row,1) self.setting_data += [[setting, value]] def get_h(self): (w,h) = self.GetClientSizeTuple() rows = self.GetNumberRows() minh = 0 for i in range (0,rows): minh += self.GetRowSize(i) minh += 120 return minh def on_size(self,evt): (w,h) = self.GetClientSizeTuple() cols = self.GetNumberCols() col_w = w/(cols) for i in range(0,cols): self.SetColSize(i,col_w) self.Refresh() ##----------------------------- ## Preferences Dialog ##----------------------------- class prefs_dialog(wxDialog): "Preferences dialog for OpenRPG" def __init__(self,parent,setobj,openrpg): SETTINGS_TABS = wxNewId() wxDialog.__init__(self,parent,-1,"OpenRPG Preferences",wxDefaultPosition,size = wxSize(-1,-1), style = wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION) self.chat = openrpg.get_component('chat') self.settings_tabs = wxNotebook(self, SETTINGS_TABS) self.settings_handlers = [] chat = [] tabs = [] general = [] map = [] gametree = [] macros = [] roomlist = [] toolbar = [] colors = [] settings = setobj.get_setting_keys() for m in range(len(settings)): if setobj.get_catagory(settings[m]) == "chat": chat.append(settings[m]) elif setobj.get_catagory(settings[m]) == "tabs": tabs.append(settings[m]) elif setobj.get_catagory(settings[m]) == "general": general.append(settings[m]) elif setobj.get_catagory(settings[m]) == "map": map.append(settings[m]) elif setobj.get_catagory(settings[m]) == "gametree": gametree.append(settings[m]) elif setobj.get_catagory(settings[m]) == "macros": macros.append(settings[m]) elif setobj.get_catagory(settings[m]) == "roomlist": roomlist.append(settings[m]) elif setobj.get_catagory(settings[m]) == "toolbar": toolbar.append(settings[m]) elif setobj.get_catagory(settings[m]) == "colors": colors.append(settings[m]) # general tab general_tab = settings_grid(self.settings_tabs,setobj,general) self.settings_handlers.append(general_tab) self.settings_tabs.AddPage(self.settings_handlers[0],"General") # chat tab chat_tab = settings_grid(self.settings_tabs,setobj,chat) self.settings_handlers.append(chat_tab) self.settings_tabs.AddPage(self.settings_handlers[1],"Chat") # tabs tab tabs_tab = settings_grid(self.settings_tabs,setobj,tabs) self.settings_handlers.append(tabs_tab) self.settings_tabs.AddPage(self.settings_handlers[2],"Chat Tabs") # map tab map_tab = settings_grid(self.settings_tabs,setobj,map) self.settings_handlers.append(map_tab) self.settings_tabs.AddPage(self.settings_handlers[3],"Map") # gametree tab gametree_tab = settings_grid(self.settings_tabs,setobj,gametree) self.settings_handlers.append(gametree_tab) self.settings_tabs.AddPage(self.settings_handlers[4],"Game Tree") # macros tab macros_tab = settings_grid(self.settings_tabs,setobj, macros) self.settings_handlers.append(macros_tab) self.settings_tabs.AddPage(self.settings_handlers[5],"Macros") # Game Server/Room List tab roomlist_tab = settings_grid(self.settings_tabs,setobj, roomlist) self.settings_handlers.append(roomlist_tab) self.settings_tabs.AddPage(self.settings_handlers[6],"Server/Room Lists") # Chat Toolbar tab toolbar_tab = settings_grid(self.settings_tabs,setobj, toolbar) self.settings_handlers.append(toolbar_tab) self.settings_tabs.AddPage(self.settings_handlers[7],"Chat Toolbar") # Chat Colors tab colors_tab = settings_grid(self.settings_tabs,setobj, colors) self.settings_handlers.append(colors_tab) self.settings_tabs.AddPage(self.settings_handlers[8],"Chat Colors") winsizer = wxBoxSizer(wxVERTICAL) sizer = wxBoxSizer(wxHORIZONTAL) tab_sizer = wxBoxSizer(wxHORIZONTAL) tab_sizer.Add(self.settings_tabs, 1, wxEXPAND) sizer.Add(wxButton(self, wxID_OK, "OK"), 1, wxEXPAND) sizer.Add(wxSize(10,10)) sizer.Add(wxButton(self, wxID_CANCEL, "Cancel"), 1, wxEXPAND) winsizer.Add(tab_sizer, 1, wxEXPAND | wxALIGN_TOP) winsizer.Add(sizer, 0, wxEXPAND | wxALIGN_BOTTOM) self.general_tab = general_tab self.chat_tab = chat_tab self.tabs_tab = tabs_tab self.map_tab = map_tab self.gametree_tab = gametree_tab self.macros_tab = macros_tab self.roomlist_tab = roomlist_tab self.toolbar_tab = toolbar_tab self.colors_tab = colors_tab self.setobj = setobj self.winsizer = winsizer minh = self.general_tab.get_h() if minh > 750: minh = 750 self.SetSize((580,minh+10)) self.winsizer.SetDimension(0,0,580,minh-25) EVT_BUTTON(self, wxID_OK, self.on_ok) EVT_NOTEBOOK_PAGE_CHANGED(self, SETTINGS_TABS, self.on_page_change) EVT_SIZE(self, self.on_size) def on_size(self,evt): (w,h) = self.GetClientSizeTuple() self.winsizer.SetDimension(0,0,w,h-25) def on_page_change(self,evt): p = self.settings_tabs.GetPage(evt.GetOldSelection()) p.SaveEditControlValue() p.HideCellEditControl() tmp = evt.GetSelection() if tmp == 0: minh = self.general_tab.get_h() elif tmp == 1: minh = self.chat_tab.get_h() elif tmp == 2: minh = self.tabs_tab.get_h() elif tmp == 3: minh = self.map_tab.get_h() elif tmp == 4: minh = self.gametree_tab.get_h() elif tmp == 5: minh = self.macros_tab.get_h() elif tmp == 6: minh = self.roomlist_tab.get_h() elif tmp == 7: minh = self.toolbar_tab.get_h() elif tmp == 8: minh = self.colors_tab.get_h() if minh > 750: minh = 750 self.SetSize((580,minh+10)) self.winsizer.SetDimension(0,0,580,minh-25) def on_ok(self,evt): #tablist = [self.settings_tabs.GetPage(t) for t in range(0,self.settings_tabs.GetPageCount())] for t in range(0,self.settings_tabs.GetPageCount()): self.settings_tabs.GetPage(t).SaveEditControlValue() for m in self.general_tab.setting_data: self.setobj.set_setting(m[0],m[1]) for m in self.chat_tab.setting_data: self.setobj.set_setting(m[0],m[1]) if m[0] == "tabbedwhispers": self.warning_msg() try: if len(self.chat.parent.panel_list) > 0: for panel in self.chat.parent.panel_list: if m[0] == "defaultfont": panel.set_default_font(fontname=m[1]) elif m[0] == "defaultfontsize": panel.set_default_font(fontsize=int(m[1])) raise Exception() except: if m[0] == "defaultfont": self.chat.set_default_font(fontname=m[1]) elif m[0] == "defaultfontsize": self.chat.set_default_font(fontsize=int(m[1])) for m in self.map_tab.setting_data: self.setobj.set_setting(m[0],m[1]) for m in self.tabs_tab.setting_data: self.setobj.set_setting(m[0],m[1]) if m[0] == "tabbedwhispers": self.warning_msg() if m[0] == "GMWhisperTab" and m[1] == '1': self.chat.parent.create_gm_tab() for m in self.gametree_tab.setting_data: self.setobj.set_setting(m[0],m[1]) for m in self.macros_tab.setting_data: self.setobj.set_setting(m[0],m[1]) for m in self.roomlist_tab.setting_data: self.setobj.set_setting(m[0],m[1]) for m in self.colors_tab.setting_data: self.setobj.set_setting(m[0],m[1]) for m in self.toolbar_tab.setting_data: self.setobj.set_setting(m[0],m[1]) ##tabbed whispers are on try: if len(self.chat.parent.panel_list) > 0: for panel in self.chat.parent.panel_list: if m[0] == 'AliasTool_On': panel.toggle_alias(m[1]) elif m[0] == 'ToGMsButton_On': panel.toggle_gm(m[1]) elif m[0] == 'DiceButtons_On': panel.toggle_dice(m[1]) elif m[0] == 'FormattingButtons_On': panel.toggle_formating(m[1]) raise Exception() except: if m[0] == 'AliasTool_On': self.chat.toggle_alias(m[1]) elif m[0] == 'ToGMsButton_On': self.chat.toggle_gm(m[1]) elif m[0] == 'DiceButtons_On': self.chat.toggle_dice(m[1]) elif m[0] == 'FormattingButtons_On': self.chat.toggle_formating(m[1]) self.general_tab.DisableCellEditControl() self.chat_tab.DisableCellEditControl() self.map_tab.DisableCellEditControl() self.gametree_tab.DisableCellEditControl() self.macros_tab.DisableCellEditControl() self.roomlist_tab.DisableCellEditControl() self.toolbar_tab.DisableCellEditControl() self.colors_tab.DisableCellEditControl() self.EndModal(wxID_OK) def warning_msg(self): warning_dlg = wxMessageBox("You will need to restart for\nthese changes to take effect", "Information") #################### ## settings xml object #################### class settings: def __init__(self): ini_xml="ini.xml" index=1 while(index<len(sys.argv)-1): if (sys.argv[index] == "-i"): ini_xml=sys.argv[index+1] sys.argv[index]="" sys.argv[index+1]="" index = index + 1 # This stores a dictionary of runnable objects that will be called # when a key's value gets set. See settings.set_change_handler() self.change_handler = {} # Load the tree self.setup_ini(ini_xml) #=================================================== # setup_ini() # # Reworked for version 1.6.3 release. --Snowdog (5/10/05) # Revamped tree loading proceedure # Added new user ini updater to auto-add missing keys #=================================================== def setup_ini(self,ini_xml): default_filename = "default_ini.xml" #default ini template name self.filename = orpg.dirpath.dir_struct["user"] + ini_xml # This is the filename we're going attempt to use template = orpg.dirpath.dir_struct["template"]+default_filename #template fully qualified filename result = config_files.validate_config_file(ini_xml,default_filename) #ensures user ini file exists (by creating it if it doesn't) if (result == 2): #file user_file was created. Print console warning. print("Config file "+ini_xml+" was created from default template.") if (result == 0): msg = wxMessageDialog(None,"Restore " + ini_xml + " or default_ini.xml and start again.","Settings files bad or missing",wxOK) msg.ShowModal() msg.Destroy() sys.exit() my_tree = self.loadTree(self.filename) #get the DOM for the config file if ( not my_tree ): text = ini_xml + " structure invalid.\nUsing default config file instead.\nPlease remove or repair "+ini_xml+" file." msg = wxMessageDialog(None,text,"Config File Error",wxOK) msg.ShowModal() msg.Destroy() if (os.path.exists(template)): my_tree = self.loadTree(template) if (not my_tree): text = default_filename + " template invalid.\nPlease obtain a new copy of the template file. OpenRPG cannot load config information and will terminate." msg = wxMessageDialog(None,text,"Unrecoverable Error",wxOK) msg.ShowModal() msg.Destroy() sys.exit() #savedAs = self.saveTreeSafely(ini_xml, my_tree) #move the old ini.xml file out of the way. This has to be done with file I/O cause the tree is not viable savedAs = self.saveTreeSafely(ini_xml, my_tree) text = "Your "+ini_xml+" config file has been automatically repaired.\nYour original version has been saved as "+savedAs+" if needed." msg = wxMessageDialog(None,text,"Config File Updated",wxOK) msg.ShowModal() msg.Destroy() if (result == 1): #file was loaded from the user file... if (config_update.UpdateIniFile(my_tree, template)): #verify all keys against the template ini file and update/add if required. #user ini has been updated. Save to disk. savedAs = self.saveTreeSafely(ini_xml, my_tree) text = "Your "+ini_xml+" config file has been automatically updated.\nYour original version has been saved as "+savedAs+" if needed." msg = wxMessageDialog(None,text,"Config File Updated",wxOK) msg.ShowModal() msg.Destroy() #At this point my_tree should contain valid and template updated config data self.xml_dom = my_tree def reload_settings(self,chat): try: chat.session.set_name(self.get_setting("player")) chat.set_colors() chat.set_buffersize() chat.roller_manager.set_roller(self.get_setting('dieroller')) except Exception,e: print e chat.InfoPost("One or more settings were invalid check your settings") def loadTree(self, filename): try: ini = open(filename,"r") txt = ini.read() tree = parseXml(txt)._get_documentElement() ini.close() return tree except: return None def load(self, filename): self.xml_dom = self.loadTree(filename) if self.xml_dom: return 1 else: return 0 def get_tree_setting_keys(self,tree,hidden=0): node_list = tree._get_childNodes() keys = [] for n in node_list: if not hidden and n.getAttribute("hidden"): #all none hidden elements continue keys.append(n._get_tagName()) return keys def get_setting_keys(self,hidden=0): return self.get_tree_setting_keys(self.xml_dom,hidden) def get_tree_xml_node(self,tree,name): node_list = tree.getElementsByTagName(name) if not len(node_list): node = minidom.Element(name) node = tree.appendChild(node) #print tree.toxml(1) node_list = tree.getElementsByTagName(name) return node_list[0] def get_xml_node(self,name): return self.get_tree_xml_node(self.xml_dom,name) def get_tree_value(self,tree,name,create = 1,attrib = "value"): node = self.get_tree_xml_node(tree,name) return node.getAttribute(attrib) def get_setting(self,name,create=1): return self.get_tree_value(self.xml_dom,name,create) def get_help(self,name): node = self.get_tree_xml_node(self.xml_dom,name) try: str = node.getAttribute("help") # # funkyness to allow \n in help names display properly in dialog. # if you can find a better way then go for it. # splited = str.split("\\n") return_str = "" for m in range(len(splited)): return_str = return_str + splited[m] +"\n" # # end of funkyness # if return_str == "\n": return_str = "No help available for this setting" return return_str except: return "No help available for this setting" def get_catagory(self,name): node = self.get_tree_xml_node(self.xml_dom,name) try: catagory = node.getAttribute("catagory").lower() if catagory == "": catagory = "general" return catagory except: return "general" def get_options(self,name): node = self.get_tree_xml_node(self.xml_dom,name) try: option = node.getAttribute("options") except: option = "" return option def set_change_handler(self,key,handler): # takes a key (key) to watch and runnable object (handler) to execute # when key changes. When handler is executed, it is passed a single # argument, which will hold the value being stored. self.change_handler[key] = handler def get_change_handler(self,key): if self.change_handler.has_key(key): return self.change_handler[key] else: return None def set_tree_value(self,tree,name,value,hidden = 0, attrib="value"): node = self.get_tree_xml_node(tree,name) node.setAttribute(attrib,value) if hidden: node.setAttribute("hidden", "true") if self.change_handler.has_key(name) and attrib == "value": self.change_handler[name](value) def set_setting(self,name,value,hidden=0): node = self.get_xml_node(name) node.setAttribute("value",value) if hidden: node.setAttribute("hidden", "true") if self.change_handler.has_key(name): self.change_handler[name](value) def get_tree_multi_setting(self,tree,name): node_list = tree.getElementsByTagName(name) node_list = node_list[0]._get_childNodes() if len(node_list) == 0: return None ary = [] for n in node_list: ary.append(n.getAttribute("value")) return ary def get_multi_setting(self,name): return self.get_tree_multi_setting(self.xml_dom,name) def saveTree(self,tree): ini = open(self.filename,"w") ini.write(toxml(tree,1)) ini.close() def save(self): self.saveTree(self.xml_dom) #========================================================== # saveTreeSafely() # # Moves a copy of the original ini file out of the way # then saves the (updated) ini data to the original location # automatic filename postfix prevents file overwrite # 5/10/05 --Snowdog #========================================================== def saveTreeSafely(self, baseFilename, tree): #write file to disk making sure not to overwrite an existing file. index = 1 file = baseFilename+"-"+str(index) while ( os.path.exists(orpg.dirpath.dir_struct["user"]+file)): index = index +1 file = baseFilename+"-"+str(index) #move the original ini out of the way os.rename(orpg.dirpath.dir_struct["user"]+baseFilename, orpg.dirpath.dir_struct["user"]+file) #write the updated file ini = open(orpg.dirpath.dir_struct["user"] + baseFilename,"w") ini.write(toxml(tree,1)) ini.close() return file --- NEW FILE: predTextCtrl.py --- # Copyright (C) 2001 The OpenRPG Project # # ope...@li... # # 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: predTextCtrl.py # Author: Andrew Bennett # Maintainer: Andrew Bennett # Version: $id:$ # # Description: This file contains an extension to the wxPython wxTextCtrl that provides predictive word completion # based on a word file loaded at instantiation. Also, it learns new words as you type, dynamically # adjusting a weight for each word based on how often you type it. # ## ## Module Loading ## import string from orpg.orpg_windows import * # This line added to test CVS commit ## ## Class Definitions ## # This class implements a tree node that represents a letter # # Defines: # __init__(self,filename) # class Letter: def __init__(self,asciiCharIn,parentNodeIn): self.asciiChar = asciiCharIn # should be an ASCII char self.parentNode = parentNodeIn # should be ref to a class Letter self.priority = 0 # should be an int self.mostCommon = self # should be a ref to a class Letter self.children = {} # should be a ref to a dictionary of class Letter # This class implements the tree structure to hold the words # # Defines: # __init__(self,filename) # updateMostCommon(self,target) # setWord(self,wordText,priority,sumFlag) # addWord(self,wordText) # setWord(self,wordText) # setWordPriority(self,wordText,priority) # findWordNode(self,wordText) returns class Letter # findWordPriority(self,wordText) returns int # getPredition(self,k,cur) returns string class LetterTree: # Initialization subroutine. # # self : instance of self # filename : name of word file to use # # returns None # # Purpose: Constructor for LetterTree. Basically, it initializes itself with a word file, if present. def __init__(self,filename): self.rootNode = Letter("",None) # rootNode is a class Letter self.rootNode.children = {} # initialize the children list try: FILE = open(filename,"r") for line in FILE.readlines(): # read-in each line and ... self.addWord(string.lower(string.strip(line))) # ... add a stripped, lowercased version of it to the tree FILE.close() except: # silently ignore errors here pass # updateMostCommon subroutine. # # self : instance of self # target : class Letter that was updated # # Returns None # # Purpose: Updates all of the parent nodes of the target, such that their mostCommon member # points to the proper class Letter, based on the newly updated priorities. def updateMostCommon(self, target): # cur is a class Letter prev = target.parentNode # prev is a class Letter while prev: if prev.mostCommon is None: prev.mostCommon = target else: if target.priority > prev.mostCommon.priority: prev.mostCommon = target prev = prev.parentNode # setWord subroutine. # # self : instance of self # wordText : string representing word to add # priority : integer priority to set the word # sumFlag : if true, add the priority to the existing, else assign the priority # # Returns: None # # Purpose: Sets or increments the priority of a word, adding the word if necessary def setWord(self,wordText,priority = 1,sumFlag = 0): cur = self.rootNode # start from the root for ch in wordText: # for each character in the word if cur.children.has_key(ch): # check to see if we've found a new word cur = cur.children[ch] # if we haven't found a new word, move to the next letter and try again else: # in this clause, we're creating a new branch, as the word is new newLetter = Letter(ch,cur) # create a new class Letter using this ascii code and the current letter as a parent if cur is self.rootNode: # special case: Others expect the top level letters to point to None, not self.rootNode newLetter.parentNode = None cur.children[ch] = newLetter # add the new letter to the list of children of the current letter cur = newLetter # make the new letter the current one for the next time through # at this point, cur is pointing to the last letter of either a new or existing word. if sumFlag: # if the caller wants to add to the existing (0 if new) cur.priority += priority else: # else, the set the priority directly cur.priority = priority self.updateMostCommon(cur) # this will run back through the tree to fix up the mostCommon members # addWord subroutine. # # self : instance of self # wordText : string representing word to add # # Returns: None # # Purpose: Convenience method that wraps setWord. Used to add words known not to exist. def addWord(self,wordText): self.setWord(wordText,priority = 1) # incWord subroutine. # # self : instance of self # wordText : string representing word to add # # Returns: None # # Purpose: Convenience method that wraps setWord. Used to increment the priority of existing words and add new words. # Note: Generally, this method can be used instead of addWord. def incWord(self,wordText): self.setWord(wordText,priority = 1, sumFlag = 1) # setWordPriority subroutine. # # self : instance of self # wordText : string representing word to add # priority: int that is the new priority # # Returns: None # # Purpose: Convenience method that wraps setWord. Sets existing words to priority or adds new words with priority = priority def setWordPriority(self,wordText,priority): self.setWord(wordText,priority = priority) # findWordNode subroutine. # # self : instance of self # wordText : string representing word to add # # Returns: class Letter or None if word isn't found. # # Purpose: Given a word, it returns the class Letter node that corresponds to the word. Used mostly in prep for a call to # getPrediction() def findWordNode(self,wordText): #returns class Letter that represents the last letter in the word cur = self.rootNode # start at the root for ch in wordText: # move through each letter in the word if cur.children.has_key(ch): # if the next letter exists, make cur equal that letter and loop cur = cur.children[ch] else: return None # return None if letter not found return cur # return cur, as this points to the last letter if we got this far # findWordPriority subroutine. # # self : instance of self # wordText : string representing word to add # # Returns: Int representing the word's priority or 0 if not found. # # Purpose: Returns the priority of the given word def findWordPriority(self,wordText): cur = self.findWordNode(wordText) # find the class Letter node that corresponds to this word if cur: return cur.priority # if it was found, return it's priority else: return 0 # else, return 0, meaning word not found # getPrediction subroutine. # # self : instance of self # k : ASCII char that was typed # cur : class Letter that points to the current node in LetterTree # # Returns: The predicted text or "" if none found # # Purpose: This is the meat and potatoes of data structure. It takes the "current" Letter node and the next key typed # and returns it's guess of the rest of the word, based on the highest priority letter in the rest of the branch. def getPrediction(self,k,cur): if cur.children.has_key(k) : # check to see if the key typed is a sub branch # If so, make a prediction. Otherwise, do the else at the bottom of # the method (see below). cur = cur.children[k] # set the cur to the typed key's class Letter in the sub-branch backtrace = cur.mostCommon # backtrace is a class Letter. It's used as a placeholder to back trace # from the last letter of the mostCommon word in the # sub-tree up through the tree until we meet ourself at cur. We'll # build the guess text this way returnText = "" # returnText is a string. This will act as a buffer to hold the string # we build. while cur is not backtrace: # Here's the loop. We loop until we've snaked our way back to cur returnText = backtrace.asciiChar + returnText # Create a new string that is the character at backtrace + everything # so far. So, for "tion" we'll build "n","on","ion","tion" as we .. backtrace = backtrace.parentNode # ... climb back towards cur return returnText # And, having reached here, we've met up with cur, and returnText holds # the string we built. Return it. else: # This is the else to the original if. # If the letter typed isn't in a sub branch, then # the letter being typed isn't in our tree, so return "" # return the empty string # End of class LetterTree! # This class extends wxTextCtrl # # Extends: wxTextCtrl # # Overrides: # wxTextCtrl.__init__(self,parent,id,value,size,style,name) # wxTextCtrl.OnChar(self,Event) # # Defines: # findWord(self,insert,st) class predTextCtrl(orpgTextCtrl): # Initialization subroutine. # # self : instance of self # parent: reference to parent window (wxWindow, me-thinks) # id: new Window Id, default to -1 to create new (I think: see docs for wxPython) # value: String that is the initial value the control holds, defaulting to "" # size: defaults to wxDefaultSize # style: defaults to 0 # name: defaults to "text" # keyHook: must be a function pointer that takes self and a KeyCode object # validator: defaults to None # # Note: These parameters are essentially just passed back to the native wxTextCtrl. # I basically just included (stole) enough of them from chatutils.py to make # it work. Known missing args are pos and validator, which aren't used by # chatutils.py. # # Returns: None # # Purpose: Constructor for predTextCtrl. Calls wxTextCtrl.__init__ to get default init # behavior and then inits a LetterTree and captures the parent for later use in # passing events up the chain. def __init__(self, parent, id = -1, value = "" , size = wxDefaultSize, style = 0, name = "text",keyHook = None, validator=None): # Call super() for default behavior orpgTextCtrl.__init__(self,parent,id = id,value = value,size = size,style = style,name = name, validator = validator ) self.tree = LetterTree("defaultwordlist.txt") # Instantiate a new LetterTree. # TODO: make name of word file an argument. self.parent = parent # Save parent for later use in passing KeyEvents self.cur = self.tree.rootNode # self.cur is a short cut placeholder for typing consecutive chars # It may be vestigal self.keyHook = keyHook # Save the keyHook passed in # findWord subroutine. # # self : instance of self # insert: index of last char in st # st : string from insert to the left # # Note: This implementation is about the third one for this method. Originally, # st was an arbitrary string and insert was the point within # this string to begin looking left. Since, I finally got it # to work right as it is around 2 in the morning, I'm not touching it, for now. # # Returns: String that is the word or "" if none found. This generally doesn't # happen, as st usually ends in a letter, which will be returned. # # Purpose: This function is generally used to figure out the beginning of the # current word being typed, for later use in a LetterTree.getPrediction() def findWord(self,insert,st): # Good luck reading this one. Basically, I started out with an idea, and fiddled with the # constants as best I could until it worked. It's not a piece of work of which I'm too # proud. Basically, it's intent is to check each character to the left until it finds one # that isn't a letter. If it finds such a character, it stops and returns the slice # from that point to insert. Otherwise, it returns the whole thing, due to begin being # initialized to 0 begin = 0 for offset in range(insert - 1): if st[-(offset + 2)] not in string.letters: begin = insert - (offset + 1) break return st[begin:insert] # OnChar subroutine. # # self : instance of self # event: a KeyCode object # # Returns: None # # Purpose: This function is the key event handler for predTextCtrl. It handles what it # needs to and passes the event on to it's parent's OnChar method. def OnChar(self,event): # Before we do anything, call the keyHook handler, if not None # This is currently used to implement the typing/not_typing messages in a manner that # doesn't place the code here. Maybe I should reconsider that. :) if(self.keyHook): if self.keyHook(event) == 1: # if the passed in keyHook routine returns a one, it wants no predictive behavior self.parent.OnChar(event) return # This bit converts the KeyCode() return (int) to a char if it's in a certain range asciiKey = "" if (event.KeyCode() < 256) and (event.KeyCode() > 19): asciiKey = chr(event.KeyCode()) if asciiKey == "": # If we didn't convert it to a char, then process based on the int KeyCodes if event.KeyCode() == WXK_TAB: # We want to hook tabs to allow the user to signify acceptance of a # predicted word. # Handle Tab key fromPos = toPos = 0 # get the current selection range (fromPos,toPos) = self.GetSelection() if (toPos - fromPos) == 0: # if there is no selection, pass tab on self.parent.OnChar(event) return else: # This means at least one char is selected self.SetInsertionPoint(toPos) # move the insertion point to the end of the selection self.SetSelection(toPos,toPos) # and set the selection to no chars # The prediction, if any, had been inserted into the text earlier, so # moving the insertion point to the spot directly afterwards is # equivalent to acceptance. Without this, the next typed key would # clobber the prediction. return # Don't pass tab on in this case elif event.KeyCode() == WXK_RETURN: # We want to hook returns, so that we can update the word list st = self.GetValue() # Grab the text from the control newSt = "" # Init a buffer # This block of code, by popular demand, changes the behavior of the control to ignore any prediction that # hasn't been "accepted" when the enter key is struck. (startSel,endSel) = self.GetSelection() # get the curren selection # # Start update # Changed the following to allow for more friendly behavior in # a multilined predTextCtrl. # # front = st[:startSel] # Slice off the text to the front of where we are # back = st[endSel:] # Slice off the text to the end from where we are # st = front + back # This expression creates a string that get rid of any selected text. # self.SetValue(st) self.Remove( startSel, endSel ) st = string.strip( self.GetValue() ) # # End update # # this loop will walk through every character in st and add it to # newSt if it's a letter. If it's not a letter, (e.g. a comma or # hyphen) a space is added to newSt in it's place. for ch in st: if ch not in string.letters: newSt += " " else: newSt += ch # Now that we've got a string of just letter sequences (words) and spaces # split it and to a LetterTree.incWord on the lowercase version of it. # Reminder: incWord will increment the priority of existing words and add # new ones for aWord in string.split(newSt): self.tree.incWord(string.lower(aWord)) self.parent.OnChar(event) # Now that all of the words are added, pass the event and return return # We want to capture the right arrow key to fix a slight UI bug that occurs when one right arrows # out of a selection. I set the InsertionPoint to the beginning of the selection. When the default # right arrow event occurs, the selection goes away, but the cursor is in an unexpected location. # This snippet fixes this behavior and then passes on the event. elif event.KeyCode() == WXK_RIGHT: (startSel,endSel) = self.GetSelection() self.SetInsertionPoint(endSel) self.parent.OnChar(event) return # Ditto as WXK_RIGHT, but for completeness sake elif event.KeyCode() == WXK_LEFT: (startSel,endSel) = self.GetSelection() self.SetInsertionPoint(startSel) self.parent.OnChar(event) return else: # Handle any other non-ascii events by calling parent's OnChar() self.parent.OnChar(event) #Call super.OnChar to get default behavior return elif asciiKey in string.letters: # This is the real meat and potatoes of predTextCtrl. This is where most of the # wxTextCtrl logic is changed. (startSel,endSel) = self.GetSelection() # get the curren selection st = self.GetValue() # and the text in the control front = st[:startSel] # Slice off the text to the front of where we are back = st[endSel:] # Slice off the text to the end from where we are st = front + asciiKey + back # This expression creates a string that will insert the # typed character (asciiKey is generated at the # beginning of OnChar()) into the text. If there # was text selected, that text will not be part # of the new string, due to the way front and back # were sliced. insert = startSel + 1 # creates an int that denotes where the new InsertionPoint # should be. curWord = "" # Assume there's a problem with finding the curWord if (len(back) == 0) or (back[0] not in string.letters): # We should only insert a prediction if we are typing # at the end of a word, not in the middle. There are # three cases: we are typing at the end of the string or # we are typing in the middle of the string and the next # char is NOT a letter or we are typing in the middle of the # string and the next char IS a letter. Only the former two # cases denote that we should make a prediction # Note: The order of the two logical clauses here is important! # If len(back) == 0, then the expression back[0] will # blow up with an out of bounds array subscript. Luckily # the or operator is a short-circuit operator and in this # case will only evaluate back[0] if len(back) != 0, in # which we're safely in bounds. curWord = self.findWord(insert,front + asciiKey) # Now that we know we're supposed to make a prediction, # let's find what word root to use in our prediction. # Note: This is using the confusing findWord method. I # send it insert and the text from the beginning # of the text through the key just entered. This is # NOT the original usage, but it does work. See # findWord() for more details. else: # Here, we've found we're in the middle of a word, so we're # going to call the parent's event handler. self.parent.OnChar(event) return if curWord == "": # Here, we do a quick check to make sure we have a good root # word. If not, allow the default thing to happen. Of course, # now that I'm documenting this, it occurs to me to wonder why # I didn't do the same thing I just talked about. Hmmmmmm. self.parent.OnChar(event) # we're done here return self.cur = self.tree.findWordNode(string.lower(curWord[:-1])) # Still with me? We're almost done. At this point, we # need to convert our word string to a Letter node, # because that's what getPrediction expects. Notice # that we're feeding in the string with the last # char sliced off. For developmentally historical # reasons, getPrediction wants the node just before # the typed character and the typed char separately. if self.cur is None: self.parent.OnChar(event) # if there's no word or no match, we're done return # get the prediction predictText = self.tree.getPrediction(string.lower(asciiKey),self.cur) # This is the big prediction, as noted above # Note the use of string.lower() because we # keep the word list in all lower case,but we # want to be able to match any capitalization if predictText == "": self.parent.OnChar(event) # if there's no prediction, we're done return # And now for the big finale. We're going to take the string st # we created earlier and insert the prediction right after the # newly typed character. front = st[:insert] # Grab a new front from st back = st[insert:] # Grab a new back st = front + predictText + back # Insert the prediction self.SetValue(st) # Now, overwrite the controls text with the new text self.SetInsertionPoint(insert) # Set the proper insertion point, directly behind the # newly typed character and directly in front of the # predicted text. self.SetSelection(insert,insert+len(predictText)) # Very important! Set the selection to encompass the predicted # text. This way, the user can ignore the prediction by simply # continuing to type. Remember, if the user wants the prediction # s/he must strike the tab key at this point. Of course, one could # just use the right arrow key as well, but that's not as easy to # reach. return # Done! Do NOT pass the event on at this point, because it's all done. else: # Handle every other non-letter ascii (e.g. semicolon) by passing the event on. self.parent.OnChar(event) #Call super.OnChar to get default behavior return # End of class predTextCtrl! --- NEW FILE: config_files.py --- # file: config_files.py # # Author: Todd Faris (Snowdog) # Date: 5/10/2005 # # Misc. config file service methods # import orpg.dirpath import os def validate_config_file(user_file,template_file): #STEP 1: verify the template exists if (not os.path.exists(orpg.dirpath.dir_struct["template"] + template_file)): return 0 #STEP 2: verify the user file exists. If it doesn't then create it from template if (not os.path.exists(orpg.dirpath.dir_struct["user"]+user_file)): default = open(orpg.dirpath.dir_struct["template"] + template_file,"r") file = default.read() newfile = open(orpg.dirpath.dir_struct["user"] + user_file,"w") newfile.write(file) default.close() newfile.close() return 2 #returning 2 (True) so calling method will know if file was created #STEP 3: user file exists (is openable) return 1 indicating no-create operation required else: return 1 --- NEW FILE: __init__.py --- __all__ = ['inittool','inputValidatior', 'orpg_settings' , 'orpg_update', 'predTextCtrl', 'rgbhex', 'scriptkit', 'server_probe', 'toolBars' ] --- NEW FILE: config_update.py --- # file: config_update.py # # Author: Todd Faris (Snowdog) # Date: 5/10/2005 # # Comparison and update functions for openrpg's main config (.ini) file # #----IMPORTS---- from orpg.orpg_xml import * #----CONSTANTS---- AUTOUPDATE_KEY_NAME = "autoupdate_config" #---------------------------------------------------------------------------------------- # UpdateIniFile() # Orchistrates the updating of the users settings ini (ini.xml) file. # Returns number of chances made to memory loaded tree. If non-zero the # tree should be resaved. #---------------------------------------------------... [truncated message content] |