[VOEditors] Fixed a problem with extra spaces when loading settings from cavowed.inf

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
USING System.Collections.Generic
USING System.Collections
USING System.Windows.Forms
USING System.Drawing
USING System.IO
USING XSharpModel

INTERNAL ENUM CavoWedInfSection
	MEMBER None
	MEMBER Control
	MEMBER StdProp
	MEMBER AssignMap
	MEMBER Supplemental
	MEMBER options
END ENUM

STATIC CLASS VOWindowEditorTemplate
	STATIC PRIVATE aControls AS ArrayList
	STATIC PRIVATE aEnumTypes AS Dictionary<STRING,STRING>
	STATIC PRIVATE aAssignMap AS Dictionary<STRING,STRING>
	STATIC PRIVATE lLoaded AS LOGIC
	STATIC EXPORT aPages AS HashTable
	//STATIC EXPORT GridX , GridY AS INT
	STATIC CONSTRUCTOR()

		VOWindowEditorTemplate.aControls := ArrayList{}
		VOWindowEditorTemplate.aEnumTypes := Dictionary<STRING , STRING>{}
		VOWindowEditorTemplate.aAssignMap := Dictionary<STRING , STRING>{}
		VOWindowEditorTemplate.aPages := HashTable{}

		VOWindowEditorTemplate.aEnumTypes:Add("YESNO" , "Yes,No")
		VOWindowEditorTemplate.aEnumTypes:Add("__genBOOL" , "True,False")
		VOWindowEditorTemplate.aEnumTypes:Add("__menuTOOLBARSTYLE" , "No Toolbar,Flat Toolbar,Raised Toolbar")
		VOWindowEditorTemplate.aEnumTypes:Add("__menuSHOW" , "Text,Icon,Text and Icon")
		VOWindowEditorTemplate.aEnumTypes:Add("__menuToolBarButtons" , VOMenuEditor.VOMenuToolBarString)

		VOWindowEditorTemplate.aEnumTypes:Add("__fieldspecDataTypes" , "Character,Numeric,Date,Logic,Memo,OLE,Multimedia")

//		VOWindowEditorTemplate.aEnumTypes:Add("DIALOGPOSITON" , "Auto,Center,Center Mouse")

		VOWindowEditorTemplate.aAssignMap:Add("FILLUSING" , "FillUsing")
		VOWindowEditorTemplate.aAssignMap:Add("FONT" , "Font")

	RETURN
	STATIC METHOD Load(cDirectory AS STRING) AS LOGIC
		LOCAL cCavoWed AS STRING
      LOCAL cOrigDir AS STRING
		LOCAL lSuccess AS LOGIC

		IF VOWindowEditorTemplate.lLoaded
			RETURN TRUE
		ENDIF

//		oReader := StreamReader{"C:\CAVOWED.INF"}
//		oReader := StreamReader{"CAVOWED.INF"}
//		oReader := StreamReader{"C:\CAVO28\BIN\CAVOWED.INF"}
//		cCavoWed := "C:\CAVO28\BIN\CAVOWED.INF"
//		cCavoWed := "C:\CAVO28\BIN\CAVOWED.INF"
      cOrigDir := cDirectory
        TRY
        	cCavoWed := cDirectory + "\Properties\CAVOWED.INF"
	        IF !System.IO.File.Exists(cCavoWed)
		        cCavoWed := cDirectory + "\CAVOWED.INF"
				IF !System.IO.File.Exists(cCavoWed)
					cDirectory := Directory.GetParent(cDirectory):FullName
					cCavoWed := cDirectory + "\CAVOWED.INF"
			        IF !System.IO.File.Exists(cCavoWed)
			        	cCavoWed := cDirectory + "\Properties\CAVOWED.INF"
				        IF !System.IO.File.Exists(cCavoWed) .and. Funcs.InstallTemplatesFolder != ""
				        	cCavoWed := Funcs.InstallTemplatesFolder  + "\CAVOWED.INF"
				        ENDIF
			        ENDIF
				ENDIF
			END IF
         CATCH
            NOP
        END TRY
		IF !System.IO.File.Exists(cCavoWed)
			MessageBox.Show("File Cavowed.inf was not found, please locate it on disk." , Resources.EditorName)
		ENDIF
		DO WHILE !System.IO.File.Exists(cCavoWed)
			LOCAL oDlg AS OpenFileDialog
			oDlg := OpenFileDialog{}
			oDlg:Filter := "CavoWED files (*.inf)|*.inf"
			oDlg:Title := "Open cavowed.inf file"
			IF oDlg:ShowDialog() == DialogResult.OK
				cCavoWed := oDlg:FileName:ToLower()
            TRY
               IF cCavoWed:Contains("cavowed") .and. cCavoWed:EndsWith(".inf")
                  File.Copy(cCavoWed , cOrigDir + "\cavowed.inf" , FALSE)
               ENDIF
            CATCH
               NOP
            END TRY
			ELSE
				RETURN FALSE
			ENDIF
		END DO

		IF VOWindowEditorTemplate.LoadInfFile(cCavoWed)
			VOWindowEditorTemplate.lLoaded := TRUE
			lSuccess := TRUE
		ENDIF

	RETURN lSuccess
	INTERNAL STATIC METHOD LoadInfFile(cCavoWed AS STRING) AS LOGIC
		LOCAL oControl AS VOControlTemplate
		LOCAL oProp AS VODesignProperty
		LOCAL oReader AS StreamReader
		LOCAL cLine , cUpper AS STRING
		LOCAL cLeft , cRight AS STRING
		LOCAL cProp , cCaption AS STRING
		LOCAL cParent AS STRING
		LOCAL cPage AS STRING
		LOCAL cType AS STRING
		LOCAL cInitMethod AS STRING
		LOCAL cEnumValues AS STRING
		LOCAL eSection AS CavoWedInfSection
		LOCAL aPages AS List<STRING>
		LOCAL lSuccess AS LOGIC
		LOCAL nAt AS INT

		eSection := CavoWedInfSection.None

		TRY

			oReader := StreamReader{cCavoWed}
			DO WHILE !oReader:Peek() == -1
				cLine := oReader:ReadLine():Trim()
				cUpper := cLine:ToUpper()
				IF cLine:Length == 0
					LOOP
				ENDIF
				cType := ""
                cInitMethod := ""
				IF cUpper[cUpper:Length - 1] == ')' .OR. cUpper:StartsWith("INITMETHOD")
					nAt := cUpper:LastIndexOf('(')
					IF nAt != -1
						cType := cLine:Substring(nAt + 1 , cLine:Length - nAt - 2):ToUpper()
						nAt := cLine:IndexOf('(')
						IF nAt == -1
							nAt := cLine:IndexOf("=")
							IF nAt == -1
								nAt := 0
							ELSE
								nAt ++
							END IF
						END IF
						cInitMethod := cLine:Substring(nAt)
						cUpper := cUpper:Substring(0 , nAt)
						cLine := cLine:Substring(0 , nAt)
					ENDIF
				ENDIF
				DO CASE
				CASE cLine[0] == ';' .or. cLine[0] == '/'
					LOOP
				CASE cLine[0] == '['
					cUpper := cUpper:Substring(1 , cUpper:Length - 2)
					DO CASE
					CASE cUpper:IndexOf("CONTROL") == 0 .or. cUpper:IndexOf("FORM") == 0
						eSection := CavoWedInfSection.Control
						oControl := VOControlTemplate{}
						oControl:lForm := cUpper:IndexOf("FORM") == 0
						oControl:cFullClass := cUpper
						IF VOWindowEditorTemplate.GetFromFullClass(oControl:cFullClass) == NULL
							VOWindowEditorTemplate.aControls:Add(oControl)
						END IF
						cParent := ""
						nAt := cUpper:LastIndexOf(':')
						IF nAt == -1
							oControl:aProperties:Add(VODesignProperty{"_Left","Left",NULL,PropertyType.Numeric})
							oControl:aProperties:Add(VODesignProperty{"_Top","Top",NULL,PropertyType.Numeric})
							oControl:aProperties:Add(VODesignProperty{"_Width","Width",NULL,PropertyType.Numeric})
							oControl:aProperties:Add(VODesignProperty{"_Height","Height",NULL,PropertyType.Numeric})
							oControl:aProperties:Add(VODesignProperty{"_Visible","Visible",NULL,"YESNO"})
							oControl:aProperties:Add(VODesignProperty{"_GenCode","Generate Code",NULL,"YESNO"})
