2006년 7월호

 

PowerBuilder - The ClassDefinition Object

...or how to create a simple object browser - Part 2

 

저번 뉴스 내용에서 ClassDefinition 오브젝트에 관한 몇가지 이론들을 살펴보았고, 트리뷰 컨트롤 안에서 PB 어플리케이션의

라이브러리들을 볼수 있었습니다. 이번에는 살펴본 내용을 조사하고 라이브러리로 부터 오브젝트들을 살펴볼 것입니다.

사용자가 Treeview에서 어떤 항목을 확장할 , 그것이 이미 확장되었는지를 검사해야 하는데, 만일 확장되어 있다면,

별다른 작업을 하지 않아도 됩니다. Treeview 컨트롤의 Itemexpanding 이벤트에서 This.GetItem 호출함으로써 선택되어져 있는

TreeviewItem 선택할 있습니다.

 

 사전에 확장되어 있지 않았다면, Treeviewitem 레벨 2 같은지를 검사해야 하는데, 이것은 라이브러리 이름을 확장하는

것을 뜻합니다. 문장 분석을 위해 모든 로직을 포함하는 NVO 만들 수도 있으나, 여기서는 간단한 데모이므로 NVO 만들지 않습니다.

윈도우 필요한 함수들을 정의할 때는 컨트롤들에서 주어지는 argument들을 이용하면 사용자가 나중에 해당 로직을 NVO 옮기는

것을 쉽게 있습니다.

 

다음은 PBL에서 PB 오브젝트들을 읽을 때 사용되는 of_ShowLibraryItems 함수를 생성할 것입니다.

여기서는 LibraryDirectoryEx 함수를 사용해서 오브젝트들을 추출합니다. LibraryDirectoryEx 함수는 수정된 date/time 주석뿐만 아니라

오브젝트들의 이름과 타입도 제공해 줍니다. External DataSource를 이용해 DataWindow 사용합니다.

Figure 1 해당 DataWindow 컬럼정보입니다. 정렬(sorting) objtype column으로 정하고 d_libobj 이름으 저장합니다.

                                         

 

byLibrary-DirectoryEx에서 리턴된 스트링은 ImportString 의해 데이터스토어로 임포트될 것입니다. 데이터를 정렬한 후에, 스크립트는

오브젝트들을 통해 루프를 돌며  treeview 추가됩니다.  Listing 1  함수 코드입니다. 레벨이 2 일때, treeview 컨트롤의 itemexpanding

이벤트에서 of_ShowLibraryItems  함수를 호출합니다. 이때에 ll_TviCurrent는 핸들 argument 의해 정의된 treeviewItem입니다.

 

Listing 1: Adding the Library Items
/* Name: of_ShowLibraryItems
Parameters: 
treeview atv_disp
long al_Parent
string as_Library
Returns: (none)
*/
string ls_Entries, ls_Obj, ls_Type
long ll_Tot, ll_Row
datastore lds_Sort
treeviewitem ll_TviObj
 
// Get Entries
ls_Entries=LibraryDirectoryEx(as_Library,DirAll!)
ls_Entries=ls_Entries+"~n" // Add NewLine at the end
 
// Use datastore to sort the objects
lds_Sort=CREATE datastore
lds_Sort.DataObject="d_libobj"
lds_Sort.ImportString(ls_Entries)
lds_Sort.Sort()
 
// Loop through all entries
ll_Tot=lds_Sort.RowCount()
FOR ll_Row=1 TO ll_Tot
   ls_Obj=lds_Sort.GetItemString(ll_Row,"objname")
   ls_Type=lds_Sort.GetItemString(ll_Row,"objtype")
               
   CHOOSE CASE ls_Type 
      CASE "Application"
         ll_TviObj.PictureIndex=PICT_APPLICATION
      CASE "Function"
         ll_TviObj.PictureIndex=PICT_FUNCTION
      CASE "Window"
          ll_TviObj.PictureIndex=PICT_WINDOW
      CASE "Menu"
         ll_TviObj.PictureIndex=PICT_MENU
      CASE "Structure"
         ll_TviObj.PictureIndex=PICT_STRUCTURE
      CASE "UserObject"
         ll_TviObj.PictureIndex=PICT_USEROBJECT
      CASE ELSE
         ll_TviObj.PictureIndex=0
   END CHOOSE
   // use classes from above only
   IF ll_TviObj.PictureIndex>0 THEN
      ll_TviObj.Label=ls_Obj
      ll_TviObj.SelectedPictureIndex=ll_TviObj.PictureIndex
      ll_TviObj.Children=TRUE
      atv_Disp.InsertItemLast( al_Parent, ll_TviObj)
   END IF
