'''
Created on 23.07.2019

@author: wang
'''
import sys # @NoMove @UnusedImport
import os
import wx
import collections
import six
import sqlite3
from wx.lib import buttons
from functools import singledispatch, update_wrapper
from types import MethodType
from p2c.window import BORDER, BIGBORDER, SMALLBORDER, MINIBORDER, OptiCheckBox, getOpticamIcon
    
from p2c.window import BaseDialog, ListEnableCheck, NormalButton, NiceButton
from p2c.window import getToolTip, PopupWindow, TOOLTIP_DELAYTIME, GetTooltipHoldingTime # @NoMove @UnusedImport
from p2c.window import EditField, TextField, BasePanel, LabeledEditField, LabeledChoiceBox, getText, BEHAVIOUR, IsMethod  # @NoMove @UnusedImport
from p2c.utils import logger, _DEBUG, inPeps, inPepsUG, inPepsSW # Debug @UnusedImport
from p2c.postoptionsdlg import postVar

from p2cpython import getCurrentDoc, Point3d, Vector3d, Plane, getMessageW, PYTHON_MESSAGES  # @UnresolvedImport
from p2cpython import P2C_VERTEX, P2C_SKETCH, SEL_OPTICAM_FIRST_OFFSET, RAY_TYPE, Ray, SEL_OPITCAM_RAY, SEL_CAD_VERTEX  # @UnresolvedImport  @UnusedImport
from p2cpython import SEL_CAD_POINT, SEL_MID_POINT, SEL_CEN_POINT, SEL_END_POINT, P2C_POINT, SEL_OPITCAM_POINT3D, SEL_OPITCAM_POINT2D, SEL_OPITCAM_LINE, SEL_OPITCAM_ARC, SEL_OPITCAM_CIRCLE # @UnresolvedImport
import xml.dom.minidom as dom
import xml.etree.ElementTree as ET

#TOOLTIP_HOLDTIME = 2000
TOOLTIP_DELAYTIME = 600

import p2cpython as opticam # @UnresolvedImport

# python 3.8+ compatibility
try:
    collectionsAbc = collections.abc
except:
    collectionsAbc = collections

LOG_TAG = "measurecycledlg.py "

SHOWCOLORS = False      # for developing / debug purpose 

# Machine Mapping Name with ID, Use it in order to maintain compatibility with PEPS. Why isn't PEPS compatible with Opticam?
# Because the Measure Cycle part is first implemented in PEPS. Why need to consider compatibility issues?
# Because it is very likely that in the future, the saved parameters of Opticam and PEPS need to be cross-used.
# More info please ask peps programmer or file dialog_profiles.ovm, name in lower case, id in string format
# Why should I write those comments? No more questions please. I break down in tears every time I talk about it
MACHINE_MAPPING_NAME_TO_ID = {
    "accut": "01",
    "accutex": "02",
    "accutx00": "03",
    "acfanuc": "04",
    "acmillennium": "05",
    "acorange": "06",
    "acvision": "07",
    #"agiecnc123": "08",
    "agie": "08",
    "ona": "09",
    #"andrews": "09",
    "brother": "10",
    #"opticam": "10",
    "robo": "11",
    "chmer": "12",
    "cutexx0": "13",
    "accutexx0": "13",
    "excetek": "14",
    "fanuc": "15",
    "hitachi": "16",
    "japax": "17",
    "joemars": "18",
    "makino": "19",
    "mitsubishi": "20",
    "mseibu": "21",
    "onaaricut": "22",
    "seibu": "23",
    "sodick": "24",
    "accutuniqua": "25",
    
    }


SQLITE3_MUSTER_DICT_TYPE_38 = { "VERSION" : "38", # 38 mean, 38 field of this table type
                                "KEY_PART1": "", # type_id of MeasureType
                                "SEARCHTERM":"1", # records index of one MeasureType
                                "KEY" : "",     # KEY_PART1 bind with SEARCHTERM, unique, primary key
                                "COMMENT1": "", # customer input comment
                                "COMMENT2": "", # example: EDG GOP,1  SEP,1
                                "COMMENT3": "", # example: P +X DR=1  X=0  Y=0
                                "COMMENT4": "", # example: MOV,C,X15  MOV,C,Y16
                                "CUSTOMER1":"",  # CUSTOMER1 <- post processor id
                                "CUSTOMER2":"",  # CUSTOMER2 <- post processor name
                                "PAR_1" :"", # -32768 NOT_SET is default
                                "PAR_2" :"",
                                "PAR_3" :"",
                                "PAR_4" :"",
                                "PAR_5" :"",
                                "PAR_6" :"",
                                "PAR_7" :"",
                                "PAR_8" :"",
                                "PAR_9" :"",
                                "PAR_10" :"",
                                "PAR_11" :"",
                                "PAR_12" :"",
                                "PAR_13" :"",
                                "PAR_14" :"",
                                "PAR_15" :"",
                                "PAR_16" :"",
                                "PAR_17" :"",
                                "PAR_18" :"",
                                "PAR_19" :"",
                                "PAR_20" :"",
                                "PAR_21" :"",
                                "PAR_22" :"",
                                "PAR_23" :"",
                                "PAR_24" :"",
                                "PAR_25" :"",
                                "PAR_26" :"",
                                "PAR_27" :"",
                                "PAR_28" :"" # <- strVDMVersion
                                }


SQLITE_MCY_TABLE_SCHEMA_TYPE28  = """ CREATE TABLE IF NOT EXISTS {0!r} (
                                        ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
                                        VERSION INT NOT NULL,
                                        KEY_PART1 CHAR(10) NOT NULL,
                                        SEARCHTERM INT NOT NULL,
                                        KEY CHAR(10) NOT NULL,
                                        COMMENT1 TEXT DEFAULT '',
                                        COMMENT2 TEXT DEFAULT '',
                                        COMMENT3 TEXT DEFAULT '',
                                        COMMENT4 TEXT DEFAULT '',
                                        PAR_1 REAL DEFAULT -32768, 
                                        PAR_2 REAL DEFAULT -32768, 
                                        PAR_3 REAL DEFAULT -32768, 
                                        PAR_4 REAL DEFAULT -32768, 
                                        PAR_5 REAL DEFAULT -32768, 
                                        PAR_6 REAL DEFAULT -32768, 
                                        PAR_7 REAL DEFAULT -32768, 
                                        PAR_8 REAL DEFAULT -32768, 
                                        PAR_9 REAL DEFAULT -32768, 
                                        PAR_10 REAL DEFAULT -32768, 
                                        PAR_11 REAL DEFAULT -32768, 
                                        PAR_12 REAL DEFAULT -32768, 
                                        PAR_13 REAL DEFAULT -32768, 
                                        PAR_14 REAL DEFAULT -32768, 
                                        PAR_15 REAL DEFAULT -32768, 
                                        PAR_16 REAL DEFAULT -32768, 
                                        PAR_17 REAL DEFAULT -32768, 
                                        PAR_18 REAL DEFAULT -32768, 
                                        PAR_19 REAL DEFAULT -32768, 
                                        PAR_20 REAL DEFAULT -32768, 
                                        PAR_21 REAL DEFAULT -32768, 
                                        PAR_22 REAL DEFAULT -32768, 
                                        PAR_23 REAL DEFAULT -32768, 
                                        PAR_24 REAL DEFAULT -32768, 
                                        PAR_25 REAL DEFAULT -32768, 
                                        PAR_26 REAL DEFAULT -32768, 
                                        PAR_27 REAL DEFAULT -32768, 
                                        PAR_28 REAL DEFAULT -32768,
                                        CUSTOMER1 TEXT DEFAULT '',
                                        CUSTOMER2 TEXT DEFAULT ''
                                    ); """

PROFILE_TABLE_TYPE28 = "opticam_measure_cycle_profile_type_28"


SQLITE_MCY_TABLE_SCHEMA_TYPE64  = """CREATE TABLE "{}" (
            "ID"    INTEGER NOT NULL,
            "VERSION"    INT NOT NULL,
            "KEY_PART1"    CHAR(10) NOT NULL,
            "SEARCHTERM"    INT NOT NULL,
            "KEY"    CHAR(10) NOT NULL,
            "COMMENT1"    TEXT DEFAULT '',
            "COMMENT2"    TEXT DEFAULT '',
            "COMMENT3"    TEXT DEFAULT '',
            "COMMENT4"    TEXT DEFAULT '',
            "PAR_1"    REAL DEFAULT -32768,
            "PAR_2"    REAL DEFAULT -32768,
            "PAR_3"    REAL DEFAULT -32768,
            "PAR_4"    REAL DEFAULT -32768,
            "PAR_5"    REAL DEFAULT -32768,
            "PAR_6"    REAL DEFAULT -32768,
            "PAR_7"    REAL DEFAULT -32768,
            "PAR_8"    REAL DEFAULT -32768,
            "PAR_9"    REAL DEFAULT -32768,
            "PAR_10"    REAL DEFAULT -32768,
            "PAR_11"    REAL DEFAULT -32768,
            "PAR_12"    REAL DEFAULT -32768,
            "PAR_13"    REAL DEFAULT -32768,
            "PAR_14"    REAL DEFAULT -32768,
            "PAR_15"    REAL DEFAULT -32768,
            "PAR_16"    REAL DEFAULT -32768,
            "PAR_17"    REAL DEFAULT -32768,
            "PAR_18"    REAL DEFAULT -32768,
            "PAR_19"    REAL DEFAULT -32768,
            "PAR_20"    REAL DEFAULT -32768,
            "PAR_21"    REAL DEFAULT -32768,
            "PAR_22"    REAL DEFAULT -32768,
            "PAR_23"    REAL DEFAULT -32768,
            "PAR_24"    REAL DEFAULT -32768,
            "PAR_25"    REAL DEFAULT -32768,
            "PAR_26"    REAL DEFAULT -32768,
            "PAR_27"    REAL DEFAULT -32768,
            "PAR_28"    REAL DEFAULT -32768,
            "PAR_29"    REAL DEFAULT -32768,
            "PAR_30"    REAL DEFAULT -32768,
            "PAR_31"    REAL DEFAULT -32768,
            "PAR_32"    REAL DEFAULT -32768,
            "PAR_33"    REAL DEFAULT -32768,
            "PAR_34"    REAL DEFAULT -32768,
            "PAR_35"    REAL DEFAULT -32768,
            "PAR_36"    REAL DEFAULT -32768,
            "PAR_37"    REAL DEFAULT -32768,
            "PAR_38"    REAL DEFAULT -32768,
            "PAR_39"    REAL DEFAULT -32768,
            "PAR_40"    REAL DEFAULT -32768,
            "PAR_41"    REAL DEFAULT -32768,
            "PAR_42"    REAL DEFAULT -32768,
            "PAR_43"    REAL DEFAULT -32768,
            "PAR_44"    REAL DEFAULT -32768,
            "PAR_45"    REAL DEFAULT -32768,
            "PAR_46"    REAL DEFAULT -32768,
            "PAR_47"    REAL DEFAULT -32768,
            "PAR_48"    REAL DEFAULT -32768,
            "PAR_49"    REAL DEFAULT -32768,
            "PAR_50"    REAL DEFAULT -32768,
            "PAR_51"    REAL DEFAULT -32768,
            "PAR_52"    REAL DEFAULT -32768,
            "PAR_53"    REAL DEFAULT -32768,
            "PAR_54"    REAL DEFAULT -32768,
            "PAR_55"    REAL DEFAULT -32768,
            "PAR_56"    REAL DEFAULT -32768,
            "PAR_57"    REAL DEFAULT -32768,
            "PAR_58"    REAL DEFAULT -32768,
            "PAR_59"    REAL DEFAULT -32768,
            "PAR_60"    REAL DEFAULT -32768,
            "PAR_61"    REAL DEFAULT -32768,
            "PAR_62"    REAL DEFAULT -32768,
            "PAR_63"    REAL DEFAULT -32768,
            "PAR_64"    REAL DEFAULT -32768,            
            "CUSTOMER1"    TEXT DEFAULT '',
            "CUSTOMER2"    TEXT DEFAULT '',
            PRIMARY KEY("ID" AUTOINCREMENT)
        )"""

PROFILE_TABLE_TYPE64 = "opticam_measure_cycle_profile_type_64"

########################################################################
class MyWidgetLinkageEvent(wx.PyCommandEvent):
    def __init__(self, evtType, id, args):  # @ReservedAssignment
        wx.PyCommandEvent.__init__(self, evtType, id)
        self.eventArgs = args
        
    def GetEventArgs(self):
        return self.eventArgs
    
    def SetEventArgs(self, args):
        self.eventArgs = args


########################################################################
class MyMethodLinkageEvent(wx.PyCommandEvent):
    def __init__(self, evtType, id, args):  # @ReservedAssignment
        wx.PyCommandEvent.__init__(self, evtType, id)
        self.eventArgs = args
        
    def GetEventArgs(self):
        return self.eventArgs
    
    def SetEventArgs(self, args):
        self.eventArgs = args

WidgetLinkageEventType = wx.NewEventType() # new event type
MethodLinkageEventType = wx.NewEventType() # new event type
EVT_WIDGETLINKAGE = wx.PyEventBinder(WidgetLinkageEventType, 1) # create a binder object
EVT_METHODLINKAGE = wx.PyEventBinder(MethodLinkageEventType, 1) # create a binder object


########################################################################
class MyMainButtonsPanel(wx.Panel):
    def __init__(self, parent, id=wx.ID_ANY, style=wx.TAB_TRAVERSAL, name=""):  # @ReservedAssignment
        """
        Button part: 
        """
        wx.Panel.__init__(self, parent, id=id, style=style, name=name)
        #self.SetBackgroundColour('GREEN')
        
        self.vbxV0 = wx.BoxSizer(wx.VERTICAL)
        
        parent.vbxH0 = wx.BoxSizer( wx.HORIZONTAL )
        parent.titleBar = wx.StaticText(self, wx.ID_ANY, parent.GetTitle(), name="_" + "panelTitle")
        parent.vbxH0.Add(parent.titleBar )
        parent.vbxH0.Show(parent.titleBar, False)
        self.vbxV0.Add(parent.vbxH0, 0, wx.EXPAND)
        
        self.vbxH1 = wx.GridBagSizer(1, 6)
        self.vbxH1.Add((BIGBORDER, 1), (0, 5), (1, 2), wx.EXPAND)
        self.vbxH1.Add((BORDER, 1), (0, 9))
        self.vbxH1.AddGrowableRow(0)
        self.vbxH1.AddGrowableCol(5)
        
        self.btnOK = NiceButton(self, wx.ID_OK, 'okup.ico', 'okdown.ico', 'okup_grey.ico', name="BTN_OK")
        self.btnOK.SetToolTipString("OK")
        self.btnOK.Bind(wx.EVT_BUTTON, parent.OnOK)
        self.vbxH1.Add(self.btnOK, (0, 0), flag=wx.LEFT, border=BORDER)

        self.btnESC = NiceButton(self, wx.ID_CANCEL, 'cancelup.ico', 'canceldown.ico', 'cancelup_grey.ico', name="BTN_CANCEL")
        self.btnESC.SetToolTipString("Cancel")
        self.btnESC.Bind(wx.EVT_BUTTON, parent.OnESC)
        self.vbxH1.Add(self.btnESC, (0, 1))

        self.btnHelp = NiceButton(self, wx.ID_HELP, 'helpup.ico', 'helpdown.ico', 'helpup_grey.ico', name="BTN_HELP")
        self.btnHelp.SetToolTipString("Help")
        self.btnHelp.Bind(wx.EVT_BUTTON, parent.OnHelp)
        self.vbxH1.Add(self.btnHelp, (0, 2))
            
        if _DEBUG & 0x4:
            self.btnSave = NiceButton(self, wx.ID_SAVE, 'savedefault.ico', 'Warning.ico', name="BTN_SAVESETTINGS")
        else:
            self.btnSave = NiceButton(self, wx.ID_SAVE, 'savedefault.ico', 'savedefault_OK.ico', name="BTN_SAVESETTINGS", pressed=True)
        self.btnSave.Bind(wx.EVT_BUTTON, parent.OnSave)
        self.vbxH1.Add(self.btnSave, (0, 3))

            
        # Add a image button for Reset
        if _DEBUG & 0x4:
            self.btnReset= NiceButton(self, wx.ID_RESET, '3_Load Default_Liste.ico', 'Warning.ico', name="BTN_RESET_SETTINGS")
        else:
            self.btnReset = NiceButton(self, wx.ID_RESET, '3_Load Default_Liste.ico', name="BTN_RESET_SETTINGS")
        self.btnReset.SetToolTipString("Reset entries")
        self.btnReset.Bind(wx.EVT_BUTTON, parent.OnReset)
        self.vbxH1.Add(self.btnReset, (0, 4), flag=wx.TOP, border=4)

        self.btnTRA = NiceButton(self, wx.ID_ANY, 'translator.ico', name="BTN_TRANSLATOR")
        self.btnTRA.SetToolTipString("Translation")
        self.btnTRA.Bind(wx.EVT_BUTTON, parent.OnTranslate)
        self.vbxH1.Add(self.btnTRA, (0, 7))
        
        if os.environ.get('OPTICAM_LANGUAGE_TRANSLATOR', '').upper() == 'TRUE':
            self.btnTRA.Show(True)
        else:
            self.btnTRA.Show(False)

        self.btnDOC = NiceButton(self, wx.ID_ANY, 'pindown.ico', name="BTN_PIN")
        self.btnDOC.SetToolTipString("Pin")
        self.btnDOC.Bind(wx.EVT_BUTTON, parent.OnDock)
        self.vbxH1.Add(self.btnDOC, (0, 8))
        self.vbxV0.Add(self.vbxH1, 0, wx.TOP | wx.BOTTOM | wx.EXPAND, BORDER)
        topLine = wx.StaticLine(self, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
           style=wx.LI_HORIZONTAL, name="Top Line")
        self.vbxV0.Add(topLine, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 1)
        self.SetSizer(self.vbxV0)


########################################################################
class DummyPanel(wx.Panel):
    """"""
    #----------------------------------------------------------------------
    def __init__(self, parent, id=wx.ID_ANY, style=wx.TAB_TRAVERSAL, name="DUMMY"):  # @ReservedAssignment
        """Constructor"""
        wx.Panel.__init__(self, parent, id=id, style=style, name=name)
        #self.SetBackgroundColour('GREEN')
        self.vbxV0 = wx.BoxSizer(wx.VERTICAL)
        self.txt = wx.StaticText(self, wx.ID_ANY, "DUMMY")
        self.vbxV0.Add(self.txt, 0, wx.EXPAND, 1)
        self.SetSizer(self.vbxV0)


#+++++++++++++++++++++++++++++++++++++++++++++++++++++
# a class for very beautiful toggle buttons:
#+++++++++++++++++++++++++++++++++++++++++++++++++++++
class NiceBitmapButton(buttons.GenBitmapButton):
    def __init__(self, parent, id=wx.ID_ANY, buttonUpICO=None,  # @ReservedAssignment
                  buttonDownICO=None, disabledButtonICO=None, style = wx.NO_BORDER,
                   name='NiceButton', toolTipString=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize):  # @ReservedAssignment @UnusedVariable
        self.bWidgetLinkage = None # if not none, use callafter call this method
        self.bMethodLinkage = None # if not none, use callafter call this method
        self.typeOfValue = None
        self.keyOfParams = "" # for example [DR], [R], if not defined, use value directly
        self.indexOfKey = None # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
        self.typeOfParams = None # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
        self.valuesOfParams = None # if typeOfParams ist not none, this attribute must be defined
        self.decimalDigitsOfOuput = 0 # for function round, 0 is integer
        self.buttonValue = None
        
        self.popUpWin = None
        self.shouldPOP = False
        
        # c'tor saves current, The local setting of SW is special
        local = opticam.LocalPy()  # @UndefinedVariable
        local.set("C")
        
        bmp = wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE, wx.ART_OTHER, (32, 32))
        buttons.GenBitmapButton.__init__(self, parent, id, bmp, wx.DefaultPosition, size, style, wx.DefaultValidator, name) 
        
        if buttonUpICO != None:
            self.SetBitmapLabel( getOpticamIcon(buttonUpICO) )

        if buttonDownICO != None:
            self.SetBitmapSelected( getOpticamIcon(buttonDownICO) )

        if disabledButtonICO != None:
            self.SetBitmapDisabled( getOpticamIcon(disabledButtonICO) )

        self.SetToolTipString(toolTipString)
    
    def DrawLabel(self, dc, width, height, dx=0, dy=0):
        bmp = self.bmpLabel
        if self.bmpDisabled and not self.IsEnabled():
            bmp = self.bmpDisabled
        if self.bmpFocus and self.hasFocus:
            bmp = self.bmpFocus
        if self.bmpSelected and not self.up:
            bmp = self.bmpSelected
        bw,bh = bmp.GetWidth(), bmp.GetHeight()
        if not self.up:
            dx = dy = self.labelDelta
        hasMask = bmp.GetMask() != None
        dc.DrawBitmap(bmp, (width-bw)//2+dx, (height-bh)//2+dy, hasMask)

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        buttons.GenBitmapToggleButton.Enable(self, enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)

    def Disable(self):
        buttons.GenBitmapToggleButton.Disable(self)
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        self.shouldPOP = False
        logger.debug("%s%s" % ('LeaveButton called ', self.popUpWin))
        # destroy the popup window
        self.killPop()

    def showPop(self, pos):
        for objChild in self.GetParent().GetChildren():
            if objChild != self:
                if hasattr(objChild, "popUpWin"):
                    if objChild.popUpWin and objChild.shouldPOP: 
                        objChild.popUpWin.Destroy() 
                        objChild.popUpWin = None
                        objChild.shouldPOP = False
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString())
            if GetTooltipHoldingTime() is not None:
                wx.FutureCall(GetTooltipHoldingTime(), self.killPop)

    def killPop(self):
        if self.popUpWin is not None:  # only when we have one, we can kill it
            self.popUpWin.Destroy()
            self.popUpWin = None

    def setButtonUpICO(self, ico):
        if ico is not None:
            self.SetBitmapLabel( getOpticamIcon(ico) )

    def setButtonDownICO(self, ico):
        if ico is not None:
            self.SetBitmapSelected( getOpticamIcon(ico) )

    def setDisabledButtonICO(self, ico):
        if ico is not None:
            self.SetBitmapDisabled( getOpticamIcon(ico) )

    def setButtonHasFocusICO(self, ico):
        if ico is not None:
            self.SetBitmapFocus( getOpticamIcon(ico) )

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.BitmapButton.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def GetWindowText(self):
        return self.buttonValue

    def GetValue(self):
        return self.buttonValue

    def SetValue(self, val):
        self.buttonValue = val
            