//							oControl:aProperties:Add(VODesignProperty{"Inherit From Class","Inherit From Class",PropertyType.Text})

							oControl:aProperties:Add(VODesignProperty{"_DBInhFrom","Browser Inherit From",NULL,PropertyType.Text})
							oControl:aProperties:Add(VODesignProperty{"_DCInhFrom","Columns Inherit From",NULL,PropertyType.Text})

							oControl:aProperties:Add(VODesignProperty{"_IsDataPage","Page Data Aware",NULL,"YESNO"})
							oControl:aProperties:Add(VODesignProperty{"_PageCaption","Page Caption",NULL,PropertyType.Text})
							oControl:aProperties:Add(VODesignProperty{"_PageName","Page Name",NULL,PropertyType.Text})
						ELSE
							cParent := cUpper:Substring(0 , nAt)
							cUpper := cUpper:Substring(nAt + 1)
/*							nAt := cParent:LastIndexOf(':')
							IF nAt != -1
								cParent := cParent:Substring(nAt + 1)
							ENDIF*/
							oControl:AddFrom(cParent)
						ENDIF
						oControl:cParent := cParent
						oControl:cControl := cUpper
					CASE cUpper == "STDPROPERTIES"
						eSection := CavoWedInfSection.StdProp
					CASE cUpper == "ASSIGNMAP"
						eSection := CavoWedInfSection.AssignMap
					CASE cUpper == "SUPPLEMENTALFILES"
						eSection := CavoWedInfSection.Supplemental
					CASE cUpper == "OPTIONS"
						eSection := CavoWedInfSection.Options
					OTHERWISE
						eSection := CavoWedInfSection.None
					ENDCASE
				CASE eSection == CavoWedInfSection.StdProp
					nAt := cLine:IndexOf('=')
					IF nAt != -1
						cLeft := cLine:Substring(0 , nAt):ToUpper()
						IF cLine:LastIndexOf(')') == -1
							cRight := cLine:Substring(nAt + 1):Trim()
							VOWindowEditorTemplate.aEnumTypes:Add(cLeft , cRight)
						ELSE
							nAt := cLine:LastIndexOf(')')
							cRight := cLine:Substring(nAt + 1):Trim()
							aPages := Funcs.SplitString(cRight , ',')
/*							aPages := List<STRING>{}
							DO WHILE cRight:Length != 0
								nAt := cRight:IndexOf(',')
								IF nAt == -1
									aPages:Add(cRight)
									cRight := ""
								ELSE
									aPages:Add(cRight:Substring(0 , nAt))
									cRight := cRight:Substring(nAt + 1)
								ENDIF
							END DO*/
							VOWindowEditorTemplate.aPages:Add(cLeft , aPages)
						ENDIF
					ENDIF
				CASE eSection == CavoWedInfSection.Control
					nAt := cLine:IndexOf('=')
					IF nAt != -1
						cLeft := cLine:Substring(0 , nAt):ToUpper()
						cRight := cLine:Substring(nAt + 1):Trim()
						DO CASE
						CASE cLeft == "NAME"
							oControl:cName := cRight
							oControl:lUse := TRUE
						CASE cLeft == "TEXT"
							oControl:cStartText := cRight
						CASE cLeft == "CONTTITLE"
							oControl:cTitle := cRight
						CASE cLeft == "CLASSNAME"
							IF oControl:cWinClass == "" // might have been already assigned by OptClassName
								oControl:cWinClass := cRight
							END IF
						CASE cLeft == "OPTCLASSNAME"
							oControl:cWinClass := cRight
						CASE cLeft == "TYPE"
							IF cRight:ToUpper() == "COMMANDCONTROL"
								oControl:lForceCommandControl := TRUE
							ENDIF
						CASE cLeft == "DIALOGTEMPLATE"
							oControl:lCreateResource := cRight == "1"
						CASE cLeft == "INITMETHOD"
/*							nAt := cRight:IndexOf('(')
							IF nAt != -1
								cRight := cRight:Substring(nAt + 1)
								nAt := cRight:LastIndexOf(')')
								IF nAt != -1
									cRight := cRight:Substring(0, nAt - 1)
									oControl:cInitMethod := cRight
								ENDIF
							ENDIF*/
							oControl:cInitMethod := cInitMethod
						CASE cLeft == "STYLE"
							oControl:aStyles := Funcs.SplitString(cRight , '|')
						CASE cLeft == "EXSTYLE"
							oControl:aExStyles := Funcs.SplitString(cRight , '|')
						CASE cLeft == "SIZE"
							TRY
								nAt := cRight:IndexOf(',')
								oControl:oSize := Size{ Convert.ToInt32(cRight:Substring(0 , nAt)) , Convert.ToInt32(cRight:Substring(nAt + 1)) }
                     CATCH
                        NOP
							END TRY
						CASE cLeft == "PROPTABS"
							aPages := oControl:aPages
							DO WHILE cRight:Length != 0
								nAt := cRight:IndexOf(',')
								IF nAt == -1
									cPage := cRight
									cRight := ""
								ELSE
									cPage := cRight:Substring(0 , nAt)
									cRight := cRight:Substring(nAt + 1)
								ENDIF
/*								nAt := cPage:IndexOf(':')
								IF nAt != -1
									cPage := cPage:Substring(nAt + 1)
								ENDIF*/
								aPages:Add(cPage)
							END DO
						CASE cLeft:IndexOf("WINDOWSTYLE") == 0 .or. cLeft:IndexOf("EXWINDOWSTYLE") == 0
							nAt := cRight:IndexOf(',')
							IF nAt != - 1
								cCaption := cRight:Substring(0 , nAt)
								cEnumValues := cRight:Substring(nAt + 1)
								IF cLeft:IndexOf("WINDOWSTYLE") == 0
									oControl:cRawStyles := cEnumValues
									oProp := VODesignProperty{cCaption , cType , cEnumValues , VOStyle.Style}
									oControl:aProperties:Add(oProp)
								ELSE
									oProp := VODesignProperty{cCaption , cType , cEnumValues , VOStyle.ExStyle}
									oControl:aProperties:Add(oProp)
								ENDIF
							ENDIF

						CASE cLeft:IndexOf("ASSIGN") == 0 .or. cLeft:IndexOf("INHERITCLASSNAME") == 0
							nAt := cRight:IndexOf(',')
							IF nAt != - 1
								cCaption := cRight:Substring(0 , nAt)
								cProp := cRight:Substring(nAt + 1)
								DO CASE
								CASE cProp:ToUpper():IndexOf("HYPERLABEL") != -1 .and. FALSE
									oProp := VODesignProperty{cCaption , cCaption , cCaption , PropertyType.Text}
									oProp:lMultiple := TRUE
									oProp:lNoCode := TRUE
									oProp:lNoAuto := TRUE
									oControl:aProperties:Add(oProp)
								CASE cType == "STRING"
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
									oControl:aProperties:Add(oProp)
								CASE cType == "NUMERIC"
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Numeric}
									oControl:aProperties:Add(oProp)
								CASE cType:IndexOf("CLASS:") == 0
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Type}
									nAt := cType:IndexOf("CLASS:")
									oProp:cType := cType:Substring(nAt + 6)
									oControl:aProperties:Add(oProp)
								CASE cType:IndexOf(',') == -1 .AND. cType:Length != 0
									IF cType[0] != '%'
										oProp := VODesignProperty{cCaption , cCaption , cProp , cType}
									ELSE
										cType := cType:Substring(1 , cType:Length - 2)
										oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
										oProp:cSymbolProp := cType
									ENDIF
									oControl:aProperties:Add(oProp)
								CASE cType:IndexOf(',') != -1
									LOCAL nMultiPos AS INT
									nAt := 0
									nMultiPos := 1
									DO WHILE nAt < cType:Length
										IF cType[nAt] == ','
											nMultiPos ++
											nAt ++
										ELSE
											cType := cType:Substring(nAt)
											nAt := cType:IndexOf(',')
											IF nAt != -1
												cType := cType:Substring(0 , nAt)
											ENDIF
											nAt := cType:IndexOf(')')
											IF nAt != -1
												cType := cType:Substring(0 , nAt)
											ENDIF