NEXT
DESTROY lds_Sort
RETURN
 

Parent.of_ShowLibraryItems( This, handle, ltvi_Current.Data )

 

On to Class Details


이제까지 어플리케이션은 라이브러리와 안에 있는 PB 오브젝트들을 보여주었습니다. 이제는 classdefinitionobject 오브젝트와 그들의

자손들을 차례입니다. 저번 달에 보았던것 같이, 우리는 다양한 자손 엔트리들의 정보를 보여줄 입니다. 처음 부분은 Variables 불리며

여기서 우리는 오브젝트의 모든 변수들을 리스트합니다. 두번째 부분에는 스크립트가 있고 세번째 부분에는 nested 클래스들이 있습니다.

마지막으로, 네번째 부분은 조상 클래스의 레퍼런스가 있습니다. 생성한 함수는 순환함수라고 불려질 있고 PB 오브젝트의 타입으로

쓰여질 있습니다.

PB 오브젝트의 ClassDefinition 오브젝트 변수 리스트를 통해 정보를 보여주는 것은 불가능하기 떄문에 다음 단계는 2개의 도움이 되는

함수를 만들 것입니다. 첫번째 함수는 of_ValueString 라고 불리고 열거된(enumerated) 값을 스트링으로 바꾸어줍니다. (Listing 2 보십시오).

 

Listing 2: Translating Enumerated Values
/* Name: of_ValueString
Parameters: 
string  as_Type
any aa_Data
Returns: string
*/
string      ls_Ret
ls_Ret = as_Type + Char(9)
CHOOSE CASE as_Type
CASE "CallingConvention"
      ArgCallingConvention lcca_Temp
         lcca_Temp=aa_Data
CHOOSE CASE lcca_Temp
            CASE ByReferenceArgument!
                ls_Ret=ls_Ret+": ByReferenceArgument!"
            CASE ByValueArgument!
                ls_Ret=ls_Ret+": ByValueArgument!"
            CASE ReadOnlyArgument!
                ls_Ret=ls_Ret+": ReadOnlyArgument!"
            CASE VarListArgument!
                ls_Ret=ls_Ret+": VarListArgument!"
END CHOOSE
CASE "Cardinality"
         VariableCardinalityDefinition lvcd_Temp
         lvcd_Temp = aa_Data
         CHOOSE CASE lvcd_Temp.Cardinality
                 CASE ScalarType!
                       ls_Ret = ls_Ret + ": ScalarType!"
                 CASE UnboundedArray!
                        ls_Ret = ls_Ret + ": UnboundedArray!"
                 CASE BoundedArray!
                       ls_Ret = ls_Ret + ": BoundedArray!"
              END CHOOSE
CASE "VariableKind"
              VariableKind lvk_Temp
              lvk_Temp = aa_Data
              CHOOSE CASE lvk_Temp
                             CASE VariableGlobal!
                                           ls_Ret=ls_Ret+": VariableGlobal!"
                             CASE VariableShared!
                                           ls_Ret= ls_Ret+": VariableShared!"
                               CASE VariableInstance!
                                           ls_Ret=ls_Ret+": VariableInstance!"
                             CASE VariableArgument!
                                           ls_Ret=ls_Ret+": VariableArguement"
                             CASE VariableLocal!
                                           ls_Ret=ls_Ret+": VariableLocal!"
               END CHOOSE
CASE "ScriptKind"
              /* Is 0/1 instead of the following
              ScriptKind lsk_Temp
              lsk_Temp = aa_Data
              CHOOSE CASE lsk_Temp
                             CASE ScriptEvent!
                                           ls_Ret=ls_Ret+": ScriptEvent!"
                             CASE ScriptFunction!
                                           ls_Ret= ls_Ret+": ScriptFunction!"
               END CHOOSE
               */
               ls_Ret=ls_Ret +": " + String( aa_Data )
