File: n_svc_tv.sru
Size: 24035
Date: Mon, 07 Apr 2008 21:31:29 +0200
$PBExportHeader$n_svc_tv.sru
$PBExportComments$Treeview Service
forward
global type n_svc_tv from n_svc_base
end type
end forward

global type n_svc_tv from n_svc_base
event ke_itemclicked ( ref n_svc_mgr anv_svc,  readonly u_tv atv,  readonly long al_itemhandle,  readonly integer xpos,  readonly integer ypos )
event ke_key ( readonly u_tv atv,  readonly keycode key,  readonly unsignedlong keyflags )
end type
global n_svc_tv n_svc_tv

type variables
Public :
CONSTANT long CHECKED = 1
CONSTANT long UNCHECKED = -5

Protected:
////treeview states
//CONSTANT long BOX_CHECKED = 1
//CONSTANT long BOX_UNCHECKED = 2
//CONSTANT long RADIO_CHECKED = 3
//CONSTANT long RADIO_UNCHECKED = 4
//treeview
CONSTANT long TV_FIRST = 4352
CONSTANT long TVM_GETCOUNT = (TV_FIRST + 5)
CONSTANT long TVM_SETIMAGELIST = (TV_FIRST + 9)
CONSTANT long TVSIL_NORMAL            = 0
CONSTANT long TVSIL_STATE             = 2
CONSTANT UInt TVM_HITTEST = 4369
CONSTANT UInt TVHT_ONITEMSTATEICON = 64
CONSTANT uint TVHT_NOWHERE         = 1
CONSTANT uint TVHT_ONITEMICON      = 2
CONSTANT uint TVHT_ONITEMLABEL     = 4
CONSTANT uint TVHT_ONITEM          = 70 // (TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON)
CONSTANT uint TVHT_ONITEMINDENT    = 8
CONSTANT uint TVHT_ONITEMBUTTON    = 16
CONSTANT uint TVHT_ONITEMRIGHT     = 32

Private:
CONSTANT string ROW_ID = "<#row_id#>"
end variables

forward prototypes
public function integer of_deletechildren (readonly treeview atv, readonly long al_handle)
public function long of_finditem (readonly treeview atv, readonly long al_itemhandle, readonly string as_searchtext)
public function long of_finditem (readonly treeview atv, readonly string as_searchtext)
public function long of_getchildren (readonly treeview atv, readonly long al_itemhandle, ref treeviewitem atvi_items[])
public function long of_getrootitem (readonly treeview atv, readonly long al_itemhandle, ref treeviewitem atvi_root)
public function string of_getstringpath (readonly treeview atv, readonly long al_itemhandle)
public subroutine of_reset (readonly treeview atv)
public function long of_totalitems (readonly treeview atv)
public subroutine of_setimagelist (readonly u_tv atv, readonly long al_himl)
public subroutine of_setstateimagelist (readonly u_tv atv, readonly long al_himl)
public subroutine of_loadstateimages (ref n_svc_mgr anv_svc, readonly u_tv atv)
public function boolean of_isitemchecked (readonly u_tv atv, readonly long al_itemhandle)
public subroutine of_getselecteditems (readonly u_tv atv, readonly long al_root, ref treeviewitem atvi[])
public subroutine of_getselecteditems (readonly u_tv atv, ref treeviewitem atvi[])
protected subroutine of_statechange (readonly u_tv atv, readonly long al_itemhandle)
public subroutine of_checkitem (readonly u_tv atv, readonly long al_itemhandle, readonly boolean ab_selected)
public subroutine of_uncheckall (readonly u_tv atv, readonly long al_root, readonly boolean ab_recurse)
public subroutine of_uncheckall (readonly u_tv atv, readonly long al_itemhandle)
public subroutine of_uncheckall (readonly u_tv atv, boolean ab_recurse)
public subroutine of_loadstandardimages (ref n_svc_mgr anv_svc, readonly treeview atv)
public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly string as_parentvalue, readonly long al_parentitemhandle)
public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly string as_parentvalue)
public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly string as_parentvalue, readonly long al_parentitemhandle, readonly boolean ab_userowiddata)
public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly string as_parentvalue, readonly boolean ab_userowiddata)
public function long of_getitemfrompath (ref n_svc_mgr anv_svc, readonly treeview atv, readonly string as_path)
public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly integer ai_rootnode, readonly string as_parentcolumnname, readonly string as_parentcolumnvalue, readonly string as_childcolumnname, readonly string as_displaytextcolumn, readonly string as_tagdatacolumn, readonly string as_sortbycolumn, readonly string as_pictureindexcolumn, readonly string as_selectedpictureindexcolumn, readonly string as_statepictureindexcolumn, readonly string as_expandedcolumn, readonly powerobject apo_callback)
public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly integer ai_rootnode, readonly string as_parentcolumnname, readonly string as_parentcolumnvalue, readonly string as_childcolumnname, readonly string as_displaytextcolumn, readonly string as_tagdatacolumn, readonly string as_sortbycolumn, readonly string as_pictureindexcolumn, readonly string as_selectedpictureindexcolumn, readonly string as_statepictureindexcolumn, readonly string as_expandedcolumn)
end prototypes

