EventGhost/EventGhost

View on GitHub
plugins/System/Registry.py

Summary

Maintainability
F
6 days
Test Coverage
# -*- coding: utf-8 -*-
#
# This file is part of EventGhost.
# Copyright © 2005-2020 EventGhost Project <http://www.eventghost.net/>
#
# EventGhost 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.
#
# EventGhost 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 EventGhost. If not, see <http://www.gnu.org/licenses/>.

import binascii
import wx
import _winreg

# Local imports
import eg
from eg.cFunctions import RegEnumKeysAndValues

regKeys = (
    (_winreg.HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT", "HKCR"),
    (_winreg.HKEY_CURRENT_USER, "HKEY_CURRENT_USER", "HKCU"),
    (_winreg.HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE", "HKLM"),
    (_winreg.HKEY_USERS, "HKEY_USERS", "HKU"),
    (_winreg.HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG", "HKCC")
)

regTypes = (
    (None, "Auto"),
    (_winreg.REG_BINARY, "REG_BINARY"),
    (_winreg.REG_DWORD, "REG_DWORD"),
    (_winreg.REG_EXPAND_SZ, "REG_EXPAND_SZ"),
    (_winreg.REG_MULTI_SZ, "REG_MULTI_SZ"),
    (_winreg.REG_NONE, "REG_NONE"),
    (_winreg.REG_SZ, "REG_SZ")
)

class Config(eg.PersistentData):
    lastKeySelected = _winreg.HKEY_CURRENT_USER
    lastSubkeySelected = "Software"
    lastValueNameSelected = None


class Text:
    name = description = "Registry"

    noKeyError = "No key given"
    noSubkeyError = "No subkey given"
    noTypeError = "No type given"
    noNewValueError = "No new value given"
    noValueNameError = "No value name given"
    keyOpenError = "Error opening registry key"
    valueChangeError = "Error while modifying value"

    defaultText = "(Default)"
    chooseText = "Choose Registry Key:"
    keyText = "Key:"
    valueText = "Value:"
    valueName = "Value name:"
    actionText = "Action:"
    newValue = "New value:"
    oldValue = "Current value:"
    oldType = "Current Type:"
    typeText = "Type:"

    keyText2 = "Key"
    noValueText = "value not found"


class RegistryChange(eg.ActionBase):
    name = "Change Registry Value"
    description = "Changes a value in the Windows registry."
    iconFile = "icons/Registry"

    class text:
        actions = ("create or change", "change if exists only", "delete")
        labels = (
            'Change "%s" to %s',
            'Change "%s" to %s if exists only',
            'Delete "%s"'
        )
        disableParsing = "Disable parsing of string"

    def __call__(
        self,
        key,
        subkey,
        valueName,
        action,
        keyType,
        newValue,
        disableParsing=False
    ):
        if not disableParsing:
            newValue = eg.ParseString(newValue)
        if not key:
            self.PrintError(self.text2.noKeyError)
            return 0
        if not subkey:
            self.PrintError(self.text2.noSubkeyError)
            return 0
        if not valueName:
            self.PrintError(self.text2.noValueNameError)
            return 0

        #try to get handle
        try:
            if action == 0:
                regHandle = _winreg.CreateKey(key, subkey)
            else:
                regHandle = _winreg.OpenKey(
                    key,
                    subkey,
                    0,
                    _winreg.KEY_WRITE | _winreg.KEY_READ
                )
        except EnvironmentError, exc:
            if action != 1:
                eg.PrintError(self.text2.keyOpenError + ": " + str(exc))
            return 0

        #getting old value
        oldType = None
        try:
            regValue = _winreg.QueryValueEx(regHandle, valueName)
            oldType = regValue[1]
        except EnvironmentError, exc:
            #exit because value does not exist
            if (action == 1):
                _winreg.CloseKey(regHandle)
                return 1
            if (action == 2):
                _winreg.CloseKey(regHandle)
                return 0

        #try to determine type if none is given
        if ((action == 0) or (action == 1)) and keyType is None:
            if oldType is None:
                try:
                    int(newValue)
                    #is int
                    keyType = _winreg.REG_DWORD
                except ValueError, exc:
                    if newValue.count("%") > 1:
                        keyType = _winreg.REG_EXPAND_SZ
                    else:
                        keyType = _winreg.REG_SZ
            #if key already exists use the old type
            else:
                keyType = oldType

        #set or delete key
        try:
            if (action == 0) or (action == 1):
                if keyType == _winreg.REG_DWORD:
                    newValue = int(newValue)
                #change key
                _winreg.SetValueEx(regHandle, valueName, 0, keyType, newValue)
            elif (action == 2):
                #delete value
                _winreg.DeleteValue(regHandle, valueName)
            return 1
        except (EnvironmentError, ValueError), exc:
            self.PrintError(self.text2.valueChangeError + ": " + str(exc))
            return 0

    def Configure(
        self,
        key = None,
        subkey = None,
        valueName = None,
        action = 0,
        keyType = None,
        newValue = "",
        disableParsing=False
    ):
        text = self.text
        text2 = self.text2

        if key is None:
            key = Config.lastKeySelected
            subkey = Config.lastSubkeySelected
            valueName = Config.lastValueNameSelected
        else:
            Config.lastKeySelected = key
            Config.lastSubkeySelected = subkey
            Config.lastValueNameSelected = valueName

        panel = eg.ConfigPanel(resizable=True)
        disableParsingBox = panel.CheckBox(
            bool(disableParsing),
            text.disableParsing
        )
        #keyChooser
        regChooserCtrl = RegistryChooser(
            panel,
            -1,
            text2,
            key,
            subkey,
            valueName
        )

        def UpdateLastSelectedKeys(event):
            a, b, c = regChooserCtrl.tree.GetValue()
            Config.lastKeySelected = a
            Config.lastSubkeySelected = b
            Config.lastValueNameSelected = c
            event.Skip()

        regChooserCtrl.Bind(wx.EVT_TREE_SEL_CHANGED, UpdateLastSelectedKeys)

        panel.sizer.Add(regChooserCtrl, 1, flag=wx.EXPAND)
        panel.sizer.Add(wx.Size(5, 5))

        #Action
        actionSizer = wx.BoxSizer(wx.HORIZONTAL)

        choices = len(text.actions)
        rb = range(0, choices)

        actionSizer.Add(
            wx.StaticText(panel, -1, text2.actionText),
            flag=wx.ALIGN_CENTER_VERTICAL
        )

        def OnRadioButton(event):
            #disables elements depending on action selection
            flag = not rb[2].GetValue()
            newValueCtrl.Enable(flag)
            typeChoice.Enable(flag)
            event.Skip()

        rb[0] = wx.RadioButton(panel, -1, text.actions[0], style = wx.RB_GROUP)
        rb[0].SetValue(action == 0)
        actionSizer.Add(rb[0], flag = wx.ALIGN_CENTER_VERTICAL)

        rb[1] = wx.RadioButton(panel, -1, text.actions[1])
        rb[1].SetValue(action == 1)
        actionSizer.Add(rb[1], flag = wx.ALIGN_CENTER_VERTICAL)

        rb[2] = wx.RadioButton(panel, -1, text.actions[2])
        rb[2].SetValue(action == 2)
        actionSizer.Add(rb[2], flag = wx.ALIGN_CENTER_VERTICAL)

        panel.sizer.Add(actionSizer)
        panel.sizer.Add(wx.Size(5, 5))

        #new Value Input
        newValueSizer = wx.FlexGridSizer(2, 4, 5, 5)
        newValueSizer.AddGrowableCol(1)

        newValueSizer.Add(
            wx.StaticText(panel, -1, text2.newValue),
            flag = wx.ALIGN_CENTER_VERTICAL
        )

        newValueCtrl = wx.TextCtrl(panel, -1, newValue, size=(200, -1))
        newValueSizer.Add(newValueCtrl, flag = wx.EXPAND)

        newValueSizer.Add(
            wx.StaticText(panel, -1, text2.typeText),
            flag = wx.ALIGN_CENTER_VERTICAL
        )

        typeChoice = wx.Choice(panel, -1)
        for i, value in enumerate(regTypes):
            typeChoice.Append(value[1])
            if value[0] == keyType:
                typeChoice.SetSelection(i)

        newValueSizer.Add(typeChoice)
        newValueSizer.Add((-1, -1))
        newValueSizer.Add(disableParsingBox)

        OnRadioButton(wx.CommandEvent())
        rb[0].Bind(wx.EVT_RADIOBUTTON, OnRadioButton)
        rb[1].Bind(wx.EVT_RADIOBUTTON, OnRadioButton)
        rb[2].Bind(wx.EVT_RADIOBUTTON, OnRadioButton)

        panel.sizer.Add(newValueSizer, flag = wx.EXPAND)

        while panel.Affirmed():
            key, subkey, valueName = regChooserCtrl.GetValue()

            for i, item in enumerate(rb):
                if item.GetValue():
                    action = i
                    break

            keyType = regTypes[typeChoice.GetSelection()][0]

            newValue = newValueCtrl.GetValue()

            panel.SetResult(
                key,
                subkey,
                valueName,
                action,
                keyType,
                newValue,
                disableParsingBox.GetValue()
            )

    def GetLabel(
        self,
        key,
        subkey,
        valueName,
        action,
        keyType,
        newValue,
        disableParsing=False
    ):
        hkey = FullKeyName(key, subkey, valueName)
        if action == 2:
            return self.text.labels[action] % hkey
        return self.text.labels[action] % (hkey, newValue)

    @classmethod
    def OnAddAction(cls):
        cls.text2 = cls.plugin.text.RegistryGroup


class RegistryQuery(eg.ActionBase):
    name = "Query Registry"
    description = (
        "Queries the Windows registry and returns or compares the value."
    )
    iconFile = "icons/Registry"

    class text:
        actions = ("check if exists", "return as result", "compare to")
        labels = (
            'Check if "%s" exists',
            'Return "%s" as result',
            'Compare "%s" with %s'
        )

    def __call__(self, key, subkey, valueName, action, compareValue):
        if not key:  #nothing selected
            return None

        success = False
        try:
            regHandle = _winreg.OpenKey(key, subkey)
            success = True
        except EnvironmentError:
            pass

        #key does not exist or is not readable
        if not success:
            if action == 0:
                return False
            elif action == 1:
                return None
            elif action == 2:
                return False

        #key found and no value specfied
        if valueName is None:
            if action == 0:
                return True
            self.PrintError(self.text2.noValueNameError)
            if action == 1:
                return None
            elif action == 2:
                return False

        #reading value
        try:
            regValue = _winreg.QueryValueEx(regHandle, valueName)
            value = regValue[0]
            if action == 0:
                return True
            elif action == 1:
                return value
            elif action == 2:
                return str(value) == compareValue
        except EnvironmentError:
            if action == 0:
                return False
            elif action == 1:
                return None
            elif action == 2:
                return False

    def Configure(
        self,
        key = None,
        subkey = None,
        valueName = None,
        action = 0,
        compareValue = ""
    ):
        text = self.text
        text2 = self.text2

        if key is None:
            key = Config.lastKeySelected
            subkey = Config.lastSubkeySelected
            valueName = Config.lastValueNameSelected
        else:
            Config.lastKeySelected = key
            Config.lastSubkeySelected = subkey
            Config.lastValueNameSelected = valueName

        panel = eg.ConfigPanel(resizable=True)

        #keyChooser
        regChooserCtrl = RegistryChooser(
            panel,
            -1,
            text2,
            key,
            subkey,
            valueName
        )

        def UpdateLastSelectedKeys(event):
            a, b, c = regChooserCtrl.tree.GetValue()
            Config.lastKeySelected = a
            Config.lastSubkeySelected = b
            Config.lastValueNameSelected = c
            event.Skip()

        regChooserCtrl.tree.Bind(
            wx.EVT_TREE_SEL_CHANGED, UpdateLastSelectedKeys
        )

        panel.sizer.Add(regChooserCtrl, 1, flag=wx.EXPAND)
        panel.sizer.Add(wx.Size(5, 5))

        choices = len(text.actions)
        rb = range(0, choices)
        sizer2 = wx.FlexGridSizer(1, choices + 2, 5, 5)
        sizer2.AddGrowableCol(4)

        sizer2.Add(
            wx.StaticText(panel, -1, text2.actionText),
            flag=wx.ALIGN_CENTER_VERTICAL
        )

        def OnRadioButton(event):
            flag = rb[2].GetValue()
            compareValueCtrl.Enable(flag)
            event.Skip()

        rb[0] = wx.RadioButton(
            panel,
            -1,
            text.actions[0],
            style = wx.RB_GROUP
        )
        rb[0].SetValue(action == 0)
        sizer2.Add(rb[0], flag = wx.ALIGN_CENTER_VERTICAL)

        rb[1] = wx.RadioButton(panel, -1, text.actions[1])
        rb[1].SetValue(action == 1)
        sizer2.Add(rb[1], flag = wx.ALIGN_CENTER_VERTICAL)

        rb[2] = wx.RadioButton(panel, -1, text.actions[2])
        rb[2].SetValue(action == 2)
        sizer2.Add(rb[2], flag = wx.ALIGN_CENTER_VERTICAL)

        compareValueCtrl = wx.TextCtrl(panel, -1, compareValue, size=(200, -1))
        sizer2.Add(compareValueCtrl, flag = wx.EXPAND)

        OnRadioButton(wx.CommandEvent())
        rb[0].Bind(wx.EVT_RADIOBUTTON, OnRadioButton)
        rb[1].Bind(wx.EVT_RADIOBUTTON, OnRadioButton)
        rb[2].Bind(wx.EVT_RADIOBUTTON, OnRadioButton)

        panel.sizer.Add(sizer2, flag = wx.EXPAND)

        while panel.Affirmed():
            key, subkey, valueName = regChooserCtrl.GetValue()
            compareValue = compareValueCtrl.GetValue()
            for i in range(0, 3):
                if rb[i].GetValue():
                    action = i
                    break
            panel.SetResult(key, subkey, valueName, action, compareValue)

    def GetLabel(self, key, subkey, valueName, action, compareValue):
        hkey = FullKeyName(key, subkey, valueName)
        if action == 2:
            return self.text.labels[action] % (hkey, compareValue)
        return self.text.labels[action] % hkey

    @classmethod
    def OnAddAction(cls):
        cls.text2 = cls.plugin.text.RegistryGroup


class RegistryChooser(wx.Window):
    def __init__(
        self,
        parent,
        id = -1,
        text = None,
        key = _winreg.HKEY_CURRENT_USER,
        subkey = "Software",
        valueName = None,
        pos = wx.DefaultPosition,
        size = wx.DefaultSize,
        style = wx.EXPAND
    ):
        self.text = text
        wx.Window.__init__(self, parent, id, pos, size, style)
        sizer = wx.GridBagSizer(5, 5)

        sizer.SetEmptyCellSize((0, 0))
        sizer.Add(
            wx.StaticText(self, -1, text.chooseText),
            (0, 0),
            (1, 6),
            flag = wx.ALIGN_CENTER_VERTICAL
        )

        sizer.Add(
            wx.StaticText(self, -1, text.keyText),
            (2, 0),
            flag = wx.ALIGN_CENTER_VERTICAL
        )

        #key
        keyChoice = wx.Choice(self, -1)
        for i in range(0, len(regKeys)):
            keyChoice.Append(regKeys[i][1])
            if regKeys[i][0] == key:
                keyChoice.SetSelection(i)
        sizer.Add(keyChoice, (2, 1))

        sizer.Add(
            wx.StaticText(self, -1, "\\"),
            (2, 2),
            flag = wx.ALIGN_CENTER_VERTICAL
        )

        #subkey
        subkeyCtrl = wx.TextCtrl(self, -1, subkey, size=(200, -1))
        sizer.Add(subkeyCtrl, (2, 3), flag = wx.EXPAND)

        sizer.Add(
            wx.StaticText(self, -1, text.valueName),
            (2, 4),
            flag = wx.ALIGN_CENTER_VERTICAL
        )

        #old Value
        sizer.Add(
            wx.StaticText(self, -1, text.oldValue),
            (3, 0),
            flag = wx.ALIGN_CENTER_VERTICAL
        )
        self.oldValueCtrl = wx.TextCtrl(self, -1, style=wx.TE_READONLY)
        self.oldValueCtrl.Enable(False)
        sizer.Add(
            self.oldValueCtrl,
            (3, 1),
            (1, 3),
            flag = wx.EXPAND
        )
        sizer.Add(
            wx.StaticText(self, -1, text.oldType),
            (3, 4),
            flag = wx.ALIGN_CENTER_VERTICAL
        )
        self.oldTypeCtrl = wx.TextCtrl(self, -1)
        self.oldTypeCtrl.Enable(False)
        sizer.Add(
            self.oldTypeCtrl,
            (3, 5),
            flag = wx.EXPAND
        )
        self.FillOldValue(key, subkey, valueName)

        #Create TreeCtrl
        tree = RegistryLazyTree(self, -1, key, subkey, valueName, text=text)
        sizer.Add(tree, (1, 0), (1, 6), flag = wx.EXPAND)

        if valueName is None:
            valueName = ""
        elif len(valueName) == 0:
            valueName = text.defaultText
        valueNameCtrl = wx.TextCtrl(self, -1, valueName, size=(100, -1))
        sizer.Add(valueNameCtrl, (2, 5), flag = wx.EXPAND)
        sizer.AddGrowableRow(1)
        sizer.AddGrowableCol(3, 2)
        sizer.AddGrowableCol(5, 1)

        self.SetSizer(sizer)
        self.SetAutoLayout(True)
        sizer.Fit(self)
        self.Layout()
        self.SetMinSize(self.GetSize())

        self.keyChoice = keyChoice
        self.subkeyCtrl = subkeyCtrl
        self.valueNameCtrl = valueNameCtrl
        self.tree = tree
        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeSelect)
        self.subkeyCtrl.Bind(wx.EVT_TEXT, self.OnSubkeyEnter)
        self.Bind(wx.EVT_SIZE, self.OnSize)

    def FillOldValue(self, key, subkey, valueName):
        curType = None
        curValue = None
        if valueName is not None:
            try:
                regHandle = _winreg.OpenKey(key, subkey)
                regValue = _winreg.QueryValueEx(regHandle, valueName)
                _winreg.CloseKey(regHandle)
                for i in range(1, len(regTypes)):
                    if regTypes[i][0] == regValue[1]:
                        curType = regTypes[i][1]
                        break
            except EnvironmentError:
                curType = ""
                curValue = self.text.noValueText
            if len(curType) > 0:
                try:
                    curValue = unicode(regValue[0])
                except:
                    #convert to hex
                    curValue = "0x" + binascii.hexlify(regValue[0]).upper()
        else:
            curType = self.text.keyText2
            curValue = ""

        self.oldValueCtrl.SetValue(str(curValue))
        self.oldTypeCtrl.SetValue(curType)

    def GetValue(self):
        #key
        key = regKeys[self.keyChoice.GetSelection()][0]

        #subkey
        subkey = self.subkeyCtrl.GetValue()

        #valueName
        valueName = self.valueNameCtrl.GetValue()
        if len(valueName) == 0:
            valueName = None
        elif valueName == self.text.defaultText:
            valueName = ""

        return key, subkey, valueName

    def OnSize(self, dummyEvent):
        if self.GetAutoLayout():
            self.Layout()

    def OnSubkeyEnter(self, event):
        value = self.subkeyCtrl.GetValue()
        if value.startswith("HK") and value.count("\\") > 0:
            #probably a whole key pasted
            tmp = value.split("\\", 1)
            key = tmp[0].upper()  #get first part
            value = tmp[1]
            for i in range(0, len(regKeys)):
                if regKeys[i][1] == key or regKeys[i][2] == key:
                    self.keyChoice.SetSelection(i)
                    self.subkeyCtrl.SetValue(value)
                    break
        event.Skip()

    def OnTreeSelect(self, event):
        key, subkey, valueName = self.tree.GetValue()
        if key is not None:  #change only if not root node
            if valueName is None:
                self.valueNameCtrl.SetValue("")
            elif len(valueName) == 0:
                self.valueNameCtrl.SetValue(self.text.defaultText)
            else:
                self.valueNameCtrl.SetValue(valueName)
            self.subkeyCtrl.SetValue(subkey)
            for i in range(0, len(regKeys)):
                if regKeys[i][0] == key:
                    self.keyChoice.SetSelection(i)
                    break
        self.FillOldValue(key, subkey, valueName)
        event.Skip()


class RegistryLazyTree(wx.TreeCtrl):
    def __init__(
        self,
        parent,
        id=-1,
        key = _winreg.HKEY_CURRENT_USER,
        subkey = "Software",
        valueName = None,
        pos = wx.DefaultPosition,
        size = wx.DefaultSize,
        style = wx.TR_HAS_BUTTONS,
        validator = wx.DefaultValidator,
        name="RegistryLazyTree",
        text = None
    ):
        self.text = text
        wx.TreeCtrl.__init__(
            self, parent, id, pos, size, style, validator, name
        )

        self.imageList = imageList = wx.ImageList(16, 16)
        rootIcon = imageList.Add(eg.Icons.GetInternalBitmap("root"))
        self.folderIcon = imageList.Add(eg.Icons.GetInternalBitmap("folder"))
        self.valueIcon = imageList.Add(eg.Icons.GetInternalBitmap("action"))
        self.SetImageList(imageList)
        self.SetMinSize((-1, 200))
        self.treeRoot = self.AddRoot(
            "Registry",
            image = rootIcon,
            data = wx.TreeItemData((True, None, None, None))
        )
        #Adding keys
        for item in regKeys:
            #a tupel of 4 values is assigned to every item
            #1) stores if the key has yet to be queried for subkey, when
            #   selected
            #2) _winreg.hkey constant
            #3) name of the key
            #4) value name, None if just a key, empty string for default value
            tmp = self.AppendItem(
                self.treeRoot,
                item[1],
                image = self.folderIcon,
                data =wx.TreeItemData((False, item[0], "", None))
            )
            self.SetItemHasChildren(tmp, True)
            if item[0] == key:
                self.SelectItem(tmp)

        #select old value in tree
        self.OnTreeChange(wx.CommandEvent(), key, subkey, valueName)
        self.EnsureVisible(self.GetSelection())

        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeChange)
        self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnExpandNode)

    def GetValue(self):
        data = self.GetItemData(self.GetSelection()).GetData()
        return data[1], data[2], data[3]

    def OnExpandNode(self, event):
        self.OnTreeChange(event, node = event.GetItem())

    def OnTreeChange(
        self,
        event,
        key2Select = None,
        subkey2Select = None,
        valueName2Select = None,
        node = None
    ):
        if not node:
            node = self.GetSelection()

        keyHasBeenQueried, fatherKey, \
            fatherSubkey, fatherValueName = self.GetItemData(node).GetData()
        subkey2Find = None
        newItemSelected = False

        if not keyHasBeenQueried:  #check for subkeys
            self.SetItemData(
                node,
                wx.TreeItemData(
                    (True, fatherKey, fatherSubkey, fatherValueName)
                )
            )

            #buildung tree
            try:
                regHandle = _winreg.OpenKey(fatherKey, fatherSubkey)
            except EnvironmentError, exc:
                eg.PrintError(self.text.keyOpenError + ": " + str(exc))
                return 0

            #query subkeys
            if len(fatherSubkey) == 0:
                parentSubkey = ""
            else:
                parentSubkey = fatherSubkey + "\\"

            #preparing strings to find the subkey2Select key
            if valueName2Select:
                valueName2Select = valueName2Select.lower()
            if subkey2Select:
                subkey2Select = subkey2Select.lower()
            if key2Select and subkey2Select and key2Select == fatherKey:
                length = len(fatherSubkey)
                if subkey2Select[0:length] == fatherSubkey.lower():
                    subkey2Find = subkey2Select[length:]
                    if subkey2Find.startswith("\\"):
                        subkey2Find = subkey2Find[1:]
                    subkeys = subkey2Find.split("\\", 1)
                    subkey2Find = subkeys[0]

            #building Tree
            keyNames, valueList = RegEnumKeysAndValues(regHandle.handle)

            #sorting
            keyNames.sort(lambda a, b: cmp(a[0].lower(), b[0].lower()))
            valueList.sort(lambda a, b: cmp(a[0].lower(), b[0].lower()))

            #subkeys
            for keyName, numSubKeys, numSubValues in keyNames:
                hasChildren = bool(numSubKeys + numSubValues > 0)
                data = (
                    not hasChildren,
                    fatherKey,
                    parentSubkey + keyName,
                    None
                )
                tmp = self.AppendItem(
                    node,
                    keyName,
                    image=self.folderIcon,
                    data=wx.TreeItemData(data)
                )
                if subkey2Find == keyName.lower():
                    newItemSelected = True
                    self.SelectItem(tmp)
                self.SetItemHasChildren(tmp, hasChildren)

            #values
            for valueName, valueType in valueList:
                if len(valueName) == 0:
                    enumValueName = self.text.defaultText
                else:
                    enumValueName = valueName
                data = (True, fatherKey, fatherSubkey, valueName)
                tmp = self.AppendItem(
                    node,
                    enumValueName,
                    image = self.valueIcon,
                    data = wx.TreeItemData(data)
                )
                if (
                    valueName2Select is not None and
                    valueName.lower() == valueName2Select and
                    subkey2Select == fatherSubkey.lower()
                ):
                    newItemSelected = True
                    self.SelectItem(tmp)

        if newItemSelected:
            self.OnTreeChange(
                wx.CommandEvent(),
                key2Select,
                subkey2Select,
                valueName2Select
            )
        event.Skip()


def FullKeyName(key, subkey, valueName, maxSubkeyLength=15):
    label = "root"
    if not key:
        return label

    for i in range(0, len(regKeys)):
        if regKeys[i][0] == key:
            label = regKeys[i][2]
            break

    if not subkey:
        return label

    if (
        maxSubkeyLength and
        len(subkey) > maxSubkeyLength and
        subkey.count("\\") != 0
    ):
        label += "\\...\\" + subkey.rsplit("\\", 1)[1]
    else:
        label += "\\" + subkey

    if valueName is None:
        return label
    elif len(valueName) == 0:
        return label + "\\" + Text.RegistryGroup.defaultText
    else:
        return label + "\\" + valueName