//											System.Windows.Forms.MessageBox.Show(cType)
											cType := cType:ToUpper()
											DO CASE
											CASE cType:ToUpper() == "NUMERIC"
												oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Numeric}
											CASE cType[0] == '%'
												cType := cType:Substring(1 , cType:Length - 2)
												oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
												oProp:cSymbolProp := cType
											OTHERWISE
												oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
											END CASE
											oProp:lMultiple := TRUE
											oProp:nMultiPos := nMultiPos
											EXIT
										ENDIF
									END DO
									oControl:aProperties:Add(oProp)
								END CASE
							ENDIF

						CASE cLeft:IndexOf("METHOD") == 0
							nAt := cRight:IndexOf(',')
							IF nAt != - 1
								cCaption := cRight:Substring(0 , nAt)
								cProp := cRight:Substring(nAt + 1)
								DO CASE
								CASE cType:IndexOf("CODE:") == 0
									IF cType:Length > 5
										cProp := cType:Substring(5):Trim()
									END IF
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Callback}
									oControl:aProperties:Add(oProp)
								CASE cType == "STRING"
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
									oProp:lMethod := TRUE
									oControl:aProperties:Add(oProp)
								CASE cCaption == "Group Value" .and. cProp == "Value" // DIRTY HACK
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
									oProp:lMethod := TRUE
									oControl:aProperties:Add(oProp)
								CASE cType:IndexOf("CLASS:") == 0
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Type}
									oProp:lMethod := TRUE
									oControl:aProperties:Add(oProp)