event ke_itemclicked(ref n_svc_mgr anv_svc, readonly u_Tv atv, readonly long al_itemhandle, readonly integer xpos, readonly integer ypos);tvhittestinfo lstr_tvhittest
long ll_flags
n_svc_bit lnv_bit
n_svc_win32 lnv_win32

//load services
anv_svc.of_loadsvc(lnv_bit, CSvc.BIT)
anv_svc.of_loadsvc(lnv_win32, CSvc.WIN32)

lstr_tvhittest.str_point.px = UnitsToPixels(xpos, XUnitsToPixels!)
lstr_tvhittest.str_point.py = UnitsToPixels(ypos, YUnitsToPixels!)

lnv_win32.HitMsg(Handle(atv), TVM_HITTEST, 0, lstr_tvhittest)

IF lstr_tvhittest.hItem <> 0 THEN
   IF (lnv_bit.of_bitwiseand({TVHT_ONITEMSTATEICON, lstr_tvhittest.flags}) = lstr_tvhittest.flags) THEN
      this.of_statechange(atv, al_itemhandle)
   END IF
END IF
end event

event ke_key(readonly u_Tv atv, readonly keycode key, readonly unsignedlong keyflags);treeviewitem ltvi
long ll_index

ll_index = atv.FindItem(CurrentTreeItem!, 0)

IF atv.GetItem(ll_index, ltvi) = CRet.FAILURE THEN RETURN

IF key = KeySpaceBar! THEN
   of_StateChange(atv, ll_index)
END IF
end event

public function integer of_deletechildren (readonly treeview atv, readonly long al_handle);treeviewitem ltvi
long n, ll_find

DO
   ll_find = atv.FindItem(ChildTreeItem!, al_handle)
   IF ll_find > 0 THEN
      n++
      atv.DeleteItem(ll_find)
   END IF
LOOP WHILE ll_find > 0

RETURN n
end function

public function long of_finditem (readonly treeview atv, readonly long al_itemhandle, readonly string as_searchtext);treeviewitem ltvi_node
Integer li_rc
Long ll_root
Long lc, ll_ret

IF al_itemhandle > 0 THEN
   ll_root = al_itemhandle
   
   //compare string
   atv.GetItem(al_itemhandle, ltvi_node)
   IF lower(ltvi_node.Label) = lower(as_searchtext) THEN RETURN al_itemhandle
   
   DO
      ll_root = atv.FindItem(ChildTreeItem!, ll_root)
      Do
         ll_ret = of_FindItem(atv, ll_root, as_searchtext)
         IF ll_ret > 0 THEN RETURN ll_ret
         ll_root = atv.FindItem(NextTreeItem!, ll_root)
      LOOP WHILE ll_root > 0
   LOOP WHILE ll_root > 0
END IF

RETURN CRet.FAILURE
end function

public function long of_finditem (readonly treeview atv, readonly string as_searchtext);long ln, ll_ret

ln = atv.FindItem(RootTreeItem!, 0)