CASE  "ReadAccess", "WriteAccess","Access"
              VarAccess lva_Temp
              lva_Temp=aa_Data
              CHOOSE CASE lva_Temp
                             CASE Private!
                                           ls_Ret=ls_Ret+": Private!"
                             CASE Public!
                                           ls_Ret=ls_Ret+": Public!"
                             CASE Protected!
                                          ls_Ret=ls_Ret+": Protected!"
                             CASE System!
                                           ls_Ret=ls_Ret+": System!"
                             CASE ELSE
                                           ls_Ret=ls_Ret+":"
               END CHOOSE
CASE "Category"
              TypeCategory ltc_Temp
              ltc_Temp=aa_Data
              CHOOSE CASE ltc_Temp
                             CASE SimpleType!
                                           ls_Ret=ls_Ret+": SimpleType!"
                             CASE EnumeratedType!
                                           ls_Ret=ls_Ret+ ": EnumeratedType!"
                             CASE ClassOrStructureType!
                                           ls_Ret=ls_Ret+": ClassOrStructureType!"
  END CHOOSE
CASE "InitialValue"
              IF NOT IsNull( String( aa_Data ) ) THEN
                           ls_Ret=ls_Ret+": "+ String( aa_Data )
              END IF
CASE "DataTypeOf"
              TypeDefinition ltd_Temp
              EnumerationDefinition led_Temp
              EnumerationItemDefinition lei_Temp[]
              integer li_Counter
              ls_Ret=ls_Ret+": "+String(aa_Data)
               ltd_Temp=FindTypeDefinition(aa_Data)
              IF ltd_Temp.Category=EnumeratedType! THEN
                            led_Temp=ltd_Temp
                            lei_Temp=led_Temp.Enumeration
                             FOR li_Counter=1 TO UpperBound(lei_Temp)
                                         ls_Ret=ls_Ret+"~r~n~t"+"- "+ &
                                         lei_Temp[li_Counter].Name+": " + &
                                         String( lei_Temp[ li_Counter ].Value)
                               NEXT
              END IF
CASE ELSE
              IF NOT IsNull( String( aa_Data ) ) THEN
                            ls_Ret=ls_Ret+": "+ String(aa_Data)
              END IF
END CHOOSE
RETURN ls_Ret
 

함수의 argument들은 변수 타입(. Cardinality 혹은 InitialValue)이고 자체의 값입니다. 이것은 2 모두를 읽을 있는 스트링으로

리턴합니다. 값을 스트링으로 변환하는 것은 간단하게 불린(Boolean) 값입니다; 그러나 나열된(enumerated) 데이터 타입들은 각각 다루어야합니다.

만약 변수가 나열된(enumerated) 데이터 타입이면, FindTypeDefinition 사용해서 모든 가능한 데이터타입의 열거(enumeration)들을 얻어냅니다.

두번째 함수는 of_FormatInfo 입니다. (Listing 3 보십시오.) 이것의 argument classdefinitionobject 사용합니다.

 

Listing 3: Format Information
/* Name: of_FormatInfo
Parameters: 
classdefinitionobject acdo_Temp
returns: string
*/
string      ls_Ret
ClassDefinition lcd_Temp
VariableDefinition lvd_Temp
ScriptDefinition       lsd_Temp
CHOOSE CASE acdo_Temp.TypeOf()
CASE ClassDefinition!
        lcd_Temp = acdo_Temp
        ls_Ret = This.of_ValueString( "Category", lcd_Temp.Category) + "~r~n" + &
This.of_ValueString( "IsAutoinstantiate", lcd_Temp.IsAutoinstantiate) + "~r~n" + &
This.of_ValueString( "IsStructure", lcd_Temp.IsStructure) + "~r~n" + &
This.of_ValueString( "IsSystemType", lcd_Temp.IsSystemType) + "~r~n" + &
This.of_ValueString( "IsVariableLength", lcd_Temp.IsVariableLength) + "~r~n" + &
This.of_ValueString( "IsVisualType", lcd_Temp.IsVisualType) + "~r~n" + &
This.of_ValueString( "LibraryName", lcd_Temp.LibraryName)
 
CASE VariableDefinition!
lvd_Temp = acdo_Temp
ls_Ret = This.of_ValueString( "CallingConvention", lvd_Temp.CallingConvention ) + "~r~n" + &
        This.of_ValueString( "Cardinality", lvd_Temp.Cardinality ) + "~r~n"
IF Lower( lvd_Temp.name ) <> "imemode" AND lvd_Temp.TypeInfo.DataTypeOf <> "string" THEN
// Crash otherwise e.g. string s = 'crash'
         ls_Ret = ls_Ret + This.of_ValueString( "InitialValue", lvd_Temp.InitialValue) + "~r~n"