class MYNiceButton(NiceBitmapButton):
    def __init__(self, parent, id=wx.ID_ANY, buttonUpICO=None,  # @ReservedAssignment
                  buttonDownICO=None, disabledButtonICO=None, style = 1, measureType = "", 
                   name='NiceButton', toolTipString=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize):  # @ReservedAssignment @UnusedVariable

        # c'tor saves current, The local setting of SW is special
        local = opticam.LocalPy()  # @UndefinedVariable
        local.set("C")
        # d'tor resets to saved!
        if buttonUpICO != None:
            bmp = getOpticamIcon(buttonUpICO)
        else:
            bmp = wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE, wx.ART_OTHER, (140, 90))
        buttons.GenBitmapButton.__init__(self, parent, id, bmp, wx.DefaultPosition, size, style, wx.DefaultValidator, name) 
        #wx.BitmapButton.__init__(self, parent, id, wx.NullBitmap, wx.DefaultPosition, size, style, wx.DefaultValidator, name)
        #No wx.NullBitmap does not work here, use wx.missing-image as default
        self.strMeasureCycleType = measureType

        # if buttonUpICO != None:
        #     self.SetBitmapLabel(getOpticamIcon(buttonUpICO))

        if buttonDownICO != None:
            img = getOpticamIcon(buttonDownICO)
            img.SetMaskColour((240, 240, 240, 255))
            self.SetBitmapSelected(img)

        if disabledButtonICO != None:
            self.SetBitmapDisabled(getOpticamIcon(disabledButtonICO))

        self.SetToolTipString(toolTipString)
        self.SetForegroundColour((240, 240, 240, 255))
        ##self.SetBackgroundColour((240, 240, 240, 255))
        self.SetBezelWidth(5)
        self.popUpWin = None
        self.shouldPOP = False
    
    def DrawLabel(self, dc, width, height, dx=0, dy=0):
        bmp = self.bmpLabel
        if self.bmpDisabled and not self.IsEnabled():
            bmp = self.bmpDisabled
        if self.bmpFocus and self.hasFocus:
            bmp = self.bmpFocus
        if self.bmpSelected and not self.up:
            bmp = self.bmpSelected
        bw,bh = bmp.GetWidth(), bmp.GetHeight()
        if not self.up:
            dx = dy = self.labelDelta
        hasMask = bmp.GetMask() != None
        dc.DrawBitmap(bmp, (width-bw)//2+dx, (height-bh)//2+dy, hasMask)
    
    def GetMeasureCycleType(self):
        return self.strMeasureCycleType
    
    def SetMeasureCycleType(self, strNT=""):
        self.strMeasureCycleType = strNT
    
    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)
        
    def showPop(self, pos):
        for objChild in self.GetParent().GetChildren():
            if objChild != self:
                if hasattr(objChild, "popUpWin"):
                    if objChild.popUpWin and objChild.shouldPOP: 
                        objChild.popUpWin.Destroy() 
                        objChild.popUpWin = None
                        objChild.shouldPOP = False
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString())
            if GetTooltipHoldingTime() is not None:
                wx.FutureCall(GetTooltipHoldingTime(), self.killPop)


class RightLabeledEditField(LabeledEditField):
    '''Represents an label field with an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, value=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0, behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString, name='labeledEditField', style=0, ContextMenu = False, editSize=wx.DefaultSize, Callback=False, minSizeEdit=(100, -1)):  # @ReservedAssignment
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        BasePanel.__init__(self, parent, id, pos=pos, size=size, style=wx.NO_BORDER, name=name)

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)

        self.SetToolTipString(toolTipString)
        self.bWidgetLinkage = None # if not none, use callafter call this method
        self.bMethodLinkage = None # if not none, use callafter call this method
        self.typeOfValue = None
        self.keyOfParams = "" # for example [DR], [R], if not defined, use value directly
        self.indexOfKey = None # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
        self.typeOfParams = None # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
        self.valuesOfParams = None # if typeOfParams ist not none, this attribute must be defined
        self.decimalDigitsOfOuput = 0 # for function round, 0 is integer
        self.popUpWin = None
        self.shouldPOP = False

        # an optional bitmap (not used, just to see how artprovider works)
        """
        bmp = wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_OTHER, (16, 16))
        ico = wx.StaticBitmap(parent, wx.ID_ANY, bmp)
        self.hbox.Add(ico, 0, wx.ALL|wx.ALIGN_CENTER, SMALLBORDER)
        """

        self.edit = EditField(self, wx.ID_ANY, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name="__" + name, style=style)
        self.edit.SetInitialSize((-1, -1))
        self.edit.Unbind(wx.EVT_TEXT)
        #override the method of EditFiled
        def _setText(self, val):
            """
            update the TextCtrl without triggering its callbacks.
            """
            oldSetting = self.GetEvtHandlerEnabled()
            self.SetEvtHandlerEnabled(False)    # for programmatic changes we don't want an event
            try:
                if not isinstance(val, str):
                    val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            except NameError:
                val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            finally:                            # so the old setting is safely restored
                self.SetEvtHandlerEnabled(oldSetting)
        self.edit.setText = MethodType(_setText, self.edit)
        if minSizeEdit != None:
            self.edit.SetInitialSize(minSizeEdit)
        self.hbox.Add(self.edit, 0, wx.TOP|wx.BOTTOM|wx.RIGHT, 1)
        
        self.lbl = wx.StaticText(self, wx.ID_ANY, label, style=wx.ALIGN_LEFT, name="_" + name)
        self.lbl.SetInitialSize((-1, -1))
        
        self.hbox.Add(self.lbl, 0, wx.LEFT | wx.TOP | wx.BOTTOM, 1)
        #self.hbox.Add(SPACER, 1, wx.ALL, SMALLBORDER)
        
        if _DEBUG & 0x4:
            self.lbl.SetBackgroundColour('YELLOW')


        self.SetSizerAndFit(self.hbox)
        
        #Check if we have a custom Popup Menu
        if ContextMenu != False:
            if IsMethod(ContextMenu) == True:
                self.ContextMenu = ContextMenu
                self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        # allow a callback function to inform the calling code if this widget is focused
        if Callback:
            self.Bind(wx.EVT_CHILD_FOCUS, self.OnCildFocus) 
        self.Callback = Callback
    
    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)
    
    def showPop(self, pos):
        for objChild in self.GetParent().GetChildren():
            if objChild != self:
                if hasattr(objChild, "popUpWin"):
                    if objChild.popUpWin and objChild.shouldPOP: 
                        objChild.popUpWin.Destroy() 
                        objChild.popUpWin = None
                        objChild.shouldPOP = False
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString())
            if GetTooltipHoldingTime() is not None:
                wx.FutureCall(GetTooltipHoldingTime(), self.killPop)

    # def Enable(self, enable=True):
    #     if enable is None:
    #         return
    #     LabeledEditField.Enable(self, enable)
        

class LeftLabeledChoiceBox(LabeledChoiceBox):
    '''Represents an label field with an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, value=wx.EmptyString,  # @ReservedAssignment
                  pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0,  # @ReservedAssignment
                  behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString,
                  name='labeledChoiceBox', style=0, ContextMenu = False, 
                  editSize=wx.DefaultSize, Callback=False, minSizeEdit=(50, -1), bWithCheckbox=False):  # @ReservedAssignment
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        BasePanel.__init__(self, parent, id, pos=pos, size=size, style= wx.RAISED_BORDER, name=name)
        if SHOWCOLORS:
            BasePanel.SetBackgroundColour(self, 'yellow')

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        
        self.SetToolTipString(toolTipString)
        self.bWidgetLinkage = None # if not none, use callafter call this method
        self.bMethodLinkage = None # if not none, use callafter call this method
        self.typeOfValue = None
        self.keyOfParams = "" # for example [DR], [R], if not defined, use value directly
        self.indexOfKey = None # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
        self.typeOfParams = None # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
        self.valuesOfParams = None # if typeOfParams ist not none, this attribute must be defined
        self.decimalDigitsOfOuput = 0 # for function round, 0 is integer
        self.popUpWin = None
        self.shouldPOP = False

        # an optional bitmap (not used, just to see how artprovider works)
        """
        bmp = wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_OTHER, (16, 16))
        ico = wx.StaticBitmap(parent, wx.ID_ANY, bmp)
        self.hbox.Add(ico, 0, wx.ALL|wx.ALIGN_CENTER, SMALLBORDER)
        """
        #hRowLeft = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, wx.EmptyString), wx.HORIZONTAL) 
        hRowLeft = wx.BoxSizer(wx.HORIZONTAL) 
        self.lbl = wx.StaticText(self, wx.ID_ANY, label, style=wx.ALIGN_LEFT, name="_" + name)
        self.lbl.SetInitialSize((-1,-1))
        if _DEBUG & 0x4:
            self.lbl.SetBackgroundColour('YELLOW')

        ###hRowLeft.Add(self.lbl, 1, wx.EXPAND, 0)
        hRowLeft.Add(self.lbl, 1, wx.ALIGN_CENTER_VERTICAL, 0)
        self.hbox.Add(hRowLeft, 8, wx.EXPAND, 0)
        #self.hbox.Add(SPACER, 1, wx.ALL, SMALLBORDER)
        
        #hRowRight = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, wx.EmptyString), wx.HORIZONTAL) 
        hRowRight = wx.BoxSizer(wx.HORIZONTAL)
        #self.edit = EditField(self, wx.ID_ANY, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name="__" + name, style=style)
        self.cb = LabeledChoiceBox(self, wx.ID_ANY, label='', name="__" + name, toolTipString=toolTipString, propChoice=1.0)

        # self.cb.SetInitialSize((-1, -1))
        # self.cb.Unbind(wx.EVT_TEXT)
        #override the method of EditFiled
        def _setText(self, val):
            """
            update the TextCtrl without triggering its callbacks.
            """
            oldSetting = self.GetEvtHandlerEnabled()
            self.SetEvtHandlerEnabled(False)    # for programmatic changes we don't want an event
            try:
                if not isinstance(val, str):
                    val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            except NameError:
                val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            finally:                            # so the old setting is safely restored
                self.SetEvtHandlerEnabled(oldSetting)
        self.cb.setText = MethodType(_setText, self.cb)
        if minSizeEdit != None:
            self.cb.SetInitialSize(minSizeEdit)
        hRowRight.Add(self.cb, 1, wx.EXPAND, 0)
        if bWithCheckbox:
            self.cbCheck = OptiCheckBox(self, wx.ID_ANY, label=wx.EmptyString, style=wx.ALIGN_RIGHT, name = "__CB_" + name)
            hRowRight.Add(self.cbCheck, 0, wx.EXPAND | wx.LEFT| wx.RIGHT, SMALLBORDER)
        else:
            hRowRight.AddSpacer(24)
        self.hbox.Add(hRowRight, 2, wx.ALL, 0)

        self.FitInside()
        self.SetSizerAndFit(self.hbox)
        #self.SetSize((-1, 35))
        
        #Check if we have a custom Popup Menu
        if ContextMenu != False:
            if IsMethod(ContextMenu) == True:
                self.ContextMenu = ContextMenu
                self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        # allow a callback function to inform the calling code if this widget is focused
        if Callback:
            self.Bind(wx.EVT_CHILD_FOCUS, self.OnCildFocus) 
        self.Callback = Callback
    
    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)
    
    def showPop(self, pos):
        try:
            for objChild in self.GetParent().GetChildren():
                if objChild != self:
                    if hasattr(objChild, "popUpWin"):
                        if objChild.popUpWin and objChild.shouldPOP: 
                            objChild.popUpWin.Destroy() 
                            objChild.popUpWin = None
                            objChild.shouldPOP = False
            if self.popUpWin is None and self.shouldPOP:
                self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString())
                if GetTooltipHoldingTime() is not None:
                    wx.FutureCall(GetTooltipHoldingTime(), self.killPop)
        except:
            pass

    # def Enable(self, enable=True):
    #     if enable is None:
    #         return
    #     LabeledEditField.Enable(self, enable)

    def SetSelection(self, choice):
        self.cb.SetSelection(choice)
        
    def GetSelection(self):
        return self.cb.GetSelection()
        
    def GetValue(self):
        """
        Returns the int-value of the selected item (as string)
        """
        try:
            return self.cb.GetSelection()
        except:
            return None

    def SetValue(self, choice):
        """
        Set the item with the specifed item-number (string)
        """
        if isinstance(choice, str):
            try:
                self.cb.SetSelection(int(choice))   # out first list-entry is '0'
            except:
                return
        else:
            try:
                self.cb.SetSelection(choice)
            except:
                return  
          
    def GetWindowText(self):
        #return self.cb.GetStringSelection()
        return self.cb.GetSelection()
    
class LabeledChoiceBox2(LabeledChoiceBox):
    #
    def __init__(self, *args, **kwargs):
        self.items    = kwargs.get("choices", [])       # get from arg-list
        self.minIndex = kwargs.pop("minIndex", 0)       # get and remove from arg-list
        self.maxIndex = kwargs.pop("maxIndex", 1000)
        self.bWithCheckbox = kwargs.pop("bWithCheckbox", False)
        self.name=kwargs.get("name", "")

        LabeledChoiceBox.__init__(self, *args, **kwargs)
        
        self.bWidgetLinkage = None  # if not none, use callafter call this method
        self.bMethodLinkage = None  # if not none, use callafter call this method
        self.typeOfValue = None
        self.keyOfParams = ""       # for example [DR], [R], if not defined, use value directly
        self.indexOfKey = None      # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
        self.typeOfParams = None    # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
        self.valuesOfParams = None  # if typeOfParams ist not none, this attribute must be defined
        self.decimalDigitsOfOuput = 0 # for function round, 0 is integer
        
        if self.bWithCheckbox:
            self.cbCheck = OptiCheckBox(self, wx.ID_ANY, label=wx.EmptyString, style=wx.ALIGN_RIGHT, name = "__CB_" + self.name)
            self.hbox.Add(self.cbCheck, 0, wx.EXPAND | wx.LEFT| wx.RIGHT, SMALLBORDER)
            self.SetSizerAndFit(self.hbox)
            
        
    def GetValue(self):
        """
        Returns the int-value of the selected item (as string)
        """
        try:
            return self.cb.GetSelection() + self.minIndex
        except:
            return None

    def SetValue(self, choice):
        """
        Set the item with the specifed item-number (string)
        """
        try:
            self.cb.SetSelection(int(choice) - self.minIndex)   # out first list-entry is '0'
        except:
            return
          
    def GetWindowText(self):
        return self.cb.GetStringSelection()
    
    def SetItems(self, items, minIndex=None, maxIndex=None):
        self.items = items
        if minIndex is not None:
            self.minIndex = minIndex
        if maxIndex is not None:
            self.maxIndex = maxIndex
        LabeledChoiceBox.SetItems(self, items[self.minIndex:self.maxIndex+1])
        
    def SetMinMaxIndex(self, minIndex=None, maxIndex=None):
        if minIndex is not None:
            self.minIndex = minIndex
        if maxIndex is not None:
            self.maxIndex = maxIndex
        LabeledChoiceBox.SetItems(self, self.items[self.minIndex:self.maxIndex+1])

    def SetSelection(self, choice):
        try:
            self.cb.SetSelection(int(choice) - self.minIndex)   # out first list-entry is '0'
        except:
            return
        
    def GetSelection(self):
        return self.cb.GetSelection() + self.minIndex



    
class LeftLabeledEditField(LabeledEditField):
    '''Represents an label field with an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, value=wx.EmptyString,  # @ReservedAssignment
                  pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0,  # @ReservedAssignment
                  behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString,
                   name='labeledEditField', style=0, ContextMenu = False, propChoice=8,
                   editSize=wx.DefaultSize, Callback=False, minSizeEdit=(70, -1), bWithCheckbox=False):  # @ReservedAssignment
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        BasePanel.__init__(self, parent, id, pos=pos, size=size, style=wx.RAISED_BORDER, name=name)
        if SHOWCOLORS:
            BasePanel.SetBackgroundColour(self, 'yellow')

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        
        self.SetToolTipString(toolTipString)
        self.bWidgetLinkage = None # if not none, use callafter call this method
        self.bMethodLinkage = None # if not none, use callafter call this method
        self.typeOfValue = None
        self.keyOfParams = "" # for example [DR], [R], if not defined, use value directly
        self.indexOfKey = None # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
        self.typeOfParams = None # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
        self.valuesOfParams = None # if typeOfParams ist not none, this attribute must be defined
        self.decimalDigitsOfOuput = 0 # for function round, 0 is integer
        self.popUpWin = None
        self.shouldPOP = False

        # an optional bitmap (not used, just to see how artprovider works)
        """
        bmp = wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_OTHER, (16, 16))
        ico = wx.StaticBitmap(parent, wx.ID_ANY, bmp)
        self.hbox.Add(ico, 0, wx.ALL|wx.ALIGN_CENTER, SMALLBORDER)
        """
        #hRowLeft = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, wx.EmptyString), wx.HORIZONTAL) 
        hRowLeft = wx.BoxSizer(wx.HORIZONTAL) 
        self.lbl = wx.StaticText(self, wx.ID_ANY, label, style=wx.ALIGN_LEFT, name="_" + name)
        self.lbl.SetInitialSize((-1,-1))
        if _DEBUG & 0x4:
            self.lbl.SetBackgroundColour('YELLOW')

        ###hRowLeft.Add(self.lbl, 1, wx.EXPAND, 0)
        hRowLeft.Add(self.lbl, 1, wx.ALIGN_CENTER_VERTICAL, 0)
        self.hbox.Add(hRowLeft, propChoice, wx.EXPAND, 0)
        #self.hbox.Add(SPACER, 1, wx.ALL, SMALLBORDER)
        
        #hRowRight = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, wx.EmptyString), wx.HORIZONTAL) 
        hRowRight = wx.BoxSizer(wx.HORIZONTAL)
        self.edit = EditField(self, wx.ID_ANY, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name="__" + name, style=style)
        self.edit.SetInitialSize((-1, -1))
        self.edit.Unbind(wx.EVT_TEXT)
        #override the method of EditFiled
        def _setText(self, val):
            """
            update the TextCtrl without triggering its callbacks.
            """
            oldSetting = self.GetEvtHandlerEnabled()
            self.SetEvtHandlerEnabled(False)    # for programmatic changes we don't want an event
            try:
                if not isinstance(val, str):
                    val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            except NameError:
                val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            finally:                            # so the old setting is safely restored
                self.SetEvtHandlerEnabled(oldSetting)
        self.edit.setText = MethodType(_setText, self.edit)
        if minSizeEdit != None:
            self.edit.SetInitialSize(minSizeEdit)
        hRowRight.Add(self.edit, 1, wx.EXPAND, 0)
        if bWithCheckbox:
            self.cbCheck = OptiCheckBox(self, wx.ID_ANY, label=wx.EmptyString, style=wx.ALIGN_RIGHT, name = "__CB_" + name)
            hRowRight.Add(self.cbCheck, 0, wx.EXPAND | wx.LEFT| wx.RIGHT, SMALLBORDER)
        else:
            hRowRight.AddSpacer(24)
        self.hbox.Add(hRowRight, 2, wx.ALL, 0)

        self.FitInside()
        self.SetSizerAndFit(self.hbox)
        #self.SetSize((-1, 35))
        
        #Check if we have a custom Popup Menu
        if ContextMenu != False:
            if IsMethod(ContextMenu) == True:
                self.ContextMenu = ContextMenu
                self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        # allow a callback function to inform the calling code if this widget is focused
        if Callback:
            self.Bind(wx.EVT_CHILD_FOCUS, self.OnCildFocus) 
        self.Callback = Callback
    
    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)
    
    def showPop(self, pos):
        try:
            for objChild in self.GetParent().GetChildren():
                if objChild != self:
                    if hasattr(objChild, "popUpWin"):
                        if objChild.popUpWin and objChild.shouldPOP: 
                            objChild.popUpWin.Destroy() 
                            objChild.popUpWin = None
                            objChild.shouldPOP = False
            if self.popUpWin is None and self.shouldPOP:
                self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString())
                if GetTooltipHoldingTime() is not None:
                    wx.FutureCall(GetTooltipHoldingTime(), self.killPop)
        except:
            pass

    # def Enable(self, enable=True):
    #     if enable is None:
    #         return
    #     LabeledEditField.Enable(self, enable)

    # Enables the whole widget including the checkboc
    def EnableCompleteWidget(self, enable=True):
        LabeledEditField.Enable(self, enable)
        if hasattr(self, "cbCheck"):
            self.cbCheck.Enable(enable)

    def GetWindowText(self):
        return self.edit.GetWindowText()
    
    def Show(self, *args, **kwargs):
        try:
            self.cbCheck.Show(*args, **kwargs)
        except:
            pass
        self.lbl.Show(*args, **kwargs)
        self.edit.Show(*args, **kwargs)
        
class LeftLabeledEditField2(LabeledEditField):
    '''Represents an label field with an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, value=wx.EmptyString,  # @ReservedAssignment
                  pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0,  # @ReservedAssignment
                  behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString,
                   name='labeledEditField', style=wx.RAISED_BORDER, ContextMenu = False, 
                   editSize=wx.DefaultSize, Callback=False, minSizeEdit=(75, -1), bWithCheckbox=False, layoutChoice=wx.HORIZONTAL, propChoice=8):  # @ReservedAssignment
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        BasePanel.__init__(self, parent, id, pos=pos, size=size, style=style, name=name)
        if SHOWCOLORS:
            BasePanel.SetBackgroundColour(self, 'yellow')


        
        self.SetToolTipString(toolTipString)
        self.bWidgetLinkage = None # if not none, use callafter call this method
        self.bMethodLinkage = None # if not none, use callafter call this method
        self.typeOfValue = None
        self.keyOfParams = "" # for example [DR], [R], if not defined, use value directly
        self.indexOfKey = None # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
        self.typeOfParams = None # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
        self.valuesOfParams = None # if typeOfParams ist not none, this attribute must be defined
        self.decimalDigitsOfOuput = 0 # for function round, 0 is integer
        self.popUpWin = None
        self.shouldPOP = False
        
        #override the method of EditFiled
        def _setText(self, val):
            """
            update the TextCtrl without triggering its callbacks.
            """
            oldSetting = self.GetEvtHandlerEnabled()
            self.SetEvtHandlerEnabled(False)    # for programmatic changes we don't want an event
            try:
                if not isinstance(val, str):
                    val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            except NameError:
                val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            finally:                            # so the old setting is safely restored
                self.SetEvtHandlerEnabled(oldSetting)

        # an optional bitmap (not used, just to see how artprovider works)
        """
        bmp = wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_OTHER, (16, 16))
        ico = wx.StaticBitmap(parent, wx.ID_ANY, bmp)
        self.hbox.Add(ico, 0, wx.ALL|wx.ALIGN_CENTER, SMALLBORDER)
        """    
        self.hbox = wx.BoxSizer(layoutChoice)
                           
        hSub = wx.BoxSizer(wx.HORIZONTAL)
        
        self.lbl = wx.StaticText(self, wx.ID_ANY, label, name="_" + name)
        if _DEBUG & 0x4:
            self.lbl.SetBackgroundColour('YELLOW')
        hSub.Add(self.lbl, 0, wx.EXPAND | wx.TOP , border=10) # border=10 is needed so the label is centered within the sizer ... don't ask why 

        self.edit = EditField(self, wx.ID_ANY, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name="__" + name, style=0)
        self.edit.SetInitialSize((-1, -1))
        self.edit.Unbind(wx.EVT_TEXT)                 
        self.edit.setText = MethodType(_setText, self.edit)
        if minSizeEdit != None:
            self.edit.SetInitialSize(minSizeEdit)
        hSub.Add(self.edit, 0, wx.EXPAND|wx.ALL, SMALLBORDER)
        
        if bWithCheckbox:
            self.cbCheck = OptiCheckBox(self, wx.ID_ANY, label=wx.EmptyString, style=wx.ALIGN_RIGHT, name = "__CB_" + name)
            hSub.Add(self.cbCheck, 0, wx.EXPAND|wx.RIGHT, MINIBORDER)
        else:
            hSub.AddSpacer(24)
                  
        self.hbox.Add(hSub, 0, wx.EXPAND)

        self.FitInside()
        self.SetSizerAndFit(self.hbox)
        
        #Check if we have a custom Popup Menu
        if ContextMenu != False:
            if IsMethod(ContextMenu) == True:
                self.ContextMenu = ContextMenu
                self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        # allow a callback function to inform the calling code if this widget is focused
        if Callback:
            self.Bind(wx.EVT_CHILD_FOCUS, self.OnCildFocus) 
        self.Callback = Callback
    
    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)
    
    def showPop(self, pos):
        try:
            for objChild in self.GetParent().GetChildren():
                if objChild != self:
                    if hasattr(objChild, "popUpWin"):
                        if objChild.popUpWin and objChild.shouldPOP: 
                            objChild.popUpWin.Destroy() 
                            objChild.popUpWin = None
                            objChild.shouldPOP = False
            if self.popUpWin is None and self.shouldPOP:
                self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString())
                if GetTooltipHoldingTime() is not None:
                    wx.FutureCall(GetTooltipHoldingTime(), self.killPop)
        except:
            pass

    # def Enable(self, enable=True):
    #     if enable is None:
    #         return
    #     LabeledEditField.Enable(self, enable)

    # Enables the whole widget including the checkboc
    def EnableCompleteWidget(self, enable=True):
        LabeledEditField.Enable(self, enable)
        if hasattr(self, "cbCheck"):
            self.cbCheck.Enable(enable)

    def GetWindowText(self):
        return self.edit.GetWindowText()
    
    def Show(self, *args, **kwargs):
        try:
            self.cbCheck.Show(*args, **kwargs)
        except:
            pass
        self.lbl.Show(*args, **kwargs)
        self.edit.Show(*args, **kwargs)


