Page 1 of 1

Drag and drop within the same Grid in a Visual LANSA component

Posted: Wed Sep 19, 2018 1:29 am
by HamadSheikh
I have been trying to write a simple VL Form that shows how to move a grid list entry within the displayed list by simply dragging and dropping the entry from one location to another. So far, I have not been able to make things work. I am unable to retrieve the current row number where the drop will take place. Here is my VL Form:

Function Options(*DIRECT)
Begin_Com Role(*EXTENDS #PRIM_FORM) Clientwidth(484) Clientheight(438) Componentversion(2) Left(850) Top(187)
Define_Com Class(#PRIM_GRID) Name(#Grid1) Captionnoblanklines(True) Columnscroll(False) Componentversion(1) Displayposition(1) Left(16) Parent(#COM_OWNER) Showselection(True) Showselectionhilight(False) Showsortarrow(True) Tabposition(1) Top(8) Height(385) Width(217) Columnbuttonheight(33) Selectionstyle(WholeRow) Dragcolumns(True) Dragstyle(Automatic)
Define_Com Class(#PRIM_GDCL) Name(#GridColumn1) Displayposition(1) Parent(#Grid1) Source(#EMPNO) Width(32)
Define_Com Class(#PRIM_GDCL) Name(#GridColumn2) Displayposition(2) Parent(#Grid1) Source(#SALARY) Width(41) Widthtype(Remainder)
Define_Com Class(#PRIM_STBR) Name(#StatusBar1) Displayposition(2) Height(24) Left(0) Messageposition(1) Parent(#COM_OWNER) Tabposition(2) Tabstop(False) Top(414) Width(484)

Define Field(#HoverEntry) Reffld(#std_num)
Define Field(#WEMPNO) Reffld(#EMPNO)
Define Field(#WSalary) Reffld(#Salary)
Def_List Name(#wrklst) Fields(#EMPNO #SALARY) Type(*WORKING) Entrys(1)

Evtroutine Handling(#com_owner.CreateInstance)
Select Fields(#Grid1) From_File(PSLMST)
Add_Entry To_List(#Grid1)
Endselect
#grid1.DragStyle := Automatic
Endroutine

Evtroutine Handling(#Grid1.StartDrag) Options(*NOCLEARMESSAGES *NOCLEARERRORS)
#std_num := #Grid1.CurrentItem.Entry
Clr_List Named(#wrklst)
Add_Entry To_List(#wrklst)
Endroutine

Evtroutine Handling(#Grid1.DragDrop) Options(*NOCLEARMESSAGES *NOCLEARERRORS)
Dlt_Entry Number(#STD_NUM) From_List(#Grid1)
Get_Entry Number(1) From_List(#wrklst)
Add_Entry To_List(#Grid1) After(#HoverEntry)
Endroutine

Evtroutine Handling(#grid1.DragOver) Acceptdrop(#AcceptDrop)
Set Com(#AcceptDrop) Value(True)
Endroutine

Evtroutine Handling(#Grid1.MouseHover) Options(*NOCLEARMESSAGES *NOCLEARERRORS)
#HoverEntry := #Grid1.FocusItem.Entry
Endroutine
End_Com

I was wondering if anyone else has done this? Can you share your code?

Re: Drag and drop within the same Grid in a Visual LANSA component

Posted: Wed Sep 19, 2018 5:17 am
by TomC
Have you looked at the sample form in the IDE xDemoDragandDrop?

It shows dragging and dropping within a single list view (to reorder), as well as from one list view to another.

Re: Drag and drop within the same Grid in a Visual LANSA component

Posted: Thu Sep 20, 2018 4:39 am
by HamadSheikh
Thanks Tom, there were some very good pointers in that example, though it uses a Tree view. I needed to use a Grid or List view, so I used that example to come up with a working example. Here it is:

Function Options(*DIRECT)
Begin_Com Role(*EXTENDS #PRIM_FORM) Caption('Drag and Drop') Height(491) Left(865) Width(400) Clientwidth(384) Clientheight(452)
Define_Com Class(#PRIM_GRID) Name(#GridList) Columnbuttonheight(19) Displayposition(1) Height(378) Left(0) Parent(#COM_OWNER) Tabposition(1) Top(32) Width(380) Selectionstyle(Multiple) Dragstyle(Automatic)
Define_Com Class(#PRIM_GDCL) Name(#GridColumn1) Displayposition(1) Parent(#GridList) Source(#xDemoCaption) Widthtype(Remainder)

Define_Com Class(#PRIM_LABL) Name(#Label) Caption('Drag items between lists and within the same list') Displayposition(2) Tabstop(False)
Define_Com Class(#xDemoDragandDropImage) Name(#DragImage)
Define Field(#wxdemocaption) Reffld(#xDemoCaption)

Evtroutine Handling(#Com_owner.CreateInstance)
* Populate Grid list with some data
Begin_Loop To(10)
#xDemoCaption := ("Left &1").Substitute( (#GridList.Items.ItemCount + 1).AsString )
Add_Entry To_List(#GridList)
End_Loop
Endroutine

* The user has started a dragging operation
Evtroutine Handling(#GridList.StartDrag) Com_Sender(#Sender) Continue(#Continue) Payload(#Payload) Draglist(#DragList)
* Get the selected items from the list firing the event and store in the drag payload
#Payload <= #Com_owner.GetSelectedItems( #Sender )
* Drag can continue if there's something in the payload
#Continue := (#Payload *As #Prim_acol<#prim_gdit>).ItemCount > 0
* Drag to use a popup panel as the drag image
#DragList.DragListStyle := Popup
* Hook up the Dragimage Popup
#DragList.DragPopup <= #DragImage
* Set the drag image appearance
#DragImage.DragCaption := (#Payload *As #Prim_acol<#prim_gdit>).ItemCount.AsString
#DragImage.DragImage <= #xImageFavorites32
* Store the selected entry values
#wxdemocaption := #xDemoCaption
#std_num := #GridList.CurrentItem.Entry
Endroutine

* Allow Dragover on the Grid list and highlight the selected grid rows
Evtroutine Handling(#GridList.DragOver) Com_Sender(#Sender) Acceptdrop(#Accept) Payload(#Payload) Source(#Source) Showdrophilight(#DropHilight)
* Highlight the item
#DropHilight := True
* Allow the drop if the payload is not empty
#Accept := (#Payload *As #Prim_acol<#prim_gdit>).ItemCount > 0
Endroutine

* Drop into the Grid List
Evtroutine Handling(#GridList.DragDrop) Payload(#Payload) Dragresult(#DragResult) Source(#Source)
#COM_OWNER.DoGridDrop Source(#source) Dropitem(#GridList.CurrentItem) Payload(#Payload *As #Prim_acol<#prim_gdit>)
#DragResult := Accepted
Endroutine

Mthroutine Name(DoGridDrop) Access(*PRIVATE)
Define_Map For(*INPUT) Class(#Prim_objt) Name(#Source) Pass(*BY_REFERENCE)
Define_Map For(*INPUT) Class(#Prim_gdit) Name(#DropItem) Pass(*BY_REFERENCE)
Define_Map For(*INPUT) Class(#Prim_acol<#prim_gdit>) Name(#Payload) Pass(*BY_REFERENCE)

* Iterate over the items in the payload
For Each(#Item) In(#Payload)
* Set the Field value(s)
#xDemoCaption := #item.ValueAt<1>
* Delete the old row
Dlt_Entry Number(#Item.entry) From_List(#GridList)

#std_num := #DropItem.Position - 1
If (#STD_NUM <= 2)
#std_num := 2
Endif
* Add the deleted row into the new position
Add_Entry To_List(#GridList) After((#DropItem.Position - 1))
#STD_NUM := 0
Endfor
Endroutine

Mthroutine Name(GetSelectedItems) Access(*PRIVATE)
Define_Map For(*INPUT) Class(#Prim_GRID) Name(#Grid) Pass(*BY_REFERENCE)
Define_Map For(*RESULT) Class(#Prim_acol<#prim_gdit>) Name(#Result) Pass(*BY_REFERENCE)
#Result <= *New #Prim_acol<#prim_gdit>
For Each(#Item) In(#Grid.Items)
Continue If(*Not #Item.Selected)
#Result.Insert( #Item )
Endfor
Endroutine
End_Com

Note that the code would have been significantly simpler if the .Position property could be set in a Grid or List component.
Position is settable in a Tree view. I have logged that as an Enhancement request.