Drag Drop in Listbox and reorder lines

Dear,

For a while I have let users order a listbox with drag and drop.
As far as I know it has worked, but for some reason I randomly get
wrong result because the source not being correct.
To this listbox I can also drop from other sources and therefore I try to split
the code based upon the source of the drop.

What I can see is not working is the detection of the Source parameter in
DRAG AND DROP PROPERTIES($source;$row;$process)

I do like this in the listbox OM.

<< should have been a nice code here, But HOW?>>

Case of
: ($formEvent_l=On Drop)
DRAG AND DROP PROPERTIES($source;$arrayrow;$processnum) //From where
If ($source=Self)

End Case

I have also tried with:
If ($source=OBJECT Get pointer(Object current)), but no change

However the problems seem to be that randomly the $source is the ListBox
and sometimes it is a pointer to the Column (ie a pointer to a Field)

I am using a Current selection Listbox.

What am I doing wrong?
What approach is better?

Best Regards

Magnus

To inspire you, here’s some code how I handle drag n drop of a file onto listbox thru a subform:

<code 4D>
: (Form event=On Drop)

	C_POINTER($P_Subform_container)
	$P_Subform_container:=OBJECT Get pointer(Object subform container)  // container doit etre un objet
	If ($P_Subform_container->#Null)
		  // #20200313-1
		  // Ici c'est juste pour savoir comment on a droppe
		C_LONGINT($L_Ligne;$L_Colonne)
		$L_Ligne:=Drop position($L_Colonne)
		
		C_OBJECT($O_Drop_Callback)
		$O_Drop_Callback:=New object
		$O_Drop_Callback.dropline:=$L_Ligne
		$O_Drop_Callback.dropcol:=$L_Colonne
		
		$P_Subform_container->dropcallback:=$O_Drop_Callback
		  /// fin nature du drop
	End if 
	
	  // #20181224-1
	C_TEXT($T_Signature)
	$T_Signature:="com.4d.private.file.url"
	
	ARRAY TEXT($rT_Signatures4D;0)
	ARRAY TEXT($rT_TypesNatifs;0)
	GET PASTEBOARD DATA TYPE($rT_Signatures4D;$rT_TypesNatifs)
	
	If (Find in array($rT_Signatures4D;$T_Signature)>-1)
		
		
		C_TEXT($T_Text_error)
		C_LONGINT($L_Erreur)
		$L_Erreur:=4DLB_File_Drop_to_rec ($P_Subform_container->;->$T_Text_error)
		
		If ($L_Erreur#1)
			ALERT($T_Text_error)
		Else 
			CALL SUBFORM CONTAINER(call_drop)
		End if 
	End if 

</code 4D>

4DLB_File_Drop_to_rec

<code 4D>

C_OBJECT($1;$O_Target)
$O_Target:=$1
C_POINTER($2;$P_Message)
$P_Message:=$2

C_LONGINT($L_MyError)
$L_MyError:=1

C_BOOLEAN($B_Allow_RO)
$B_Allow_RO:=$O_Target.allow_read_state
  // #20200313-1
If ($O_Target.header#Null) & ($O_Target.target#Null)  // on veut importer un fichier
	
	ARRAY POINTER($rP_FieldTarget;0)
	ARRAY TEXT($rT_FileHeader;0)
	OB GET ARRAY($O_Target;"header";$rT_FileHeader)
	OB GET ARRAY($O_Target;"target";$rP_FieldTarget)
	
	C_BOOLEAN($B_RO)
	$B_RO:=Read only state(Table(Table($rP_FieldTarget{1}))->)
	
	
	C_TEXT($T_Reject)
	$T_Reject:=""
	If (OB Is defined($O_Target;"reject"))
		$T_Reject:=OB Get($O_Target;"reject";Is text)
	End if 
	
	
	ARRAY TEXT($rT_Path;0)
	  // 1 on a bien depose un fichier 1 = "com.4d.private.file.url"
	
	C_LONGINT($i;$L_Length)
	$i:=0
	$L_Length:=0
	
	Repeat 
		
		$i:=$i+1
		C_TEXT($T_Path)
		$T_Path:=Get file from pasteboard($i)
		
		$L_Length:=Length($T_Path)
		If ($L_Length>0)
			APPEND TO ARRAY($rT_Path;$T_Path)
		End if 
	Until ($L_Length=0)
	
	
	Case of 
		: ($T_Reject#"")
			$L_MyError:=-9
		: ($B_RO) & ($B_Allow_RO=False)  // on interdit un drop en read-only
			$L_MyError:=-7
		: (Size of array($rT_Path)>1)
			$L_MyError:=-2
		Else 
			
			C_TEXT($T_Content)
			$T_Content:=Document to text($rT_Path{1};"UTF-8";Document with native format)
			
			ARRAY TEXT($rT_Record;0)
			LB_Split_string (->$rT_Record;"\r(\n|)";$T_Content)
			
			
			  // test du header
			C_TEXT($T_Header)
			$T_Header:=LB_Splitted2string (->$rT_FileHeader;"\t")
			
			C_LONGINT($L_Avec_alerte)
			$L_Avec_alerte:=0  // sans alerte
			If (OB Is defined($O_Target;"alerte"))
				$L_Avec_alerte:=OB Get($O_Target;"alerte";Is longint)
			End if 
			
			ASSERT(($L_Avec_alerte=0) | ($L_Avec_alerte=1);"Alerte mal configuree")
			
			C_LONGINT($L_Import)
			$L_Import:=1  // 1 on continue l'import
			If ($L_Avec_alerte=1)
				CONFIRM("Importer le fichier:\r"+$rT_Path{1})
				$L_Import:=OK
			End if 
			
			Case of 
				: ($L_Import=0)
					$L_MyError:=-5
				: (Size of array($rT_Record)=0)
					$L_MyError:=-6
				: ($rT_Record{1}#$T_Header)
					$L_MyError:=-4
				Else 
					
					C_LONGINT($L_Action)
					$L_Action:=OB Get($O_Target;"action";Is longint)  // 1 = demander 2 = remplacer 3 = ajouter
					If ($L_Action=1)
						$L_Action:=Num(Request("Ajouter (3) ou remplacer (2) les enregistrements"))
					End if 
					
					If ($L_Action#2) & ($L_Action#3)
						$L_MyError:=-3
					Else 
						
						ARRAY LONGINT($rL_RecNumToPressepapiers;0)  // pour transferer a la base hote
						
						START TRANSACTION
						
						C_LONGINT($i)
						For ($i;2;Size of array($rT_Record))  // $i=2 : on zappe l'entete
							
							ARRAY TEXT($rT_Field;0)
							LB_Split_string (->$rT_Field;"\t";$rT_Record{$i})
							
							If (Size of array($rT_Field)>=Size of array($rP_FieldTarget))
								
								  // si le nombre de colonnes dans le fichier texte est au moins egal au nombre de champ
								  // Les colonnes supplementaires du fichier texte sont ignorees
								
								C_POINTER($P_Table)
								$P_Table:=Table(Table($rP_FieldTarget{1}))  // tous les champs cibles sont de la meme table
								
								ASSERT(Is table number valid(Table($P_Table));"La table n'existe pas")
								
								If ($i=2)
									If ($L_Action=2)  //remplacer (2)
										  // on verrouillera avant d'appeler la fonction
										C_BOOLEAN($B_RO)
										$B_RO:=Read only state($P_Table->)
										READ WRITE($P_Table->)
										ALL RECORDS($P_Table->)
										DELETE SELECTION($P_Table->)
										If ($B_RO)
											READ ONLY($P_Table->)
										End if 
									End if 
								End if 
								
								CREATE RECORD($P_Table->)
								C_LONGINT($j)
								For ($j;1;Size of array($rP_FieldTarget))
									
									ASSERT(Is field number valid($P_Table;Field($rP_FieldTarget{$j}));"Le champ n'existe pas")
									
									C_LONGINT($L_Type)
									$L_Type:=Type($rP_FieldTarget{$j}->)
									Case of 
										: ($L_Type=Is date)
											
											$rP_FieldTarget{$j}->:=Date($rT_Field{$j})
											
										: ($L_Type=Is real) | ($L_Type=Is longint) | ($L_Type=Is integer)
											
											$rP_FieldTarget{$j}->:=Num($rT_Field{$j})
											
										: ($L_Type=Is boolean)
											
											If ($rT_Field{$j}="TRUE") | ($rT_Field{$j}="1") | ($rT_Field{$j}="VRAI")
												$rP_FieldTarget{$j}->:=True
											Else 
												$rP_FieldTarget{$j}->:=False
											End if 
											
										: ($L_Type=Is time)
											
											$rP_FieldTarget{$j}->:=Time($rT_Field{$j})
											
										: ($L_Type=Is alpha field) | ($L_Type=Is text)
											
											$rP_FieldTarget{$j}->:=$rT_Field{$j}
										Else 
											ALERT("champ non defini")
									End case 
								End for 
								SAVE RECORD($P_Table->)
								APPEND TO ARRAY($rL_RecNumToPressepapiers;Record number($P_Table->))
							End if 
						End for 
						VALIDATE TRANSACTION
						
						ALL RECORDS($P_Table->)
						
						C_BLOB($X_BLOB)
						VARIABLE TO BLOB($rL_RecNumToPressepapiers;$X_BLOB)
						CLEAR PASTEBOARD
						APPEND DATA TO PASTEBOARD("DROP";$X_BLOB)
					End if 
			End case 
	End case 
	
End if 

</code 4D>

Thanks Bertrand,

I will keep the code as inspiration for dropping onto subforms.
Much appreciated.

For the ordering of lines I found that following code in the Listbox OM
caused the Self or Object get Pointer(Object Current) to point at the
field that I was redirecting to (edit item) in the on getting focus instead of what
I was expecting, namely the ListBox itself.

: ($formEvent_l=On Getting Focus)
If ($row=0)
GOTO OBJECT(*;$objName)
GOTO SELECTED RECORD([TOMtrl];1)
EDIT ITEM([TOMtrl]AntalLev;1)
End if

I can live without this code, but the purpose was to help the user to the first entry area
of the first row, if he tabbed to the listbox or clicked below the rows.

Best Regards
Magnus