END IF
        ls_Ret = ls_Ret + This.of_ValueString( "IsConstant", lvd_Temp.IsConstant) + "~r~n" + &
        This.of_ValueString( "IsControl", lvd_Temp.IsControl) + "~r~n" + &
        This.of_ValueString( "IsUserDefined", lvd_Temp.IsUserDefined) + "~r~n" + &
        This.of_ValueString( "VariableKind", lvd_Temp.Kind) + "~r~n" + &
        This.of_ValueString( "OverridesAncestorValue", lvd_Temp.OverridesAncestorValue) + "~r~n" + &
        This.of_ValueString( "ReadAccess", lvd_Temp.ReadAccess) + "~r~n" + &
This.of_ValueString( "WriteAccess", lvd_Temp.WriteAccess) + "~r~n" + & "~r~nTypeInfo~r~n" + & 
   This.of_ValueString( "Category", lvd_Temp.TypeInfo.Category) + "~r~n" + & 
   This.of_ValueString( "DataTypeOf", lvd_Temp.TypeInfo.DataTypeOf) + "~r~n" + &
This.of_ValueString( "IsStructure", lvd_Temp.TypeInfo.IsStructure) + "~r~n" + &
 This.of_ValueString( "IsSystemType", lvd_Temp.TypeInfo.IsSystemType) + "~r~n" + &
 This.of_ValueString( "IsVariableLength", lvd_Temp.TypeInfo.IsVariableLength) + "~r~n" +&
 This.of_ValueString( "IsVisualType", lvd_Temp.TypeInfo.IsVisualType) + "~r~n" +&
 This.of_ValueString( "LibraryName", lvd_Temp.TypeInfo.LibraryName) + "~r~n" +&
 This.of_ValueString( "Name", lvd_Temp.TypeInfo.Name)
 
CASE ScriptDefinition!
lsd_Temp = acdo_Temp
          ls_Ret = This.of_ValueString( "Access", lsd_Temp.Access ) + "~r~n" + &
           This.of_ValueString( "AliasName", lsd_Temp.AliasName) + "~r~n" + &
           This.of_ValueString( "EventId", lsd_Temp.EventID ) + "~r~n" + &
           This.of_ValueString( "EventIdName", lsd_Temp.EventID ) + "~r~n" + &
           This.of_ValueString( "ExternalUserFunction", lsd_Temp.EventID ) + "~r~n" + &
           This.of_ValueString( "IsExternalEvent", lsd_Temp.IsExternalEvent ) + "~r~n" + &
           This.of_ValueString( "IsLocallyDefined", lsd_Temp.IsLocallyDefined ) + "~r~n" + &
           This.of_ValueString( "IsLocallyScripted", lsd_Temp.IsLocallyScripted ) + "~r~n" + &
           This.of_ValueString( "IsRPCFunction", lsd_Temp.IsRPCFunction ) + "~r~n" + &
           This.of_ValueString( "IsScripted", lsd_Temp.IsScripted ) + "~r~n" + &
           This.of_ValueString( "ScriptKind", lsd_Temp.Kind ) + "~r~n" + &
           This.of_ValueString( "SystemFunction", lsd_Temp.SystemFunction ) 
           IF IsValid( lsd_Temp.ReturnType ) THEN
               ls_Ret = ls_Ret + "~r~n" + & "~r~nReturnType~r~n" + & 
               This.of_ValueString( "Category", lsd_Temp.ReturnType.Category ) + "~r~n" + & 
               This.of_ValueString( "DataTypeOf", lsd_Temp.ReturnType.DataTypeOf) + "~r~n" + &
               This.of_ValueString( "IsStructure", lsd_Temp.ReturnType.IsStructure) + "~r~n" + &
               This.of_ValueString( "IsSystemType", lsd_Temp.ReturnType.IsSystemType) + "~r~n" + &
               This.of_ValueString( "IsVariableLength", lsd_Temp.ReturnType.IsVariableLength) + "~r~n" +&
               This.of_ValueString( "IsVisualType", lsd_Temp.ReturnType.IsVisualType) + "~r~n" +&
               This.of_ValueString( "LibraryName", lsd_Temp.ReturnType.LibraryName) + "~r~n" +&
               This.of_ValueString( "Name", lsd_Temp.ReturnType.Name) 
           END IF