IF ln > 0 THEN
   ll_ret = of_FindItem(atv, ln, as_searchtext)
   IF ll_ret > 0 THEN RETURN ll_ret
   ln = atv.FindItem(NextTreeItem!, ln)
   DO WHILE ln > 0
      ll_ret = of_FindItem(atv, ln, as_searchtext)
      IF ll_ret > 0 THEN RETURN ll_ret
      ln = atv.FindItem(NextTreeItem!, ln)
   LOOP
END IF

RETURN ln
end function

public function long of_getchildren (readonly treeview atv, readonly long al_itemhandle, ref treeviewitem atvi_items[]);treeviewitem ltvi
long n, ll_find

n = CRet.NO_ACTION

atv.GetItem(al_itemhandle, ltvi)

IF NOT ltvi.Children THEN RETURN n

ll_find = atv.FindItem(ChildTreeItem!, al_itemhandle)

DO WHILE ll_find > 0
   n++
   atv.GetItem(ll_find, atvi_items[n])
   ll_find = atv.FindItem(NextTreeItem!, ll_find)
LOOP

RETURN n
end function

public function long of_getrootitem (readonly treeview atv, readonly long al_itemhandle, ref treeviewitem atvi_root);long ll_find

ll_find = atv.FindItem(ParentTreeItem!, al_itemhandle)

IF ll_find <= 0 THEN RETURN -1

//loop up
DO WHILE ll_find > 0
   atv.GetItem(ll_find, atvi_root)
   ll_find = atv.FindItem(ParentTreeItem!, atvi_root.itemhandle)
LOOP

RETURN atvi_root.itemhandle
end function

public function string of_getstringpath (readonly treeview atv, readonly long al_itemhandle);treeviewitem ltvi
long ll_parent
string ls_ret

atv.GetItem(al_itemhandle, ltvi)

ls_ret = ltvi.Label

ll_parent = atv.FindItem(ParentTreeItem!, ltvi.itemhandle)
DO WHILE ll_parent > 0
   atv.GetItem(ll_parent, ltvi)
   ls_ret = ltvi.Label + CString.BACKSLASH + ls_ret
   ll_parent = atv.FindItem(ParentTreeItem!, ltvi.itemhandle)
LOOP

RETURN ls_ret
end function

public subroutine of_reset (readonly treeview atv);long ll_find

ll_find = atv.FindItem(RootTreeItem!, 0)

//turn-off drawing
atv.SetRedraw(FALSE)
atv.POST SetRedraw(TRUE)

DO WHILE ll_find > 0
   atv.DeleteItem(ll_find)
   ll_find = atv.FindItem(RootTreeItem!, 0)
LOOP
end subroutine

public function long of_totalitems (readonly treeview atv);RETURN Send(Handle(atv), TVM_GETCOUNT, 0, 0)
end function

public subroutine of_setimagelist (readonly u_tv atv, readonly long al_himl);Send(Handle(atv), TVM_SETIMAGELIST, TVSIL_NORMAL, al_himl)
//tell the treeview to swap dummy on destruct
atv.of_imagelistassigned()
end subroutine

public subroutine of_setstateimagelist (readonly u_tv atv, readonly long al_himl);Send(Handle(atv), TVM_SETIMAGELIST, TVSIL_STATE, al_himl)
//tell the treeview to swap dummy on destruct
atv.of_imagelistassigned()
end subroutine

public subroutine of_loadstateimages (ref n_svc_mgr anv_svc, readonly u_tv atv);long ll_himl
n_svc_resource lnv_res

anv_svc.of_LoadSvc(lnv_res, CSvc.RESOURCE)
ll_himl = lnv_res.of_GetStateImagelist(anv_svc)
of_setstateimagelist(atv, ll_himl)
end subroutine

public function boolean of_isitemchecked (readonly u_tv atv, readonly long al_itemhandle);treeviewitem ltvi_node
Long ll_rc

ll_rc = atv.GetItem(al_itemhandle, ltvi_node)

IF ll_rc > 0 THEN
   RETURN ltvi_node.StatePictureIndex = CResource.RADIO_CHECKED &
         OR ltvi_node.StatePictureIndex = CResource.BOX_CHECKED
END IF

RETURN FALSE
end function

public subroutine of_getselecteditems (readonly u_tv atv, readonly long al_root, ref treeviewitem atvi[]);treeviewitem ltvi_node
Integer li_rc
Long ll_root
Long lc