//								CASE cType == "BOOL"
//								CASE cType == "LOGIC"
								OTHERWISE
									oProp := VODesignProperty{cCaption , cCaption , cProp , cType}
									oProp:lMethod := TRUE
									oControl:aProperties:Add(oProp)
								END CASE
							ENDIF

						END CASE
					ENDIF

				CASE eSection == CavoWedInfSection.AssignMap
					nAt := cLine:IndexOf('=')
					IF nAt != -1
						cLeft := cLine:Substring(0 , nAt):ToUpper()
						cRight := cLine:Substring(nAt + 1):Trim()
						IF !VOWindowEditorTemplate.aAssignMap:ContainsKey(cLeft)
							VOWindowEditorTemplate.aAssignMap:Add(cLeft , cRight)
						ENDIF
					ENDIF

				CASE eSection == CavoWedInfSection.Supplemental
					nAt := cLine:IndexOf('=')
					IF nAt != -1
						cLeft := cLine:Substring(0 , nAt):ToUpper()
						cRight := cLine:Substring(nAt + 1):Trim()
						IF cRight:Length != 0
							nAt := cRight:LastIndexOf("\")
							IF nAt != -1 .and. nAt < cRight:Length - 1
								cRight := cRight:Substring(nAt + 1):Trim()
							END IF
							cRight := Funcs.GetFileDir(cCavoWed) + "\" + cRight
							IF System.IO.File.Exists(cRight)
								VOWindowEditorTemplate.LoadInfFile(cRight)
							ELSE
								Funcs.ErrorBox("Could not find file " + cRight , Resources.EditorName)
							ENDIF
						ENDIF
					ENDIF

/*				CASE eSection == CavoWedInfSection.Options
					nAt := cLine:IndexOf('=')
					IF nAt != -1
						cLeft := cLine:Substring(0 , nAt):ToUpper()
						cRight := cLine:Substring(nAt + 1):Trim()
						TRY
							DO CASE
							CASE cLeft == "GRIDX"
								VOWindowEditorTemplate.GridX := Int32.Parse(cRight)
							CASE cLeft == "GRIDY"
								VOWindowEditorTemplate.GridY := Int32.Parse(cRight)
							END CASE
						CATCH
                            NOP
						END TRY
					ENDIF*/

				END CASE

			END DO

			lSuccess := TRUE

		CATCH

			Funcs.ErrorBox("Error loading file " + cCavoWed , Resources.EditorName)

		FINALLY

			IF oReader != NULL
				oReader:Close()
			END IF

		END TRY

	RETURN lSuccess

	STATIC ACCESS Loaded AS LOGIC
	RETURN VOWindowEditorTemplate.lLoaded
	STATIC ACCESS Count AS INT
	RETURN VOWindowEditorTemplate.aControls:Count
	STATIC METHOD Get(n AS INT) AS VOControlTemplate
	RETURN (VOControlTemplate)VOWindowEditorTemplate.aControls[n]
	STATIC METHOD Get(cControl AS STRING) AS VOControlTemplate
		cControl := cControl:ToUpper()
		FOREACH oTemplate AS VOControlTemplate IN VOWindowEditorTemplate.aControls
			IF oTemplate:cControl:ToUpper() == cControl
				RETURN oTemplate
			ENDIF
		NEXT
	RETURN NULL

	STATIC METHOD GetFromFullClass(cFullClass AS STRING) AS VOControlTemplate
		cFullClass := cFullClass:ToUpper()
		FOREACH oTemplate AS VOControlTemplate IN VOWindowEditorTemplate.aControls
			IF oTemplate:cFullClass:ToUpper() == cFullClass
				RETURN oTemplate
			ENDIF
		NEXT
	RETURN NULL

	STATIC METHOD GetParent(cParent AS STRING) AS VOControlTemplate
		cParent := cParent:ToUpper()
		FOREACH oTemplate AS VOControlTemplate IN VOWindowEditorTemplate.aControls
			IF oTemplate:cFullClass:ToUpper() == cParent
				RETURN oTemplate
			ENDIF
		NEXT
	RETURN NULL
	STATIC METHOD GetEnumerator(cKey AS STRING) AS STRING
		IF VOWindowEditorTemplate.aEnumTypes:ContainsKey(cKey)
			RETURN VOWindowEditorTemplate.aEnumTypes[cKey]
		ENDIF
		DO WHILE cKey:Length > 3 // TODO looks like the VO WED works this way, for all types
			cKey := cKey:Substring(0, cKey:Length - 1)
			IF VOWindowEditorTemplate.aEnumTypes:ContainsKey(cKey)
				RETURN VOWindowEditorTemplate.aEnumTypes[cKey]
			ENDIF
		END DO
	RETURN NULL
	STATIC METHOD GetAssignMap(cKey AS STRING) AS STRING
		cKey := cKey:ToUpper()
		IF VOWindowEditorTemplate.aAssignMap:ContainsKey(cKey)
			RETURN VOWindowEditorTemplate.aAssignMap[cKey]
		ENDIF
	RETURN NULL

END CLASS

CLASS VOControlTemplate
	EXPORT cControl AS STRING
	EXPORT cParent AS STRING
	EXPORT cName AS STRING
	EXPORT cFullClass AS STRING
	EXPORT cStartText AS STRING
	EXPORT oSize AS Size
	EXPORT lForm AS LOGIC
	EXPORT lUse AS LOGIC
	EXPORT cTitle AS STRING
	EXPORT cWinClass AS STRING
	EXPORT aPages AS List<STRING>
	EXPORT aProperties AS ArrayList
	EXPORT aStyles AS List<STRING>
	EXPORT aExStyles AS List<STRING>
	EXPORT cInitMethod AS STRING
	EXPORT lCreateResource AS LOGIC
	EXPORT lForceCommandControl AS LOGIC
	EXPORT cRawStyles AS STRING
	CONSTRUCTOR()
		SUPER()
		SELF:cStartText := ""
		SELF:cName := ""
		SELF:cParent := ""
		SELF:cFullClass := ""
		SELF:cControl := ""
		SELF:cTitle := ""
		SELF:cWinClass := ""
		SELF:cInitMethod := ""
		SELF:cRawStyles := ""
		SELF:aProperties := ArrayList{}
		SELF:aPages := List<STRING>{}
      SELF:aExStyles := List<STRING>{}
      SELF:aStyles := List<STRING>{}
	RETURN
	METHOD AddFrom(cControl AS STRING) AS VOID
		LOCAL oTemplate AS VOControlTemplate
		LOCAL n AS INT
//		oTemplate := VOWindowEditorTemplate.Get(cControl)
		oTemplate := VOWindowEditorTemplate.GetParent(cControl)
		IF oTemplate != NULL
			FOR n := 0 UPTO oTemplate:aProperties:Count - 1
				SELF:aProperties:Add(oTemplate:aProperties[n])
				SELF:lCreateResource := oTemplate:lCreateResource
			NEXT
			IF oTemplate:aExStyles != NULL
				SELF:aExStyles := List<STRING>{}
				FOR n := 0 UPTO oTemplate:aExStyles:Count - 1
					SELF:aExStyles:Add(oTemplate:aExStyles[n])
				NEXT
			END IF
		ENDIF
	RETURN
	ACCESS ToolboxTitle AS STRING
		IF .NOT. String.IsNullOrWhiteSpace(SELF:cTitle)
			RETURN SELF:cTitle
		END IF
	RETURN SELF:cName

END CLASS

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
USING System.Collections.Generic
USING System.Collections
USING System.Windows.Forms
USING System.Drawing
USING System.IO
USING XSharpModel

INTERNAL ENUM CavoWedInfSection
	MEMBER None
	MEMBER Control
	MEMBER StdProp
	MEMBER AssignMap
	MEMBER Supplemental
	MEMBER options
END ENUM

STATIC CLASS VOWindowEditorTemplate
	STATIC PRIVATE aControls AS ArrayList
	STATIC PRIVATE aEnumTypes AS Dictionary<STRING,STRING>
	STATIC PRIVATE aAssignMap AS Dictionary<STRING,STRING>
	STATIC PRIVATE lLoaded AS LOGIC
	STATIC EXPORT aPages AS HashTable
	//STATIC EXPORT GridX , GridY AS INT
	STATIC CONSTRUCTOR()

		VOWindowEditorTemplate.aControls := ArrayList{}
		VOWindowEditorTemplate.aEnumTypes := Dictionary<STRING , STRING>{}
		VOWindowEditorTemplate.aAssignMap := Dictionary<STRING , STRING>{}
		VOWindowEditorTemplate.aPages := HashTable{}

		VOWindowEditorTemplate.aEnumTypes:Add("YESNO" , "Yes,No")
		VOWindowEditorTemplate.aEnumTypes:Add("__genBOOL" , "True,False")
		VOWindowEditorTemplate.aEnumTypes:Add("__menuTOOLBARSTYLE" , "No Toolbar,Flat Toolbar,Raised Toolbar")
		VOWindowEditorTemplate.aEnumTypes:Add("__menuSHOW" , "Text,Icon,Text and Icon")
		VOWindowEditorTemplate.aEnumTypes:Add("__menuToolBarButtons" , VOMenuEditor.VOMenuToolBarString)

		VOWindowEditorTemplate.aEnumTypes:Add("__fieldspecDataTypes" , "Character,Numeric,Date,Logic,Memo,OLE,Multimedia")

//		VOWindowEditorTemplate.aEnumTypes:Add("DIALOGPOSITON" , "Auto,Center,Center Mouse")

		VOWindowEditorTemplate.aAssignMap:Add("FILLUSING" , "FillUsing")
		VOWindowEditorTemplate.aAssignMap:Add("FONT" , "Font")

	RETURN
	STATIC METHOD Load(cDirectory AS STRING) AS LOGIC
		LOCAL cCavoWed AS STRING
      LOCAL cOrigDir AS STRING
		LOCAL lSuccess AS LOGIC

		IF VOWindowEditorTemplate.lLoaded
			RETURN TRUE
		ENDIF

//		oReader := StreamReader{"C:\CAVOWED.INF"}
//		oReader := StreamReader{"CAVOWED.INF"}
//		oReader := StreamReader{"C:\CAVO28\BIN\CAVOWED.INF"}
//		cCavoWed := "C:\CAVO28\BIN\CAVOWED.INF"
//		cCavoWed := "C:\CAVO28\BIN\CAVOWED.INF"
      cOrigDir := cDirectory
        TRY
        	cCavoWed := cDirectory + "\Properties\CAVOWED.INF"
	        IF !System.IO.File.Exists(cCavoWed)
		        cCavoWed := cDirectory + "\CAVOWED.INF"
				IF !System.IO.File.Exists(cCavoWed)
					cDirectory := Directory.GetParent(cDirectory):FullName
					cCavoWed := cDirectory + "\CAVOWED.INF"
			        IF !System.IO.File.Exists(cCavoWed)
			        	cCavoWed := cDirectory + "\Properties\CAVOWED.INF"
				        IF !System.IO.File.Exists(cCavoWed) .and. Funcs.InstallTemplatesFolder != ""
				        	cCavoWed := Funcs.InstallTemplatesFolder  + "\CAVOWED.INF"
				        ENDIF
			        ENDIF
				ENDIF
			END IF
         CATCH
            NOP
        END TRY
		IF !System.IO.File.Exists(cCavoWed)
			MessageBox.Show("File Cavowed.inf was not found, please locate it on disk." , Resources.EditorName)
		ENDIF
		DO WHILE !System.IO.File.Exists(cCavoWed)
			LOCAL oDlg AS OpenFileDialog
			oDlg := OpenFileDialog{}
			oDlg:Filter := "CavoWED files (*.inf)|*.inf"
			oDlg:Title := "Open cavowed.inf file"
			IF oDlg:ShowDialog() == DialogResult.OK
				cCavoWed := oDlg:FileName:ToLower()
            TRY
               IF cCavoWed:Contains("cavowed") .and. cCavoWed:EndsWith(".inf")
                  File.Copy(cCavoWed , cOrigDir + "\cavowed.inf" , FALSE)
               ENDIF
            CATCH
               NOP
            END TRY
			ELSE
				RETURN FALSE
			ENDIF
		END DO

		IF VOWindowEditorTemplate.LoadInfFile(cCavoWed)
			VOWindowEditorTemplate.lLoaded := TRUE
			lSuccess := TRUE
		ENDIF

	RETURN lSuccess
	INTERNAL STATIC METHOD LoadInfFile(cCavoWed AS STRING) AS LOGIC
		LOCAL oControl AS VOControlTemplate
		LOCAL oProp AS VODesignProperty
		LOCAL oReader AS StreamReader
		LOCAL cLine , cUpper AS STRING
		LOCAL cLeft , cRight AS STRING
		LOCAL cProp , cCaption AS STRING
		LOCAL cParent AS STRING
		LOCAL cPage AS STRING
		LOCAL cType AS STRING
		LOCAL cInitMethod AS STRING
		LOCAL cEnumValues AS STRING
		LOCAL eSection AS CavoWedInfSection
		LOCAL aPages AS List<STRING>
		LOCAL lSuccess AS LOGIC
		LOCAL nAt AS INT

		eSection := CavoWedInfSection.None

		TRY

			oReader := StreamReader{cCavoWed}
			DO WHILE !oReader:Peek() == -1
				cLine := oReader:ReadLine():Trim()
				cUpper := cLine:ToUpper()
				IF cLine:Length == 0
					LOOP
				ENDIF
				cType := ""
                cInitMethod := ""
				IF cUpper[cUpper:Length - 1] == ')' .OR. cUpper:StartsWith("INITMETHOD")
					nAt := cUpper:LastIndexOf('(')
					IF nAt != -1
						cType := cLine:Substring(nAt + 1 , cLine:Length - nAt - 2):ToUpper()
						nAt := cLine:IndexOf('(')
						IF nAt == -1
							nAt := cLine:IndexOf("=")
							IF nAt == -1
								nAt := 0
							ELSE
								nAt ++
							END IF
						END IF
						cInitMethod := cLine:Substring(nAt)
						cUpper := cUpper:Substring(0 , nAt)
						cLine := cLine:Substring(0 , nAt)
					ENDIF
				ENDIF
				DO CASE
				CASE cLine[0] == ';' .or. cLine[0] == '/'
					LOOP
				CASE cLine[0] == '['
					cUpper := cUpper:Substring(1 , cUpper:Length - 2)
					DO CASE
					CASE cUpper:IndexOf("CONTROL") == 0 .or. cUpper:IndexOf("FORM") == 0
						eSection := CavoWedInfSection.Control
						oControl := VOControlTemplate{}
						oControl:lForm := cUpper:IndexOf("FORM") == 0
						oControl:cFullClass := cUpper
						IF VOWindowEditorTemplate.GetFromFullClass(oControl:cFullClass) == NULL
							VOWindowEditorTemplate.aControls:Add(oControl)
						END IF
						cParent := ""
						nAt := cUpper:LastIndexOf(':')
						IF nAt == -1
							oControl:aProperties:Add(VODesignProperty{"_Left","Left",NULL,PropertyType.Numeric})
							oControl:aProperties:Add(VODesignProperty{"_Top","Top",NULL,PropertyType.Numeric})
							oControl:aProperties:Add(VODesignProperty{"_Width","Width",NULL,PropertyType.Numeric})
							oControl:aProperties:Add(VODesignProperty{"_Height","Height",NULL,PropertyType.Numeric})
							oControl:aProperties:Add(VODesignProperty{"_Visible","Visible",NULL,"YESNO"})
							oControl:aProperties:Add(VODesignProperty{"_GenCode","Generate Code",NULL,"YESNO"})
//							oControl:aProperties:Add(VODesignProperty{"Inherit From Class","Inherit From Class",PropertyType.Text})

							oControl:aProperties:Add(VODesignProperty{"_DBInhFrom","Browser Inherit From",NULL,PropertyType.Text})
							oControl:aProperties:Add(VODesignProperty{"_DCInhFrom","Columns Inherit From",NULL,PropertyType.Text})

							oControl:aProperties:Add(VODesignProperty{"_IsDataPage","Page Data Aware",NULL,"YESNO"})
							oControl:aProperties:Add(VODesignProperty{"_PageCaption","Page Caption",NULL,PropertyType.Text})
							oControl:aProperties:Add(VODesignProperty{"_PageName","Page Name",NULL,PropertyType.Text})
						ELSE
							cParent := cUpper:Substring(0 , nAt)
							cUpper := cUpper:Substring(nAt + 1)
/*							nAt := cParent:LastIndexOf(':')
							IF nAt != -1
								cParent := cParent:Substring(nAt + 1)
							ENDIF*/
							oControl:AddFrom(cParent)
						ENDIF
						oControl:cParent := cParent
						oControl:cControl := cUpper
					CASE cUpper == "STDPROPERTIES"
						eSection := CavoWedInfSection.StdProp
					CASE cUpper == "ASSIGNMAP"
						eSection := CavoWedInfSection.AssignMap
					CASE cUpper == "SUPPLEMENTALFILES"
						eSection := CavoWedInfSection.Supplemental
					CASE cUpper == "OPTIONS"
						eSection := CavoWedInfSection.Options
					OTHERWISE
						eSection := CavoWedInfSection.None
					ENDCASE
				CASE eSection == CavoWedInfSection.StdProp
					nAt := cLine:IndexOf('=')
					IF nAt != -1
						cLeft := cLine:Substring(0 , nAt):ToUpper()
						cRight := cLine:Substring(nAt + 1)
						IF cLine:LastIndexOf(')') == -1
							VOWindowEditorTemplate.aEnumTypes:Add(cLeft , cRight)
						ELSE
							nAt := cLine:LastIndexOf(')')
							cRight := cLine:Substring(nAt + 1)
							aPages := Funcs.SplitString(cRight , ',')
/*							aPages := List<STRING>{}
							DO WHILE cRight:Length != 0
								nAt := cRight:IndexOf(',')
								IF nAt == -1
									aPages:Add(cRight)
									cRight := ""
								ELSE
									aPages:Add(cRight:Substring(0 , nAt))
									cRight := cRight:Substring(nAt + 1)
								ENDIF
							END DO*/
							VOWindowEditorTemplate.aPages:Add(cLeft , aPages)
						ENDIF
					ENDIF
				CASE eSection == CavoWedInfSection.Control
					nAt := cLine:IndexOf('=')
					IF nAt != -1
						cLeft := cLine:Substring(0 , nAt):ToUpper()
						cRight := cLine:Substring(nAt + 1)
						DO CASE
						CASE cLeft == "NAME"
							oControl:cName := cRight
							oControl:lUse := TRUE
						CASE cLeft == "TEXT"
							oControl:cStartText := cRight
						CASE cLeft == "CONTTITLE"
							oControl:cTitle := cRight
						CASE cLeft == "CLASSNAME"
							IF oControl:cWinClass == "" // might have been already assigned by OptClassName
								oControl:cWinClass := cRight
							END IF
						CASE cLeft == "OPTCLASSNAME"
							oControl:cWinClass := cRight
						CASE cLeft == "TYPE"
							IF cRight:ToUpper() == "COMMANDCONTROL"
								oControl:lForceCommandControl := TRUE
							ENDIF
						CASE cLeft == "DIALOGTEMPLATE"
							oControl:lCreateResource := cRight == "1"
						CASE cLeft == "INITMETHOD"
/*							nAt := cRight:IndexOf('(')
							IF nAt != -1
								cRight := cRight:Substring(nAt + 1)
								nAt := cRight:LastIndexOf(')')
								IF nAt != -1
									cRight := cRight:Substring(0, nAt - 1)
									oControl:cInitMethod := cRight
								ENDIF
							ENDIF*/
							oControl:cInitMethod := cInitMethod
						CASE cLeft == "STYLE"
							oControl:aStyles := Funcs.SplitString(cRight , '|')
						CASE cLeft == "EXSTYLE"
							oControl:aExStyles := Funcs.SplitString(cRight , '|')
						CASE cLeft == "SIZE"
							TRY
								nAt := cRight:IndexOf(',')
								oControl:oSize := Size{ Convert.ToInt32(cRight:Substring(0 , nAt)) , Convert.ToInt32(cRight:Substring(nAt + 1)) }
                     CATCH
                        NOP
							END TRY
						CASE cLeft == "PROPTABS"
							aPages := oControl:aPages
							DO WHILE cRight:Length != 0
								nAt := cRight:IndexOf(',')
								IF nAt == -1
									cPage := cRight
									cRight := ""
								ELSE
									cPage := cRight:Substring(0 , nAt)
									cRight := cRight:Substring(nAt + 1)
								ENDIF
/*								nAt := cPage:IndexOf(':')
								IF nAt != -1
									cPage := cPage:Substring(nAt + 1)
								ENDIF*/
								aPages:Add(cPage)
							END DO
						CASE cLeft:IndexOf("WINDOWSTYLE") == 0 .or. cLeft:IndexOf("EXWINDOWSTYLE") == 0
							nAt := cRight:IndexOf(',')
							IF nAt != - 1
								cCaption := cRight:Substring(0 , nAt)
								cEnumValues := cRight:Substring(nAt + 1)
								IF cLeft:IndexOf("WINDOWSTYLE") == 0
									oControl:cRawStyles := cEnumValues
									oProp := VODesignProperty{cCaption , cType , cEnumValues , VOStyle.Style}
									oControl:aProperties:Add(oProp)
								ELSE
									oProp := VODesignProperty{cCaption , cType , cEnumValues , VOStyle.ExStyle}
									oControl:aProperties:Add(oProp)
								ENDIF
							ENDIF

						CASE cLeft:IndexOf("ASSIGN") == 0 .or. cLeft:IndexOf("INHERITCLASSNAME") == 0
							nAt := cRight:IndexOf(',')
							IF nAt != - 1
								cCaption := cRight:Substring(0 , nAt)
								cProp := cRight:Substring(nAt + 1)
								DO CASE
								CASE cProp:ToUpper():IndexOf("HYPERLABEL") != -1 .and. FALSE
									oProp := VODesignProperty{cCaption , cCaption , cCaption , PropertyType.Text}
									oProp:lMultiple := TRUE
									oProp:lNoCode := TRUE
									oProp:lNoAuto := TRUE
									oControl:aProperties:Add(oProp)
								CASE cType == "STRING"
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
									oControl:aProperties:Add(oProp)
								CASE cType == "NUMERIC"
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Numeric}
									oControl:aProperties:Add(oProp)
								CASE cType:IndexOf("CLASS:") == 0
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Type}
									nAt := cType:IndexOf("CLASS:")
									oProp:cType := cType:Substring(nAt + 6)
									oControl:aProperties:Add(oProp)
								CASE cType:IndexOf(',') == -1 .AND. cType:Length != 0
									IF cType[0] != '%'
										oProp := VODesignProperty{cCaption , cCaption , cProp , cType}
									ELSE
										cType := cType:Substring(1 , cType:Length - 2)
										oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
										oProp:cSymbolProp := cType
									ENDIF
									oControl:aProperties:Add(oProp)
								CASE cType:IndexOf(',') != -1
									LOCAL nMultiPos AS INT
									nAt := 0
									nMultiPos := 1
									DO WHILE nAt < cType:Length
										IF cType[nAt] == ','
											nMultiPos ++
											nAt ++
										ELSE
											cType := cType:Substring(nAt)
											nAt := cType:IndexOf(',')
											IF nAt != -1
												cType := cType:Substring(0 , nAt)
											ENDIF
											nAt := cType:IndexOf(')')
											IF nAt != -1
												cType := cType:Substring(0 , nAt)
											ENDIF