CASE ELSE
           ls_Ret = "Missing " + ClassName( acdo_Temp         )
END CHOOSE
RETURN ls_Ret
 

이것의 목적은 classdefinitionobject 정보 바깥에서 포멧된 스트링을 만드는 것입니다. Argument classdefinitionobject 타입이고, 이는

classdefinition, scriptdefinition, 그리고 variabledefinition 타입의 변수로 전달 있게 합니다.

 

Display the Information about a Class

 

다음 함수들을 만들기위해, treeview 되돌아 갑니다. Treeview에서 PB 오브젝트를 확장했을때, of_ShowClassDefinition 함수를 불러와야 합니다.

함수의 정의는 Listing 4 있습니다.

 

Listing 4: Show ClassDefinition
/* Name: of_ShowClassDefinition
Parameters: 
treeview atv_Disp
long al_Parent
classdefinition acd_Data
returns: (none)
*/
integer    li_Counter
treeviewitem ltvi_Temp
long          ll_Handle
classdefinition        lcd_Parent
// Show Varables. No Controls
ll_Handle = atv_disp.InsertItemLast( al_Parent, "Variables", PICT_VARIABLES)
FOR li_Counter = 1 TO UpperBound( acd_Data.VariableList )
               IF NOT acd_Data.VariableList[li_Counter].IsControl THEN
                               of_ShowVariable( atv_Disp, ll_Handle, acd_Data.VariableList[li_Counter])
               END IF
NEXT
// Add Scripts
ll_Handle = atv_disp.InsertItemLast( al_Parent, "Scripts",PICT_FUNCTION)
FOR li_Counter = 1 TO UpperBound( acd_Data.ScriptList )
               of_ShowScript( atv_Disp, ll_Handle, acd_Data.ScriptList[li_Counter] )
NEXT
 
// All the Nested classes
ll_Handle = atv_disp.InsertItemLast( al_Parent, "Nested Classes", PICT_NESTED )
FOR li_Counter = 1 TO UpperBound( acd_Data.nestedclasslist )
               // Checking the parent prevents showing of nested classes from an ancestor
               and recursive information e.g. on structures
               lcd_Parent  = acd_Data.nestedclasslist[li_Counter].ParentClass
               IF NOT IsNull( lcd_Parent ) THEN
                               IF lcd_Parent.Name = acd_Data.Name THEN
                                              ltvi_Temp.Label = acd_Data.nestedclasslist[li_Counter].name
                                              ltvi_Temp.Children = TRUE
                                              ltvi_Temp.PictureIndex = PICT_USEROBJECT
                                              ltvi_Temp.SelectedPictureIndex = ltvi_Temp.PictureIndex
                                              atv_disp.InsertItemLast( ll_Handle, ltvi_Temp )
                               END IF
               END IF
NEXT
// Show ancestor entry
IF NOT IsNull( acd_Data.Ancestor ) THEN
               ltvi_Temp.Label = acd_Data.Ancestor.Name
               ltvi_Temp.Children = TRUE
               // Get same picture as parent item
               treeviewitem          ltvi_Parent
               atv_disp.GetItem( al_Parent, ltvi_Parent)
               ltvi_Temp.PictureIndex = ltvi_Parent.PictureIndex
               ltvi_Temp.SelectedPictureIndex = ltvi_Temp.PictureIndex
               atv_disp.InsertItemLast( al_Parent, ltvi_Temp )
END IF
RETURN
 

세개의 아귀먼트: treeview 컨트롤, 클릭된 아이템의 처리, 그리고 ClassDefinition 오브젝트를 가지고 있습니다. 소스의 번째 레벨에서

ClassDefinition 오브젝트는 FindClassDefinition 함수를 argument treeview 아이템 라벨과 같게 부름으로서 결정됩니다. 여기에 레벨이 2보다

클때의 treeview itemexpanding 이벤트에 있는 코드가 있습니다. 변수 lcd_Temp ClassDefinition 타입이고 ll_Child long 타입입니다:

 

ll_Child = This.FindItem( ChildTreeItem!, handle )
IF ll_Child = -1 THEN // No children yet
    lcd_Temp= FindClassDefinition (&
      ltvi_Current.Label,il_LibList )
    IF NOT IsNull(lcd_Temp) THEN
      Parent.of_ShowClassDefinition(&
        tv_1,handle,lcd_Temp)
    END IF

END IF