IF al_root > 0 THEN
   ll_root = al_root
   DO
      ll_root = atv.FindItem(ChildTreeItem!, ll_root)
      DO
         atv.GetItem(ll_root, ltvi_node)
         IF ltvi_node.StatePictureIndex = CResource.BOX_CHECKED &
            OR ltvi_node.StatePictureIndex = CResource.RADIO_CHECKED THEN
            lc = UpperBound(atvi) + 1
            atvi[lc] = ltvi_node          
         END IF

         //recurse
         of_GetSelectedItems(atv, ltvi_node.ItemHandle, atvi)

         ll_root = atv.FindItem(NextTreeItem!, ll_root)
      LOOP WHILE ll_root > 0
   LOOP WHILE ll_root > 0
END IF
end subroutine

public subroutine of_getselecteditems (readonly u_tv atv, ref treeviewitem atvi[]);treeviewitem ltvi_node
Long ll_root
Long lc

ll_root = atv.FindItem(RootTreeItem!, 0)

DO WHILE ll_root > 0 
   atv.GetItem(ll_root, ltvi_node)
   IF ltvi_node.StatePictureIndex = CResource.BOX_CHECKED &
      OR ltvi_node.StatePictureIndex = CResource.RADIO_CHECKED THEN
      lc = UpperBound(atvi) + 1
      atvi[lc] = ltvi_node          
   END IF

   of_GetSelectedItems(atv, ll_root, atvi)
   ll_root = atv.FindItem(NextTreeItem!, ll_root)
LOOP
end subroutine

protected subroutine of_statechange (readonly u_tv atv, readonly long al_itemhandle);Boolean lb
long ll_rc

lb = of_IsItemChecked(atv, al_itemhandle) 

//trigger statechanging
IF NOT atv.EVENT ke_statechanging(al_itemhandle, NOT lb) THEN RETURN
//change state and trigger statechanged
of_CheckItem(atv, al_itemhandle, NOT lb)
//trigger statechanged
atv.EVENT ke_statechanged(al_itemhandle, NOT lb)
end subroutine

public subroutine of_checkitem (readonly u_tv atv, readonly long al_itemhandle, readonly boolean ab_selected);treeviewitem ltvi_node
Long ll_handle, n
treenavigation ltn

IF al_itemhandle > 0 THEN
   atv.GetItem(al_itemhandle, ltvi_node)
   IF ab_selected THEN
      CHOOSE CASE ltvi_node.StatePictureIndex
         CASE CResource.BOX_UNCHECKED
            ltvi_node.StatePictureIndex = CResource.BOX_CHECKED // Check Box
            atv.SetItem(al_itemhandle, ltvi_node)
            //make sure to check parent
            ll_handle = atv.FindItem(ParentTreeItem!, al_itemhandle)
            IF ll_handle > 0 THEN of_CheckItem(atv, ll_handle, ab_selected)
         CASE CResource.RADIO_UNCHECKED
            ltvi_node.StatePictureIndex = CResource.RADIO_CHECKED // Check Radio
            atv.SetItem(al_itemhandle, ltvi_node)
            
            // Uncheck all sibling radio buttons.
            FOR n = 1 to 2
               IF n = 1 THEN
                  //go up
                  ltn = PreviousTreeItem!
               ELSE
                  //go down
                  ltn = NextTreeItem!
               END IF

               ll_handle = al_itemhandle
               DO WHILE ll_handle <> -1
                  ll_handle = atv.FindItem(ltn, ll_handle)
                  IF ll_handle > 0 THEN
                     atv.GetItem(ll_handle, ltvi_node)
                     IF ltvi_node.StatePictureIndex = CResource.RADIO_CHECKED THEN
                        ltvi_node.StatePictureIndex = CResource.RADIO_UNCHECKED
                        atv.SetItem(ll_handle, ltvi_node)
                     END IF
                  END IF
               LOOP
            NEXT
      END CHOOSE
   ELSE
      CHOOSE CASE ltvi_node.StatePictureIndex
         CASE CResource.BOX_CHECKED
            of_UncheckAll(atv, al_itemhandle, TRUE)
         CASE CResource.RADIO_CHECKED
            // Cannot uncheck radio -- Only through checking another item.
      END CHOOSE
   END IF