//											System.Windows.Forms.MessageBox.Show(cType)
											cType := cType:ToUpper()
											DO CASE
											CASE cType:ToUpper() == "NUMERIC"
												oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Numeric}
											CASE cType[0] == '%'
												cType := cType:Substring(1 , cType:Length - 2)
												oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
												oProp:cSymbolProp := cType
											OTHERWISE
												oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
											END CASE
											oProp:lMultiple := TRUE
											oProp:nMultiPos := nMultiPos
											EXIT
										ENDIF
									END DO
									oControl:aProperties:Add(oProp)
								END CASE
							ENDIF

						CASE cLeft:IndexOf("METHOD") == 0
							nAt := cRight:IndexOf(',')
							IF nAt != - 1
								cCaption := cRight:Substring(0 , nAt)
								cProp := cRight:Substring(nAt + 1)
								DO CASE
								CASE cType:IndexOf("CODE:") == 0
									IF cType:Length > 5
										cProp := cType:Substring(5):Trim()
									END IF
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Callback}
									oControl:aProperties:Add(oProp)
								CASE cType == "STRING"
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
									oProp:lMethod := TRUE
									oControl:aProperties:Add(oProp)
								CASE cCaption == "Group Value" .and. cProp == "Value" // DIRTY HACK
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Text}
									oProp:lMethod := TRUE
									oControl:aProperties:Add(oProp)
								CASE cType:IndexOf("CLASS:") == 0
									oProp := VODesignProperty{cCaption , cCaption , cProp , PropertyType.Type}
									oProp:lMethod := TRUE
									oControl:aProperties:Add(oProp)