변수 부분은 ClassDefinition VariableList 프로퍼티를 통한 반복(looping)으로 채워져있고, IsControl 프로퍼티들을 사용하여 컨트롤들이

추가되는것을 막고 IsUserDefined 사용해서 treeviewitem 이미지를 지정합니다. 변수에서 of_ShowVarible 함수는 (Listing 5 보십시오.)

 

Listing 5: Show Variable
/* Name: of_ShowVariable
Parameters: 
treeview atv_Disp
long al_Parent
variabledefinition avd_Data
returns: (none)
*/
treeviewitem          ltvi_Temp
ltvi_Temp.Label = avd_Data.Name
ltvi_Temp.Data  = This.of_FormatInfo( avd_Data )
// Get picture depending of kind of variable and user defined or not
CHOOSE CASE avd_Data.Kind
CASE VariableGlobal!
                               ltvi_Temp.PictureIndex=PICT_VARGLOBAL
               CASE VariableInstance!
                               ltvi_Temp.PictureIndex=PICT_VARINSTANCE
                               IF avd_Data.IsUserDefined THEN
                                              ltvi_Temp.OverlayPictureIndex = 1
                               END IF
               CASE Variableshared!
                               ltvi_Temp.PictureIndex=PICT_VARSHARED
               CASE VariableArgument!
                               ltvi_Temp.PictureIndex= PICT_VARARGUMENT
               CASE VariableLocal!
                               ltvi_Temp.PictureIndex=PICT_VARLOCAL
END CHOOSE
ltvi_Temp.SelectedPictureIndex = ltvi_Temp.PictureIndex  
atv_disp.InsertItemLast( al_Parent, ltvi_Temp )
RETURN
 

함수는 변수 정보를 treeviewitem 데이터 프로퍼티로 채워넣기 위해 호출됩니다. 변수들을 다루고 , 함수는 스크립트들로 넘어갑니다.

ClassDefinition ScriptList 프로퍼티에서의 엔트리에서, the function of_ShowScript (Listing 6) 함수가 불려집니다.

 

Listing 6: Show Script
/* Name: of_ShowScript
Parameters: 
treeview atv_Disp
long al_Parent
scriptdefinition asd_Data
returns: (none)
*/
treeviewitem          ltvi_Temp
long ll_Handle, ll_Handle2
integer    li_Counter
 
ltvi_Temp.Label = asd_Data.Name
ltvi_Temp.Data = This.of_FormatInfo( asd_Data )
IF asd_Data.IsLocallyScripted                THEN
               ltvi_Temp.OverlayPictureIndex = 1
ELSE
               ltvi_Temp.OverlayPictureIndex = 0
END IF
IF asd_Data.IsScripted THEN
               ltvi_Temp.PictureIndex = PICT_SCRIPTYES
ELSE
               ltvi_Temp.PictureIndex = PICT_SCRIPTNO
END IF
ltvi_Temp.SelectedPictureIndex = ltvi_Temp.PictureIndex
ll_Handle = atv_disp.InsertItemLast( al_Parent, ltvi_Temp )
 
// Use Picture index and overlay index from parent
ltvi_Temp.Label = "Source"
ltvi_Temp.Data = asd_Data.Source
ltvi_Temp.SelectedPictureIndex = ltvi_Temp.PictureIndex
atv_disp.InsertItemLast( ll_Handle, ltvi_Temp )
 
ltvi_Temp.OverlayPictureIndex = 0
ltvi_Temp.Label= "ArgumentList"
SetNull( ltvi_Temp.Data )
ltvi_Temp.PictureIndex=PICT_VARARGUMENT
ltvi_Temp.SelectedPictureIndex = ltvi_Temp.PictureIndex
ll_Handle2 = atv_disp.InsertItemLast( ll_Handle, ltvi_Temp )
variabledefinition    lvd_Temp[]
lvd_Temp = asd_Data.ArgumentList
FOR li_Counter = 1 TO UpperBound( lvd_Temp )
               This.of_ShowVariable( atv_disp, ll_Handle2,lvd_Temp[li_Counter] )
NEXT
 
ltvi_Temp.Label= "LocalVariableList"
SetNull( ltvi_Temp.Data )
ltvi_Temp.PictureIndex=PICT_VARLOCAL
ltvi_Temp.SelectedPictureIndex = ltvi_Temp.PictureIndex
ll_Handle2 = atv_disp.InsertItemLast( ll_Handle, ltvi_Temp )
lvd_Temp = asd_Data.LocalVariableList
FOR li_Counter = 1 TO UpperBound(lvd_Temp )
               This.of_ShowVariable( atv_disp, ll_Handle2, lvd_Temp[li_Counter] )