class LeftLabeledEditFieldPickPos(LabeledEditField):
    '''Represents an label field with an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, value=wx.EmptyString,  # @ReservedAssignment
                  pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0,  # @ReservedAssignment
                  behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString,
                   name='labeledEditField', style=0, ContextMenu = False, 
                   editSize=wx.DefaultSize, Callback=False, minSizeEdit=(50, -1), bWithCheckbox=False):  # @ReservedAssignment
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        BasePanel.__init__(self, parent, id, pos=pos, size=size, style= wx.RAISED_BORDER, name=name)

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        
        self.SetToolTipString(toolTipString)
        self.bWidgetLinkage = None # if not none, use callafter call this method
        self.bMethodLinkage = None # if not none, use callafter call this method
        self.typeOfValue = None 
        self.keyOfParams = "" # for example [DR], [R], if not defined, use value directly
        self.indexOfKey = None # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
        self.typeOfParams = None # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
        self.valuesOfParams = None # if typeOfParams ist not none, this attribute must be defined
        self.decimalDigitsOfOuput = 0 # for function round, 0 is integer
        self.popUpWin = None
        self.shouldPOP = False

        # an optional bitmap (not used, just to see how artprovider works)
        """
        bmp = wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_OTHER, (16, 16))
        ico = wx.StaticBitmap(parent, wx.ID_ANY, bmp)
        self.hbox.Add(ico, 0, wx.ALL|wx.ALIGN_CENTER, SMALLBORDER)
        """
        #hRowLeft = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, wx.EmptyString), wx.HORIZONTAL) 
        hRowLeft = wx.BoxSizer(wx.HORIZONTAL) 
        self.lbl = wx.StaticText(self, wx.ID_ANY, label, style=wx.ALIGN_LEFT, name="_" + name)
        self.lbl.SetInitialSize((-1, -1))
        if _DEBUG & 0x4:
            self.lbl.SetBackgroundColour('YELLOW')

        hRowLeft.Add(self.lbl, 1, wx.EXPAND, 0)
        self.btnPickPos = NormalButton(self, wx.ID_ANY, ">>", wx.DefaultPosition, (25, 30), style=0, name="_BTN_" + name)
        
        hRowLeft.Add(self.btnPickPos, 0, wx.ALL, 0)
        self.hbox.Add(hRowLeft, 8, wx.EXPAND, 0)
        #self.hbox.Add(SPACER, 1, wx.ALL, SMALLBORDER)
        
        #hRowRight = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, wx.EmptyString), wx.HORIZONTAL) 
        hRowRight = wx.BoxSizer(wx.HORIZONTAL)
        self.edit = EditField(self, wx.ID_ANY, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name="__" + name, style=style)
        self.edit.SetInitialSize((-1, -1))
        self.edit.Unbind(wx.EVT_TEXT)
        #override the method of EditFiled
        def _setText(self, val):
            """
            update the TextCtrl without triggering its callbacks.
            """
            oldSetting = self.GetEvtHandlerEnabled()
            self.SetEvtHandlerEnabled(False)    # for programmatic changes we don't want an event
            try:
                if not isinstance(val, str):
                    val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            except NameError:
                val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            finally:                            # so the old setting is safely restored
                self.SetEvtHandlerEnabled(oldSetting)
        self.edit.setText = MethodType(_setText, self.edit)
        if minSizeEdit != None:
            self.edit.SetInitialSize(minSizeEdit)
        hRowRight.Add(self.edit, 1, wx.EXPAND, 0)
        if bWithCheckbox:
            self.cbCheck = OptiCheckBox(self, wx.ID_ANY, label=wx.EmptyString, style=wx.ALIGN_RIGHT, name = "__CB_" + name)
            hRowRight.Add(self.cbCheck, 0, wx.EXPAND | wx.LEFT| wx.RIGHT, SMALLBORDER)
        else:
            hRowRight.AddSpacer(24)
        self.hbox.Add(hRowRight, 2, wx.ALL, 0)

        self.FitInside()
        self.SetSizerAndFit(self.hbox)
        #self.SetSize((-1, 35))
        
        #Check if we have a custom Popup Menu
        if ContextMenu != False:
            if IsMethod(ContextMenu) == True:
                self.ContextMenu = ContextMenu
                self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        # allow a callback function to inform the calling code if this widget is focused
        if Callback:
            self.Bind(wx.EVT_CHILD_FOCUS, self.OnCildFocus) 
        self.Callback = Callback
    
    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)
    
    def showPop(self, pos):
        for objChild in self.GetParent().GetChildren():
            if objChild != self:
                if hasattr(objChild, "popUpWin"):
                    if objChild.popUpWin and objChild.shouldPOP: 
                        objChild.popUpWin.Destroy() 
                        objChild.popUpWin = None
                        objChild.shouldPOP = False
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString())
            if GetTooltipHoldingTime() is not None:
                wx.FutureCall(GetTooltipHoldingTime(), self.killPop)

    # Enables the whole widget including the checkboc
    def EnableCompleteWidget(self, enable=True):
        LabeledEditField.Enable(self, enable)
        if hasattr(self, "cbCheck"):
            self.cbCheck.Enable(enable)
            

                

class LeftLabeledDobbleEditFieldPickPos(LabeledEditField):
    '''Represents an label field with an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, id1=wx.ID_ANY, id2=wx.ID_ANY, label1=wx.EmptyString, label2=wx.EmptyString,value=wx.EmptyString,  # @ReservedAssignment
                  pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0,
                  behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString,
                  name='labeledEditField', name1='labeledEditField-1', name2='labeledEditField-2', style=0, ContextMenu = False, 
                  editSize=wx.DefaultSize, Callback=False, minSizeEdit=(70, -1), id3=wx.ID_ANY, label3=wx.EmptyString, name3='labeledEditField-3', bWithCheckbox=True):  # @ReservedAssignment

        
        _label1 = getText(label1, name1)
        if label2 != wx.EmptyString:
            _label2 = getText(label2, name2)
        if label3 != wx.EmptyString:
            _label3 = getText(label3, name3)
        self.popUpWin = None
        self.shouldPOP = False

        BasePanel.__init__(self, parent, id, pos=pos, size=size, style= wx.RAISED_BORDER, name=name)
        if SHOWCOLORS:
            BasePanel.SetBackgroundColour(self, 'yellow')

        self.SetToolTipString(toolTipString)
        
        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        
        # +++++++++++++++++++++++++++++++++++++++ Left side +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        hGribBagLeft = wx.GridBagSizer(0, 0)
        hGribBagLeft.AddGrowableCol(0)
        #self.lbl1 = TextField(self, wx.ID_ANY, _label1, style=wx.ALIGN_LEFT, name=name1)
        self.lbl1 = wx.StaticText(self, wx.ID_ANY, _label1, style=wx.ALIGN_LEFT, name=name1)
        self.lbl1.SetInitialSize((-1, -1))
        #self.lbl1.SetBackgroundColour('YELLOW')
        hGribBagLeft.Add(self.lbl1, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL)
        hGribBagLeft.AddGrowableRow(0)
        
        if label2 != wx.EmptyString:
            # add static line after main buttons  
            topLine = wx.StaticLine(self, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(-1, 2), style=wx.LI_HORIZONTAL, name="Top Line")
            hGribBagLeft.Add(topLine, (1, 0), flag=wx.EXPAND)
            
            self.lbl2 = wx.StaticText(self, wx.ID_ANY, _label2, style=wx.ALIGN_LEFT, name=name2)
            self.lbl2.SetInitialSize((-1, -1))
            #self.lb2.SetBackgroundColour('RED')
            hGribBagLeft.Add(self.lbl2, (2, 0), flag=wx.ALIGN_CENTER_VERTICAL)
            hGribBagLeft.AddGrowableRow(2)

        if label3 != wx.EmptyString:
            topLine = wx.StaticLine(self, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(-1, 2), style=wx.LI_HORIZONTAL, name="Top Line")
            hGribBagLeft.Add(topLine, (3, 0), flag=wx.EXPAND)
    
            self.lbl3 = wx.StaticText(self, wx.ID_ANY, _label3, style=wx.ALIGN_LEFT, name=name3)
            self.lbl3.SetInitialSize((-1, -1))
            #self.lb2.SetBackgroundColour('RED')
            hGribBagLeft.Add(self.lbl3, (4, 0), flag=wx.ALIGN_CENTER_VERTICAL)
            hGribBagLeft.AddGrowableRow(4)
                
        if label2 != wx.EmptyString and label3 != wx.EmptyString:
            self.btnPickPos = NormalButton(self, wx.ID_ANY, "XYZ>>", wx.DefaultPosition, (45, -1), style=0, name="_BTN_" + name)
            hGribBagLeft.Add(self.btnPickPos, (0, 1), (5, 1), flag= wx.EXPAND|wx.ALL, border=SMALLBORDER)
        elif label2 != wx.EmptyString or label3 != wx.EmptyString:
            self.btnPickPos = NormalButton(self, wx.ID_ANY, "XY>>", wx.DefaultPosition, (45, -1), style=0, name="_BTN_" + name)
            hGribBagLeft.Add(self.btnPickPos, (0, 1), (3, 1), flag= wx.EXPAND|wx.ALL, border=SMALLBORDER)
        else:
            self.btnPickPos = NormalButton(self, wx.ID_ANY, ">>", wx.DefaultPosition, (45, -1), style=0, name="_BTN_" + name)
            hGribBagLeft.Add(self.btnPickPos, (0, 1), (1, 1), flag= wx.EXPAND|wx.BOTTOM, border=2)
        
        self.hbox.Add(hGribBagLeft, 8, wx.EXPAND, 0)
        
        #override the method of EditFiled
        def _setText(self, val):
            """
            update the TextCtrl without triggering its callbacks.
            """
            oldSetting = self.GetEvtHandlerEnabled()
            self.SetEvtHandlerEnabled(False)    # for programmatic changes we don't want an event
            try:
                if not isinstance(val, str):
                    val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            except NameError:
                val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            finally:                            # so the old setting is safely restored
                self.SetEvtHandlerEnabled(oldSetting)

        # +++++++++++++++++++++++++++++++++++++++ Right side +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        hGribBagRight = wx.GridBagSizer(0, 0)
        hGribBagRight.AddGrowableCol(0)
        
        #hRowRightUp = wx.BoxSizer(wx.HORIZONTAL)
        self.edit1 = EditField(self, id1, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name=name1, style=style)
        self.edit1.Unbind(wx.EVT_TEXT)
        self.edit1.setText = MethodType(_setText, self.edit1)
        # if minSizeEdit != None:
        #     self.edit1.SetInitialSize(minSizeEdit)
        # else:
        #     self.edit1.SetInitialSize((-1, -1))
        
        self.edit1.SetToolTipString(toolTipString)
        self.edit1.bWidgetLinkage = None # if not none, use callafter call this method
        self.edit1.bMethodLinkage = None # if not none, use callafter call this method
        self.edit1.typeOfValue = None 
        self.edit1.keyOfParams = "" # for example [DR], [R], if not defined, use value directly
        self.edit1.indexOfKey = None # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
        self.edit1.typeOfParams = None # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
        self.edit1.valuesOfParams = None # if typeOfParams ist not none, this attribute must be defined
        self.edit1.decimalDigitsOfOuput = 0 # for function round, 0 is integer
        self.edit1.popUpWin = None
        self.edit1.shouldPOP = False
        
        # 09/03/2024
        # jorgk
        # 09/03/2024
        vFlags = wx.ALL | wx.EXPAND
        
        # 09/04/2024 jorgk!
        hGribBagRight.Add(self.edit1, (0, 0), flag=wx.ALL|wx.EXPAND, border=0)
        hGribBagRight.AddGrowableRow(0)
        if bWithCheckbox:
            self.cbCheck1 = OptiCheckBox(self, wx.ID_ANY, label=wx.EmptyString, style=wx.ALIGN_RIGHT, name = "__CB_" + name1)
            hGribBagRight.Add(self.cbCheck1, (0, 1), (1, 1), flag= wx.EXPAND|wx.ALL, border=SMALLBORDER)
            self.cbCheck1.edit = self.edit1
            self.cbCheck1.lbl = self.lbl1
            self.edit1.cbCheck = self.cbCheck1
        
        if label2 != wx.EmptyString:
            # add static line after main buttons  
            topLine = wx.StaticLine(self, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(-1, 2), style=wx.LI_HORIZONTAL, name="_TopLine1")
            # hGribBagRight.Add(topLine, (1, 0), flag=wx.EXPAND)
            
            #hRowRightMid = wx.BoxSizer(wx.HORIZONTAL)
            self.edit2 = EditField(self, id2, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name=name2, style=style)
            self.edit2.Unbind(wx.EVT_TEXT)
            self.edit2.setText = MethodType(_setText, self.edit2)
            # if minSizeEdit != None:
            #     self.edit2.SetInitialSize(minSizeEdit)
            # else:
            #     self.edit2.SetInitialSize((-1, -1))
                
            self.edit2.SetToolTipString(toolTipString)
            self.edit2.bWidgetLinkage = None # if not none, use callafter call this method
            self.edit2.bMethodLinkage = None # if not none, use callafter call this method
            self.edit2.typeOfValue = None 
            self.edit2.keyOfParams = "" # for example [DR], [R], if not defined, use value directly
            self.edit2.indexOfKey = None # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
            self.edit2.typeOfParams = None # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
            self.edit2.valuesOfParams = None # if typeOfParams ist not none, this attribute must be defined
            self.edit2.decimalDigitsOfOuput = 0 # for function round, 0 is integer
            self.edit2.popUpWin = None
            self.edit2.shouldPOP = False
            
            # 09/04/2024 jorgk!
            hGribBagRight.Add(self.edit2, (2, 0), flag=wx.EXPAND)
            hGribBagRight.AddGrowableRow(2)
            if bWithCheckbox:
                self.cbCheck2 = OptiCheckBox(self, wx.ID_ANY, label=wx.EmptyString, style=wx.ALIGN_RIGHT, name = "__CB_" + name2)
                hGribBagRight.Add(topLine, (1, 0), (1, 2), flag=wx.EXPAND)
                hGribBagRight.Add(self.cbCheck2, (2, 1), (1, 1), flag= wx.EXPAND|wx.ALL, border=SMALLBORDER)
                self.cbCheck2.edit = self.edit2
                self.cbCheck2.lbl = self.lbl2
                self.edit2.cbCheck = self.cbCheck2
            else:
                hGribBagRight.Add(topLine, (1, 0), flag=wx.EXPAND)
            
        if label3 != wx.EmptyString:
            # add static line  
            topLine = wx.StaticLine(self, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(-1, 2), style=wx.LI_HORIZONTAL, name="_TopLine2")
            # hGribBagRight.Add(topLine, (3, 0), flag=wx.EXPAND)
            
            #hRowRightDown = wx.BoxSizer(wx.HORIZONTAL)
            self.edit3 = EditField(self, id3, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name=name3, style=style)
            self.edit3.Unbind(wx.EVT_TEXT)
            self.edit3.setText = MethodType(_setText, self.edit3)
            # if minSizeEdit != None:
            #     self.edit3.SetInitialSize(minSizeEdit)
            # else:
            #     self.edit3.SetInitialSize((-1, -1))
                
            self.edit3.SetToolTipString(toolTipString)
            self.edit3.bWidgetLinkage = None # if not none, use callafter call this method
            self.edit3.bMethodLinkage = None # if not none, use callafter call this method
            self.edit3.typeOfValue = None 
            self.edit3.keyOfParams = "" # for example [DR], [R], if not defined, use value directly
            self.edit3.indexOfKey = None # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
            self.edit3.typeOfParams = None # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
            self.edit3.valuesOfParams = None # if typeOfParams ist not none, this attribute must be defined
            self.edit3.decimalDigitsOfOuput = 0 # for function round, 0 is integer
            self.edit3.popUpWin = None
            self.edit3.shouldPOP = False
            
            # 09/04/2024 jorgk!
            hGribBagRight.Add(self.edit3, (4, 0), flag=wx.EXPAND)
            hGribBagRight.AddGrowableRow(4)
            if bWithCheckbox:
                self.cbCheck3 = OptiCheckBox(self, wx.ID_ANY, label=wx.EmptyString, style=wx.ALIGN_RIGHT, name = "__CB_" + name3)
                hGribBagRight.Add(topLine, (3, 0), (1, 2), flag=wx.EXPAND)
                hGribBagRight.Add(self.cbCheck3, (4, 1), (1, 1), flag= wx.EXPAND|wx.ALL, border=SMALLBORDER)
                self.cbCheck3.edit = self.edit3
                self.cbCheck3.lbl = self.lbl3
                self.edit3.cbCheck = self.cbCheck3
            else:
                hGribBagRight.Add(topLine, (3, 0), flag=wx.EXPAND)
        
        self.hbox.Add(hGribBagRight, 2, wx.EXPAND, 0)

        self.FitInside()
        self.SetSizerAndFit(self.hbox)
        #self.SetSize((-1, 35))
        
        #Check if we have a custom Popup Menu
        if ContextMenu != False:
            if IsMethod(ContextMenu) == True:
                self.ContextMenu = ContextMenu
                self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        # allow a callback function to inform the calling code if this widget is focused
        if Callback:
            self.Bind(wx.EVT_CHILD_FOCUS, self.OnCildFocus) 
        self.Callback = Callback

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def showPop(self, pos):
        for objChild in self.GetParent().GetChildren():
            if objChild != self:
                if hasattr(objChild, "popUpWin"):
                    if objChild.popUpWin and objChild.shouldPOP: 
                        objChild.popUpWin.Destroy() 
                        objChild.popUpWin = None
                        objChild.shouldPOP = False
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString())
            if GetTooltipHoldingTime() is not None:
                wx.FutureCall(GetTooltipHoldingTime(), self.killPop)

    # Enables the whole widget including the checkboc
    def EnableCompleteWidget(self, enable=True):
        LabeledEditField.Enable(self, enable)
        if hasattr(self, "cbCheck"):
            self.cbCheck.Enable(enable)
            
