4. Moving an Item

The move subcommand was extended in Tablelist release 5.2 to support moving an item outside its parent programmatically, and version 5.3 added support for performing this interactively, too.  The subcommand now has two forms:

pathName move sourceIndex targetIndex
pathName move sourceIndex targetParentNodeIndex targetChildIndex

The first form of the command moves the item indicated by sourceIndex just before the one given by targetIndex if the tablelist's state is not disabled.  If targetIndex equals the nunber of items or is specified as end then the source item is moved after the last one.  The item specified by targetIndex must have the same parent as the one given by sourceIndex, or else it must be the item just below the last descendant of the source node's parent.

The command's second form moves the item indicated by sourceIndex just before the node having the parent indicated by targetParentNodeIndex and the index targetChildIndex in the parent's list of children if the tablelist's state is not disabledtargetChildIndex must be a number or end; if it equals the number of children of the target parent node or is specified as end then the source item is moved after the target parent node's last child.

Both forms of the command preserve the node hierarchy under the source item, by moving its descendants accordingly.  The return value is an empty string.

According to this description, the interactive row move operation now supports dragging an item outside its parent and dropping it under another item as a child.  During this local drag & drop, the new item position (if any) is visualized with the aid of a gap placed before the target row or a bar placed inside the latter (depending on the current mouse position), indicating whether the source item would be moved before this row or become a child of it.

Depending on the current mouse position during the local drag & drop, there can be a corresponding potential target row or not.  For instance, a tree item cannot become a sibling of one of its descendants, and not all items might be allowed to have children or to become top-level ones.  To decide whether the row corresponding to the y-coordinate of the current mouse position represents a valid potential target, the Tablelist code first checks whether moving the source item before that row or making it a child of the latter is allowed from the point of view of the general tree structure.  If this is the case and the move operation would change the source item's parent, then the command specified by the -acceptchildcommand configuration option (introduced in Tablelist 5.3) is used to decide whether to allow to move the dragged item to the intended target position:  If the value of this option is an empty string then the move operation is allowed (and the target position is visualized as described above).  Otherwise the command is concatenated with the name of the tablelist widget, the node index of the would-be new parent node, and the row index of the dragged item, the resulting script is evaluated in the global scope, and the return value (which must be a boolean) will determine whether to allow to move the source item to the current mouse position.

The following example is a slightly modified and extended version of the demo script dirViewer_tile.tcl:

proc displayContents dir {
    #
    # Create a scrolled tablelist widget with 3 dynamic-
    # width columns and interactive sort capability
    #
    set tf .tf
    ttk::frame $tf -class ScrollArea
    set tbl $tf.tbl
    set vsb $tf.vsb
    set hsb $tf.hsb
    tablelist::tablelist $tbl \
	-columns {0 "Name"	    left
		  0 "Size"	    right
		  0 "Date Modified" left} \
	-expandcommand expandCmd -collapsecommand collapseCmd \
	-xscrollcommand [list $hsb set] -yscrollcommand [list $vsb set] \
	-movablecolumns no -showseparators yes -height 18 -width 80 \
        -acceptchildcommand acceptChildCmd -movablerows true -selectmode single

    . . .

    #
    # Populate the tablelist with the contents of the given directory
    #
    $tbl sortbycolumn 0
    putContents $dir $tbl root
}

The procedure acceptChildCmd, specified as the value of the -acceptchildcommand configuration option, makes sure that the top-level items remain restricted to the ones displaying volumes and only directories will accept child items:

proc acceptChildCmd {tbl targetParentNodeIdx sourceRow} {
    if {[string compare $targetParentNodeIdx "root"] == 0} {
	#
	# Allow only volumes as top-level items
	#
	return [expr {[$tbl depth $sourceRow] == 1}]
    } else {
	#
	# Allow only directories as parent items
	#
	return [$tbl hasrowattrib $targetParentNodeIdx pathName]
    }
}

Contents