Omnis Technical Note TNGI0020 December 2007

Manually changing the sort order of list lines

For Omnis Studio 3/4
By Andreas Pfeiffer

In an application, you may want to allow end users to change the sort order of lines in a list by hand - normally a list is sorted according to one of the columns in the underlying list and the user may be able to select the column to sort the list. However, you can allow users to select individual or multiple list lines and reorder the list by dragging and dropping the list lines.

For this you can use a Headed List Box. To make sure the user can select multiple lines in the list you should set the property $multipleselect in the "Action" group to kTrue.

To activate drag & drop

In order to make the Headed List Box accept drag & drop you have to activate the properties $dragmode and $dropmode in the "Action" group. Set the property $dragmode to kDragData and the property $dropmode to kAcceptList so that the data can be dragged onto itself. In addition, you should set the property $dropbetweenlines to kTrue so that the selected lines can be dropped between other lines - to do this you need to set the property $highliteline to kTrue, otherwise the $dropbetweenlines property cannot be changed.

Headed list properties

Prevent other objects from dropping onto this Headed List Box

You can ensure that other data from other objects cannot be dragged onto the Headed List Box by adding the following method to the $event method of the list:

On evWillDrop
If pDropField<>$cobj
; only drag and drop to reorder fields allowed
Quit event handler (Discard event)
End If

And now changing the sorting order

To change the order of the list lines, you have to code the evDrop in the $event method for the list. You can use the pDragData event parameter which contains the contents of the "dragged" data:

On evDrop
; rearrange the line order
Calculate lineNumber as mouseover(kMLine)
Do pDragValue.$first(kTrue)
; set the first selected line to be current
While ivList.$line>0
Do pDragValue.$addbefore(lineNumber) Returns lineRef
; adds an empty line before the dropped line number
If pDragValue.$line>lineNumber
Calculate pDragValue.$line as pDragValue.$line+1
End If
Do lineRef.$assignrow(pDragValue)
; assign the data from the current row to the new empty line
Calculate lineNumber as lineNumber+1
Do pDragValue.$next(PDragValue.$line,kTrue)
; make the next selected line current
End While
Do pDragValue.$remove(KListDeleteSelected)
; delete the original data
Do $cinst.$redraw() ;. redraw the list

The method uses a local Integer variable which uses the mouseover(kMLine) function to detect the line number on which the user has dropped. Note that you cannot set a breakpoint before the mouseover() function, since you are using the mouse while debugging and so at that point the kMLine parameter will not return the required value.