class RealLeftLabeledDobbleEditFieldPickPos(LabeledEditField):
    '''Represents an label field with an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, id1=wx.ID_ANY, id2=wx.ID_ANY, label1=wx.EmptyString, label2=wx.EmptyString,value=wx.EmptyString,  # @ReservedAssignment
                  pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0,
                  behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString,toolTipString1=wx.EmptyString,toolTipString2=wx.EmptyString,toolTipString3=wx.EmptyString,
                  name='labeledEditField', name1='labeledEditField-1', name2='labeledEditField-2', style=0, ContextMenu = False, 
                  editSize=wx.DefaultSize, Callback=False, minSizeEdit=(70, -1), id3=wx.ID_ANY, label3=wx.EmptyString, name3='labeledEditField-3', bWithCheckbox=True):  # @ReservedAssignment


        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                _label1 = getText(label1, name1, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
                toolTipString1= getToolTip(toolTipString1, name1, classnameofparent=classnameofparent)
            else:
                _label1 = getText(label1, name1)
                toolTipString= getToolTip(toolTipString, name)
                toolTipString1= getToolTip(toolTipString1, name1)
        else:
            _label1 = getText(label1, name1)
            toolTipString= getToolTip(toolTipString, name)
            toolTipString1= getToolTip(toolTipString1, name1)
        if label2 != wx.EmptyString:
            #measurecycle widgets are treated differently
            if hasattr(parent,"isMainPanel"):
                if parent.isMainPanel==True:
                    classnameofparent=type(parent).__name__
                    _label2 = getText(label2, name2, classnameofparent=classnameofparent)
                    toolTipString2= getToolTip(toolTipString2, name2, classnameofparent=classnameofparent)
                else:
                    _label2 = getText(label2, name2)
                    toolTipString2= getToolTip(toolTipString2, name2)
            else:
                _label2 = getText(label2, name2)
                toolTipString2= getToolTip(toolTipString2, name2)
        if label3 != wx.EmptyString:
            #measurecycle widgets are treated differently
            if hasattr(parent,"isMainPanel"):
                if parent.isMainPanel==True:
                    classnameofparent=type(parent).__name__
                    _label3 = getText(label3, name3, classnameofparent=classnameofparent)
                    toolTipString3= getToolTip(toolTipString3, name3, classnameofparent=classnameofparent)
                else:
                    _label3 = getText(label3, name3)
                    toolTipString3= getToolTip(toolTipString3, name3)
            else:
                _label3 = getText(label3, name3)
                toolTipString3= getToolTip(toolTipString3, name3)
                
        

        self.popUpWin = None
        self.shouldPOP = False

        BasePanel.__init__(self, parent, id, pos=pos, size=size, style= wx.BORDER_NONE, name=name)
        if SHOWCOLORS:
            BasePanel.SetBackgroundColour(self, 'yellow')

        self.SetToolTipString(toolTipString)
        
        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        
        # +++++++++++++++++++++++++++++++++++++++ Left side +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        hGribBagLeft = wx.GridBagSizer(0, 0)
        hGribBagLeft.AddGrowableCol(0)
        #self.lbl1 = TextField(self, wx.ID_ANY, _label1, style=wx.ALIGN_LEFT, name=name1)
        self.llef1=LeftLabeledEditField(self, wx.ID_ANY, _label1, min=min, max=max, minSizeEdit=minSizeEdit,
                                             behaviour=behaviour, name=name1, bWithCheckbox=bWithCheckbox)
        #self.lbl1 = wx.StaticText(self, wx.ID_ANY, _label1, style=wx.ALIGN_LEFT, name=name1)
        self.llef1.SetInitialSize((-1, -1))
        self.llef1.SetToolTipString(toolTipString1)
        #self.lbl1.SetBackgroundColour('YELLOW')
        #hGribBagLeft.Add(self.llef1, (0, 0), flag=wx.ALIGN_CENTER_VERTICAL)
        hGribBagLeft.Add(self.llef1, (0, 0), flag=wx.EXPAND)
        hGribBagLeft.AddGrowableRow(0)
        
        if label2 != wx.EmptyString:
            # add static line after main buttons  
            topLine = wx.StaticLine(self, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(-1, 2), style=wx.LI_HORIZONTAL, name="Top Line")
            hGribBagLeft.Add(topLine, (1, 0), flag=wx.EXPAND)
            self.llef2=LeftLabeledEditField(self, wx.ID_ANY, _label2, min=min, max=max, minSizeEdit=minSizeEdit,
                                             behaviour=behaviour, name=name2, bWithCheckbox=bWithCheckbox)
            #self.lbl2 = wx.StaticText(self, wx.ID_ANY, _label2, style=wx.ALIGN_LEFT, name=name2)
            self.llef2.SetInitialSize((-1, -1))
            self.llef2.SetToolTipString(toolTipString2)
            #self.lb2.SetBackgroundColour('RED')
            hGribBagLeft.Add(self.llef2, (2, 0), flag=wx.EXPAND)
            hGribBagLeft.AddGrowableRow(2)

        if label3 != wx.EmptyString:
            topLine = wx.StaticLine(self, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(-1, 2), style=wx.LI_HORIZONTAL, name="Top Line")
            hGribBagLeft.Add(topLine, (3, 0), flag=wx.EXPAND)
    
            self.llef3=LeftLabeledEditField(self, wx.ID_ANY, _label3, min=min, max=max, minSizeEdit=minSizeEdit,
                                             behaviour=behaviour, name=name3, bWithCheckbox=bWithCheckbox)
            #self.lbl3 = wx.StaticText(self, wx.ID_ANY, _label3, style=wx.ALIGN_LEFT, name=name3)
            self.llef3.SetInitialSize((-1, -1))
            self.llef3.SetToolTipString(toolTipString3)
            #self.lb2.SetBackgroundColour('RED')
            hGribBagLeft.Add(self.llef3, (4, 0), flag=wx.EXPAND)
            hGribBagLeft.AddGrowableRow(4)
                

        
        self.hbox.Add(hGribBagLeft, 8, wx.EXPAND, 0)
        
        #override the method of EditFiled
        def _setText(self, val):
            """
            update the TextCtrl without triggering its callbacks.
            """
            oldSetting = self.GetEvtHandlerEnabled()
            self.SetEvtHandlerEnabled(False)    # for programmatic changes we don't want an event
            try:
                if not isinstance(val, str):
                    val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            except NameError:
                val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            finally:                            # so the old setting is safely restored
                self.SetEvtHandlerEnabled(oldSetting)

        # +++++++++++++++++++++++++++++++++++++++ Right side +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #hGribBagRight = wx.GridBagSizer(0, 0)
        #hGribBagRight.AddGrowableCol(0)
        
        
        if label2 != wx.EmptyString and label3 != wx.EmptyString:
            self.btnPickPos = NormalButton(self, wx.ID_ANY, "XYZ>>", wx.DefaultPosition, (60, -1), style=0, name="_BTN_" + name)
            hGribBagLeft.Add(self.btnPickPos, (0, 1), (5, 3), flag= wx.EXPAND|wx.ALL, border=SMALLBORDER)
        elif label2 != wx.EmptyString or label3 != wx.EmptyString:
            self.btnPickPos = NormalButton(self, wx.ID_ANY, "XY>>", wx.DefaultPosition, (60, -1), style=0, name="_BTN_" + name)
            hGribBagLeft.Add(self.btnPickPos, (0, 1), (3, 2), flag= wx.EXPAND|wx.ALL, border=SMALLBORDER)
        else:
            self.btnPickPos = NormalButton(self, wx.ID_ANY, ">>", wx.DefaultPosition, (60, -1), style=0, name="_BTN_" + name)
            hGribBagLeft.Add(self.btnPickPos, (0, 1), (1, 1), flag= wx.EXPAND|wx.ALL, border=2)
        
        #hRowRightUp = wx.BoxSizer(wx.HORIZONTAL)
        # self.edit1 = EditField(self, id1, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name=name1, style=style, label=label1)
        # self.edit1.Unbind(wx.EVT_TEXT)
        # self.edit1.setText = MethodType(_setText, self.edit1)
        # # if minSizeEdit != None:
        # #     self.edit1.SetInitialSize(minSizeEdit)
        # # else:
        # #     self.edit1.SetInitialSize((-1, -1))
        #
        # self.edit1.SetToolTipString(toolTipString)
        # self.edit1.bWidgetLinkage = None # if not none, use callafter call this method
        # self.edit1.bMethodLinkage = None # if not none, use callafter call this method
        # self.edit1.typeOfValue = None 
        # self.edit1.keyOfParams = "" # for example [DR], [R], if not defined, use value directly
        # self.edit1.indexOfKey = None # not yet used, index of key, after TYPE in MCY Output, EDG,M,+X,DR33.0000, the position index of key in output, start count from 0
        # self.edit1.typeOfParams = None # list: the value of text ctrl is index. dict: the value of text ctrl is key, else, the value is directly used for output. 
        # self.edit1.valuesOfParams = None # if typeOfParams ist not none, this attribute must be defined
        # self.edit1.decimalDigitsOfOuput = 0 # for function round, 0 is integer
        # self.edit1.popUpWin = None
        # self.edit1.shouldPOP = False
        
        # 09/04/2024 jorgk!
        #hGribBagRight.Add(self.edit1, (0, 0), flag=wx.ALL|wx.EXPAND, border=0)
        #hGribBagRight.AddGrowableRow(0)
        
        
        
        self.FitInside()
        self.SetSizerAndFit(self.hbox)
        #self.SetSize((-1, 35))
        
        #Check if we have a custom Popup Menu
        if ContextMenu != False:
            if IsMethod(ContextMenu) == True:
                self.ContextMenu = ContextMenu
                self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        # allow a callback function to inform the calling code if this widget is focused
        if Callback:
            self.Bind(wx.EVT_CHILD_FOCUS, self.OnCildFocus) 
        self.Callback = Callback
        
class RealLeftLabeledDobbleEditFieldPickPos2(LabeledEditField):
    '''Represents an label field with an alphanumerical input field and more compact layout.''' # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, id1=wx.ID_ANY, id2=wx.ID_ANY, label1=wx.EmptyString, label2=wx.EmptyString,value=wx.EmptyString,  # @ReservedAssignment
                  pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0,
                  behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString,toolTipString1=wx.EmptyString,toolTipString2=wx.EmptyString,toolTipString3=wx.EmptyString,
                  name='labeledEditField', name1='labeledEditField-1', name2='labeledEditField-2', style=0, ContextMenu = False, extraLabel=wx.EmptyString,
                  editSize=wx.DefaultSize, Callback=False, id3=wx.ID_ANY, label3=wx.EmptyString, name3='labeledEditField-3', bWithCheckbox=True, layoutChoice=wx.HORIZONTAL):  # @ReservedAssignment


        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                _label1 = getText(label1, name1, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
                toolTipString1= getToolTip(toolTipString1, name1, classnameofparent=classnameofparent)
            else:
                _label1 = getText(label1, name1)
                toolTipString= getToolTip(toolTipString, name)
                toolTipString1= getToolTip(toolTipString1, name1)
        else:
            _label1 = getText(label1, name1)
            toolTipString= getToolTip(toolTipString, name)
            toolTipString1= getToolTip(toolTipString1, name1)
        if label2 != wx.EmptyString:
            #measurecycle widgets are treated differently
            if hasattr(parent,"isMainPanel"):
                if parent.isMainPanel==True:
                    classnameofparent=type(parent).__name__
                    _label2 = getText(label2, name2, classnameofparent=classnameofparent)
                    toolTipString2= getToolTip(toolTipString2, name2, classnameofparent=classnameofparent)
                else:
                    _label2 = getText(label2, name2)
                    toolTipString2= getToolTip(toolTipString2, name2)
            else:
                _label2 = getText(label2, name2)
                toolTipString2= getToolTip(toolTipString2, name2)
        if label3 != wx.EmptyString:
            #measurecycle widgets are treated differently
            if hasattr(parent,"isMainPanel"):
                if parent.isMainPanel==True:
                    classnameofparent=type(parent).__name__
                    _label3 = getText(label3, name3, classnameofparent=classnameofparent)
                    toolTipString3= getToolTip(toolTipString3, name3, classnameofparent=classnameofparent)
                else:
                    _label3 = getText(label3, name3)
                    toolTipString3= getToolTip(toolTipString3, name3)
            else:
                _label3 = getText(label3, name3)
                toolTipString3= getToolTip(toolTipString3, name3)
                
        

        self.popUpWin = None
        self.shouldPOP = False

        BasePanel.__init__(self, parent, id, pos=pos, size=size, style= wx.BORDER_RAISED, name=name)
        if SHOWCOLORS:
            BasePanel.SetBackgroundColour(self, 'yellow')

        self.SetToolTipString(toolTipString)
        
        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        
        # +++++++++++++++++++++++++++++++++++++++ Left side +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        hGribBagLeft = wx.GridBagSizer(0, 0)
        hGribBagLeft.AddGrowableRow(0)
        
        self.lbl = wx.StaticText(self, wx.ID_ANY, extraLabel, name="_")
        hGribBagLeft.Add(self.lbl, (0, 0), flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL)
        hGribBagLeft.AddGrowableCol(0)
        
        # Edit Fields
        self.llef1=LeftLabeledEditField2(self, wx.ID_ANY, _label1, min=min, max=max,
                                             behaviour=behaviour, name=name1, bWithCheckbox=bWithCheckbox, 
                                             layoutChoice=wx.HORIZONTAL, propChoice=1, style=wx.NO_BORDER)
        self.llef1.SetToolTipString(toolTipString1)
        hGribBagLeft.Add(self.llef1, (0, 1), flag=wx.EXPAND)
        hGribBagLeft.AddGrowableCol(1)
        
        if label2 != wx.EmptyString:
            self.llef2=LeftLabeledEditField2(self, wx.ID_ANY, _label2, min=min, max=max,
                                             behaviour=behaviour, name=name2, bWithCheckbox=bWithCheckbox, 
                                             layoutChoice=wx.HORIZONTAL, propChoice=1, style=wx.NO_BORDER)
            self.llef2.SetToolTipString(toolTipString2)
            hGribBagLeft.Add(self.llef2, (0, 2), flag=wx.EXPAND)
            hGribBagLeft.AddGrowableCol(2)

        if label3 != wx.EmptyString: 
            self.llef3=LeftLabeledEditField2(self, wx.ID_ANY, _label3, min=min, max=max,
                                             behaviour=behaviour, name=name3, bWithCheckbox=bWithCheckbox, 
                                             layoutChoice=wx.HORIZONTAL, propChoice=1, style=wx.NO_BORDER)
            self.llef3.SetToolTipString(toolTipString3)
            hGribBagLeft.Add(self.llef3, (0, 3), flag=wx.EXPAND)
            hGribBagLeft.AddGrowableCol(3)
                   
        # Button
        if label2 != wx.EmptyString and label3 != wx.EmptyString:
            self.btnPickPos = NormalButton(self, wx.ID_ANY, "XYZ>>", wx.DefaultPosition, (-1, -1), style=0, name="_BTN_" + name)
            hGribBagLeft.Add(self.btnPickPos, (0, 4), (1, 1), flag=wx.EXPAND|wx.ALL, border=SMALLBORDER)
        elif label2 != wx.EmptyString or label3 != wx.EmptyString:
            self.btnPickPos = NormalButton(self, wx.ID_ANY, "XY>>", wx.DefaultPosition, (-1, -1), style=0, name="_BTN_" + name)
            hGribBagLeft.Add(self.btnPickPos, (0, 3), (1, 1), flag= wx.EXPAND|wx.ALL, border=SMALLBORDER)
        else:
            self.btnPickPos = NormalButton(self, wx.ID_ANY, ">>", wx.DefaultPosition, (-1, -1), style=0, name="_BTN_" + name)
            hGribBagLeft.Add(self.btnPickPos, (0, 2), (1, 1), flag= wx.EXPAND|wx.ALL, border=SMALLBORDER)
        
        self.hbox.Add(hGribBagLeft, 1, flag=wx.EXPAND | wx.ALL, border=MINIBORDER)
        
        #override the method of EditFiled
        def _setText(self, val):
            """
            update the TextCtrl without triggering its callbacks.
            """
            oldSetting = self.GetEvtHandlerEnabled()
            self.SetEvtHandlerEnabled(False)    # for programmatic changes we don't want an event
            try:
                if not isinstance(val, str):
                    val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            except NameError:
                val = str(val)
                wx.TextCtrl.ChangeValue(self, val)
            finally:                            # so the old setting is safely restored
                self.SetEvtHandlerEnabled(oldSetting)
        
        self.FitInside()
        self.SetSizerAndFit(self.hbox)
        
        #Check if we have a custom Popup Menu
        if ContextMenu != False:
            if IsMethod(ContextMenu) == True:
                self.ContextMenu = ContextMenu
                self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        # allow a callback function to inform the calling code if this widget is focused
        if Callback:
            self.Bind(wx.EVT_CHILD_FOCUS, self.OnCildFocus) 
        self.Callback = Callback

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def showPop(self, pos):
        for objChild in self.GetParent().GetChildren():
            if objChild != self:
                if hasattr(objChild, "popUpWin"):
                    if objChild.popUpWin and objChild.shouldPOP: 
                        objChild.popUpWin.Destroy() 
                        objChild.popUpWin = None
                        objChild.shouldPOP = False
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString())
            if GetTooltipHoldingTime() is not None:
                wx.FutureCall(GetTooltipHoldingTime(), self.killPop)

    # Enables the whole widget including the checkboc
    def EnableCompleteWidget(self, enable=True):
        LabeledEditField.Enable(self, enable)
        if hasattr(self, "cbCheck"):
            self.cbCheck.Enable(enable)
            

class MeasureCycleBaseDialog(BaseDialog):
    """
    This is the base dialog for measure cycle of all post-processor
    
    Since the display style of each PP measure cycle is different, 
    we implement the control of the dialog window in the word class.
    In the future some common class methods should be placed in this base class.
    
    """
    def __init__(self, *args, **kwargs):
        
        # for database io 
        self.strDBPath = postVar.get("DbPathField", "")     # instead postVar[DbPathField]; this throws an exception  (JK)
        self.strMcyProfileTablle = PROFILE_TABLE_TYPE64     # 64 parameters
        self.dbConn = None
        self.dbCursor = None
        # dictionary for sqlite database contain the dictionary of tmpParams and "extra part"
        self.tmpSQLite = {} # type SQLITE3_MUSTER_DICT_TYPE_XX
        # Get current machine name
        objMachine = getCurrentDoc().GetMachine()
        self.strMachineName = objMachine.Name.getPyString()
        # Get current input unit
        objCurProgram = getCurrentDoc().program
        if objCurProgram.GetInputUnits() == opticam.UNITS_TYPE.MM:
            self.strCurrentOpticamUnit = "mm"
        else:
            self.strCurrentOpticamUnit = "inch"
        #Init Base class
        BaseDialog.__init__(self, *args, **kwargs)
        # use pre create style
        self.preCreateMode = False

    def OnReset(self, event):
        pass
    
    def OnTranslateA(self, event):  # @UnusedVariable
        pass
    
    def OnTranslate(self, event):  # @UnusedVariable
        #
        from p2c.dialogtranslations import TranslationDialogMeasureCycle
        # Handle the Translation of the controls captions for MeasureCycleBaseDialog
        logger.info("%s%s" % ("MeasureCycleBaseDialog" , ".OnTranslate"))
        #
        language = opticam.getLanguageW()
        messageFileName = getattr(self, "messageFileName", self.__class__.__name__)
        #title = getMessageW("Translation for Dialog", opticam.PYTHON_MESSAGES,20) + " " + self.__class__.__name__ + "(" + language + ")" + ".xml"
        title = getMessageW("Translation for Dialog", opticam.PYTHON_MESSAGES,20) + " " + messageFileName + "(" + language + ")" + ".xml"
        # Now we can use objects directly from p2cpython if there is no document! (extension for opticam-free run-environment)
        if self.doc is None:
            if not hasattr(opticam, "ApplicationWindow"):
                raise ReferenceError('BaseDialog: no ApplicationWindow!')
            win = opticam.ApplicationWindow()      # does really blocking the system
        else:
            win = self.doc.ApplicationWindow()      # does really blocking the system

        if win is not None:
            try:
                dlg = TranslationDialogMeasureCycle(win, self, wx.ID_ANY, title,
                                style=wx.CAPTION|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL,
                                messageFileName=messageFileName,
                                )
                win.Enable(True)
                dlg.Destroy()
            except:
                win.Enable(True)
    
    def OnDock(self, event):
        if self.docked: # currently is docked
            #self.size = self.unDockBestSize
            if self.style != 537395264:
                self.style = 524288 | wx.CAPTION|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL
        BaseDialog.OnDock(self, event)
        
        

    
    def ConnectSQLiteDatabase(self):
        """
        for load and save profile into sqlite3 database
        """
        try:
            # re-set database path, keep it fresh
            self.strDBPath = postVar.get("DbPathField", "")     # instead postVar[DbPathField]; this throws an exception  (JK)
            # Create a connection with sqlite database
            logger.info(LOG_TAG + ' * ConnectSQLiteDatabase(), try to connect with the sqlite database: %s' % self.strDBPath)
            self.dbConn = sqlite3.connect("%s" % self.strDBPath)
            # Create a cursor of the connection
            self.dbCursor = self.dbConn.cursor()
            # Check if the measure cycle profile table exist 
            logger.info(LOG_TAG + ' * ConnectSQLiteDatabase(), check if the profile table: %s is exist already' % self.strMcyProfileTablle)
            self.dbCursor.execute(''' SELECT count(name) FROM sqlite_master WHERE type='table' AND name='%s' ''' % self.strMcyProfileTablle)
            if self.dbCursor.fetchone()[0]==1 :
                logger.info(LOG_TAG + ' * ConnectSQLiteDatabase(), the profile table: %s was exist already' % self.strMcyProfileTablle)
                return True
            else:
                # Create a table by name for storing the profile 
                logger.info(LOG_TAG + ' * ConnectSQLiteDatabase(), the profile table: %s was not exist already, then create it as new' % self.strMcyProfileTablle)
                strTableSchema = SQLITE_MCY_TABLE_SCHEMA_TYPE64.format(self.strMcyProfileTablle)
                self.dbCursor.execute(strTableSchema)
                self.dbConn.commit()
                logger.info(LOG_TAG + ' * ConnectSQLiteDatabase(), successfully create the new profile table %s' % self.strMcyProfileTablle)
                return True
        except Exception as e:
            logger.error(LOG_TAG + ' * ConnectSQLiteDatabase(), can not to connect with the sqlite database: %s' % self.strDBPath)
            logger.error(LOG_TAG + ' * ConnectSQLiteDatabase(), error details: %' % e)
            return False
    
    def CheckIfSearchTermAlreadyExist(self, strSearchTerm="1", strKeyPart1="0001", strMachineID="00"):
        strQuery = """SELECT count(*) FROM {0!r} WHERE  SEARCHTERM = {1!r} and KEY_PART1 = {2!r} and CUSTOMER1 = {3!r} """.format(self.strMcyProfileTablle,
                                                                                                                                   strSearchTerm, strKeyPart1,
                                                                                                                                   strMachineID)
        self.dbCursor.execute(strQuery)
        if self.dbCursor.fetchone()[0]==1:
            logger.info(LOG_TAG + ' * CheckIfSearchTermAlreadyExist(), in the profile record with SEARCHTERM: %s , KEY_PART1: %s was exist already' % (strSearchTerm, strKeyPart1))
            return True
        else:
            logger.info(LOG_TAG + ' * CheckIfSearchTermAlreadyExist(), in the profile record with SEARCHTERM: %s , KEY_PART1: %s is not exist yet' % (strSearchTerm, strKeyPart1))
            return False
        
    def CheckIfEntriesOfMeasureTypeAlreadyExist(self, strKeyPart1="0001", strMachineID="00"):
        strQuery = """SELECT count(*) FROM {0!r} WHERE  KEY_PART1 = {1!r} and CUSTOMER1 = {2!r} """.format(self.strMcyProfileTablle,strKeyPart1,
                                                                                                                                   strMachineID)
        self.dbCursor.execute(strQuery)
        if self.dbCursor.fetchone()[0] != 0:
            logger.info(LOG_TAG + ' * CheckIfEntriesOfMeasureTypeAlreadyExist(), in the profile record with Machine ID: %s , KEY_PART1: %s was exist already' % (strMachineID, strKeyPart1))
            return True
        else:
            logger.info(LOG_TAG + ' * CheckIfSearchTermAlreadyExist(), in the profile record with Machine ID: %s , KEY_PART1: %s is not exist yet' % (strMachineID, strKeyPart1))
            return False
    
    def SelectSingleEntireEntryFromDatabase(self, whereConditions={}):
        """
        return type dictionary  
        """
        try:
            tupleValues = []
            strWhereChain = " and ".join(list(map(lambda a: a + '=?', whereConditions.keys())))
            tupleValues.extend(whereConditions.values())
            self.dbCursor.execute('SELECT *' + ' FROM ' +self.strMcyProfileTablle + ' WHERE '+ strWhereChain, tupleValues)
            rtsFields = self.dbCursor.description
            listFields = list(map(lambda a: a[0], rtsFields))
            rtsValues = self.dbCursor.fetchone()
            listValues = list(map(str, rtsValues))
            rtsDict = dict(zip(listFields, listValues))
            return rtsDict, ""
        except Exception as e:
            return {}, str(e)
            
    
    def SelectEntriesFromDatabase(self, valuesKeysList=[], whereConditions={}, orderKeysList=[]):
        """
        return type list  
        
        orderKeysList item style: field name + space + (DESC oder ASC)
        """
        try:
            tupleValues = []
            strKeysChain = ','.join(valuesKeysList)
            if len(whereConditions):
                strWhereChain = " and ".join(list(map(lambda a: a + '=?', whereConditions.keys())))
                tupleValues.extend(whereConditions.values())
            else:
                strWhereChain = ""
            if len(orderKeysList):
                strOrderChain = ' ORDER BY ' + ','.join(orderKeysList)
            else:
                strOrderChain = ""
            if len(whereConditions):
                self.dbCursor.execute('SELECT '  + strKeysChain + ' FROM ' +self.strMcyProfileTablle + ' WHERE '+ strWhereChain + strOrderChain, tupleValues)
            else:
                self.dbCursor.execute('SELECT ' + strKeysChain + ' FROM ' +self.strMcyProfileTablle + strOrderChain)
            listOfTuples = self.dbCursor.fetchall()
            return listOfTuples, ""
        except Exception as e:
            return [], str(e)
    
    def DeleteEntryFromDatabase(self, whereConditions={}, bCommitAfter=True):
        """
        return boolean, to indicate whether the sqlite string was successfully executed
        """
        try:
            tupleValues = []
            strWhereChain = " and ".join(list(map(lambda a: a + '=?', whereConditions.keys())))
            tupleValues.extend(whereConditions.values())
            self.dbCursor.execute('DELETE' + ' FROM ' +self.strMcyProfileTablle + ' WHERE '+ strWhereChain, tupleValues)
            if bCommitAfter:
                self.dbConn.commit()
            else:
                pass
            return True, ""
        except Exception as e:
            return False, str(e)

    def InsertEntryToDatabase(self, dictSQLite={}, bCommitAfter=True):
        try:
            strKeysChain = ','.join(dictSQLite.keys())
            strQuestionMarksChain = ','.join(list('?'*len(dictSQLite)))
            tupleValues = tuple(dictSQLite.values())
            self.dbCursor.execute('INSERT INTO '+self.strMcyProfileTablle+' ('+strKeysChain+') VALUES ('+strQuestionMarksChain+')', tupleValues)
            if bCommitAfter:
                self.dbConn.commit()
            else:
                pass
            return True, ""
        except Exception as e:
            return False, str(e)
    
    def UpdateEntryToDatabase(self, dictNewValues={}, whereConditions={}, bCommitAfter=True):
        try:
            tupleValues = []
            strSetsChain = ",".join(list(map(lambda a: a + '=?', dictNewValues.keys())))
            tupleValues.extend(dictNewValues.values())
            strWhereChain = " and ".join(list(map(lambda a: a + '=?', whereConditions.keys())))
            tupleValues.extend(whereConditions.values())
            self.dbCursor.execute('UPDATE '+ self.strMcyProfileTablle +' SET '+ strSetsChain +' WHERE '+ strWhereChain + '', tupleValues)
            if bCommitAfter:
                self.dbConn.commit()
            else:
                pass
            return True, ""
        except Exception as e:
            return False, str(e)
    
    def SetTempSQLiteDict(self, inputDict={}, cls=SQLITE3_MUSTER_DICT_TYPE_38):
        if not bool(self.tmpSQLite):
            logger.info(LOG_TAG + ' * SetTempSQLiteDict(), the attribute tmpSQLite dictionary is empty, create with input muster dict ')
            self.tmpSQLite = cls.copy()
        else:
            logger.info(LOG_TAG + ' * SetTempSQLiteDict(), update the tmpSQLite dictionary with input')
        UpdateDictRecursively(self.tmpSQLite, inputDict)
    
    def GetTempSQLiteDict(self, cls=SQLITE3_MUSTER_DICT_TYPE_38):
        if not bool(self.tmpSQLite):
            logger.info(LOG_TAG + ' * GetTempSQLiteDict(), the attribute tmpSQLite dictionary is empty, create with input muster dict ')
            self.tmpSQLite = cls.copy()
        logger.info(LOG_TAG + ' * GetTempSQLiteDict(), return the copy of tmpSQLite dictionary')
        return self.tmpSQLite
    
    def GetMachineName(self):
        logger.info(LOG_TAG + ' * GetMachineName(), the machine name is: %s' % self.strMachineName)
        return self.strMachineName
    
    def GetMachineID(self):
        logger.info(LOG_TAG + ' * GetMachineID(), the machine name is: %s' % self.strMachineName)
        if self.strMachineName.lower() in MACHINE_MAPPING_NAME_TO_ID:
            iMID = MACHINE_MAPPING_NAME_TO_ID[self.strMachineName.lower()]
            logger.info(LOG_TAG + ' * GetMachineID(), found machine id: %s' % iMID)
        else:
            iMID = "00"
            logger.info(LOG_TAG + ' * GetMachineID(), not found machine id, use default: %s' % iMID)
        return iMID
    
    def GetCurrentUnitString(self):
        logger.info(LOG_TAG + ' * GetMachineName(), the machine name is: %s' % self.strCurrentOpticamUnit)
        return self.strCurrentOpticamUnit
    
    def showModal(self):
        # Bind to Application
        ret = super(BaseDialog, self).ShowModal() # Program is blocked
        self.GetParent().Enable(True)
        return ret

    ########################################################################################
    ###### Selection stuff
    ########################################################################################
    
    # def OnKeyDown(self, evt):
    #     # if self.logKeyDn:
    #     #     self.GetParent().keylog.LogKeyEvent("KeyDown", evt)
    #     # if self.callSkip:
    #     #     evt.Skip()
    #     key = evt.GetKeyCode()
    #     logger.info("OnKeyDown code={}".format(key))
    #
    #     if hasattr(self, "selectionobject"):
    #
    #         if key == wx.WXK_CONTROL:
    #             self.left_control_was_pressed = 1
    #             selectionMode = " SNP"
    #             self.selectionobject.SetSelectionFilter( 0 , SEL_CAD_POINT, (SEL_MID_POINT | SEL_CEN_POINT) ) # only in hcnt, nx
    #         elif key == wx.WXK_SHIFT:
    #             self.left_control_was_pressed = 2
    #             selectionMode = " <SHIFT>"
    #             self.selectionobject.SetSelectionFilter( SEL_OPITCAM_RAY , SEL_CAD_VERTEX, 0 )
    #         else:
    #             self.left_control_was_pressed = False
    #             selectionMode = ""
    #             self.selectionobject.SetSelectionFilter( SEL_OPITCAM_RAY , SEL_CAD_VERTEX, 0 )
    #
    #         if self.statusbar:
    #             self.stabar.SetText2(getMessageW('Positioning', PYTHON_MESSAGES, 1100) + selectionMode)
    #
    #     evt.Skip()
    #
    # def OnKeyUp(self, evt):
    #     # if self.logKeyUp:
    #     #     self.GetParent().keylog.LogKeyEvent("KeyUp", evt)
    #     # if self.callSkip:
    #     #     evt.Skip()
    #     logger.info("OnKeyUp code={}".format(evt.GetKeyCode()))
    #     evt.Skip()
    #
    def OnChar(self, evt):
        # if self.logChar:
        #     self.GetParent().keylog.LogKeyEvent("Char", evt)
        logger.info("OnChar code={}".format(evt.GetKeyCode()))
        evt.Skip()

    def StartSelection(self):
        if inPeps():
            if not hasattr(self, "peps_selection_in_progress"):
                from peps import Command, ReadGlobalString
                
                setattr(self, "peps_selection_in_progress", True)   # prevents second call while the first is not completed
                
                Command("wri $_return $_Null")      # Reset
                #
                self.GetTopLevelParent().Hide()     # make dialog invisible, this does an endloop in modal dlg's!
                #self.GetTopLevelParent().Iconize()
                Command("call point_selection")     # <- here we are in the peps selection, prg. is waiting until returning
                self.GetTopLevelParent().Show()     # make dialog visible again
                #self.GetTopLevelParent().Restore()
                r_return = ReadGlobalString("$_return")
                #r_return = "X95.627 Y149.271 Z0.0"
                logger.info("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< after peps.Command call point_selection returned:{}".format(r_return))
                #
                # put digitized values into widgets
                if hasattr(self, "WritePickPosition"):      # this is true for main-dialogs (and most sub-dialogs)
                    if r_return:
                        param = r_return.strip().split()  # get list
                        try:
                            x = y = z = None
                            if len(param) > 0:
                                xs = param[0].replace('X', '').replace('x', '')
                                if True:    # TODO : get cad units
                                    x  = float(xs) * opticam.mm(1)
                                else:
                                    x  = float(xs) * opticam.inch(1)
                            if len(param) > 1:
                                ys = param[1].replace('Y', '').replace('y', '')
                                if True:    # TODO : get cad units
                                    y  = float(ys) * opticam.mm(1)
                                else:
                                    y  = float(ys) * opticam.inch(1)
                            if len(param) > 2:
                                zs = param[2].replace('Z', '').replace('z', '')
                                if True:    # TODO : get cad units
                                    z  = float(zs) * opticam.mm(1)
                                else:
                                    z  = float(zs) * opticam.inch(1)
                            self.WritePickPosition(x, y, z)
                        except:
                            pass

                delattr(self, "peps_selection_in_progress")
            return

        if not hasattr(self, "selectionobject"):
            logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> StartSelection")
            #
            self.selectionobject = getCurrentDoc().GetSelection()
            self.selectionobject.ClearSelection()
            self.selectionobject.ClearSelectionFilter()

            if inPeps():
                    selectionMode = ""
                    self.selectionobject.SetSelectionFilter( (SEL_OPITCAM_RAY | SEL_OPITCAM_LINE | SEL_OPITCAM_ARC | SEL_OPITCAM_CIRCLE) , SEL_CAD_POINT, (SEL_MID_POINT | SEL_CEN_POINT | SEL_END_POINT) )
            elif inPepsUG():
                selectionMode = ""
                self.selectionobject.SetSelectionFilter( (SEL_OPITCAM_RAY) , (SEL_CAD_VERTEX | SEL_CAD_POINT), (SEL_MID_POINT | SEL_CEN_POINT | SEL_END_POINT) )          
            elif inPepsSW():
                selectionMode = ""
                self.selectionobject.SetSelectionFilter( SEL_OPITCAM_RAY , ( SEL_CAD_VERTEX | SEL_CAD_POINT ), (SEL_MID_POINT | SEL_CEN_POINT | SEL_END_POINT) ) # only sw
            else:
                if wx.GetKeyState(wx.WXK_CONTROL):
                    selectionMode = " SNP"
                    self.selectionobject.SetSelectionFilter( 0 , SEL_CAD_POINT, (SEL_MID_POINT | SEL_CEN_POINT | SEL_END_POINT) ) # only in hcnt, nx
                elif wx.GetKeyState(wx.WXK_ALT):
                    selectionMode = " <ALT>"
                    self.selectionobject.SetSelectionFilter( 0 , SEL_CAD_POINT , (SEL_MID_POINT | SEL_CEN_POINT | SEL_END_POINT | SEL_OPITCAM_POINT3D | SEL_OPITCAM_POINT2D) ) # experimental
                elif wx.GetKeyState(wx.WXK_SHIFT):
                    selectionMode = " <SHIFT>"
                    self.selectionobject.SetSelectionFilter( 0 , SEL_CAD_POINT, (SEL_MID_POINT | SEL_CEN_POINT) ) # only in hcnt, nx
                else:   # no special keypress
                    selectionMode = ""
                    self.selectionobject.SetSelectionFilter( SEL_OPITCAM_RAY , SEL_CAD_POINT, (SEL_MID_POINT | SEL_CEN_POINT | SEL_END_POINT) ) # only in hcnt, nx

            self.selectionobject.StartSelection()

            if self.statusbar:
                if hasattr(self,"stabar"):
                    self.stabar.SetText2(getMessageW('Positioning', PYTHON_MESSAGES, 1100) + selectionMode)
                if hasattr(self,"stabar1"):
                    self.stabar1.SetText2(getMessageW('Positioning', PYTHON_MESSAGES, 1100) + selectionMode)

    def StopSelection(self, clear=True):
        if hasattr(self, "selectionobject"):
            logger.info("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< StopSelection")
            
            self.selectionobject.EndSelection()
            self.selectionobject.ClearSelectionFilter()
            if clear:
                self.selectionobject.ClearSelection()   # it clears also the graphical selection symbols
            delattr(self, "selectionobject")
            if self.statusbar:
                #self.stabar.SetText1( getattr(self, "strOutput", "Statusbar") )
                if hasattr(self,"stabar"):
                    self.stabar.SetText2("")
                if hasattr(self,"stabar1"):
                    self.stabar1.SetText2("")
                    

    def ReadSelection(self):
        sel_size = self.selectionobject.GetSelectionSize()
        objNam = None
        if sel_size > 0:
            pos3 = None
            #
            for i in range(1 , sel_size+1):             # 1. search for P2C_VERTEX
                typ = self.selectionobject.GetSelectedType(i) # These are starting with 1
                logger.info(LOG_TAG + " * ReadSelection(), GET OBJECT OF TYPE: %s " % typ)
                if typ in [P2C_VERTEX]:                     
                    vertex1 = self.selectionobject.GetSelectedVertex(i)
                    if(vertex1):
                        ent   = vertex1.GetEntity()
                        pos3 = vertex1.GetPoint()
                        # del is needed here!!!!!!!!
                        del vertex1    
                        objNam = "vertex"
                        break
            else:
                for i in range(1 , sel_size+1):         # 2. search for P2C_POINT
                    typ = self.selectionobject.GetSelectedType(i) # These are starting with 1
                    logger.info(LOG_TAG + " * ReadSelection(), GET OBJECT OF TYPE: %s " % typ)
                    if typ in [P2C_POINT]:     
                        point = self.selectionobject.GetSelectedP2CPointP(i)
                        if(point):
                            ent =  point.GetEntity()
                            pos3 = point.GetPoint()
                            del point
                            objNam = "point"
                            break
                else:
                    for i in range(1 , sel_size+1):     # 3. search for P2C_SKETCH
                        typ = self.selectionobject.GetSelectedType(i) # These are starting with 1
                        logger.info(LOG_TAG + " * ReadSelection(), GET OBJECT OF TYPE: %s " % typ)
                        if typ in [P2C_SKETCH]:    # search for typ P2C_SKETCH  
                            sketch = self.selectionobject.GetSelectedSketchPy(i)
                            if(sketch):
                                # Test for None
                                ent = sketch.GetEntity()
                                b3d = sketch.Is3D()
                                nam = sketch.GetName()
                                if b3d == False:
                                    objNam = nam.getPyString()
                                break
                    else:
                        for i in range(1 , sel_size+1): # 4. search for SEL_OPTICAM_FIRST_OFFSET + RAY_TYPE
                            typ = self.selectionobject.GetSelectedType(i) # These are starting with 1
                            logger.info(LOG_TAG + " * ReadSelection(), GET OBJECT OF TYPE: %s " % typ)
                            if typ in [SEL_OPTICAM_FIRST_OFFSET + RAY_TYPE]:
                                ray = self.selectionobject.GetSelectedRay(i)
                                if(ray):
                                    if ray.ok:
                                        p3d = ray.GetPoint3d()
                                        v3d = ray.GetVector3d()
                                        doc = getCurrentDoc()
                                        ope = doc.program.getActiveOperation()
                                        # program.getOrigin()
                                        ori = ope.getOrigin()
                                        hei = ope.GetReferencePlaneHeight()
                                                                
                                        pos = Point3d(0,0,hei)
                                        pos.Transform(ori.TM)
                                        
                                        vec = Vector3d(0,0,1)
                                        vec.Transform(ori.TM)
                                        
                                        # geoff_geometry::Plane ref_plane(geoff_geometry::Point3d(0, 0, op->GetReferenceGlobalHeight()).Transformed(origin->TM), 
                                        # geoff_geometry::Vector3d(0, 0, 1).Transformed(origin->TM));
                                        plane = Plane(pos, vec, True) 
                                        
                                        pos2 = Point3d(0,0,0)
                                        
                                        if plane.IntofPy(ray, pos2):    # get an Interscetion?    
                                            pos3 = pos2.Transformed(ori.invTM) # That ends up in error, some lines down it will be done.
                                            # The transformation will be done in if pos3:
                                            pos3 = pos2
                                        del( pos2 )
                                        objNam = "ray"
                                    break
                        else:
                            for i in range(1 , sel_size+1): # 5. look if there is anything at all
                                typ = self.selectionobject.GetSelectedType(i) # These are starting with 1
                                logger.info(LOG_TAG + " * ReadSelection(), GET OBJECT OF TYPE: %s " % typ)
                                if typ:
                                    pass
                                    objNam = "unknown"
                                    
                            else:
                                pass    # nothing found at all
                                      
            if pos3:
                # put digitized values into widgets
                if hasattr(self, "WritePickPosition"):      # this is true for main-dialogs (and most sub-dialogs)
                    doc = getCurrentDoc()
                    ope = doc.program.getActiveOperation()
                    ori = ope.getOrigin()
                    pos3.Transform(ori.invTM)
                    
                    self.WritePickPosition(pos3.x, pos3.y, pos3.z)
                del( pos3 )
                    
        # 04/07/2025
        # Does it make sense to transform the Point3d?
        # I have taken a look into main system, sta/end hole stuff.
        # Vertex selected only the transformed value is shown in edit field!
        # Point selected 
        # intof = pPoint->getPoint_Raw();
        # pEndHole->SetRefStartHolePoint(intof.Transformed(pOrigin->invTM));
        #
        # The trick here is that the main system which holds the data will recalculate the transformed CAD data back.
        # But for handling input values in edit field we all think wit transformation.
        # In main system I thought that we transform forwards and backwards in edit fields, anyway!
        # 04/07/2025
        # Terminate selection mode
        self.StopSelection()
        return objNam

    def NewSelection(self):
        """...to come here everytime there is a change in the selection
        """
        if hasattr(self, "selectionobject"):
            if self.selectionobject.IsActive():     # selection is in progress
                name = self.ReadSelection()
                if name is not None:
                    logger.info(LOG_TAG + " * NewSelection(), selected %s " % name)
                else:
                    logger.info(LOG_TAG + " * NewSelection(), nothing hit")
        else:
            logger.info(LOG_TAG + " * NewSelection(), no selectionobject exists!")
    ########################################################################################
        

class MyFindPrefixListBox(wx.ListBox):
    def __init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize,  # @ReservedAssignment
                 choices=[], style=0, validator=wx.DefaultValidator):
        wx.ListBox.__init__(self, parent, id, pos, size, choices, style, validator)
        self.typedText = ''
        self.Bind(wx.EVT_KEY_DOWN, self.OnKey)


    def FindPrefix(self, prefix):
        logger.info(LOG_TAG + ' * FindPrefix(), loking for prefix: %s\n' % prefix)

        if prefix:
            prefix = prefix.lower()
            length = len(prefix)

            # Changed in 2.5 because ListBox.Number() is no longer supported.
            # ListBox.GetCount() is now the appropriate way to go.
            for x in range(self.GetCount()):
                text = self.GetString(x)
                text = text.lower()

                if text[:length] == prefix:
                    logger.info(LOG_TAG + ' * FindPrefix(), prefix %s is found.\n' % prefix)
                    return x

        logger.info(LOG_TAG + ' * FindPrefix(), prefix %s is not found.\n' % prefix)
        return -1


    def OnKey(self, evt):
        key = evt.GetKeyCode()

        if key >= 32 and key <= 127:
            self.typedText = self.typedText + chr(key)
            item = self.FindPrefix(self.typedText)

            if item != -1:
                self.SetSelection(item)

        elif key == wx.WXK_BACK:   # backspace removes one character and backs up
            self.typedText = self.typedText[:-1]

            if not self.typedText:
                self.SetSelection(0)
            else:
                item = self.FindPrefix(self.typedText)

                if item != -1:
                    self.SetSelection(item)
        else:
            self.typedText = ''
            evt.Skip()

    def OnKeyDown(self, evt):
        pass


class MeasureCycleWarningMessageDialog(MeasureCycleBaseDialog):
    """
    This is the info dialog for measure cycle, for warning meassage
    """
    
    def __init__(self, *args, **kwargs):
        #Init Base class
        MeasureCycleBaseDialog.__init__(self, *args, **kwargs)
        # if the pre create mode is true, it means show/hide modus
        self.preCreateMode = False  
        # hide the help button
        if hasattr(self, "btnHelp"):
            self.btnHelp.Hide()
        # hide the translation button
        if hasattr(self, "btnTRA"):
            self.btnTRA.Hide()
        # hide the doc button
        if hasattr(self, "btnDOC"):
            self.btnDOC.Hide()
        #Create Widgets 
        self.CreateWidgets()
    
    def CreateWidgets(self):
        # c'tor saves current, The local setting of SW is special
        local = opticam.LocalPy()  # @UndefinedVariable
        local.set("C")

        hSizer = wx.BoxSizer(wx.HORIZONTAL)
        bitmap = wx.ArtProvider.GetBitmap(wx.ART_WARNING)
        image = wx.ImageFromBitmap(bitmap)
        image = image.Scale(40, 40, wx.IMAGE_QUALITY_HIGH)
        bitmap = wx.BitmapFromImage(image)
        self.bmpStatic = wx.StaticBitmap(self.panel, wx.ID_ANY, bitmap, pos=wx.DefaultPosition, size=(50, 50))
        hSizer.Add(self.bmpStatic, 0, wx.EXPAND | wx.ALL, BORDER)
        # descriptions 
        self.sttWarningMsg = wx.StaticText(self.panel, wx.ID_ANY, label="Delete Record", pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_WARNING_MSG") # de, Messen mit Draht (+X), update by "axis" option changed
        hSizer.Add(self.sttWarningMsg, 0, wx.EXPAND | wx.ALL, BORDER)
        self.vbxV1.Add(hSizer, 0, wx.ALL | wx.EXPAND, BORDER)



class MeasureCycleDialogInfoMessage(MeasureCycleBaseDialog):
    """
    This is the info dialog for measure cycle, if button "info clicked"
    """
    def __init__(self, *args, **kwargs):
        #Init Base class
        MeasureCycleBaseDialog.__init__(self, *args, **kwargs)
        # if the pre create mode is true, it means show/hide modus
        self.preCreateMode = False
        # hide the ok button
        self.btnOK.Hide()
        # hide the help button
        if hasattr(self, "btnHelp"):
            self.btnHelp.Hide()
        # hide the translation button
        if hasattr(self, "btnTRA"):
            self.btnTRA.Hide()
        # hide the doc button
        if hasattr(self, "btnDOC"):
            self.btnDOC.Hide()
    
        if self.iconMFCStyle:
            # move the ecs button to the first position
            posOk = self.vbxH1.GetItemPosition(self.btnOK)
            posEsc = self.vbxH1.GetItemPosition(self.btnESC)
            self.vbxH1.SetItemPosition(self.btnOK, (0, 10))
            self.vbxH1.SetItemPosition(self.btnESC, posOk)
            self.vbxH1.SetItemPosition(self.btnOK, posEsc)
            #self.vbxH1.Layout()
        
        #Create Widgets 
        self.CreateWidgets()
    
    def CreateWidgets(self):
        # descriptions 
        self.sttDesc1 = wx.StaticText(self.panel, wx.ID_ANY, label=getText("To backup / transfer data to other computers, copy these files:", "STT_INFO_DESC"),
                                                                           pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_INFO_DESC") # de, Messen mit Draht (+X), update by "axis" option changed
        self.vbxV1.Add(self.sttDesc1, 0, wx.ALL | wx.EXPAND, BORDER)
        # table
        hBoxSizerDatabase = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, getText("Profile Database", "STB_INFO_DATABASE"), name="STB_INFO_DATABASE"), wx.HORIZONTAL)
        self.eFInfoOne = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=(700, -1), min=min, max=max,
                                            name="EF_INFO_ONE", style=wx.TE_READONLY)
        self.eFInfoOne.Disable()
        hBoxSizerDatabase.Add(self.eFInfoOne, 0, wx.ALL | wx.EXPAND, 1)
        self.vbxV1.Add(hBoxSizerDatabase, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, BORDER)
        # table
        hBoxSizerTable = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, getText("Profile Table", "STB_INFO_TABLE"), name="STB_INFO_TABLE"), wx.HORIZONTAL)
        self.eFInfoTwo = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=(700, -1), min=min, max=max,
                                            name="EF_INFO_TWO", style=wx.TE_READONLY)
        self.eFInfoTwo.Disable()
        hBoxSizerTable.Add(self.eFInfoTwo, 0, wx.ALL | wx.EXPAND, 1)
        self.vbxV1.Add(hBoxSizerTable, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, BORDER)


class MeasureCycleDialogModifyProfile(MeasureCycleBaseDialog):
    """
    transfer data via a dictionary  tmpParams + extraMuster
        
    # dictionary for sqlite database contain the dictionary of tmpParams and 
    
    """
    def __init__(self, *args, **kwargs):
        #Init Base class
        MeasureCycleBaseDialog.__init__(self, *args, **kwargs)
        self.preCreateMode = False
        # Hide the not-used button
        if hasattr(self, "btnHelp"):
            self.btnHelp.Hide()
        if hasattr(self, "btnTRA"):
            self.btnTRA.Disable()
        if hasattr(self, "btnDOC"):
            self.btnDOC.Disable()
        # ConnectSQLiteDatabase
        self.ConnectSQLiteDatabase()
        # boolean attribute 
        self.bSelfUpdate = True
        # str Old self Index 
        self.strSelfIndex = "" 
        # dictionary for sqlite database contain the dictionary of tmpParams and "extra part"
        self.tmpSQLite = {} # type SQLITE3_MUSTER_DICT_TYPE_XX
        # Create widgets
        self.CreateWidgets()
    
    def CreateWidgets(self):
        # Main
        vBoxMain = wx.BoxSizer(wx.VERTICAL) # 
        # Box Sizer 
        self.lbFree = getText("-> Free", "RLEF_TOREAGE_PLACE_FREE")
        self.lbFull = getText("-> Full", "RLEF_TOREAGE_PLACE_FULL")
        self.lbEmpty = ""
        vBoxStoragePlace = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, getText("Storage place (1-999)", "STB_STOREAGE_PLACE"), name="STB_STOREAGE_PLACE"), wx.VERTICAL)
        self.rLEFStoragePlace = RightLabeledEditField(self.panel, wx.ID_ANY, "",
                                              min=1, max=999, behaviour=BEHAVIOUR.NUMERIC|BEHAVIOUR.INTEGER,
                                               minSizeEdit=(70, -1),
                                               name='RLEF_STOREAGE_PLACE_MODIFY', style=wx.TE_PROCESS_ENTER)
        self.rLEFStoragePlace.SetToolTipString("The storage place can be changed to a nonexistent number")
        #self.rLEFStoragePlace.Disable()
        vBoxStoragePlace.Add(self.rLEFStoragePlace, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 2)
        
        vBoxMain.Add(vBoxStoragePlace, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, BORDER)
        
        # Box Sizer 
        vBoxComment= wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Comment", name="STB_COMMENT"), wx.VERTICAL)
        # 1. comment
        self.eFCommentOne = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_ONE", style=wx.TE_PROCESS_ENTER)
        # self.eFCommentOne.Disable()
        vBoxComment.Add(self.eFCommentOne, 0, wx.ALL | wx.EXPAND, 2)
        # 2. comment
        self.eFCommentTwo = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_TWO", style=wx.TE_READONLY)
        self.eFCommentTwo.Disable()
        vBoxComment.Add(self.eFCommentTwo, 0, wx.ALL | wx.EXPAND, 2)
        # 3. comment
        self.eFCommentThree = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_THREE", style=wx.TE_READONLY)
        self.eFCommentThree.Disable()
        vBoxComment.Add(self.eFCommentThree, 0, wx.ALL | wx.EXPAND, 2)
        
        # 4. comment
        self.eFCommentFour = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_FOUR", style=wx.TE_READONLY)
        self.eFCommentFour.Disable()
        vBoxComment.Add(self.eFCommentFour, 0, wx.ALL | wx.EXPAND, 2)

        vBoxMain.Add(vBoxComment, 0,  wx.LEFT | wx.RIGHT | wx.EXPAND, BORDER)
        
        # buttons
        hBoxSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.btnSaveEntry = NiceBitmapButton(self.panel, wx.ID_ANY, 'id_Save.bmp', 'id_Save.bmp', 'id_Save.bmp', size=(38, 38), style=wx.RAISED_BORDER, name='BTN_PROFILE_SAVE_CHANGES' )
        self.btnSaveEntry.SetToolTipString("Save Changes")
        hBoxSizer.Add(self.btnSaveEntry, 0, wx.ALL, 2)
        
        vBoxMain.Add(hBoxSizer, 0,  wx.ALL | wx.EXPAND, BORDER)
        
        self.vbxV1.Add(vBoxMain, 0, flag=wx.ALL | wx.EXPAND, border=SMALLBORDER)
        
        self.SetSize((-1, 390))
        #self.panel.Fit()
        
        #self.Bind(wx.EVT_LISTBOX, self.EvtMultiListBox, self.lbIndexOfEntry)
        self.btnOK.Bind(wx.EVT_BUTTON, self.OnSaveRelatedEventOccured)
        self.btnSaveEntry.Bind(wx.EVT_BUTTON, self.OnSaveRelatedEventOccured)
        self.eFCommentOne.Bind(wx.EVT_TEXT_ENTER, self.OnSaveRelatedEventOccured)
        self.rLEFStoragePlace.edit.Bind(wx.EVT_TEXT, self.OnStoragePlaceEFTextCtrlChanged)
        self.rLEFStoragePlace.edit.Bind(wx.EVT_NAVIGATION_KEY, self.OnNaviagtionKeyPressed)
        self.rLEFStoragePlace.edit.Bind(wx.EVT_TEXT_ENTER, self.OnStoragePlaceEnterKeyPressed)
    
    def TransferDataToWindow(self, *args, **kwargs):  # @UnusedVariable
        # to insert index id -> SEARCHTERM
        strIndex = self.tmpSQLite["SEARCHTERM"]
        # backup old self index
        self.strSelfIndex = strIndex
        # change it's value
        self.rLEFStoragePlace.edit.ChangeValue(strIndex)
        # change value of comment 1
        strComment1 = self.tmpSQLite["COMMENT1"]
        self.eFCommentOne.ChangeValue(strComment1)
        # change value of comment 2
        strComment2 = self.tmpSQLite["COMMENT2"]
        self.eFCommentTwo.ChangeValue(strComment2)
        # change value of comment 3
        strComment3 = self.tmpSQLite["COMMENT3"]
        self.eFCommentThree.ChangeValue(strComment3)
        # change value of comment 4
        strComment4 = self.tmpSQLite["COMMENT4"]
        self.eFCommentFour.ChangeValue(strComment4)
        
    def TransferDataFromWindow(self, *args, **kwargs):  # @UnusedVariable
        # get value of comment 1
        strValue1 = self.eFCommentOne.GetValue()
        # update the key-value of the dictionary
        self.tmpSQLite["COMMENT1"] = strValue1
        # get new value of storage 
        strValue2 = self.rLEFStoragePlace.edit.GetWindowText()
        # update SEARCHTERM from dictionary
        self.tmpSQLite["SEARCHTERM"] = strValue2
        # get KEY_PART1 from dictionary
        strMtypeID = self.tmpSQLite["KEY_PART1"]
        # create the KEY, by bind KEY_PART1 with SEARCHTERM
        strKey = strMtypeID + strValue2
        # update the KEY of dictionary
        self.tmpSQLite["KEY"] = strKey
    
    def OnNaviagtionKeyPressed(self, event):
        if event.IsFromTab():
            # transfer the storage value to sqlite dictionary
            strValue = self.rLEFStoragePlace.edit.GetWindowText()
            # update the value of dictionary
            self.tmpSQLite["SEARCHTERM"] = strValue
        
    def OnSaveRelatedEventOccured(self, event):  # @UnusedVariable
        # transfer value from windows to dictionary
        self.TransferDataFromWindow()
        # measure type id
        strMtypeID = self.tmpSQLite["KEY_PART1"]
        # to insert index id -> SEARCHTERM
        strIndex = self.tmpSQLite["SEARCHTERM"]
        # machine id -> CUSTOMER1
        strMachineID = self.tmpSQLite["CUSTOMER1"]
        # Check if the index of record is already exist in database
        bExist = self.CheckIfSearchTermAlreadyExist(strIndex, strMtypeID, strMachineID)
        if event.GetEventObject() == self.eFCommentOne:
            if bExist == True and self.bSelfUpdate:
                strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                strMsgContent = getText("Save changes", "MSG_CONTENT_SAVE_CHANGES")
                dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.CANCEL | wx.ICON_WARNING)
                if dlg.ShowModal() == wx.ID_OK:
                    strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                    strMsgContent = getText("Record saved", "MSG_CONTENT_RECORD_SAVED")
                    dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                    if dlg.ShowModal() == wx.ID_OK:
                        dictNewValues = {}
                        # get comment one from windows
                        strCommentOne = self.eFCommentOne.GetValue()
                        # append the value into new values dictionary
                        dictNewValues["COMMENT1"] = strCommentOne
                        # for the clause string where part
                        whereConditions = {}
                        # to insert index id -> SEARCHTERM
                        strIndex = self.tmpSQLite["SEARCHTERM"]
                        # append the value into where values dictionary
                        whereConditions["SEARCHTERM"] = strIndex
                        # machine id -> CUSTOMER1
                        strMachineID = self.tmpSQLite["CUSTOMER1"]
                        # append the value into where values dictionary
                        whereConditions["CUSTOMER1"] = strMachineID
                        bRts, sRts = self.UpdateEntryToDatabase(dictNewValues, whereConditions, True)
                        if bRts:
                            super(MeasureCycleBaseDialog, self).OnOK(event)
                        else:
                            dlg = wx.MessageDialog(self, sRts, "", wx.OK | wx.ICON_ERROR)
                            dlg.ShowModal()
                    else:
                        a = 0  # @UnusedVariable
            elif bExist == True and not self.bSelfUpdate:
                strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                strMsgContent = getText("Record already exist", "MSG_CONTENT_RECORD_ALREADY_EXIST")
                dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                dlg.ShowModal()
                # Use next free index value
                # measure type id
                strMtypeID = self.tmpSQLite["KEY_PART1"]
                # to insert index id -> SEARCHTERM
                strIndex = self.tmpSQLite["SEARCHTERM"]
                # machine id -> CUSTOMER1
                strMachineID = self.tmpSQLite["CUSTOMER1"]
                # set back old index 
                self.rLEFStoragePlace.edit.ChangeValue(self.strSelfIndex)
                # set the boolean flag true again
                self.bSelfUpdate = True
                # change it's label
                self.rLEFStoragePlace.SetLabel(self.lbEmpty)
            else:
                strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                strMsgContent = getText("Add Record", "MSG_CONTENT_ADD_RECORD")
                dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.CANCEL | wx.ICON_WARNING)
                if dlg.ShowModal() == wx.ID_OK:
                    strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                    strMsgContent = getText("Record has been added", "MSG_CONTENT_RECORD_BEEN_ADDED")
                    dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                    if dlg.ShowModal() == wx.ID_OK:
                        bRts, sRts = self.InsertEntryToDatabase(self.tmpSQLite)
                        if bRts:
                            super(MeasureCycleBaseDialog, self).OnOK(event)
                        else:
                            dlg = wx.MessageDialog(self, sRts, "", wx.OK | wx.ICON_ERROR)
                            dlg.ShowModal()
                    else:
                        a = 0  # @UnusedVariable
        else:
            if bExist == True and event.GetEventObject() != self.btnOK and self.bSelfUpdate != True:
                strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                strMsgContent = getText("Record already exist", "MSG_CONTENT_RECORD_ALREADY_EXIST")
                dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                dlg.ShowModal()
                # Use next free index value
                # measure type id
                strMtypeID = self.tmpSQLite["KEY_PART1"]
                # to insert index id -> SEARCHTERM
                strIndex = self.tmpSQLite["SEARCHTERM"]
                # machine id -> CUSTOMER1
                strMachineID = self.tmpSQLite["CUSTOMER1"]
                # set back old index 
                self.rLEFStoragePlace.edit.ChangeValue(self.strSelfIndex)
                # set the boolean flag true again
                self.bSelfUpdate = True
                # change it's label
                self.rLEFStoragePlace.SetLabel(self.lbEmpty)
            else:
                if bExist == True:
                    strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                    strMsgContent = getText("Record saved", "MSG_CONTENT_RECORD_SAVED")
                    dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                    if dlg.ShowModal() == wx.ID_OK:
                        dictNewValues = {}
                        # get comment one from windows
                        strCommentOne = self.eFCommentOne.GetValue()
                        # append the value into new values dictionary
                        dictNewValues["COMMENT1"] = strCommentOne
                        # for the clause string where part
                        whereConditions = {}
                        # to insert index id -> SEARCHTERM
                        strIndex = self.tmpSQLite["SEARCHTERM"]
                        # append the value into where values dictionary
                        whereConditions["SEARCHTERM"] = strIndex
                        # machine id -> CUSTOMER1
                        strMachineID = self.tmpSQLite["CUSTOMER1"]
                        # append the value into where values dictionary
                        whereConditions["CUSTOMER1"] = strMachineID
                        bRts, sRts = self.UpdateEntryToDatabase(dictNewValues, whereConditions)
                        if bRts:
                            super(MeasureCycleBaseDialog, self).OnOK(event)
                        else:
                            dlg = wx.MessageDialog(self, sRts, "", wx.OK | wx.ICON_ERROR)
                            dlg.ShowModal()
                else:
                    strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                    strMsgContent = getText("Record has been added", "MSG_CONTENT_RECORD_BEEN_ADDED")
                    dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                    if dlg.ShowModal() == wx.ID_OK:
                        bRts, sRts = self.InsertEntryToDatabase(self.tmpSQLite)
                        if bRts:
                            super(MeasureCycleBaseDialog, self).OnOK(event)
                        else:
                            dlg = wx.MessageDialog(self, sRts, "", wx.OK | wx.ICON_ERROR)
                            dlg.ShowModal()
                    else:
                        a = 0  # @UnusedVariable
                        
    def OnStoragePlaceEFTextCtrlChanged(self, event):
        objControl = event.GetEventObject().GetParent()
        logger.info(LOG_TAG + " * OnStoragePlaceEFTextCtrlChanged(), The state of : %s widgets was changed" % objControl.GetName())
        flValid = True
        objControl.edit.errMsg = " INVALID INPUT"
#        if self.flRequired and val == '':
#            flValid = False
        if flValid:
            flValid = objControl.edit.GetWindowValue()
#        if flValid and self.formatter:
#            flValid = self.formatter.validate(val)
#        if self.validationCB:
#            self.validationCB(self.dataValue, val, self.flRequired, flValid)
        objControl.edit.SetError(not flValid)
        if flValid:
            # call linkage methodm if necessary
            # measure type id
            strMtypeID = self.tmpSQLite["KEY_PART1"]
            # to insert index id -> SEARCHTERM
            strIndex = objControl.edit.GetWindowText()
            # machine id -> CUSTOMER1
            strMachineID = self.tmpSQLite["CUSTOMER1"]
            if self.strSelfIndex != strIndex:
                # set the self update flag False
                self.bSelfUpdate = False
                # Check if the index of record is already exist in database
                rts = self.CheckIfSearchTermAlreadyExist(strIndex, strMtypeID, strMachineID)
                if rts:
                    self.rLEFStoragePlace.SetLabel(self.lbFull)
                else:
                    self.rLEFStoragePlace.SetLabel(self.lbFree)
            else:
                # set the self update flag true
                self.bSelfUpdate = True
                # set the label empty
                self.rLEFStoragePlace.SetLabel(self.lbEmpty)
        return flValid
    
    def OnStoragePlaceEnterKeyPressed(self, event):  # @UnusedVariable
        # transfer the storage value to sqlite dictionary
        strValue = self.rLEFStoragePlace.edit.GetWindowText()
        # update the value of dictionary
        self.tmpSQLite["SEARCHTERM"] = strValue


class MeasureCycleDialogSaveProfile(MeasureCycleBaseDialog):
    
    def __init__(self, *args, **kwargs):
        """
        transfer data via a dictionary  tmpParams + extraMuster
        
        # dictionary for sqlite database contain the dictionary of tmpParams and 
        # pp name --> CUSTOMER1
        # pp id --> CUSTOMER1
        { "extra": {"index":"1", "comment1": "", "comment2": "", "comment3": "", "comment4": "", "type_id": "", "pp_id":"", "pp_name":""}} 
        
        """
        #Init Base class
        MeasureCycleBaseDialog.__init__(self, *args, **kwargs)
        # if the pre create mode is true, it means show/hide modus
        self.preCreateMode = False
        # Hide the not-used button
        if hasattr(self, "btnHelp"):
            self.btnHelp.Hide()
        if hasattr(self, "btnTRA"):
            self.btnTRA.Disable()
        if hasattr(self, "btnDOC"):
            self.btnDOC.Disable()
        # ConnectSQLiteDatabase
        try:
            self.ConnectSQLiteDatabase()
        except:
            logger.error("MeasureCycleDialogSaveProfile: crashed in ConnectSQLiteDatabase()")
        # dictionary for sqlite database contain the dictionary of tmpParams and "extra part"
        self.tmpSQLite = {} # type SQLITE3_MUSTER_DICT_TYPE_XX
        # Create widgets
        self.CreateWidgets()
    
    def CreateWidgets(self):
        # Main
        vBoxMain = wx.BoxSizer(wx.VERTICAL) # 
        # Box Sizer 
        self.lbFree = getText("-> Free", "RLEF_TOREAGE_PLACE_FREE")
        self.lbFull = getText("-> Full", "RLEF_TOREAGE_PLACE_FULL")
        self.lbEmpty = ""
        vBoxStoragePlace = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, getText("Storage place (1-999)", "STB_STOREAGE_PLACE"), name="STB_STOREAGE_PLACE"), wx.VERTICAL)
        self.rLEFStoragePlace = RightLabeledEditField(self.panel, wx.ID_ANY, "",
                                              min=1, max=999, behaviour=BEHAVIOUR.NUMERIC|BEHAVIOUR.INTEGER,
                                               minSizeEdit=(70, -1),
                                               name='RLEF_STOREAGE_PLACE', style=wx.TE_PROCESS_ENTER)
        self.rLEFStoragePlace.SetToolTipString("Enter nonexistent number")
        #self.rLEFStoragePlace.Disable()
        vBoxStoragePlace.Add(self.rLEFStoragePlace, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 2)
        
        # descriptions 
        self.sttDesc1 = wx.StaticText(self.panel, wx.ID_ANY, label=getText("Press Tab/CR to accept this storage place", "STT_SUB_SAVE_DESC_COMMON_1"),
                                                                            pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_SUB_SAVE_DESC_COMMON_1") # de, Messen mit Draht (+X), update by "axis" option changed
        objFont = self.sttDesc1.GetFont()
        iFontSize = objFont.GetPointSize()
        objFont.SetPointSize(iFontSize - 2)
        self.sttDesc1.SetFont(objFont)
        
        self.sttDesc2 = wx.StaticText(self.panel, wx.ID_ANY, label=getText("<-- The currently entered data is saved", "STT_SUB_SAVE_DESC_COMMON_2"),
                                                                            pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_SUB_SAVE_DESC_COMMON_2") # de, Messen mit Draht (+X), update by "axis" option changed
        self.sttDesc2.SetFont(objFont)
        vBoxStoragePlace.AddSpacer(5)
        vBoxStoragePlace.Add(self.sttDesc1, 0, wx.ALL, 2)
        vBoxStoragePlace.Add(self.sttDesc2, 0, wx.ALL, 2)
        
        topLine = wx.StaticLine(self.panel, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
           style=wx.LI_HORIZONTAL, name="Top Line")
        
        vBoxStoragePlace.Add(topLine, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 1)
        
        self.sttDesc3 = wx.StaticText(self.panel, wx.ID_ANY, label=getText("Enter a comment to make it easier to see", "STT_SUB_SAVE_DESC_COMMON_3"),
                                       pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_SUB_SAVE_DESC_COMMON_3") # de, Messen mit Draht (+X), update by "axis" option changed
        self.sttDesc3.SetFont(objFont)
        
        self.sttDesc4 = wx.StaticText(self.panel, wx.ID_ANY, label=getText("which data has been saved in the storage place", "STT_SUB_SAVE_DESC_COMMON_4"),
                                                                           pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_SUB_SAVE_DESC_COMMON_4") # de, Messen mit Draht (+X), update by "axis" option changed
        self.sttDesc4.SetFont(objFont)
        
        vBoxStoragePlace.AddSpacer(5)
        vBoxStoragePlace.Add(self.sttDesc3, 0, wx.ALL, 2)
        vBoxStoragePlace.Add(self.sttDesc4, 0, wx.ALL, 2)
        
        vBoxMain.Add(vBoxStoragePlace, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, BORDER)
        
        # Box Sizer 
        vBoxComment= wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, getText("Comment", "STB_COMMENT"), name="STB_COMMENT"), wx.VERTICAL)
        # 1. comment
        self.eFCommentOne = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_ONE", style=wx.TE_PROCESS_ENTER)
        # self.eFCommentOne.Disable()
        vBoxComment.Add(self.eFCommentOne, 0, wx.ALL | wx.EXPAND, 2)
        # 2. comment
        self.eFCommentTwo = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_TWO", style=wx.TE_READONLY)
        self.eFCommentTwo.Disable()
        vBoxComment.Add(self.eFCommentTwo, 0, wx.ALL | wx.EXPAND, 2)
        # 3. comment
        self.eFCommentThree = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_THREE", style=wx.TE_READONLY)
        self.eFCommentThree.Disable()
        vBoxComment.Add(self.eFCommentThree, 0, wx.ALL | wx.EXPAND, 2)
        
        # 4. comment
        self.eFCommentFour = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_FOUR", style=wx.TE_READONLY)
        self.eFCommentFour.Disable()
        vBoxComment.Add(self.eFCommentFour, 0, wx.ALL | wx.EXPAND, 2)

        vBoxMain.Add(vBoxComment, 0,  wx.LEFT | wx.RIGHT | wx.EXPAND, BORDER)
        
        # buttons
        hBoxSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.btnSaveEntry = NiceBitmapButton(self.panel, wx.ID_ANY, 'id_Save.bmp', 'id_Save.bmp', 'id_Save.bmp', size=(38, 38), style=wx.RAISED_BORDER, name='BTN_PROFILE_SAVE_ENTRY' )
        self.btnSaveEntry.SetToolTipString("Add record")
        hBoxSizer.Add(self.btnSaveEntry, 0, wx.ALL, 2)
        self.btnAddEntry = NiceBitmapButton(self.panel, wx.ID_ANY, 'id_Add.bmp', 'id_Add.bmp', 'id_Add.bmp', size=(38, 38), style=wx.RAISED_BORDER, name='BTN_PROFILE_ADD_ENTRY' )
        self.btnAddEntry.SetToolTipString("Add new record (search for a free storing place)")
        hBoxSizer.Add(self.btnAddEntry, 0, wx.ALL, 2)
        
        vBoxMain.Add(hBoxSizer, 0,  wx.ALL | wx.EXPAND, BORDER)
        
        self.vbxV1.Add(vBoxMain, 0, flag=wx.ALL | wx.EXPAND, border=SMALLBORDER)
        
        self.SetSize((-1, 480))
        #self.panel.Fit()2
        
        #self.Bind(wx.EVT_LISTBOX, self.EvtMultiListBox, self.lbIndexOfEntry)
        self.btnOK.Bind(wx.EVT_BUTTON, self.OnSaveRelatedEventOccured)
        self.btnSaveEntry.Bind(wx.EVT_BUTTON, self.OnSaveRelatedEventOccured)
        self.eFCommentOne.Bind(wx.EVT_TEXT_ENTER, self.OnSaveRelatedEventOccured)
        self.btnAddEntry.Bind(wx.EVT_BUTTON, self.OnBtnAddEntryClicked)
        self.rLEFStoragePlace.edit.Bind(wx.EVT_TEXT, self.OnStoragePlaceEFTextCtrlChanged)
        self.rLEFStoragePlace.Bind(wx.EVT_NAVIGATION_KEY, self.OnNaviagtionKeyPressed)
        self.rLEFStoragePlace.edit.Bind(wx.EVT_TEXT_ENTER, self.OnStoragePlaceEnterKeyPressed)
    
    def TransferDataToWindow(self, *args, **kwargs):  # @UnusedVariable
        # change value of comment 1
        strComment1 = self.tmpSQLite.get("COMMENT1","")
        self.eFCommentOne.ChangeValue(strComment1)
        # change value of comment 2
        strComment2 = self.tmpSQLite.get("COMMENT2","")
        strComment2 = "" if strComment2 is None else strComment2
        self.eFCommentTwo.ChangeValue(strComment2)
        # change value of comment 3
        strComment3 = self.tmpSQLite.get("COMMENT3","")
        strComment3 = "" if strComment3 is None else strComment3
        self.eFCommentThree.ChangeValue(strComment3)
        # change value of comment 4
        strComment4 = self.tmpSQLite.get("COMMENT4","")
        strComment4 = "" if strComment4 is None else strComment4
        self.eFCommentFour.ChangeValue(strComment4)
        # measure type id
        strMtypeID = self.tmpSQLite["KEY_PART1"]
        # to insert index id -> SEARCHTERM
        strIndex = self.tmpSQLite["SEARCHTERM"]
        # machine id -> CUSTOMER1
        strMachineID = self.tmpSQLite["CUSTOMER1"]
        # Check if the index of record is already exist in database
        #bExist = self.CheckIfSearchTermAlreadyExist(strIndex, strMtypeID, strMachineID)
        #if bExist:
        

        #show the add icon
        self.btnAddEntry.Hide()
        # enable the storage place
        self.rLEFStoragePlace.Enable()
        # change it's value
        self.rLEFStoragePlace.edit.ChangeValue(strIndex)
        # change it's label
        self.rLEFStoragePlace.SetLabel(self.lbFree) 
        
        self.SearchNextFreeEntry()
            
        return True   
        
    def TransferDataFromWindow(self, *args, **kwargs):  # @UnusedVariable
        # get value of comment 1
        strValue1 = self.eFCommentOne.GetValue()
        # update the key-value of the dictionary
        self.tmpSQLite["COMMENT1"] = strValue1
        # get new value of storage 
        strValue2 = self.rLEFStoragePlace.edit.GetWindowText()
        # update SEARCHTERM from dictionary
        self.tmpSQLite["SEARCHTERM"] = strValue2
        # get KEY_PART1 from dictionary
        strMtypeID = self.tmpSQLite["KEY_PART1"]
        # create the KEY, by bind KEY_PART1 with SEARCHTERM
        strKey = strMtypeID + strValue2
        # update the KEY of dictionary
        self.tmpSQLite["KEY"] = strKey
        
        return True
        
    def OnNaviagtionKeyPressed(self, event):
        if event.IsFromTab() or event.IsForward:
            # transfer the storage value to sqlite dictionary
            strValue = self.rLEFStoragePlace.edit.GetWindowText()
            # update the value of dictionary
            self.tmpSQLite["SEARCHTERM"] = strValue
            # hide the description one
            self.sttDesc1.Hide()
    
    def OnBtnAddEntryClicked(self, event):  # @UnusedVariable
        # measure type id
        strMtypeID = self.tmpSQLite["KEY_PART1"]
        # to insert index id -> SEARCHTERM
        strIndex = self.tmpSQLite["SEARCHTERM"]
        # machine id -> CUSTOMER1
        strMachineID = self.tmpSQLite["CUSTOMER1"]
        # Check if the index of record is already exist in database
        while self.CheckIfSearchTermAlreadyExist(strIndex, strMtypeID, strMachineID):
            strIndex = "%d" % (int(strIndex) + 1)
        #show the add icon
        self.btnAddEntry.Hide()
        # enable the storage place
        self.rLEFStoragePlace.Enable()
        # change it's value
        self.rLEFStoragePlace.edit.ChangeValue(strIndex)
        # change it's label
        self.rLEFStoragePlace.SetLabel(self.lbFree)
        
    def SearchNextFreeEntry(self):
        # measure type id
        strMtypeID = self.tmpSQLite["KEY_PART1"]
        # to insert index id -> SEARCHTERM
        strIndex = self.tmpSQLite["SEARCHTERM"]
        strIndex ="1"
        # machine id -> CUSTOMER1
        strMachineID = self.tmpSQLite["CUSTOMER1"]
        # Check if the index of record is already exist in database
        while self.CheckIfSearchTermAlreadyExist(strIndex , strMtypeID, strMachineID):
            strIndex = "%d" % (int(strIndex) + 1)
        #show the add icon
        self.btnAddEntry.Hide()
        # enable the storage place
        self.rLEFStoragePlace.Enable()
        # change it's value
        self.rLEFStoragePlace.edit.ChangeValue(strIndex)
        # change it's label
        self.rLEFStoragePlace.SetLabel(self.lbFree)
    
    def OnSaveRelatedEventOccured(self, event):  # @UnusedVariable
        # transfer value from windows to dictionary
        self.TransferDataFromWindow()
        # measure type id
        strMtypeID = self.tmpSQLite["KEY_PART1"]
        # to insert index id -> SEARCHTERM
        strIndex = self.tmpSQLite["SEARCHTERM"]
        # machine id -> CUSTOMER1
        strMachineID = self.tmpSQLite["CUSTOMER1"]
        # Check if the index of record is already exist in database
        bExist = self.CheckIfSearchTermAlreadyExist(strIndex, strMtypeID, strMachineID)
        if event.GetEventObject() == self.eFCommentOne:
            if bExist == True:
                if self.btnAddEntry.IsShown():
                    strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                    strMsgContent = getText("Save changes", "MSG_CONTENT_SAVE_CHANGES")
                    dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.CANCEL | wx.ICON_WARNING)
                    if dlg.ShowModal() == wx.ID_OK:
                        strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                        strMsgContent = getText("Record saved", "MSG_CONTENT_RECORD_SAVED")
                        dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                        if dlg.ShowModal() == wx.ID_OK:
                            dictNewValues = {}
                            # make copy of dictNewValues
                            dictNewValues = self.tmpSQLite.copy()
                            # get comment one from windows, In fact, there is no need to re-fetch text from the window,
                            # because Transfer Data From Windows has already done this, and again to facilitate debugging.
                            strCommentOne = self.eFCommentOne.GetValue()
                            # append the value into new values dictionary
                            dictNewValues["COMMENT1"] = strCommentOne
                            # for the clause string where part
                            whereConditions = {}
                            # to insert index id -> SEARCHTERM
                            strIndex = self.tmpSQLite["SEARCHTERM"]
                            # append the value into where values dictionary
                            whereConditions["SEARCHTERM"] = strIndex
                            # machine id -> CUSTOMER1
                            strMachineID = self.tmpSQLite["CUSTOMER1"]
                            # append the value into where values dictionary
                            whereConditions["CUSTOMER1"] = strMachineID
                            bRts, sRts = self.UpdateEntryToDatabase(dictNewValues, whereConditions, True)
                            if bRts:
                                super(MeasureCycleBaseDialog, self).OnOK(event)
                            else:
                                dlg = wx.MessageDialog(self, sRts, "", wx.OK | wx.ICON_ERROR)
                                dlg.ShowModal()
                        else:
                            a = 0  # @UnusedVariable
                else:
                    strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                    strMsgContent = getText("Add Record", "MSG_CONTENT_ADD_RECORD")
                    dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.CANCEL | wx.ICON_WARNING)
                    if dlg.ShowModal() == wx.ID_OK:
                        strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                        strMsgContent = getText("Record already exist", "MSG_CONTENT_RECORD_ALREADY_EXIST")
                        dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                        dlg.ShowModal()
                        # Use next free index value
                        # measure type id
                        strMtypeID = self.tmpSQLite["KEY_PART1"]
                        # to insert index id -> SEARCHTERM
                        strIndex = self.tmpSQLite["SEARCHTERM"]
                        # machine id -> CUSTOMER1
                        strMachineID = self.tmpSQLite["CUSTOMER1"]
                        # Check if the index of record is already exist in database
                        while self.CheckIfSearchTermAlreadyExist(strIndex, strMtypeID, strMachineID):
                            strIndex = "%d" % (int(strIndex) + 1)
                        #show the add icon
                        self.btnAddEntry.Hide()
                        # enable the storage place
                        self.rLEFStoragePlace.Enable()
                        # change it's value
                        self.rLEFStoragePlace.edit.ChangeValue(strIndex)
                        # change it's label
                        self.rLEFStoragePlace.SetLabel(self.lbFree)
            else:
                strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                strMsgContent = getText("Add Record", "MSG_CONTENT_ADD_RECORD")
                dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.CANCEL | wx.ICON_WARNING)
                if dlg.ShowModal() == wx.ID_OK:
                    strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                    strMsgContent = getText("Record has been added", "MSG_CONTENT_RECORD_BEEN_ADDED")
                    dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                    if dlg.ShowModal() == wx.ID_OK:
                        bRts, sRts = self.InsertEntryToDatabase(self.tmpSQLite)
                        if bRts:
                            super(MeasureCycleBaseDialog, self).OnOK(event)
                        else:
                            dlg = wx.MessageDialog(self, sRts, "", wx.OK | wx.ICON_ERROR)
                            dlg.ShowModal()
                    else:
                        a = 0  # @UnusedVariable
        else:
            if bExist == True and event.GetEventObject() != self.btnOK and self.btnAddEntry.IsShown() == False:
                strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                strMsgContent = getText("Record already exist", "MSG_CONTENT_RECORD_ALREADY_EXIST")
                dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                dlg.ShowModal()
                # Use next free index value
                # measure type id
                strMtypeID = self.tmpSQLite["KEY_PART1"]
                # to insert index id -> SEARCHTERM
                strIndex = self.tmpSQLite["SEARCHTERM"]
                # machine id -> CUSTOMER1
                strMachineID = self.tmpSQLite["CUSTOMER1"]
                # Check if the index of record is already exist in database
                while self.CheckIfSearchTermAlreadyExist(strIndex, strMtypeID, strMachineID):
                    strIndex = "%d" % (int(strIndex) + 1)
                #show the add icon
                self.btnAddEntry.Hide()
                # enable the storage place
                self.rLEFStoragePlace.Enable()
                # change it's value
                self.rLEFStoragePlace.edit.ChangeValue(strIndex)
                # change it's label
                self.rLEFStoragePlace.SetLabel(self.lbFree)
            else:
                if bExist == True:
                    strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                    strMsgContent = getText("Record saved", "MSG_CONTENT_RECORD_SAVED")
                    dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                    if dlg.ShowModal() == wx.ID_OK:
                        dictNewValues = {}
                        # make copy of dictNewValues
                        dictNewValues = self.tmpSQLite.copy()
                        # get comment one from windows, In fact, there is no need to re-fetch text from the window,
                        # because Transfer Data From Windows has already done this, and again to facilitate debugging.
                        strCommentOne = self.eFCommentOne.GetValue()
                        # append the value into new values dictionary
                        dictNewValues["COMMENT1"] = strCommentOne
                        # for the clause string where part
                        whereConditions = {}
                        # to insert index id -> SEARCHTERM
                        strIndex = self.tmpSQLite["SEARCHTERM"]
                        # append the value into where values dictionary
                        whereConditions["SEARCHTERM"] = strIndex
                        # machine id -> CUSTOMER1
                        strMachineID = self.tmpSQLite["CUSTOMER1"]
                        # append the value into where values dictionary
                        whereConditions["CUSTOMER1"] = strMachineID
                        bRts, sRts = self.UpdateEntryToDatabase(dictNewValues, whereConditions)
                        if bRts:
                            super(MeasureCycleBaseDialog, self).OnOK(event)
                        else:
                            dlg = wx.MessageDialog(self, sRts, "", wx.OK | wx.ICON_ERROR)
                            dlg.ShowModal()
                else:
                    strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
                    strMsgContent = getText("Record has been added", "MSG_CONTENT_RECORD_BEEN_ADDED")
                    dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.ICON_WARNING)
                    if dlg.ShowModal() == wx.ID_OK:
                        bRts, sRts = self.InsertEntryToDatabase(self.tmpSQLite)
                        if bRts:
                            super(MeasureCycleBaseDialog, self).OnOK(event)
                        else:
                            dlg = wx.MessageDialog(self, sRts, "", wx.OK | wx.ICON_ERROR)
                            dlg.ShowModal()
                    else:
                        a = 0  # @UnusedVariable
            
    def OnStoragePlaceEFTextCtrlChanged(self, event):
        objControl = event.GetEventObject().GetParent()
        logger.info(LOG_TAG + " * OnStoragePlaceEFTextCtrlChanged(), The state of : %s widgets was changed" % objControl.GetName())
        flValid = True
        objControl.edit.errMsg = " INVALID INPUT"
#        if self.flRequired and val == '':
#            flValid = False
        if flValid:
            flValid = objControl.edit.GetWindowValue()
#        if flValid and self.formatter:
#            flValid = self.formatter.validate(val)
#        if self.validationCB:
#            self.validationCB(self.dataValue, val, self.flRequired, flValid)
        objControl.edit.SetError(not flValid)
        if flValid:
            # call linkage methodm if necessary
            # measure type id
            if not self.sttDesc1.IsShown():
                self.sttDesc1.Show()
            strMtypeID = self.tmpSQLite["KEY_PART1"]
            # to insert index id -> SEARCHTERM
            strIndex = objControl.edit.GetWindowText()
            # machine id -> CUSTOMER1
            strMachineID = self.tmpSQLite["CUSTOMER1"]
            # Check if the index of record is already exist in database
            rts = self.CheckIfSearchTermAlreadyExist(strIndex, strMtypeID, strMachineID)
            if rts:
                self.rLEFStoragePlace.SetLabel(self.lbFull)
            else:
                self.rLEFStoragePlace.SetLabel(self.lbFree)
        return flValid
    
    def OnStoragePlaceEnterKeyPressed(self, event):  # @UnusedVariable
        # transfer the storage value to sqlite dictionary
        strValue = self.rLEFStoragePlace.edit.GetWindowText()
        # update the value of dictionary
        self.tmpSQLite["SEARCHTERM"] = strValue
        # hide the description one
        self.sttDesc1.Hide()


class MeasureCycleDialogLoadProfile(MeasureCycleBaseDialog):
    
    def __init__(self, *args, **kwargs):
        """
        transfer data via a dictionary  tmpParams + extraMuster
        
        # dictionary for sqlite database contain the dictionary of tmpParams and 
        # pp name --> CUSTOMER1
        # pp id --> CUSTOMER1
        { "extra": {"index":"1", "comment1": "", "comment2": "", "comment3": "", "comment4": "", "type_id": "", "pp_id":"", "pp_name":""}} 
        """
        # the arrtibut SEARCHTERM <--> ID
        self.dictSearchToID = {}
        #Init Base class
        MeasureCycleBaseDialog.__init__(self, *args, **kwargs)
        # if the pre create mode is true, it means show/hide modus
        self.preCreateMode = False
        # Hide the not-used button
        if hasattr(self, "btnHelp"):
            self.btnHelp.Hide()
        if hasattr(self, "btnTRA"):
            self.btnTRA.Disable()
        if hasattr(self, "btnDOC"):
            self.btnDOC.Disable()
        # ConnectSQLiteDatabase
        self.ConnectSQLiteDatabase()
        # Create widgets
        self.CreateWidgets()
    
    def CreateWidgets(self):
        # Main
        vBoxMain = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, getText("Saved entries", "STB_MAIN_SAVED_ENTRIES"), name="STB_MAIN_SAVED_ENTRIES"), wx.VERTICAL) # 
        
        # List Box for Index of Entries
        #demoList = ["1", "2", "3", "4", "5", "6", "7"]
        self.lbIndexOfEntry = MyFindPrefixListBox(self.panel, wx.ID_ANY, pos=wx.DefaultPosition, size=(-1, 120), choices=[], style=wx.LB_SINGLE)
        vBoxMain.Add(self.lbIndexOfEntry, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, BORDER)
        # Box Sizer 
        vBoxStoragePlace = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, getText("Storage place (1-999)", "STB_STOREAGE_PLACE"), name="STB_STOREAGE_PLACE"), wx.HORIZONTAL)
        self.rLEFStoragePlace = RightLabeledEditField(self.panel, wx.ID_ANY, "",
                                              min=1, max=999, behaviour=BEHAVIOUR.NUMERIC|BEHAVIOUR.INTEGER,
                                               minSizeEdit=(65, -1), style=wx.TE_READONLY, 
                                               name='RLEF_STOREAGE_PLACE_DISABLE') # no tooltip 
        self.rLEFStoragePlace.Disable()
        vBoxStoragePlace.Add(self.rLEFStoragePlace, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 2)
        vBoxMain.Add(vBoxStoragePlace, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, BORDER)
        
        # Box Sizer 
        vBoxComment= wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, getText("Comment", "STB_COMMENT"), name="STB_COMMENT"), wx.VERTICAL)
        # 1. comment
        self.eFCommentOne = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_ONE", style=wx.TE_READONLY)
        self.eFCommentOne.Disable()
        vBoxComment.Add(self.eFCommentOne, 0, wx.ALL | wx.EXPAND, 2)
        # 2. comment
        self.eFCommentTwo = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_TWO", style=wx.TE_READONLY)
        self.eFCommentTwo.Disable()
        vBoxComment.Add(self.eFCommentTwo, 0, wx.ALL | wx.EXPAND, 2)
        # 3. comment
        self.eFCommentThree = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_THREE", style=wx.TE_READONLY)
        self.eFCommentThree.Disable()
        vBoxComment.Add(self.eFCommentThree, 0, wx.ALL | wx.EXPAND, 2)
                # 4. comment
        self.eFCommentFour = EditField(self.panel, wx.ID_ANY, "", pos=wx.DefaultPosition, size=wx.DefaultSize, min=min, max=max,
                                            name="EF_COMMENT_FOUR", style=wx.TE_READONLY)
        self.eFCommentFour.Disable()
        vBoxComment.Add(self.eFCommentFour, 0, wx.ALL | wx.EXPAND, 2)

        vBoxMain.Add(vBoxComment, 0,  wx.LEFT | wx.RIGHT | wx.EXPAND, BORDER)
        
        # buttons
        hBoxSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.btnLoadEntry = NiceBitmapButton(self.panel, wx.ID_ANY, 'id_load.bmp', 'id_load.bmp', 'id_load.bmp', size=(38, 38), style=wx.RAISED_BORDER, name='BTN_PROFILE_LOAD_ENTRY' )
        self.btnLoadEntry.SetToolTipString("The entries saved under this storing place are loaded into the dialog (ditto. with [Ok] / [Return] / double click)")
        hBoxSizer.Add(self.btnLoadEntry, 0, wx.ALL, 2)
        # modify entry
        self.btnModifyEntry = NiceBitmapButton(self.panel, wx.ID_ANY, 'id_modify.bmp', 'id_modify.bmp', 'id_modify.bmp', size=(38, 38), style=wx.RAISED_BORDER, name='BTN_PROFILE_MODIFY_ENTRY' )
        self.btnModifyEntry.SetToolTipString("Change Storing place / Comment")
        hBoxSizer.Add(self.btnModifyEntry, 0, wx.ALL, 2)
        # delete entry
        self.btnDeleteEntry = NiceBitmapButton(self.panel, wx.ID_ANY, 'id_delete.bmp', 'id_delete.bmp', 'id_delete.bmp', size=(38, 38), style=wx.RAISED_BORDER, name='BTN_PROFILE_DELETE_ENTRY' )
        self.btnDeleteEntry.SetToolTipString("Delete Record")
        hBoxSizer.Add(self.btnDeleteEntry, 0, wx.ALL, 2)
        # info entry
        self.btnInfoEntry = NiceBitmapButton(self.panel, wx.ID_ANY, 'id_info.bmp', 'id_info.bmp', 'id_info.bmp', size=(38, 38), style=wx.RAISED_BORDER, name='BTN_PROFILE_INFO_ENTRY' )
        self.btnInfoEntry.SetToolTipString("Info")
        hBoxSizer.Add(self.btnInfoEntry, 0, wx.ALL, 2)
        
        vBoxMain.Add(hBoxSizer, 0,  wx.ALL | wx.EXPAND, BORDER)
        
        # descriptions 
        self.sttDesc1 = wx.StaticText(self.panel, wx.ID_ANY, label=getText("Change values: Load the entries in the dialog []<--", "STT_SUB_LOAD_DESC_COMMON_1"),
                                      pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_SUB_LOAD_DESC_COMMON_1") # de, Messen mit Draht (+X), update by "axis" option changed
        objFont = self.sttDesc1.GetFont()
        iFontSize = objFont.GetPointSize()
        objFont.SetPointSize(iFontSize - 2)
        self.sttDesc1.SetFont(objFont)
        
        self.sttDesc2 = wx.StaticText(self.panel, wx.ID_ANY, label=getText("- make changes. click [Save]", "STT_SUB_LOAD_DESC_COMMON_2"),
                                      pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_SUB_LOAD_DESC_COMMON_2") # de, Messen mit Draht (+X), update by "axis" option changed
        self.sttDesc2.SetFont(objFont)
        
        self.sttDesc3 = wx.StaticText(self.panel, wx.ID_ANY, label=getText("- overwrite loaded storage place", "STT_SUB_LOAD_DESC_COMMON_3"),
                                      pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_SUB_LOAD_DESC_COMMON_3") # de, Messen mit Draht (+X), update by "axis" option changed
        self.sttDesc3.SetFont(objFont)
        
        vBoxMain.Add(self.sttDesc1, 0, wx.ALL, 1)
        vBoxMain.Add(self.sttDesc2, 0, wx.LEFT | wx.RIGHT, 1)
        vBoxMain.Add(self.sttDesc3, 0, wx.LEFT | wx.RIGHT, 1)
        
        self.sttDesc4 = wx.StaticText(self.panel, wx.ID_ANY, label=getText("Copy record : ditto. but", "STT_SUB_LOAD_DESC_COMMON_4"),
                                                                           pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_SUB_LOAD_DESC_COMMON_4") # de, Messen mit Draht (+X), update by "axis" option changed
        self.sttDesc4.SetFont(objFont)
        
        self.sttDesc5 = wx.StaticText(self.panel, wx.ID_ANY, label=getText("- enter a new storage place []+", "STT_SUB_LOAD_DESC_COMMON_5"),
                                       pos=wx.DefaultPosition,
           size=wx.DefaultSize, style=0, name="STT_SUB_LOAD_DESC_COMMON_5") # de, Messen mit Draht (+X), update by "axis" option changed
        self.sttDesc5.SetFont(objFont)
        
        vBoxMain.Add(self.sttDesc4, 0, wx.ALL, 1)
        vBoxMain.Add(self.sttDesc5, 0, wx.LEFT | wx.RIGHT, 1)
        
        # spaces
        vBoxMain.AddSpacer(SMALLBORDER)
        
        self.vbxV1.Add(vBoxMain, 0, flag=wx.ALL | wx.EXPAND, border=SMALLBORDER)
        
        self.SetSize((-1, 640))
        #self.panel.Fit()
        
        self.btnOK.Bind(wx.EVT_BUTTON, self.OnLoadRelatedEventOccured)
        self.btnLoadEntry.Bind(wx.EVT_BUTTON, self.OnLoadRelatedEventOccured)
        self.lbIndexOfEntry.Bind(wx.EVT_LISTBOX_DCLICK, self.OnLoadRelatedEventOccured)
        self.lbIndexOfEntry.Bind(wx.EVT_LISTBOX, self.OnListBoxSelectionChanged)
        self.btnModifyEntry.Bind(wx.EVT_BUTTON, self.OnBtnModifyEntryClicked)
        self.btnDeleteEntry.Bind(wx.EVT_BUTTON, self.OnBtnDeleteEntryClicked)
        self.btnInfoEntry.Bind(wx.EVT_BUTTON, self.OnBtnInfoEntryClicked)
    
    def TransferDataToWindow(self, *args, **kwargs):  # @UnusedVariable
        # get tmpSQLite dictionary 
        tmpSQLiteDict = self.GetTempSQLiteDict()
        # clear the mapping dict 
        self.dictSearchToID.clear()
        # create a to-select value keys list
        valuesKeysList = ["SEARCHTERM", "ID"]
        # define a where conditions dictionary
        whereConditions = {}
        # Update KEY_PART1
        whereConditions["KEY_PART1"] = tmpSQLiteDict["KEY_PART1"]
        # Update machine id
        whereConditions["CUSTOMER1"] = tmpSQLiteDict["CUSTOMER1"]
        # create to-order keys list with keyword ASC oder DESC 
        orderKeysList = ["SEARCHTERM ASC"]
        # get list of entries from sqlite database
        listValuesTuple, dummy_msg = self.SelectEntriesFromDatabase(valuesKeysList, whereConditions, orderKeysList)
        if len(listValuesTuple) != 0:
            #clean windows 
            self.lbIndexOfEntry.Clear()
            # rebuild the mapping dictionary
            self.dictSearchToID = dict((str(x), y) for x, y in listValuesTuple)
            # list of keys 
            listKeys = list(self.dictSearchToID.keys())
            # transfer searchiterm to windows
            self.lbIndexOfEntry.InsertItems(listKeys, 0)
            # get searchterm from dict
            strSearchIterm = tmpSQLiteDict["SEARCHTERM"]
            # check if the strSearchIterm in list of keys
            if strSearchIterm in listKeys:
                # get index of selections 
                iIndex = listKeys.index(strSearchIterm)
                # set this index selected 
                self.lbIndexOfEntry.Select(iIndex)
            else:
                # set 0 of selections
                self.lbIndexOfEntry.Select(0)
            # fire the event handler
            self.OnListBoxSelectionChanged(None)
        else:
            # Also clear the list box if the last entry gets deleted
            self.lbIndexOfEntry.Clear()
            # fire the event handler
            self.OnListBoxSelectionChanged(None)
            
        return True
        
    def OnLoadRelatedEventOccured(self, event):  # @UnusedVariable
        """
        We can actually use self.tmpSQLite directly. Because the dictionary has been loaded from SQLite
         correctly elsewhere (OnListBoxSelectionChanged).
        We read it again from the database to ensure data security. It is also possible to confirm whether
         the program has an error by reading the data.
        """
        # because this method will be fired without event
        iSelected = self.lbIndexOfEntry.GetSelection()
        # If we have a valid selection
        if iSelected != -1:
            # get selection string
            strSelected = self.lbIndexOfEntry.GetStringSelection()
            # get id by selected string with the mapping dictionary
            iIndex = self.dictSearchToID.get(strSelected)
            # create where coditions
            whereConditions = {"ID" : iIndex}
            # get entry from sqlite database by index
            dictParams, error_msg = self.SelectSingleEntireEntryFromDatabase(whereConditions)
            # delete ID from rstDict
            if "ID" in dictParams:
                # Delete the ID key-value pair to avoid updating the key ID into tmpSQLite
                del dictParams["ID"]
                # update the self tmpSQLite with rtsDict
                self.SetTempSQLiteDict(dictParams)
                # close the this dialog
                super(MeasureCycleBaseDialog, self).OnOK(event)
            else:
                dlg = wx.MessageDialog(self, error_msg, "", wx.OK | wx.ICON_ERROR)
                dlg.ShowModal()
        # If no selection is available, e.g. all entries have been deleted
        else:
            # close the this dialog
            super(MeasureCycleBaseDialog, self).OnOK(event)
        
    def OnBtnModifyEntryClicked(self, event):  # @UnusedVariable
        # get dict of tmpSQLite, create the dict of this instance,  as a temporary storage area for those data
        tmpSQLiteDict = self.GetTempSQLiteDict()
        dlg = MeasureCycleDialogModifyProfile(parent=self, modal=True, title="Change storage place / comment",
                                              size=wx.DefaultSize, name="DLG_MEASURE_CYCLIE_MODIFY_PROFILE")
        dlg.SetTempSQLiteDict(tmpSQLiteDict)
        if dlg.Activate() == wx.ID_OK:
            # update the tmpSQLite dict by using the dictionay of dlg instance, for next open
            self.SetTempSQLiteDict(dlg.tmpSQLite)
            # reload the windows
            self.TransferDataToWindow()
        else:
            a = 0  # @UnusedVariable
        
    def OnBtnDeleteEntryClicked(self, event):  # @UnusedVariable
        # get selection string
        strSelected = self.lbIndexOfEntry.GetStringSelection()
        # get id by selected string with the mapping dictionary
        iIndex = self.dictSearchToID.get(strSelected)
        # create where coditions
        whereConditions = {"ID" : iIndex}
        # delete 
        bDeleted, dummy_msg = self.DeleteEntryFromDatabase(whereConditions, False)  # @UnusedVariable
        strMsgLabel = getText("Warning", "MSG_LABEL_WARNING")
        strMsgContent = getText("Delete Record", "MSG_CONTENT_DELETE_RECORD")
        dlg = wx.MessageDialog(self, strMsgContent, strMsgLabel, wx.OK | wx.CANCEL | wx.ICON_WARNING)
        if dlg.ShowModal() == wx.ID_OK:
            # commit the changes
            self.dbConn.commit()
            # reload the windows
            self.TransferDataToWindow()
        else:
            # rollback the changes
            self.dbConn.rollback()
    
    def OnBtnInfoEntryClicked(self, event):  # @UnusedVariable
        strMcyProfileTable = self.strMcyProfileTablle
        dlg = MeasureCycleDialogInfoMessage(parent=self, modal=True, title="Info", size=(760, 290), name="DLG_MEASURE_CYCLIE_SUB_INFO")
        dlg.eFInfoOne.ChangeValue(self.strDBPath)
        dlg.eFInfoTwo.ChangeValue(strMcyProfileTable)
        dlg.Activate()
    
    def OnListBoxSelectionChanged(self, event):  # @UnusedVariable
        # we do not get the selection through event, 
        # because this method will be fired without event
        iSelected = self.lbIndexOfEntry.GetSelection()  # @UnusedVariable
        # get selection string
        strSelected = self.lbIndexOfEntry.GetStringSelection()
        # get id by selected string with the mapping dictionary
        iIndex = self.dictSearchToID.get(strSelected)
        # create where coditions
        whereConditions = {"ID" : iIndex}
        # get entry from sqlite database by index
        dictParams, dummy_msg = self.SelectSingleEntireEntryFromDatabase(whereConditions)
        # delete ID from rstDict
        if "ID" in dictParams:
            # Delete the ID key-value pair to avoid updating the key ID into tmpSQLite
            del dictParams["ID"]
            # update the self tmpSQLite with rtsDict
            self.SetTempSQLiteDict(dictParams)
            # get value storage place, i.e. SEARCHTERM
            vStoragePlace = dictParams["SEARCHTERM"]
            # update the storage place
            self.rLEFStoragePlace.edit.ChangeValue(vStoragePlace)
            # get value of comment 1 from dictParams
            vComment1 = dictParams["COMMENT1"]
            # update comment 1
            self.eFCommentOne.ChangeValue(vComment1)
            # get value of comment 2 from dictParams
            vComment2 = dictParams["COMMENT2"]
            # update comment 2
            self.eFCommentTwo.ChangeValue(vComment2)
            # get value of comment 3 from dictParams
            vComment3 = dictParams["COMMENT3"]
            # update comment 3
            self.eFCommentThree.ChangeValue(vComment3)
            # get value of comment 4 from dictParams
            vComment4 = dictParams["COMMENT4"]
            # update comment 3
            self.eFCommentFour.ChangeValue(vComment4)
        else: # Set to "Empty" to indicate there is an error while reading data from the database.
            # update the storage place
            self.rLEFStoragePlace.edit.ChangeValue("")
            # update comment 1
            self.eFCommentOne.ChangeValue("")
            # update comment 2
            self.eFCommentTwo.ChangeValue("")
            # update comment 3
            self.eFCommentThree.ChangeValue("")
            # update comment 3
            self.eFCommentFour.ChangeValue("")




def GeneralReadMeasureCycleDefaultParams(XMLMappingFile, strPPName="", strMeasureType="", strVersion=""):
    """
    The function to read the MeasureCycleDefaults.xml of a Post-Processor. This function implements the process of reading 
    data overall control. Thereby reducing the risk of the return value is null.
    @param XMLMappingFile (string): the path of the xml mapping file
    @param strPPName (string): post-processor name
    @param strMeasureType (string): measure cycle type, if not read all
    @param strVersion (string): the vdm version name, for example 2.28 of accutexx0  
     
    """
    def _read_childs(ppNode):
        for typeNode in ppNode.childNodes:
            if typeNode.attributes != None:
                strTypeName = typeNode.nodeName
                if strMeasureType != "":
                    if strTypeName != strMeasureType:
                        continue
                XMLData[strTypeName] = {}
                for paraNode in typeNode.childNodes:
                    if paraNode.attributes != None:
                        strParaName = paraNode.nodeName
                        XMLData[strTypeName][strParaName] = dict(paraNode.attributes.items())
                        #print(dict(paraNode.attributes.items()))
        
    XMLData = {}
    try:
        tree = dom.parse(file=XMLMappingFile)
        ppNodes = tree.getElementsByTagName(strPPName)
        for ppNode in ppNodes:
            if strVersion and ppNode.getAttribute("version") == strVersion:
                _read_childs(ppNode)
                break
        else:
            # if not found the wanted version -> try taking first record
            _read_childs(ppNodes[0])
    except Exception as e: # AttributeError: class Node has no attribute 'childNodes'
        logger.error("GeneralReadMeasureCycleDefaultParams : {}".format(e))

    return XMLData


def GeneralUpdateMeasureCycleDefaultParams(XMLMappingFile, strPPName="", strMeasureType="", strVersion="", inputDict={}, XMLOutputFile=None):
    """
    The function to write/update the MeasureCycleUserDefaults.xml of a Post-Processor. This function implements the process of reading 
    data overall control. Thereby reducing the risk of the return value is null.
    @param XMLMappingFile (string): the path of the xml mapping file
    @param strPPName (string): post-processor name
    @param strMeasureType (string): measure cycle type, if not read all
    @param strVersion (string): the vdm version name, for example 2.28 of accutexx0  
    @param inputDict: the dict that contain new values 
    
    inputDict = {'EDG': {'PAR_3': {'widgets': '1', 'value': '1'}, 'PAR_4': {'widgets': '1', 'value': '1'}, ... }}
    """
    parser = ET.XMLParser(target=CommentedTreeBuilder())
    tree = ET.parse(XMLMappingFile, parser)
    root = tree.getroot()
    bUpdated = False
    if strVersion != "":
        verNode = root.find("%s[@version='%s']" % (strPPName, strVersion))
    else:
        verNode = root.find("%s[1]" % strPPName)
    if verNode:
        if strMeasureType != "":
            typeNode = verNode.find("%s[1]" % strMeasureType)
            if typeNode:
                if strMeasureType in inputDict:
                    inputParams = inputDict[strMeasureType]
                    for paraNode in typeNode:
                        strTag = paraNode.tag
                        if strTag in inputParams:
                            tmpDict = paraNode.attrib
                            tmpDict.update(inputParams[strTag])
                            bUpdated = True
                            paraNode.attrib = tmpDict
                        else: # tag name not exist in the input dict
                            pass
                else: # sMeasure Type is not match with inputDict
                    pass 
            else: # not found the matched type node
                pass
        else: # strMeasureType is not defined
            for typeNode in verNode:
                strType = typeNode.tag
                if strType in inputDict:
                    inputParams = inputDict[strType]
                    for paraNode in typeNode:
                        strTag = paraNode.tag
                        if strTag in inputParams:
                            tmpDict = paraNode.attrib
                            tmpDict.update(inputParams[strTag])
                            bUpdated = True
                            paraNode.attrib = tmpDict
                        else: # tag name not exist in the input dict
                            pass
                else: # sMeasure Type is not match with inputDict
                    pass
    else: # not found the matched version node
        pass
    
    # Check bUpdated 
    if bUpdated:
        # save the change
        if XMLOutputFile:
            tree.write(XMLOutputFile, encoding='utf-8', xml_declaration=True)
        else:
            tree.write(XMLMappingFile, encoding='utf-8', xml_declaration=True)
        return True
    else:
        return False
    

class CommentedTreeBuilder(ET.TreeBuilder):
    def comment(self, data):
        self.start(ET.Comment, {})
        self.data(data)
        self.end(ET.Comment)


def Methoddispatch(func):
    dispatcher = singledispatch(func)
    def wrapper(*args, **kw):
        return dispatcher.dispatch(args[1].__class__)(*args, **kw)
    wrapper.register = dispatcher.register
    update_wrapper(wrapper, func)
    return wrapper


def UpdateDictRecursively(d, u):
    for k, v in six.iteritems(u):
        dv = d.get(k, {})
        if not isinstance(dv, collectionsAbc.Mapping):
            d[k] = v
        elif isinstance(v, collectionsAbc.Mapping):
            d[k] = UpdateDictRecursively(dv, v)
        else:
            d[k] = v
    return d


def GetMeasurecycleEnum(measuretype):
    measureenum = f"eMEASURETYPE_{measuretype}"
    if hasattr(opticam, measureenum):
        return getattr(opticam, measureenum)
    
def CreateTranslationsDictForMeasureCylceButtons(dlg):
    #implemented way to get translated text for measurecycle type to show in opticam mainsystem tree(S.Mr 30.1.26)
    TranslatedItemsDict = {dlg.GetMachineName() : {dlg.currentLanguage: {}}}
    TranslatedButtonsDict = {}
    for child in dlg.GetChildren()[0].GetChildren():
        if "NiceButton" in child.__str__():
            if hasattr(child, "strMeasureCycleType"):
                MeasureEnum = GetMeasurecycleEnum(child.strMeasureCycleType)
                if MeasureEnum:
                    TranslatedButtonsDict[MeasureEnum.name] = child.GetToolTipString()
                    TranslatedButtonsDict[f"{MeasureEnum.name}_"] = MeasureEnum.numerator
    
    TranslatedItemsDict[dlg.GetMachineName()][dlg.currentLanguage] = TranslatedButtonsDict
    opticam.getCurrentDoc().ReadDict('TranslatedItems', TranslatedItemsDict)
    
    

class MeasureCycleNCPresenter(object):
    """
    holds all required measure type data
    """

    def __init__(self, measureObject=None, device=None):
        self.measureObject = measureObject
        self.device = device
        self.outString = ""
        pass

    def SetmeasureObject(self, measureObject):
        self.measureObject = measureObject

    def SetOutDevice(self, device):
        self.device = device

    def GetString(self, enum):
        return self.outString