NEXT
RETURN

 

여기에서 IsLocallyScripted IsScripted 프로퍼티를 사용하여 treeviewitem 이미지를 지정합니다.

Treeviewitem 데이터 프로퍼티는 스크립트에 대한 전체적인 정보를 가지고 있습니다. 우리가 추가한 스크립트에는 ArgumentList

불리는 엔트리 Source(스크립트의 소스를 저장) 있고 다른 하나는 LocalVariableList 불리는 것이 있습니다. 변수와 of_ShowVariable

함수를 불러와 엔트리 아래에 있는  정의를 포함한 argument 변수와 로컬 변수를 추가합니다. Compile 하기 위해서는 of_ShowVariableFirst,

of_ShowScript, 그리고 of_ShowClassDefinition 순서대로 정의해 주어야 합니다.

그리고 나면 nested 클래스들이 보입니다. Nested 클래스의 이름을 만드는 방법은 objectname`nestedclassname입니다. 우리는 FindClassDefinition

불러올때 nested 클래스에 대한 많은 정보를 찾기 위해 정확한 이름이 필요합니다. Nested 클래스들에서는 ParentClass 프로퍼티를 검사합니다.

만약 이것이 null이면, 클래스를 추가하지 않습니다. 나아가서 NestedClassList 오브젝트의 컨트롤들 뿐만 아니라 오브젝트 조상의

컨트롤들도 리턴합니다. NestedClass ParentClass 이름과 현재 오브젝트의 이름을 비교하여 조상 데이터가 보이는것을 막아줍니다.

이들이 일치하지 않는다면, 컨트롤은 선조로부터 상속된 것입니다. 만약 이것이 존재한다면 리스트의 끝에 선조 오브젝트를 위한 엔트리를 추가합니다.

Treeview 아이템들의 데이터 프로퍼티에 저장된 추가의 정보를 보기위해서 사용자는 treeview selectionchanged 이벤트 안에

다음의 코드를 입력해야합니다:

 

treeviewitem ltvi_Current
This.Getitem(newhandle,ltvi_Current)
IF ClassName(ltvi_Current.data)="string"THEN
      mle_1.Text=ltvi_Current.Data
ELSE
      mle_1.Text=""
END IF
RETURN

 

 

어플리케이션이 동작하고 라이브러리 엔트리가 확정되어져 있을때 해당 엔트리의 모든 정보는 한번에 로드되어집니다.

우리는 내포되어 있는 클래스와 조상단에 대한 정보를 분석하지 않아도 조회되어 집니다. 크기가 오브젝트는 시간이 좀더 걸릴수 있다.

엔트리를 드릴다운 하기 위해서 사용자는 treeview에서 아이템을 확장하여야 합니다. 만약에 nested 클래스이나 조상이고 데이터가 로드되어있지 않다면,

선택된 엔트리의 ClassDefinition 오브젝트는 FindClassDefiniton 의해 조회되고 of_ShowClassDefinition 함수가 불려지며 ClassDefinition

오브젝트 argument 이동합니다.  ClassDefinition 오브젝트가 모든 PB 클래스들에서 사용하므로, 이상의 코딩은 필요하지 않습니다.

어플리케이션은 검색할 준비가 되어있습니다. PFC-based 어플리케이션을 검색하는 것은 흥미로우며 많은 레벨로 드릴 다운할 있게 합니다.

 

Conclusion


  내용을 통해 사용자가 ClassDefinition 오브젝트와 이와 관련된 오브젝트들을 기본적으로 이해하였기를 기대합니다. Creating a browser for PB

오브젝트들을 위한 브라우져를 만드는 것은 이러한 오브젝트들을 사용하는것입니다. 오브젝트의 상속이나 어떠한 함수의 가용성(FindMatchingFunction

함수를 참조하십시오) 대한 정보를 얻기를 원할때에 아마도 사용자는 어플리케이션에서 이들을 사용할 것입니다.

다른 방법으로는  Web Service 위한 WSDL 파일들을 동적으로 만드는것이 있습니다.

 

*원본파일

- http://pbdj.sys-con.com/read/220782.htm, By:Arthur Hefti