END IF
end subroutine

public subroutine of_uncheckall (readonly u_tv atv, readonly long al_root, readonly boolean ab_recurse);treeviewitem ltvi_node
Integer li_rc
Long ll_root
Long lc

IF al_root > 0 THEN
   atv.GetItem(al_root, ltvi_node)
   IF ltvi_node.StatePictureIndex = CResource.BOX_CHECKED&
      OR ltvi_node.StatePictureIndex = CResource.BOX_UNCHECKED THEN
      ltvi_node.StatePictureIndex = CResource.BOX_UNCHECKED
   END IF
   atv.SetItem(al_root, ltvi_node)
   ll_root = al_root
   DO
      ll_root = atv.FindItem(ChildTreeItem!, ll_root)
      DO
         atv.GetItem(ll_root, ltvi_node)
         IF ltvi_node.StatePictureIndex = CResource.BOX_CHECKED THEN
            ltvi_node.StatePictureIndex = CResource.BOX_UNCHECKED
            atv.SetItem(ll_root, ltvi_node)
         END IF
         
         //recurse sub nodes
         IF ab_recurse THEN
            of_UncheckAll(atv, ll_root, ab_recurse)
         END IF
         
         ll_root = atv.FindItem(NextTreeItem!, ll_root)
      LOOP WHILE ll_root > 0
   LOOP WHILE ll_root > 0
END IF
end subroutine

public subroutine of_uncheckall (readonly u_tv atv, readonly long al_itemhandle);of_UncheckAll(atv, al_itemhandle, FALSE)
end subroutine

public subroutine of_uncheckall (readonly u_tv atv, boolean ab_recurse);Long ll_root
Long lc

ll_root = atv.FindItem(RootTreeItem!, 0)

IF ll_root > 0 THEN
   of_UncheckAll(atv, ll_root, ab_recurse)
   ll_root = atv.FindItem(NextTreeItem!, ll_root)
   DO WHILE ll_root > 0
      of_UncheckAll(atv, ll_root, ab_recurse)
      ll_root = atv.FindItem(NextTreeItem!, ll_root)
   LOOP
END IF
end subroutine

public subroutine of_loadstandardimages (ref n_svc_mgr anv_svc, readonly treeview atv);n_svc_resource lnv_res
long ll_himl

anv_svc.of_LoadSvc(lnv_res, CSvc.RESOURCE)
   
ll_himl = lnv_res.of_GetStandardImageList16(anv_svc)
of_SetImagelist(atv, ll_himl)
end subroutine

public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly string as_parentvalue, readonly long al_parentitemhandle);//assumes standard datastore_to_treeview object
of_Convertdatastore(anv_svc, &
                  ads, &
                  atv, &
                  as_parentvalue, &
                  al_parentitemhandle, &
                  FALSE)
end subroutine

public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly string as_parentvalue);//assumes standard datastore_to_treeview object
of_Convertdatastore(anv_svc, &
                  ads, &
                  atv, &
                  as_parentvalue, &
                  0, /*assumes insert as root node*/ &
                  FALSE)
end subroutine

public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly string as_parentvalue, readonly long al_parentitemhandle, readonly boolean ab_userowiddata);string ls_colname
powerobject lpo

IF ab_userowiddata THEN
   ls_colname = ROW_ID
ELSE
   ls_colname = "tagdata"
END IF

//assumes standard datastore_to_treeview object
of_Convertdatastore(anv_svc, &
                  ads, &
                  atv, &
                  al_parentitemhandle, &
                  "parentnode", &
                  as_parentvalue, &
                  "node", &
                  "displaytext", &
                  ls_colname, &
                  "sortorder", &
                  "pictureindex", &
                  "selectedpictureindex", &
                  "statepictureindex", &
                  "expanded", &
                  lpo)
end subroutine

public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly string as_parentvalue, readonly boolean ab_userowiddata);//assumes standard datastore_to_treeview object
of_Convertdatastore(anv_svc, &
                  ads, &
                  atv, &
                  as_parentvalue, &
                  0, /*assumes insert as root node*/ &
                  ab_userowiddata)
end subroutine

