class Keychain(): def __init__(self, repr: str = "", key: str = "", chord: str = "", boundFiles: [BindFile] = None): if (repr != ""): self.Parse(repr) else: self.parserBind = Bind(key=key, chord=chord) self.Key = self.parserBind.GetDefaultedKeyName() self.Chord = self.parserBind.GetDefaultedChordName() self.BoundFiles = boundFiles def Parse(self, repr: str): keychainDict = ast.literal_eval(repr) self.parserBind = Bind(key=keychainDict[KEY], chord=keychainDict[CHORD]) self.Key = self.parserBind.GetDefaultedKeyName() self.Chord = self.parserBind.GetDefaultedChordName() boundFilesRepr = keychainDict[BOUND_FILES] if boundFilesRepr == NONE: boundFiles = None else: boundFiles = [] for boundFileEntry in boundFilesRepr: boundFile = BindFile(repr=boundFileEntry[REPR]) boundFile.FilePath = boundFileEntry[PATH] boundFiles.append(boundFile) self.BoundFiles = boundFiles def GetKeyWithChord(self): return self.parserBind.GetKeyWithChord(defaultNames=True) #Dictionary structure #KEY - Key for bind in root file #CHORD - Chord for bind in root file #BOUND_FILES- Array of dictionaries for bound files #PATH - Path from load command #REPR - repr string of loaded bind file def GetDictionary(self): keychainDict = {} keychainDict[KEY] = self.Key keychainDict[CHORD] = self.Chord if self.BoundFiles == None: keychainDict[BOUND_FILES] = NONE else: bound_files = [] for boundFile in self.BoundFiles: bound_file_dict = {} bound_file_dict[PATH] = boundFile.FilePath bound_file_dict[REPR] = boundFile.__repr__() bound_files.append(bound_file_dict) keychainDict[BOUND_FILES] = bound_files return keychainDict def __repr__(self)->str: keychainDict = self.GetDictionary() return keychainDict.__repr__() def Clone(self): return Keychain(repr=self.__repr__())
def __init__(self, repr: str = "", key: str = "", chord: str = "", boundFiles: [BindFile] = None): if (repr != ""): self.Parse(repr) else: self.parserBind = Bind(key=key, chord=chord) self.Key = self.parserBind.GetDefaultedKeyName() self.Chord = self.parserBind.GetDefaultedChordName() self.BoundFiles = boundFiles
def GetBindForKey(self, key, chord = ""): if (self.Binds == None): return [] quickMatch = [b for b in self.Binds if ((b.Key == key) and ((chord == None) or (b.Chord == chord)))] if (len(quickMatch) > 0): return quickMatch dummyForConversion = Bind(key=key, chord=chord) defaultedName = dummyForConversion.GetKeyWithChord(defaultNames=True) return [b for b in self.Binds if (defaultedName == b.GetKeyWithChord(defaultNames=True))]
def test_FromString(self): input = "A \"say This test passed\"\nB \"emote Yay!\"" target = BindFile(repr=input) actual = len(target.Binds) self.assertEqual(actual, 2, "Did not find expected bind count") actual = str(target.Binds[0]) expected = str(Bind(key="A", commands=[SlashCommand("say","This test passed")])) self.assertEqual(actual, expected, "Did not find expected 1st bind") actual = str(target.Binds[1]) expected = str(Bind(key="B", commands=[SlashCommand("emote","Yay!")])) self.assertEqual(actual, expected, "Did not find expected 2nd bind")
def Load(self, bind: Bind): self.Loading = True try: if (self._lockKey): self.TextEntry.SetText(bind.GetCommands()) else: self.TextEntry.SetText(bind.__repr__()) self.SynchTextToUI() finally: self.Loading = False self.SetClean(self)
def __init__(self, parent, resultCallback, bind: Bind = None, lockKey=False, title=None, dirty=False): tk.Toplevel.__init__(self, parent) self.attributes("-topmost", 1) if (title == None): if (bind == None): title = 'New Bind' dirty = True else: title = bind.GetKeyWithChord() self.Title = title self.ResultCallback = resultCallback self.title(title) icon = GetResourcePath('.\\Resources\\keystone.ico') if (icon != None): self.iconbitmap(icon) self.protocol("WM_DELETE_WINDOW", self.OnCancel) self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) frame = KeystoneEditFrame(self) frame.columnconfigure(0, weight=0) frame.columnconfigure(1, weight=1, minsize='205') frame.rowconfigure(0, weight=1) frame.rowconfigure(1, weight=0) if (bind == None): self.Editor = BindEditor(frame, Bind(repr=DEFAULT_BIND), lockKey=lockKey, dirty=dirty) else: self.Editor = BindEditor(frame, bind, lockKey=lockKey, dirty=dirty) self.Editor.grid(column=1, row=0, rowspan=2, sticky='nsew') self.Cancel = KeystoneButton(frame, text="OK", command=self.OnOk) self.Cancel.configure(text="Cancel", command=self.OnCancel) self.Cancel.Color('red', 'black') self.Cancel.grid(column=0, row=1, sticky='nsew') self.OK = KeystoneButton(frame, text="OK", command=self.OnOk) self.OK.Color('green', 'black') self.OK.grid(column=0, row=0, sticky='nsew') frame.grid(column=0, row=0, sticky='nsew')
def Parse(self, repr: str): keychainDict = ast.literal_eval(repr) self.parserBind = Bind(key=keychainDict[KEY], chord=keychainDict[CHORD]) self.Key = self.parserBind.GetDefaultedKeyName() self.Chord = self.parserBind.GetDefaultedChordName() boundFilesRepr = keychainDict[BOUND_FILES] if boundFilesRepr == NONE: boundFiles = None else: boundFiles = [] for boundFileEntry in boundFilesRepr: boundFile = BindFile(repr=boundFileEntry[REPR]) boundFile.FilePath = boundFileEntry[PATH] boundFiles.append(boundFile) self.BoundFiles = boundFiles
def __init__(self, parent, bind: Bind, dirty=False): KeystoneEditFrame.__init__(self, parent) self.BindFileEditor = parent while (self.BindFileEditor.__class__.__name__ != "EditBindFile"): self.BindFileEditor = self.BindFileEditor.master if (self.BindFileEditor == None): break self.Editor = None self.columnconfigure(0, weight=0) self.columnconfigure(1, weight=1) self.rowconfigure(0, weight=0) self.rowconfigure(1, weight=0) self._showingEdit = True self.Button = KeystoneButton(self, text="...", width=6, command=self.OnEdit) self.Button.grid(row=0, column=0, sticky="nsew") self.Repr = tk.StringVar() self.Label = KeystoneLabel(self, textvariable=self.Repr) self.Repr.set(bind.__repr__()) self.Label.grid(row=0, column=1, sticky="nsew") self.OnSetDirty.append(self.SetEdited) self.OnSetClean.append(self.SetEdited) self.BindFileEditor.OnSetClean.append(self.SetClean) if (dirty): self.SetDirty()
def AddUploadBind(self, *args): if (self.FilePath == None): return path = os.path.abspath(self.FilePath) bind = None dirty = False #find current biind loadBinds = [ bind for bind in [item.Item.Get() for item in self.view.Items] if bind.IsLoadFileBind() ] for loadBind in loadBinds: loadCommands = loadBind.GetLoadFileCommands() for command in loadCommands: boundPath = command.GetTargetFile() if (boundPath == path): bind = loadBind break if (bind != None): break if (bind == None): bind = Bind(repr=DEFAULT_LOAD_BIND % path) dirty = True if (self.Editor == None): self.Editor = EditBindWindow(self, self.NewBindCallback, bind=bind, dirty=dirty)
def GetDefaultBindForKey(key, chord = "") -> Bind: bindFile = NewBindFile(defaults=True) binds = bindFile.GetBindForKey(key, chord) if (len(binds) > 0): return binds[0] else: return Bind(key, chord, [SlashCommand(repr=DEFAULT_COMMAND)])
def Newlink(self, filePath) -> Keylink: filePath = os.path.abspath(filePath) #create load command loadCommand = SlashCommand(name=LOAD_FILE_COMMANDS[0], text="\"%s\"" % filePath) loadBind = Bind(self.Key, self.Chord, [loadCommand]) #create new bind file bindFile = BindFile(binds=[loadBind], filePath=filePath) return Keylink(bindFile, self.Key, self.Chord)
def test_Clone(self): target = Bind(repr = "SHIFT+A \"say This test failed $$ emote No!\"") actual = target.Clone() actual.Key = "B" actual.Chord = "ALT" actual.Commands[0].Name = "em" actual.Commands[0].Text = "This test passed" actual.Commands[1].Name = "say" actual.Commands[1].Text = "Yay!" self.assertNotEqual(actual.Key, target.Key, 'Key not different') self.assertNotEqual(actual.Chord, target.Chord, 'Chord not different') self.assertNotEqual(actual.Commands[0].Name, target.Commands[0].Name, 'Commands[0].Name not different') self.assertNotEqual(actual.Commands[0].Text, target.Commands[0].Text, 'Commands[0].Text not different') self.assertNotEqual(actual.Commands[1].Name, target.Commands[1].Name, 'Commands[1].Name not different') self.assertNotEqual(actual.Commands[1].Text, target.Commands[1].Text, 'Commands[1].Text not different') self.assertEqual(actual.Key, "B", 'Key not changed') self.assertEqual(actual.Chord, "ALT", 'Chord not changed') self.assertEqual(actual.Commands[0].Name, "em", 'Commands[0].Name not changed') self.assertEqual(actual.Commands[0].Text, "This test passed", 'Commands[0].Text not changed') self.assertEqual(actual.Commands[1].Name, "say", 'Commands[1].Name not changed') self.assertEqual(actual.Commands[1].Text, "Yay!", 'Commands[1].Text not changed')
def __init__(self, bindFileCollection: BindFileCollection, key: str, chord: str = ""): self.Collection = bindFileCollection self.Anchor = Keylink(bindFileCollection.File, key, chord) self.RootPath = os.path.dirname(self.Anchor.FilePath) self.Links = [] self.Key = key self.Chord = chord keyChord = Bind(key, chord).GetKeyWithChord() for bindFile in bindFileCollection.KeyChains[keyChord]: self.Links.append(Keylink(bindFile, key, chord))
def GetBindFromUI(self) -> Bind: bind = Bind() if (self.ShowCommands.get()): bind.Commands = [item.Item.Get() for item in self.Commands.Items] else: bind.Commands = None bind.Key = self.Key.get() bind.Chord = self.Chord.get() return bind
def test__repr__(self): #test a single command key = "A" commands = [SlashCommand(name="say", text="This test passed")] expected = "A \"say This test passed\"" target = Bind(key=key, commands=commands) actual = str(target) self.assertEqual(actual, expected, "Single command") #test concatenated commands commands = [SlashCommand(name="say", text="This test passed"), SlashCommand(name="emote", text="Yay!")] expected = "A \"say This test passed$$emote Yay!\"" target = Bind(key=key, commands=commands) actual = str(target) self.assertEqual(actual, expected, "Multiple commands") #test chord key = "A" chord = "CTRL" commands = [SlashCommand(name="say", text="This test passed")] expected = "CTRL+A \"say This test passed\"" target = Bind(key=key, chord=chord, commands=commands) actual = str(target) self.assertEqual(actual, expected, "Chord in key")
def Load(self, bindFile): self.LoadedFile = bindFile.Clone() self.Loading = True try: if (self.LoadedFile.Binds != None): binds = [] if (self.List.get()): binds = self.LoadedFile.Binds else: #load in expeded order chords = [''] for chord, altname, desc in CHORD_KEYS: dummy = altname dummy = desc chords.append(chord) for key, altname, desc in KEY_NAMES: dummy = altname dummy = desc for chord in chords: keyBinds = self.LoadedFile.GetBindForKey( key, chord) if (len(keyBinds) > 0): binds.append(keyBinds[0]) #load anything in the file we didn't match at the end for bind in self.LoadedFile.Binds: loaded = [ b for b in binds if (bind.GetKeyWithChord( defaultNames=True) == b.GetKeyWithChord( defaultNames=True)) ] if (len(loaded) == 0): binds.append(bind) self.view.Load(BindListItem, binds, Bind(repr=DEFAULT_BIND)) finally: self.Loading = False self.FilePath = self.LoadedFile.FilePath if (self.FilePath == None): self.PathLabel.configure(text="") else: self.PathLabel.configure(text=self.FilePath) if (os.path.exists(self.FilePath)): self.SetClean(self) else: self.SetDirty(self) self.OnLinkedFilesFound()
def SynchTextToUI(self): key = self.Key.get() chord = self.Chord.get() text = self.TextEntry.GetText() if (self._lockKey): text = "%s %s" % (FormatKeyWithChord(key, chord), text) bind = Bind(repr=text) if (key != bind.Key): self.Key.set(bind.Key) if (chord != bind.Chord): self.Chord.set(bind.Chord) if (bind.Commands != None): self.Commands.Load(SlashCommandEditor, bind.Commands, SlashCommand(repr=DEFAULT_COMMAND)) self.ShowCommands.set(True) else: self.ShowCommands.set(False) self.ShowTextEditor.set(False)
def getBoundFiles(path, bind: Bind, foundFiles, boundFiles): for command in bind.GetLoadFileCommands(): boundPath = command.GetTargetFile() if (ComparableFilePath (boundPath) == ComparableFilePath (path)): #self load continue if (boundFiles == None): if (os.path.exists(boundPath)): action = 'read_from_disk' else: action = 'create_a_blank' else: match = [b for b in boundFiles if ComparableFilePath (b.FilePath) == ComparableFilePath (boundPath)] if (len(match) > 0): action = 'loaded_match' boundFile = match[0] elif (os.path.exists(boundPath)): action = 'read_from_disk' else: action = 'create_a_blank' if (action == 'create_a_blank'): boundFile = NewBindFile() boundFile.FilePath = boundPath elif (action == 'read_from_disk'): boundFile = ReadBindsFromFile(boundPath) #check if already included match = [b for b in foundFiles if ComparableFilePath (b.FilePath) == ComparableFilePath (boundFile.FilePath)] if (len(match) > 0): continue foundFiles.append(boundFile.Clone()) for chainBind in boundFile.GetLoadFileBinds(): for foundFile in getBoundFiles(path, chainBind, foundFiles, boundFiles): match = [b for b in foundFiles if ComparableFilePath (b.FilePath) == ComparableFilePath (boundFile.FilePath)] if (len(match) > 0): continue foundFiles.append(foundFile) return foundFiles
def AssignCommand(self, *args): model = Bind(key=self.Key.get(), chord=self.Chord.get(), commands=[SlashCommand(repr=DEFAULT_COMMAND)]) self.Load(model) self.SetDirty()
def test__repr__(self): expected = "A \"say This test passed\"\nB \"emote Yay!\"" binds = [Bind(key="A", commands=[SlashCommand("say", "This test passed")]), Bind(key="B", commands=[SlashCommand("emote", "Yay!")])] target = BindFile(binds) actual = str(target) self.assertEqual(actual, expected)
def test_GetKeyWithChord(self): target = Bind(repr = "PERIOD \"say This test passed\"") expected = "PERIOD" actual = target.GetKeyWithChord() self.assertEqual(actual, expected, 'Did not get expected non-chorded key') expected = "." actual = target.GetKeyWithChord(defaultNames=True) self.assertEqual(actual, expected, 'Did not get expected defaulted non-chorded key') target = Bind(repr = "shift+PERIOD \"say This test passed\"") expected = "shift+PERIOD" actual = target.GetKeyWithChord() self.assertEqual(actual, expected, 'Did not get expected chorded key') expected = "SHIFT+." actual = target.GetKeyWithChord(defaultNames=True) self.assertEqual(actual, expected, 'Did not get expected defaulted chorded key') target = Bind(repr = "whoknows+whatthisis \"say This test passed\"") expected = "whoknows+whatthisis" actual = target.GetKeyWithChord() self.assertEqual(actual, expected, 'Did not get expected chorded nonsense') actual = target.GetKeyWithChord(defaultNames=True) self.assertEqual(actual, expected, 'Did not get expected defaulted chorded nonsense')
def test_FromString(self): #test single command bound to key (with leading spaces) target = Bind(repr = " A \"say This test passed\"") self.assertEqual(target.Key, "A", "Did not find expected KeyName on a single command") actual = len(target.Commands) self.assertEqual(actual, 1, "Did not find expected command count on a single command") actual = target.Commands[0].Name self.assertEqual(actual, "say", "Did not find expected command name on a single command") actual = target.Commands[0].Text self.assertEqual(actual, "This test passed", "Did not find expected command text on a single command") #test concatenated commands bound to a key target = Bind(repr = "A \"say This test passed $$ emote Yay!\"") self.assertEqual(target.Key, "A", "Did not find expected KeyName on concatenated commands") actual = len(target.Commands) self.assertEqual(actual, 2, "Did not find expected command count on concatenated commands") actual = target.Commands[0].Name self.assertEqual(actual, "say", "Did not find expected 1st command name on concatenated commands") actual = target.Commands[0].Text self.assertEqual(actual, "This test passed ", "Did not find expected 1st command text on concatenated commands") actual = target.Commands[1].Name self.assertEqual(actual, "emote", "Did not find expected 2nd command name on concatenated commands") actual = target.Commands[1].Text self.assertEqual(actual, "Yay!", "Did not find expected 2nd command text on concatenated commands") #test string with quote bound space expected ="COMMA \"show chat$$beginchat /tell $target, \"" target = Bind(repr = "COMMA \"show chat$$beginchat /tell $target, \"") actual = str(target) self.assertEqual(actual, expected, "Did not get expected round trip on a Bind with a space bound by quotes") #test key with a chord target = Bind(repr = "SHIFT+A \"say This test passed\"") self.assertEqual(target.Key, "A", "Did not find expected KeyName on a chord") self.assertEqual(target.Chord, "SHIFT", "Did not find expected Chord on a chord") actual = len(target.Commands) self.assertEqual(actual, 1, "Did not find expected command count on a chord") actual = target.Commands[0].Name self.assertEqual(actual, "say", "Did not find expected command name on a chord") actual = target.Commands[0].Text self.assertEqual(actual, "This test passed", "Did not find expected command text on a chord") #test load file bind self.assertEqual(target.IsLoadFileBind(), False, "Unexpectedly set IsLoadFileBind") target = Bind(repr = "MouseChord \"powexec_name Hover$$bind_load_file \".\\TestReferences\\Jock Tamson\\MouseChord2.txt\"\"") self.assertEqual(target.IsLoadFileBind(), True, "Unexpectedly did not set IsLoadFileBind")
def Parse(self, repr: str): parts = repr.split(self.LINE_SEPARATOR) self.Binds = [Bind(repr=p) for p in parts if (p != "")]
def Get(self): return Bind(repr=self.Repr.get())