加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
ProperTree-old.py 26.20 KB
一键复制 编辑 原始数据 按行查看 历史
btwise 提交于 2020-10-14 16:16 . update
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
#!/usr/bin/env python
#coding:utf-8
import sys, os, binascii, base64, json, re, ctypes
from collections import OrderedDict
try:
import Tkinter as tk
import ttk
import tkFileDialog as fd
import tkMessageBox as mb
except:
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import filedialog as fd
from tkinter import messagebox as mb
# Add this script's dir to the local PATH var - may improve import consistency
sys.path.append(os.path.abspath(os.path.dirname(os.path.realpath(__file__))))
from Scripts import *
class ProperTree:
def __init__(self, plists = []):
# Create the new tk object
self.tk = tk.Tk()
self.tk.title("转换值")
self.tk.minsize(width=640,height=130)
self.tk.resizable(True, False)
self.tk.columnconfigure(2,weight=1)
self.tk.columnconfigure(3,weight=1)
# Build the Hex <--> Base64 converter
f_label = tk.Label(self.tk, text="从:")
f_label.grid(row=0,column=0,padx=10,pady=10)
t_label = tk.Label(self.tk, text="到:")
t_label.grid(row=1,column=0,padx=10,pady=10)
#about Window
def create_about():
about = tk.Toplevel(self.tk)
about.title('关于ProperTree')
w = 300
h = 160
about.minsize(width=w,height=h)
about.resizable(False,False)
about.columnconfigure(0,weight=1)
about.columnconfigure(1,weight=1)
x1 = about.winfo_screenwidth() // 2 - w // 2
y1 = about.winfo_screenheight() // 2 - h // 2
about.geometry("{}x{}+{}+{}".format(w,h, x, y))
top1_label = tk.Label(about,width=300,background="#ececec")
top2_label = tk.Label(about,width=300,background="#ececec")
top3_label = tk.Label(about,text="PreperTree编辑器\nCopyright© 2019 CorpNewt",font=("宋体", -15),width=300,background="#ececec")
zuozhe_label = tk.Label(about,text="作者:CorpNewt",font=("宋体", 15),foreground = "blue")
hh_label = tk.Label(about,text="汉化:草原企鹅",font=("宋体", 15),foreground = "blue")
buttom1_label = tk.Label(about,width=300,background="#ececec")
buttom2_label = tk.Label(about,width=300,background="#ececec")
top1_label.grid(row=0,column=0)
top2_label.grid(row=1,column=0)
top3_label.grid(row=2,column=0)
zuozhe_label.grid(row=3,column=0)
hh_label.grid(row=4,column=0)
buttom1_label.grid(row=5,column=0)
buttom2_label.grid(row=6,column=0)
def mountefi():
os.system('bash EasyEFI.sh')
# Create the settings window
self.settings_window = tk.Toplevel(self.tk)
self.settings_window.title("ProperTree设置")
w = 380
h = 150
self.settings_window.minsize(width=w,height=h)
self.settings_window.resizable(True, False)
self.settings_window.columnconfigure(0,weight=1)
self.settings_window.columnconfigure(1,weight=1)
# Let's also center the window
x = self.settings_window.winfo_screenwidth() // 2 - w // 2
y = self.settings_window.winfo_screenheight() // 2 - h // 2
self.settings_window.geometry("{}x{}+{}+{}".format(w,h, x, y))
# Let's add some checkboxes and stuffs
self.expand_on_open = tk.IntVar()
self.use_xcode_data = tk.IntVar()
self.sort_dict_keys = tk.IntVar()
self.expand_check = tk.Checkbutton(self.settings_window,text="打开列表时展开子项",variable=self.expand_on_open,command=self.expand_command)
self.xcode_check = tk.Checkbutton(self.settings_window,text="在XML Plist中使用Xcode风格的<data>标签(内联)",variable=self.use_xcode_data,command=self.xcode_command)
self.sort_check = tk.Checkbutton(self.settings_window,text="忽略字典键顺序",variable=self.sort_dict_keys,command=self.sort_command)
self.expand_check.grid(row=0,column=0,columnspan=2,sticky="w",padx=10,pady=(10,0))
self.xcode_check.grid(row=1,column=0,columnspan=2,sticky="w",padx=10)
self.sort_check.grid(row=2,column=0,columnspan=2,sticky="w",padx=10)
self.plist_type_string = tk.StringVar(self.settings_window)
self.plist_type_menu = tk.OptionMenu(self.settings_window, self.plist_type_string, "XML","Binary", command=self.change_plist_type)
plist_label = tk.Label(self.settings_window,text="默认新Plist类型:")
plist_label.grid(row=3,column=0,sticky="w",padx=10)
self.plist_type_menu.grid(row=3,column=1,sticky="we",padx=10)
reset_settings = tk.Button(self.settings_window,text="重置为默认值",command=self.reset_settings)
reset_settings.grid(row=4,column=1,sticky="e",padx=10,pady=(0,10))
# Setup the from/to option menus
f_title = tk.StringVar(self.tk)
t_title = tk.StringVar(self.tk)
f_title.set("Base64")
t_title.set("Hex")
f_option = tk.OptionMenu(self.tk, f_title, "Ascii", "Base64", "Decimal", "Hex", command=self.change_from_type)
t_option = tk.OptionMenu(self.tk, t_title, "Ascii", "Base64", "Decimal", "Hex", command=self.change_to_type)
self.from_type = "Base64"
self.to_type = "Hex"
f_option.grid(row=0,column=1,sticky="we")
t_option.grid(row=1,column=1,sticky="we")
self.f_text = tk.Entry(self.tk)
self.f_text.delete(0,tk.END)
self.f_text.insert(0,"")
self.f_text.grid(row=0,column=2,columnspan=2,sticky="we",padx=10,pady=10)
self.t_text = tk.Entry(self.tk)
self.t_text.configure(state='normal')
self.t_text.delete(0,tk.END)
self.t_text.insert(0,"")
self.t_text.configure(state='readonly')
self.t_text.grid(row=1,column=2,columnspan=2,sticky="we",padx=10,pady=10)
self.c_button = tk.Button(self.tk, text="转换", command=self.convert_values)
self.c_button.grid(row=2,column=3,sticky="e",padx=10,pady=10)
self.f_text.bind("<Return>", self.convert_values)
self.f_text.bind("<KP_Enter>", self.convert_values)
self.start_window = None
# Regex to find the processor serial numbers when
# opened from the Finder
self.regexp = re.compile(r"^-psn_[0-9]+_[0-9]+$")
# Setup the menu-related keybinds - and change the app name if needed
key="Control"
sign = "Ctrl+"
if str(sys.platform) == "darwin":
# Remap the quit function to our own
self.tk.createcommand('::tk::mac::Quit', self.quit)
self.tk.createcommand("::tk::mac::OpenDocument", self.open_plist_from_app)
self.tk.createcommand("::tk::mac::ReopenApplication", self.open_plist_from_app)
# Import the needed modules to change the bundle name and force focus
try:
from Foundation import NSBundle
from Cocoa import NSRunningApplication, NSApplicationActivateIgnoringOtherApps
app = NSRunningApplication.runningApplicationWithProcessIdentifier_(os.getpid())
app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)
bundle = NSBundle.mainBundle()
if bundle:
info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
if info and info['CFBundleName'] == 'Python':
info['CFBundleName'] = "ProperTree"
except:
pass
key="Command"
sign=key+"+"
self.tk.protocol("WM_DELETE_WINDOW", self.close_window)
self.settings_window.protocol("WM_DELETE_WINDOW", self.close_window)
# Close initial windows
self.tk.withdraw()
self.settings_window.withdraw()
self.default_windows = (self.tk,self.settings_window)
if str(sys.platform) == "darwin":
# Setup the top level menu
file_menu = tk.Menu(self.tk)
about_menu = tk.Menu(self.tk)
main_menu = tk.Menu(self.tk)
main_menu.add_cascade(label="文件", menu=file_menu)
main_menu.add_cascade(label="其它", menu=about_menu)
file_menu.add_command(label="新建 (Cmd+N)", command=self.new_plist)
file_menu.add_command(label="打开 (Cmd+O)", command=self.open_plist)
file_menu.add_command(label="保存 (Cmd+S)", command=self.save_plist)
file_menu.add_command(label="另存为...(Cmd+Shift+S)", command=self.save_plist_as)
file_menu.add_command(label="重复 (Cmd+D)", command=self.duplicate_plist)
file_menu.add_command(label="从磁盘重新加载 (Cmd+L)", command=self.reload_from_disk)
file_menu.add_separator()
file_menu.add_command(label="OC快照 (Cmd+R)", command=self.oc_snapshot)
file_menu.add_command(label="清除OC快照 (Cmd+Shift+R)", command=self.oc_clean_snapshot)
file_menu.add_command(label="带状禁用条目 (Cmd+E)", command=self.strip_disabled)
file_menu.add_separator()
file_menu.add_command(label="转换窗口 (Cmd+T)", command=self.show_convert)
file_menu.add_command(label="带状注释 (Cmd+M)", command=self.strip_comments)
file_menu.add_separator()
file_menu.add_command(label="切换查找/替换窗口 (Cmd+F)",command=self.hide_show_find)
file_menu.add_command(label="切换Plist/数据类型面板 (Cmd+P)",command=self.hide_show_type)
file_menu.add_separator()
about_menu.add_command(label="关于本程序",command=create_about)
about_menu.add_command(label="挂载/卸载EFI",command=mountefi)
about_menu.add_command(label="设置 (Cmd+,)",command=self.show_settings)
about_menu.add_command(label="退出 (Cmd+Q)", command=self.quit)
self.tk.config(menu=main_menu)
# Set bindings
self.tk.bind("<{}-w>".format(key), self.close_window)
self.settings_window.bind("<{}-w>".format(key), self.close_window)
self.tk.bind_all("<{}-n>".format(key), self.new_plist)
self.tk.bind_all("<{}-o>".format(key), self.open_plist)
self.tk.bind_all("<{}-s>".format(key), self.save_plist)
self.tk.bind_all("<{}-S>".format(key), self.save_plist_as)
self.tk.bind_all("<{}-d>".format(key), self.duplicate_plist)
self.tk.bind_all("<{}-t>".format(key), self.show_convert)
self.tk.bind_all("<{}-z>".format(key), self.undo)
self.tk.bind_all("<{}-Z>".format(key), self.redo)
self.tk.bind_all("<{}-m>".format(key), self.strip_comments)
self.tk.bind_all("<{}-e>".format(key), self.strip_disabled)
self.tk.bind_all("<{}-r>".format(key), self.oc_snapshot)
self.tk.bind_all("<{}-R>".format(key), self.oc_clean_snapshot)
self.tk.bind_all("<{}-l>".format(key), self.reload_from_disk)
self.tk.bind_all("<{}-comma>".format(key), self.show_settings)
if not str(sys.platform) == "darwin":
# Rewrite the default Command-Q command
self.tk.bind_all("<{}-q>".format(key), self.quit)
cwd = os.getcwd()
os.chdir(os.path.dirname(os.path.realpath(__file__)))
#
# Load the settings - current available settings are:
#
# last_window_width: width value (default is 640)
# last_window_height: height value (default is 480)
# expand_all_items_on_open: bool
# sort_dict: bool, false = OrderedDict
# xcode_data: bool, true = <data>XXXX</data>, false = different lines
# new_plist_default_type: string, XML/Binary
#
self.settings = {}
try:
if os.path.exists("Scripts/settings.json"):
self.settings = json.load(open("Scripts/settings.json"))
except:
pass
os.chdir(cwd)
# Setup the settings page to reflect our settings.json file
self.allowed_types = ("XML","Binary")
self.update_settings()
# Wait before opening a new document to see if we need to.
# This was annoying to debug, but seems to work.
self.tk.after(100, lambda:self.check_open(plists))
# Start our run loop
tk.mainloop()
def expand_command(self, event = None):
self.settings["expand_all_items_on_open"] = True if self.expand_on_open.get() else False
def xcode_command(self, event = None):
self.settings["xcode_data"] = True if self.use_xcode_data.get() else False
def sort_command(self, event = None):
self.settings["sort_dict"] = True if self.sort_dict_keys.get() else False
def change_plist_type(self, event = None):
self.settings["new_plist_default_type"] = self.plist_type_string.get()
def reset_settings(self, event = None):
self.settings = {}
self.update_settings()
def update_settings(self):
self.expand_on_open.set(self.settings.get("expand_all_items_on_open",True))
self.use_xcode_data.set(self.settings.get("xcode_data",True))
self.sort_dict_keys.set(self.settings.get("sort_dict",False))
def_type = self.settings.get("new_plist_default_type","XML")
self.plist_type_string.set(def_type if def_type in self.allowed_types else self.allowed_types[0])
def check_open(self, plists = []):
plists = [x for x in plists if not self.regexp.search(x)]
if isinstance(plists, list) and len(plists):
# Iterate the passed plists and open them
for p in set(plists):
window = self.open_plist_with_path(None,p,None)
if self.start_window == None:
self.start_window = window
elif not len(self.stackorder(self.tk)):
# create a fresh plist to start
self.start_window = self.new_plist()
def open_plist_from_app(self, *args):
if isinstance(args, str):
args = [args]
args = [x for x in args if not self.regexp.search(x)]
for arg in args:
# Let's load the plist
if self.start_window == None:
self.start_window = self.open_plist_with_path(None,arg,None)
elif self.start_window.current_plist == None:
self.open_plist_with_path(None,arg,self.start_window)
else:
self.open_plist_with_path(None,arg,None)
def change_hd_type(self, value):
self.hd_type = value
def reload_from_disk(self, event = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.reload_from_disk(event)
def change_data_display(self, new_data = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.change_data_display(new_data)
def oc_clean_snapshot(self, event = None):
self.oc_snapshot(event,True)
def oc_snapshot(self, event = None, clean = False):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.oc_snapshot(event,clean)
def hide_show_find(self, event = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.hide_show_find(event)
def hide_show_type(self, event = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.hide_show_type(event)
def close_window(self, event = None, check_close = True):
# Remove the default window that comes from it
windows = self.stackorder(self.tk)
if len(windows):
windows[-1].withdraw()
windows = windows[:-1]
if check_close and not len(windows):
# Quit if all windows are closed
self.quit()
def strip_comments(self, event = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.strip_comments(event)
def strip_disabled(self, event = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.strip_disabled(event)
def change_to_type(self, value):
self.to_type = value
self.convert_values()
def change_from_type(self, value):
self.from_type = value
def show_settings(self, event = None):
self.settings_window.deiconify()
def show_convert(self, event = None):
self.tk.deiconify()
def convert_values(self, event = None):
from_value = self.f_text.get()
if not len(from_value):
# Empty - nothing to convert
return
# Pre-check for hex potential issues
if self.from_type.lower() == "hex":
if from_value.lower().startswith("0x"):
from_value = from_value[2:]
from_value = from_value.replace(" ","").replace("<","").replace(">","")
if [x for x in from_value if x.lower() not in "0123456789abcdef"]:
self.tk.bell()
mb.showerror("无效的十六进制数据","传递的十六进制数据中的字符无效.") # ,parent=self.tk)
return
try:
if self.from_type.lower() == "decimal":
# Convert to hex bytes
from_value = "{:x}".format(int(from_value))
if len(from_value) % 2:
from_value = "0"+from_value
# Handle the from data
if sys.version_info >= (3,0):
# Convert to bytes
from_value = from_value.encode("utf-8")
if self.from_type.lower() == "base64":
from_value = base64.b64decode(from_value)
elif self.from_type.lower() in ["hex","decimal"]:
from_value = binascii.unhexlify(from_value)
# Let's get the data converted
to_value = from_value
if self.to_type.lower() == "base64":
to_value = base64.b64encode(from_value)
elif self.to_type.lower() == "hex":
to_value = binascii.hexlify(from_value)
elif self.to_type.lower() == "decimal":
to_value = str(int(binascii.hexlify(from_value),16))
if sys.version_info >= (3,0) and not self.to_type.lower() == "decimal":
# Convert to bytes
to_value = to_value.decode("utf-8")
if self.to_type.lower() == "hex":
# Capitalize it, and pad with spaces
to_value = "{}".format(" ".join((to_value[0+i:8+i] for i in range(0, len(to_value), 8))).upper())
# Set the text box
self.t_text.configure(state='normal')
self.t_text.delete(0,tk.END)
self.t_text.insert(0,to_value)
self.t_text.configure(state='readonly')
except Exception as e:
self.tk.bell()
mb.showerror("Conversion Error",str(e)) # ,parent=self.tk)
### ###
# Save/Load Plist Functions #
### ###
def duplicate_plist(self, event = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
plist_data = window.nodes_to_values()
plistwindow.PlistWindow(self, self.tk).open_plist(None,plist_data)
def save_plist(self, event = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.save_plist(event)
def save_plist_as(self, event = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.save_plist_as(event)
def undo(self, event = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.reundo(event)
def redo(self, event = None):
windows = self.stackorder(self.tk)
if not len(windows):
# Nothing to do
return
window = windows[-1] # Get the last item (most recent)
if window in self.default_windows:
return
window.reundo(event,False)
def new_plist(self, event = None):
# Creates a new plistwindow object
# Let's try to create a unique name (if Untitled.plist is used, add a number)
titles = [x.title().lower() for x in self.stackorder(self.tk)]
number = 0
final_title = "无标题.plist"
while True:
temp = "无标题{}.plist".format("" if number == 0 else "-"+str(number))
if not temp.lower() in titles:
final_title = temp
break
number += 1
window = plistwindow.PlistWindow(self, self.tk)
window.open_plist(final_title,{}) # Created an empty root
window.current_plist = None # Ensure it's initialized as new
default_type = self.settings.get("new_plist_default_type","XML")
window.plist_type_string.set(default_type if default_type in self.allowed_types else self.allowed_types[0])
window.focus_force()
window.update()
return window
def open_plist(self, event=None):
# Prompt the user to open a plist, attempt to load it, and if successful,
# set its path as our current_plist value
current_window = None
windows = self.stackorder(self.tk)
if len(windows) == 1 and windows[0] == self.start_window and windows[0].edited == False and windows[0].current_plist == None:
# Fresh window - replace the contents
current_window = windows[0]
path = fd.askopenfilename(title = "选择plist文件") #,parent=current_window) # Apparently parent here breaks on 10.15?
if not len(path):
# User cancelled - bail
return None
path = os.path.realpath(os.path.expanduser(path))
# Verify that no other window has that file selected already
for window in windows:
if window in self.default_windows:
continue
if window.current_plist == path:
# found one - just make this focus instead
window.focus_force()
window.update()
window.bell()
mb.showerror("文件已经打开", "{} 已经在这里打开.".format(path)) # , parent=window)
return
self.open_plist_with_path(event,path,current_window)
def open_plist_with_path(self, event = None, path = None, current_window = None, plist_type = "XML"):
if path == None:
# Uh... wut?
return
path = os.path.realpath(os.path.expanduser(path))
# Let's try to load the plist
try:
with open(path,"rb") as f:
plist_type = "Binary" if plist._is_binary(f) else "XML"
plist_data = plist.load(f,dict_type=dict if self.settings.get("sort_dict",False) else OrderedDict)
except Exception as e:
# Had an issue, throw up a display box
self.tk.bell()
mb.showerror("打开{}时发生错误".format(os.path.basename(path)), str(e)) # ,parent=current_window)
return None
# Opened it correctly - let's load it, and set our values
if current_window:
current_window.open_plist(path,plist_data,plist_type,self.settings.get("expand_all_items_on_open",True))
else:
# Need to create one first
current_window = plistwindow.PlistWindow(self, self.tk)
current_window.open_plist(path,plist_data,plist_type,self.settings.get("expand_all_items_on_open",True))
current_window.focus_force()
current_window.update()
return True
def stackorder(self, root):
"""return a list of root and toplevel windows in stacking order (topmost is last)"""
c = root.children
s = root.tk.eval('wm stackorder {}'.format(root))
L = [x.lstrip('.') for x in s.split()]
return [(c[x] if x else root) for x in L]
def quit(self, event=None):
# Check if we need to save first, then quit if we didn't cancel
for window in self.stackorder(self.tk)[::-1]:
if window in self.default_windows:
continue
if window.check_save() == None:
# User cancelled or we failed to save, bail
return
window.destroy()
# Actually quit the tkinter session
self.tk.destroy()
# Attempt to save the settings
cwd = os.getcwd()
os.chdir(os.path.dirname(os.path.realpath(__file__)))
try:
json.dump(self.settings,open("Scripts/settings.json","w"),indent=4)
except:
pass
os.chdir(cwd)
if __name__ == '__main__':
plists = []
if len(sys.argv) > 1:
plists = sys.argv[1:]
p = ProperTree(plists)
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化