public function long of_getitemfrompath (ref n_svc_mgr anv_svc, readonly treeview atv, readonly string as_path);string ls_paths[]
long ll_handle, ll_find
long ll_count, n
n_svc_string lnv_str
boolean lb_found
treeviewitem ltvi

anv_svc.of_LoadSvc(lnv_str, CSvc.STRING)

ll_count = lnv_str.of_parsetoarray(as_path, CString.BACKSLASH, ls_paths)
FOR n = 1 to ll_count
   lb_found = FALSE
   
   IF n = 1 THEN
      ll_find = atv.FindItem(RootTreeItem!, 0)
      IF ll_find > 0 THEN
         atv.GetItem(ll_find, ltvi)
         IF lower(ltvi.Label) = lower(ls_paths[n]) THEN
            ll_handle = ltvi.itemhandle
            lb_found = TRUE
         ELSE
            //check for next items of root
            ll_find = atv.FindItem(NextTreeItem!, ll_find)
            DO WHILE ll_find > 0
               atv.GetItem(ll_find, ltvi)
               IF lower(ltvi.Label) = lower(ls_paths[n]) THEN
                  ll_handle = ltvi.itemhandle
                  lb_found = TRUE
                  EXIT
               END IF
               
               ll_find = atv.FindItem(NextTreeItem!, ll_find)
            LOOP
         END IF
      END IF
   ELSE
      //get the first child
      ll_find = atv.FindItem(ChildTreeItem!, ll_handle)
      IF ll_find > 0 THEN
         atv.GetItem(ll_find, ltvi)
         IF lower(ltvi.Label) = lower(ls_paths[n]) THEN
            ll_handle = ltvi.itemhandle
            lb_found = TRUE
         ELSE
            //check for next items of current
            ll_find = atv.FindItem(NextTreeItem!, ll_find)
            DO WHILE ll_find > 0
               atv.GetItem(ll_find, ltvi)
               IF lower(ltvi.Label) = lower(ls_paths[n]) THEN
                  ll_handle = ltvi.itemhandle
                  lb_found = TRUE
                  EXIT
               END IF
               
               ll_find = atv.FindItem(NextTreeItem!, ll_find)
            LOOP
         END IF
      END IF
   END IF
   
   //did we find any
   IF NOT lb_found THEN EXIT
NEXT

IF NOT lb_found THEN ll_handle = -1

RETURN ll_handle
end function

public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly integer ai_rootnode, readonly string as_parentcolumnname, readonly string as_parentcolumnvalue, readonly string as_childcolumnname, readonly string as_displaytextcolumn, readonly string as_tagdatacolumn, readonly string as_sortbycolumn, readonly string as_pictureindexcolumn, readonly string as_selectedpictureindexcolumn, readonly string as_statepictureindexcolumn, readonly string as_expandedcolumn, readonly powerobject apo_callback);n_svc_dw lnv_dw
n_svc_isempty lnc
n_svc_resource lnr
long lc, n, ln
string lsf, lsv, lsc, lst
treeviewitem ltvi, ltvi_empty
any la

anv_svc.of_loadsvc(lnv_dw, CSvc.DW)
anv_svc.of_loadsvc(lnc, CSvc.ISEMPTY)
anv_svc.of_loadsvc(lnr, CSvc.RESOURCE)