//								CASE cType == "BOOL"
//								CASE cType == "LOGIC"
								OTHERWISE
									oProp := VODesignProperty{cCaption , cCaption , cProp , cType}
									oProp:lMethod := TRUE
									oControl:aProperties:Add(oProp)
								END CASE
							ENDIF

						END CASE
					ENDIF

				CASE eSection == CavoWedInfSection.AssignMap
					nAt := cLine:IndexOf('=')
					IF nAt != -1
						cLeft := cLine:Substring(0 , nAt):ToUpper()
						cRight := cLine:Substring(nAt + 1)
						IF !VOWindowEditorTemplate.aAssignMap:ContainsKey(cLeft)
							VOWindowEditorTemplate.aAssignMap:Add(cLeft , cRight)
						ENDIF
					ENDIF

				CASE eSection == CavoWedInfSection.Supplemental
					nAt := cLine:IndexOf('=')
					IF nAt != -1
						cLeft := cLine:Substring(0 , nAt):ToUpper()
						cRight := cLine:Substring(nAt + 1):Trim()
						IF cRight:Length != 0
							nAt := cRight:LastIndexOf("\")
							IF nAt != -1 .and. nAt < cRight:Length - 1
								cRight := cRight:Substring(nAt + 1):Trim()
							END IF
							cRight := Funcs.GetFileDir(cCavoWed) + "\" + cRight
							IF System.IO.File.Exists(cRight)
								VOWindowEditorTemplate.LoadInfFile(cRight)
							ELSE
								Funcs.ErrorBox("Could not find file " + cRight , Resources.EditorName)
							ENDIF
						ENDIF
					ENDIF

/*				CASE eSection == CavoWedInfSection.Options
					nAt := cLine:IndexOf('=')
					IF nAt != -1
						cLeft := cLine:Substring(0 , nAt):ToUpper()
						cRight := cLine:Substring(nAt + 1):Trim()
						TRY
							DO CASE
							CASE cLeft == "GRIDX"
								VOWindowEditorTemplate.GridX := Int32.Parse(cRight)
							CASE cLeft == "GRIDY"
								VOWindowEditorTemplate.GridY := Int32.Parse(cRight)
							END CASE
						CATCH
                            NOP
						END TRY
					ENDIF*/

				END CASE

			END DO

			lSuccess := TRUE

		CATCH

			Funcs.ErrorBox("Error loading file " + cCavoWed , Resources.EditorName)

		FINALLY

			IF oReader != NULL
				oReader:Close()
			END IF

		END TRY

	RETURN lSuccess

	STATIC ACCESS Loaded AS LOGIC
	RETURN VOWindowEditorTemplate.lLoaded
	STATIC ACCESS Count AS INT
	RETURN VOWindowEditorTemplate.aControls:Count
	STATIC METHOD Get(n AS INT) AS VOControlTemplate
	RETURN (VOControlTemplate)VOWindowEditorTemplate.aControls[n]
	STATIC METHOD Get(cControl AS STRING) AS VOControlTemplate
		cControl := cControl:ToUpper()
		FOREACH oTemplate AS VOControlTemplate IN VOWindowEditorTemplate.aControls
			IF oTemplate:cControl:ToUpper() == cControl
				RETURN oTemplate
			ENDIF
		NEXT
	RETURN NULL

	STATIC METHOD GetFromFullClass(cFullClass AS STRING) AS VOControlTemplate
		cFullClass := cFullClass:ToUpper()
		FOREACH oTemplate AS VOControlTemplate IN VOWindowEditorTemplate.aControls
			IF oTemplate:cFullClass:ToUpper() == cFullClass
				RETURN oTemplate
			ENDIF
		NEXT
	RETURN NULL

	STATIC METHOD GetParent(cParent AS STRING) AS VOControlTemplate
		cParent := cParent:ToUpper()
		FOREACH oTemplate AS VOControlTemplate IN VOWindowEditorTemplate.aControls
			IF oTemplate:cFullClass:ToUpper() == cParent
				RETURN oTemplate
			ENDIF
		NEXT
	RETURN NULL
	STATIC METHOD GetEnumerator(cKey AS STRING) AS STRING
		IF VOWindowEditorTemplate.aEnumTypes:ContainsKey(cKey)
			RETURN VOWindowEditorTemplate.aEnumTypes[cKey]
		ENDIF
		DO WHILE cKey:Length > 3 // TODO looks like the VO WED works this way, for all types
			cKey := cKey:Substring(0, cKey:Length - 1)
			IF VOWindowEditorTemplate.aEnumTypes:ContainsKey(cKey)
				RETURN VOWindowEditorTemplate.aEnumTypes[cKey]
			ENDIF
		END DO
	RETURN NULL
	STATIC METHOD GetAssignMap(cKey AS STRING) AS STRING
		cKey := cKey:ToUpper()
		IF VOWindowEditorTemplate.aAssignMap:ContainsKey(cKey)
			RETURN VOWindowEditorTemplate.aAssignMap[cKey]
		ENDIF
	RETURN NULL

END CLASS

CLASS VOControlTemplate
	EXPORT cControl AS STRING
	EXPORT cParent AS STRING
	EXPORT cName AS STRING
	EXPORT cFullClass AS STRING
	EXPORT cStartText AS STRING
	EXPORT oSize AS Size
	EXPORT lForm AS LOGIC
	EXPORT lUse AS LOGIC
	EXPORT cTitle AS STRING
	EXPORT cWinClass AS STRING
	EXPORT aPages AS List<STRING>
	EXPORT aProperties AS ArrayList
	EXPORT aStyles AS List<STRING>
	EXPORT aExStyles AS List<STRING>
	EXPORT cInitMethod AS STRING
	EXPORT lCreateResource AS LOGIC
	EXPORT lForceCommandControl AS LOGIC
	EXPORT cRawStyles AS STRING
	CONSTRUCTOR()
		SUPER()
		SELF:cStartText := ""
		SELF:cName := ""
		SELF:cParent := ""
		SELF:cFullClass := ""
		SELF:cControl := ""
		SELF:cTitle := ""
		SELF:cWinClass := ""
		SELF:cInitMethod := ""
		SELF:cRawStyles := ""
		SELF:aProperties := ArrayList{}
		SELF:aPages := List<STRING>{}
      SELF:aExStyles := List<STRING>{}
      SELF:aStyles := List<STRING>{}
	RETURN
	METHOD AddFrom(cControl AS STRING) AS VOID
		LOCAL oTemplate AS VOControlTemplate
		LOCAL n AS INT
//		oTemplate := VOWindowEditorTemplate.Get(cControl)
		oTemplate := VOWindowEditorTemplate.GetParent(cControl)
		IF oTemplate != NULL
			FOR n := 0 UPTO oTemplate:aProperties:Count - 1
				SELF:aProperties:Add(oTemplate:aProperties[n])
				SELF:lCreateResource := oTemplate:lCreateResource
			NEXT
			IF oTemplate:aExStyles != NULL
				SELF:aExStyles := List<STRING>{}
				FOR n := 0 UPTO oTemplate:aExStyles:Count - 1
					SELF:aExStyles:Add(oTemplate:aExStyles[n])
				NEXT
			END IF
		ENDIF
	RETURN
	ACCESS ToolboxTitle AS STRING
		IF .NOT. String.IsNullOrWhiteSpace(SELF:cTitle)
			RETURN SELF:cTitle
		END IF
	RETURN SELF:cName

END CLASS


[XPP] Changed modifier

[XPP] Changed modifier

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING System.Collections.Generic
USING System.Diagnostics
USING System.Linq

/// <summary>
/// The Xbase++ DataObject class.
/// </summary>
[DebuggerTypeProxy(TYPEOF(DataObjectDebugView))];
CLASS XSharp.XPP.DataObject INHERIT XSharp.XPP.Abstract IMPLEMENTS IDynamicProperties
    PRIVATE _fields  AS Dictionary<STRING, USUAL>
    PRIVATE _methods AS Dictionary<STRING, USUAL>

    CONSTRUCTOR()
        SUPER()
        _fields  := Dictionary<STRING, USUAL>{StringComparer.OrdinalIgnoreCase}
        _methods := Dictionary<STRING, USUAL>{StringComparer.OrdinalIgnoreCase}

    /// <summary>
    /// Checks if the object has a particular member variable
    /// </summary>
    /// <param name="cName">is a character string containing the symbolic identifier of a member variable.</param>
    /// <returns>The return value is .T. (true) if the object has the member variable <cVarName>, otherwise it returns .F. (false). </returns>
    PUBLIC METHOD IsMemberVar(cName AS STRING) AS LOGIC
        IF SELF:_fields:ContainsKey(cName)
            RETURN TRUE
        ENDIF
        RETURN FALSE
    /// <include file="XPPComments.xml" path="Comments/ClassDescribe/*" />
    OVERRIDE METHOD ClassDescribe(uInfo) AS ARRAY CLIPPER
        local aResult as ARRAY
        local nInfo as LONG
        IF ! IsNumeric(uInfo)
            nInfo := CLASS_DESCR_ALL
        ELSE
            nInfo := uInfo
        ENDIF
        aResult := Super:ClassDescribe(CLASS_DESCR_ALL)
        IF nInfo == CLASS_DESCR_ALL .or. nInfo == CLASS_DESCR_MEMBERS
            FOREACH var fld in _fields
                AAdd(aResult[3], {fld:Key, VAR_INSTANCE+CLASS_EXPORTED, typeof(USUAL)})
            NEXT
        ENDIF
        IF nInfo == CLASS_DESCR_ALL .or. nInfo == CLASS_DESCR_METHODS
            FOREACH var met in _methods
                AAdd(aResult[4], {met:Key, METHOD_INSTANCE+CLASS_EXPORTED, met:Value, NIL, typeof(USUAL)})
            NEXT
        ENDIF
        SWITCH nInfo
        CASE CLASS_DESCR_ALL
            RETURN aResult
        CASE CLASS_DESCR_CLASSNAME
            RETURN aResult[1]
        CASE CLASS_DESCR_SUPERCLASSES
            RETURN aResult[2]
        CASE CLASS_DESCR_MEMBERS
            RETURN aResult[3]
        CASE CLASS_DESCR_METHODS
            RETURN aResult[4]
        CASE CLASS_DESCR_SUPERDETAILS
            RETURN {}
        END SWITCH
        RETURN {}

    /// <include file="XPPComments.xml" path="Comments/NoIvarPut/*" />
    OVERRIDE METHOD NoIvarPut(cName AS STRING, uValue AS USUAL) AS VOID
        SELF:_fields[cName] := uValue
        RETURN

    /// <include file="XPPComments.xml" path="Comments/NoIvarGet/*" />
    OVERRIDE METHOD NoIvarGet(cName AS STRING) AS USUAL
        IF SELF:_fields:ContainsKey(cName)
            RETURN SELF:_fields[cName]
        ENDIF
        RETURN NIL

    VIRTUAL METHOD GetPropertyNames() AS STRING[]
        return _fields:Keys:ToArray()

    /// <summary>Creates a dependent shallow copy of this instance </summary>
    /// <returns>This method returns the new DataObject instance. </returns>
    VIRTUAL METHOD Copy() AS DataObject
        LOCAL oNew AS DataObject
        oNew := DataObject{}
        FOREACH VAR element IN _fields
            oNew:_fields:Add(element:Key, element:Value)
        NEXT
        RETURN oNew

    /// <summary>Merges exported member variables from another object into this instance.</summary>
    /// <param name="oNewObject">DataObject to copy the member variables from.</param>
    /// <param name="cMessagePrefix">Optional prefix that will be added to all fields in the DataObject.</param>
    /// <returns>This method returns the DataObject (self).</returns>

    VIRTUAL METHOD Merge(oNewObject, cMessagePrefix) AS DataObject CLIPPER
        LOCAL oObject := oNewObject AS OBJECT
        EnforceType(REF cMessagePrefix, STRING)
        IF oObject IS DataObject var oDataObject
            FOREACH VAR element IN oDataObject:_fields
                IF !SELF:_fields:ContainsKey(cMessagePrefix+element:Key)
                    SELF:_fields:Add(cMessagePrefix+element:Key, element:Value)
                ENDIF
            NEXT
        ENDIF
        RETURN SELF

    /// <summary>Defines a dynamic method. </summary>
    /// <param name="cName">The name of the method to be defined.</param>
    /// <param name="uAction">A Function name or codeblock that must be executed when the method is called.</param>
    /// <returns>This method returns the DataObject (self).</returns>
    /// <remarks>Dynamic methods in X# are called from the NoMethod method inside the DataObject class.</remarks>
    VIRTUAL METHOD DefineMethod(cName AS STRING, uAction AS USUAL) AS OBJECT
        SELF:_methods[cName] := uAction
        RETURN SELF

    /// <include file="XPPComments.xml" path="Comments/NoMethod/*" />
    OVERRIDE METHOD NoMethod(uParams) AS USUAL CLIPPER
        LOCAL aParams AS USUAL[]
        LOCAL cMethod AS STRING
        cMethod := RuntimeState.NoMethod
        IF SELF:_methods:ContainsKey(cMethod)
            aParams := USUAL[]{ PCOunt() +1}
            // The pseudo function _ARGS() returns the Clipper arguments array
            System.Array.Copy(_ARGS(), 0, aParams, 1, PCount())
            aParams[1] := SELF
            LOCAL action AS USUAL
            action := SELF:_methods[cMethod]
            IF IsString(action)
                RETURN _CallClipFunc(action, aParams)
            ELSEIF IsCodeBlock(action)
                LOCAL oBlock := action AS CODEBLOCK
                RETURN oBlock:Eval(aParams)
            ENDIF
        ENDIF
        RETURN NIL

    INTERNAL CLASS DataObjectDebugView
        PRIVATE _value AS XSharp.XPP.DataObject
        PRIVATE PROPERTY _count as INT GET _value:_fields:Count
        INTERNAL CONSTRUCTOR (d AS XSharp.XPP.DataObject)
            _value := d

        [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] ;
        [DebuggerDisplay("Count = {_count}", Type:="Dynamic Properties")];
        PUBLIC PROPERTY Properties AS IList<Prop>
        GET
            VAR result := List<Prop>{}
            FOREACH var item in _value:_fields
                result:Add( Prop{} {Name := item:Key, @@Value := item:Value})
            NEXT
            RETURN result
        END GET
        END PROPERTY

        [DebuggerDisplay("{Name,nq} = {Value}", Type:="Dynamic Property")];
        INTERNAL CLASS Prop
            INTERNAL PROPERTY Name     AS STRING AUTO
            INTERNAL PROPERTY @@Value  AS USUAL AUTO
        END CLASS

    END CLASS

END CLASS

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING System.Collections.Generic
USING System.Diagnostics
USING System.Linq

/// <summary>
/// The Xbase++ DataObject class.
/// </summary>
[DebuggerTypeProxy(TYPEOF(DataObjectDebugView))];
CLASS XSharp.XPP.DataObject INHERIT XSharp.XPP.Abstract IMPLEMENTS IDynamicProperties
    PRIVATE _fields  AS Dictionary<STRING, USUAL>
    PRIVATE _methods AS Dictionary<STRING, USUAL>

    CONSTRUCTOR()
        SUPER()
        _fields  := Dictionary<STRING, USUAL>{StringComparer.OrdinalIgnoreCase}
        _methods := Dictionary<STRING, USUAL>{StringComparer.OrdinalIgnoreCase}

    /// <summary>
    /// Checks if the object has a particular member variable
    /// </summary>
    /// <param name="cName">is a character string containing the symbolic identifier of a member variable.</param>
    /// <returns>The return value is .T. (true) if the object has the member variable <cVarName>, otherwise it returns .F. (false). </returns>
    PUBLIC METHOD IsMemberVar(cName AS STRING) AS LOGIC
        IF SELF:_fields:ContainsKey(cName)
            RETURN TRUE
        ENDIF
        RETURN FALSE
    /// <include file="XPPComments.xml" path="Comments/ClassDescribe/*" />
    OVERRIDE METHOD ClassDescribe(uInfo) AS ARRAY CLIPPER
        local aResult as ARRAY
        local nInfo as LONG
        IF ! IsNumeric(uInfo)
            nInfo := CLASS_DESCR_ALL
        ELSE
            nInfo := uInfo
        ENDIF
        aResult := Super:ClassDescribe(CLASS_DESCR_ALL)
        IF nInfo == CLASS_DESCR_ALL .or. nInfo == CLASS_DESCR_MEMBERS
            FOREACH var fld in _fields
                AAdd(aResult[3], {fld:Key, VAR_INSTANCE+CLASS_EXPORTED, typeof(USUAL)})
            NEXT
        ENDIF
        IF nInfo == CLASS_DESCR_ALL .or. nInfo == CLASS_DESCR_METHODS
            FOREACH var met in _methods
                AAdd(aResult[4], {met:Key, METHOD_INSTANCE+CLASS_EXPORTED, met:Value, NIL, typeof(USUAL)})
            NEXT
        ENDIF
        SWITCH nInfo
        CASE CLASS_DESCR_ALL
            RETURN aResult
        CASE CLASS_DESCR_CLASSNAME
            RETURN aResult[1]
        CASE CLASS_DESCR_SUPERCLASSES
            RETURN aResult[2]
        CASE CLASS_DESCR_MEMBERS
            RETURN aResult[3]
        CASE CLASS_DESCR_METHODS
            RETURN aResult[4]
        CASE CLASS_DESCR_SUPERDETAILS
            RETURN {}
        END SWITCH
        RETURN {}

    /// <include file="XPPComments.xml" path="Comments/NoIvarPut/*" />
    OVERRIDE METHOD NoIvarPut(cName AS STRING, uValue AS USUAL) AS VOID
        SELF:_fields[cName] := uValue
        RETURN

    /// <include file="XPPComments.xml" path="Comments/NoIvarGet/*" />
    OVERRIDE METHOD NoIvarGet(cName AS STRING) AS USUAL
        IF SELF:_fields:ContainsKey(cName)
            RETURN SELF:_fields[cName]
        ENDIF
        RETURN NIL

    VIRTUAL METHOD GetPropertyNames() AS STRING[]
        return _fields:Keys:ToArray()

    /// <summary>Creates a dependent shallow copy of this instance </summary>
    /// <returns>This method returns the new DataObject instance. </returns>
    VIRTUAL METHOD Copy() AS DataObject
        LOCAL oNew AS DataObject
        oNew := DataObject{}
        FOREACH VAR element IN _fields
            oNew:_fields:Add(element:Key, element:Value)
        NEXT
        RETURN oNew

    /// <summary>Merges exported member variables from another object into this instance.</summary>
    /// <param name="oNewObject">DataObject to copy the member variables from.</param>
    /// <param name="cMessagePrefix">Optional prefix that will be added to all fields in the DataObject.</param>
    /// <returns>This method returns the DataObject (self).</returns>

    VIRTUAL METHOD Merge(oNewObject, cMessagePrefix) AS DataObject CLIPPER
        LOCAL oObject := oNewObject AS OBJECT
        EnforceType(REF cMessagePrefix, STRING)
        IF oObject IS DataObject var oDataObject
            FOREACH VAR element IN oDataObject:_fields
                IF !SELF:_fields:ContainsKey(cMessagePrefix+element:Key)
                    SELF:_fields:Add(cMessagePrefix+element:Key, element:Value)
                ENDIF
            NEXT
        ENDIF
        RETURN SELF

    /// <summary>Defines a dynamic method. </summary>
    /// <param name="cName">The name of the method to be defined.</param>
    /// <param name="uAction">A Function name or codeblock that must be executed when the method is called.</param>
    /// <returns>This method returns the DataObject (self).</returns>
    /// <remarks>Dynamic methods in X# are called from the NoMethod method inside the DataObject class.</remarks>
    VIRTUAL METHOD DefineMethod(cName AS STRING, uAction AS USUAL) AS OBJECT
        SELF:_methods[cName] := uAction
        RETURN SELF

    /// <include file="XPPComments.xml" path="Comments/NoMethod/*" />
    VIRTUAL METHOD NoMethod(uParams) AS USUAL CLIPPER
        LOCAL aParams AS USUAL[]
        LOCAL cMethod AS STRING
        cMethod := RuntimeState.NoMethod
        IF SELF:_methods:ContainsKey(cMethod)
            aParams := USUAL[]{ PCOunt() +1}
            // The pseudo function _ARGS() returns the Clipper arguments array
            System.Array.Copy(_ARGS(), 0, aParams, 1, PCount())
            aParams[1] := SELF
            LOCAL action AS USUAL
            action := SELF:_methods[cMethod]
            IF IsString(action)
                RETURN _CallClipFunc(action, aParams)
            ELSEIF IsCodeBlock(action)
                LOCAL oBlock := action AS CODEBLOCK
                RETURN oBlock:Eval(aParams)
            ENDIF
        ENDIF
        RETURN NIL

    INTERNAL CLASS DataObjectDebugView
        PRIVATE _value AS XSharp.XPP.DataObject
        PRIVATE PROPERTY _count as INT GET _value:_fields:Count
        INTERNAL CONSTRUCTOR (d AS XSharp.XPP.DataObject)
            _value := d

        [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] ;
        [DebuggerDisplay("Count = {_count}", Type:="Dynamic Properties")];
        PUBLIC PROPERTY Properties AS IList<Prop>
        GET
            VAR result := List<Prop>{}
            FOREACH var item in _value:_fields
                result:Add( Prop{} {Name := item:Key, @@Value := item:Value})
            NEXT
            RETURN result
        END GET
        END PROPERTY

        [DebuggerDisplay("{Name,nq} = {Value}", Type:="Dynamic Property")];
        INTERNAL CLASS Prop
            INTERNAL PROPERTY Name     AS STRING AUTO
            INTERNAL PROPERTY @@Value  AS USUAL AUTO
        END CLASS

    END CLASS

END CLASS