TRY
   //build filter string and sort
   lsf = lnv_dw.of_BuildColumnValueString(anv_svc, ads, as_parentcolumnname, as_parentcolumnvalue, FALSE)
   ads.SetFilter(lsf)
   ads.Filter()
   IF NOT lnc.of_isempty(as_sortbycolumn) THEN
      ads.SetSort(as_sortbycolumn+ " A")
      ads.Sort()
   END IF
   
   lc = ads.RowCount()
   
   FOR n = 1 to lc
      //reset treeviewitem
      ltvi = ltvi_empty
      
      lsc = STRING(lnv_dw.of_GetItemAny(ads, n, as_childcolumnname))
      lsv = lnv_dw.of_getitemany(ads, n, as_displaytextcolumn)
      ltvi.Label = lsv
      //tag data
      IF NOT lnc.of_isempty(as_tagdatacolumn) THEN
         IF as_tagdatacolumn = ROW_ID THEN
            ltvi.Data = ads.GetRowIDFromRow(n)
         ELSE
            ltvi.Data = lnv_dw.of_GetItemAny(ads, n, as_tagdatacolumn)
         END IF
      END IF
      //picture index
      IF NOT lnc.of_isempty(as_pictureindexcolumn) THEN
         lst = lnv_dw.of_GetItemAny(ads, n, as_pictureindexcolumn)
         IF ISNUMBER(lst) THEN
            ltvi.PictureIndex = INTEGER(lst)
         ELSE
            ltvi.PictureIndex = lnr.of_standardimageindexfromstring(lst)
         END IF
      END IF
      //selected picture index
      IF NOT lnc.of_isempty(as_selectedpictureindexcolumn) THEN
         lst = lnv_dw.of_GetItemAny(ads, n, as_selectedpictureindexcolumn)
         IF ISNUMBER(lst) THEN
            ltvi.SelectedPictureIndex = INTEGER(lst)
         ELSE
            ltvi.SelectedPictureIndex = lnr.of_standardimageindexfromstring(lst)
         END IF
      END IF
      //state picture index
      IF NOT lnc.of_isempty(as_statepictureindexcolumn) THEN
         ltvi.StatePictureIndex = INTEGER(lnv_dw.of_GetItemAny(ads, n, as_statepictureindexcolumn))
      END IF
      //expanded
      IF NOT lnc.of_isempty(as_expandedcolumn) THEN
         ltvi.Expanded = STRING(lnv_dw.of_GetItemAny(ads, n, as_expandedcolumn)) = "1"
      END IF
      
      //if a callback is specified, fire the event
      IF ISVALID(apo_callback) THEN
         TRY
            la = apo_callback.DYNAMIC EVENT ke_convertdatastore(ltvi)
            IF NOT ISNULL(la) THEN
               //the call was successful
            END IF
         CATCH(Throwable t)
            //ignore
         END TRY
      END IF
      
      ln = atv.InsertItemLast(ai_rootnode, ltvi)
      
      //recurse
      of_ConvertDatastore(anv_svc, &
                          ads, &
                          atv, &
                          ln, &
                          as_parentcolumnname, &
                          lsc, &
                          as_childcolumnname, &
                          as_displaytextcolumn, &
                          as_tagdatacolumn, &
                          as_sortbycolumn, &
                          as_pictureindexcolumn, &
                          as_selectedpictureindexcolumn, &
                          as_statepictureindexcolumn, &
                          as_expandedcolumn, &
                          apo_callback)

      //re-apply filter and sort
      ads.SetFilter(lsf)
      ads.Filter()
      IF NOT lnc.of_isempty(as_sortbycolumn) THEN
         ads.SetSort(as_sortbycolumn + " A")
         ads.Sort()
      END IF
   NEXT
   //remove filter
   ads.SetFilter(CString.EMPTY)
   ads.Filter()
CATCH (Exception ex)
   //swallow
   MessageBox(this.Classname(), ex.getmessage())
END TRY
end subroutine

public subroutine of_convertdatastore (ref n_svc_mgr anv_svc, readonly datastore ads, readonly u_tv atv, readonly integer ai_rootnode, readonly string as_parentcolumnname, readonly string as_parentcolumnvalue, readonly string as_childcolumnname, readonly string as_displaytextcolumn, readonly string as_tagdatacolumn, readonly string as_sortbycolumn, readonly string as_pictureindexcolumn, readonly string as_selectedpictureindexcolumn, readonly string as_statepictureindexcolumn, readonly string as_expandedcolumn);powerobject lpo

of_ConvertDatastore(anv_svc, &
                  ads, &
                  atv, &
                  ai_rootnode, &
                  as_parentcolumnname, &
                  as_parentcolumnvalue, &
                  as_childcolumnname, &
                  as_displaytextcolumn, &
                  as_tagdatacolumn, &
                  as_sortbycolumn, &
                  as_pictureindexcolumn, &
                  as_selectedpictureindexcolumn, &
                  as_statepictureindexcolumn, &
                  as_expandedcolumn, &
                  lpo)
end subroutine

on n_svc_tv.create
call super::create
end on

on n_svc_tv.destroy
call super::destroy
end on