473,416 Members | 1,564 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,416 software developers and data experts.

drag and drop from a DataGrid

I have a slight problem implementing 'drag and drop' from a datagrid
to a tree-view. I have pasted my code below. Someone please advice me
on what to do...pretty blur right now.

==code==

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;

namespace DragDropTry
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.DataGrid grdSearch;
private System.Windows.Forms.TreeView tvMain;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.grdSearch = new System.Windows.Forms.DataGrid();
this.tvMain = new System.Windows.Forms.TreeView();
((System.ComponentModel.ISupportInitialize)(this.g rdSearch)).BeginInit();
this.SuspendLayout();
//
// grdSearch
//
this.grdSearch.DataMember = "";
this.grdSearch.HeaderForeColor =
System.Drawing.SystemColors.ControlText;
this.grdSearch.Location = new System.Drawing.Point(216, 72);
this.grdSearch.Name = "grdSearch";
this.grdSearch.Size = new System.Drawing.Size(336, 216);
this.grdSearch.TabIndex = 0;
this.grdSearch.MouseUp += new
System.Windows.Forms.MouseEventHandler(this.grdSea rch_MouseUp_1);
this.grdSearch.DragOver += new
System.Windows.Forms.DragEventHandler(this.grdSear ch_DragOver);
this.grdSearch.DragEnter += new
System.Windows.Forms.DragEventHandler(this.grdSear ch_DragEnter);
//
// tvMain
//
this.tvMain.ImageIndex = -1;
this.tvMain.Location = new System.Drawing.Point(16, 72);
this.tvMain.Name = "tvMain";
this.tvMain.SelectedImageIndex = -1;
this.tvMain.Size = new System.Drawing.Size(176, 168);
this.tvMain.TabIndex = 1;
this.tvMain.DragEnter += new
System.Windows.Forms.DragEventHandler(this.tvMain_ DragEnter);
this.tvMain.ItemDrag += new
System.Windows.Forms.ItemDragEventHandler(this.tvM ain_ItemDrag);
this.tvMain.DragDrop += new
System.Windows.Forms.DragEventHandler(this.tvMain_ DragDrop);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(576, 454);
this.Controls.Add(this.tvMain);
this.Controls.Add(this.grdSearch);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.MouseUp += new
System.Windows.Forms.MouseEventHandler(this.grdSea rch_MouseUp_1);
this.DragOver += new
System.Windows.Forms.DragEventHandler(this.grdSear ch_DragOver);
this.DragDrop += new
System.Windows.Forms.DragEventHandler(this.tvMain_ DragDrop);
this.DragEnter += new
System.Windows.Forms.DragEventHandler(this.tvMain_ DragEnter);
((System.ComponentModel.ISupportInitialize)(this.g rdSearch)).EndInit();
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Load(object sender, System.EventArgs e)
{
DataSet ds = new DataSet();
ds.ReadXml("searchResult.xml");

DataView dv = new DataView();
dv = ds.Tables[0].DefaultView;

grdSearch.DataSource = dv;
grdSearch.TableStyles.Clear();

DataGridTableStyle ts1 = new DataGridTableStyle();
ts1.MappingName = dv.Table.TableName;

System.Windows.Forms.DataGridBoolColumn col1 = new
DataGridBoolColumn();
col1.MappingName = "text";
col1.HeaderText = "";
col1.Width = 30;
col1.AllowNull = false;
col1.FalseValue = "False";
col1.TrueValue = "True";

System.Windows.Forms.DataGridTextBoxColumn col2 = new
DataGridTextBoxColumn();
col2.MappingName = "rec";
col2.HeaderText = "Rec";
col2.Width = 30;

System.Windows.Forms.DataGridTextBoxColumn col3 = new
DataGridTextBoxColumn();
col3.MappingName = "title";
col3.HeaderText = "title";
col3.Width = 220;

ts1.GridColumnStyles.Add(col1);
ts1.GridColumnStyles.Add(col2);
ts1.GridColumnStyles.Add(col3);

grdSearch.TableStyles.Add(ts1);

tvMain.BeginUpdate();
tvMain.Nodes.Add(new TreeNode("AA"));
TreeNode tnn = new TreeNode("Query_" +
System.DateTime.Now.ToString("MMM-dd-yyyy") + "_" +
System.DateTime.Now.ToShortTimeString() + " " + "aaa");
tvMain.Nodes[0].Nodes.Add(tnn);
tvMain.Nodes[0].Expand();
tvMain.EndUpdate();

//grdSearch.MouseUp += new
MouseEventHandler(grdSearch_MouseUp(sender,e));
this.grdSearch.MouseUp += new
System.Windows.Forms.MouseEventHandler(this.grdSea rch_MouseUp_1);
this.grdSearch.DragEnter += new
System.Windows.Forms.DragEventHandler(this.grdSear ch_DragEnter);
this.grdSearch.DragOver += new
System.Windows.Forms.DragEventHandler(this.grdSear ch_DragOver);
this.tvMain.DragDrop += new
System.Windows.Forms.DragEventHandler(this.tvMain_ DragDrop);
this.tvMain.DragEnter += new
System.Windows.Forms.DragEventHandler(this.tvMain_ DragEnter);
this.tvMain.ItemDrag += new
System.Windows.Forms.ItemDragEventHandler(this.tvM ain_ItemDrag);

//tvMain.Nodes[0].Nodes.Add(new TreeNode("Query_" +
System.DateTime.Now.ToShortDateString() + "@" +
System.DateTime.Now.ToShortTimeString() + "

}

private void grdSearch_MouseUp_1(object sender,
System.Windows.Forms.MouseEventArgs e)
{
try
{
DataRowView drvSelectedGridRow =
(DataRowView)grdSearch.BindingContext
[grdSearch.DataSource,grdSearch.DataMember].Current;

string sNodeName =
drvSelectedGridRow["title"].ToString().Trim();
string sSnpID = drvSelectedGridRow[""].ToString().Trim();

TreeNode tnWrHistoryRootNode = new TreeNode(sNodeName);
tnWrHistoryRootNode.Tag = sSnpID;

string dataSource;
dataSource = grdSearch.DataSource.ToString();
grdSearch.DoDragDrop(tnWrHistoryRootNode,DragDropE ffects.Move);
}
catch{}
}

private void grdSearch_DragEnter (object sender,
System.Windows.Forms.DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}

private void grdSearch_DragOver(object sender,
System.Windows.Forms.DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}

private void tvMain_DragDrop (object sender,
System.Windows.Forms.DragEventArgs e)
{
TreeNode tnNewNode = new TreeNode();

if(e.Data.GetDataPresent("System.Windows.Forms.Tre eNode",false))
{
Point pt;
TreeNode tnDestinationNode = new TreeNode();
pt = tvMain.PointToClient(new Point(e.X, e.Y));
tnDestinationNode = tvMain.GetNodeAt(pt);
tnNewNode =
(TreeNode) e.Data.GetData("System.Windows.Forms.TreeNode");

int iNodeCount = tvMain.GetNodeCount(false);

if(iNodeCount == 0)
{
this.tvMain.Nodes.Add(tnNewNode);
}
else
{
if(!tnDestinationNode.Equals(tnNewNode))
{
tnDestinationNode.Nodes.Add((TreeNode) tnNewNode.Clone());
try
{
tnNewNode.Remove();
}
catch{}
tvMain.ExpandAll();
}
}
}
}

private void tvMain_DragEnter (object sender,
System.Windows.Forms.DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}

private void tvMain_ItemDrag (object sender,
System.Windows.Forms.ItemDragEventArgs e)
{
DoDragDrop(e.Item, DragDropEffects.Move);
}

}
}
Nov 16 '05 #1
3 10366
hi
here is a working drag and drop example , form two lists whoever , try to
look at it , hope it helps
using System;
using System.Drawing;
using System.Windows.Forms;

namespace Snip_DragNDrop
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.ListBox ListDragSource;
private System.Windows.Forms.ListBox ListDragTarget;
private System.Windows.Forms.CheckBox UseCustomCursorsCheck;
private System.Windows.Forms.Label DropLocationLabel;

private int indexOfItemUnderMouseToDrag;
private int indexOfItemUnderMouseToDrop;

private Rectangle dragBoxFromMouseDown;
private Point screenOffset;

private Cursor MyNoDropCursor;
private Cursor MyNormalCursor;

/// The main entry point for the application.
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

public Form1()
{
this.ListDragSource = new System.Windows.Forms.ListBox();
this.ListDragTarget = new System.Windows.Forms.ListBox();
this.UseCustomCursorsCheck = new System.Windows.Forms.CheckBox();
this.DropLocationLabel = new System.Windows.Forms.Label();

this.SuspendLayout();

// ListDragSource
this.ListDragSource.AllowDrop = true;
this.ListDragSource.Items.AddRange(new object[] {"one", "two", "three",
"four",
"five", "six", "seven", "eight",
"nine", "ten"});
this.ListDragSource.Location = new System.Drawing.Point(10, 17);
this.ListDragSource.Size = new System.Drawing.Size(120, 225);
this.ListDragSource.MouseDown += new
System.Windows.Forms.MouseEventHandler(this.ListDr agSource_MouseDown);
this.ListDragSource.QueryContinueDrag += new
System.Windows.Forms.QueryContinueDragEventHandler (this.ListDragSource_Query
ContinueDrag);
this.ListDragSource.MouseUp += new
System.Windows.Forms.MouseEventHandler(this.ListDr agSource_MouseUp);
this.ListDragSource.MouseMove += new
System.Windows.Forms.MouseEventHandler(this.ListDr agSource_MouseMove);
this.ListDragSource.GiveFeedback += new
System.Windows.Forms.GiveFeedbackEventHandler(this .ListDragSource_GiveFeedba
ck);
this.ListDragSource.DragDrop += new
System.Windows.Forms.DragEventHandler(this.ListDra gTarget_DragDrop);
// ListDragTarget
this.ListDragTarget.AllowDrop = true;
this.ListDragTarget.Location = new System.Drawing.Point(154, 17);
this.ListDragTarget.Size = new System.Drawing.Size(120, 225);
//this.ListDragTarget.DragOver += new
System.Windows.Forms.DragEventHandler(this.ListDra gTarget_DragOver);
this.ListDragTarget.DragDrop += new
System.Windows.Forms.DragEventHandler(this.ListDra gTarget_DragDrop);
this.ListDragTarget.DragEnter += new
System.Windows.Forms.DragEventHandler(this.ListDra gTarget_DragEnter);
//this.ListDragTarget.DragLeave += new
System.EventHandler(this.ListDragTarget_DragLeave) ;

// UseCustomCursorsCheck
this.UseCustomCursorsCheck.Location = new System.Drawing.Point(10, 243);
this.UseCustomCursorsCheck.Size = new System.Drawing.Size(137, 24);
this.UseCustomCursorsCheck.Text = "Use Custom Cursors";

// DropLocationLabel
this.DropLocationLabel.Location = new System.Drawing.Point(154, 245);
this.DropLocationLabel.Size = new System.Drawing.Size(137, 24);
this.DropLocationLabel.Text = "None";

// Form1
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 270);
this.Controls.AddRange(new System.Windows.Forms.Control[]
{this.ListDragSource,
this.ListDragTarget, this.UseCustomCursorsCheck,
this.DropLocationLabel});
this.Text = "Drag and Drop Example";

this.ResumeLayout(false);

}

private void ListDragSource_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
// Get the index of the item the mouse is below.
indexOfItemUnderMouseToDrag = ListDragSource.IndexFromPoint(e.X, e.Y);

if (indexOfItemUnderMouseToDrag != ListBox.NoMatches)
{

// Remember the point where the mouse down occurred. The DragSize
indicates
// the size that the mouse can move before a drag event should be
started.
Size dragSize = SystemInformation.DragSize;

// Create a rectangle using the DragSize, with the mouse position being
// at the center of the rectangle.
dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width
/2),
e.Y - (dragSize.Height /2)), dragSize);
}
else
// Reset the rectangle if the mouse is not over an item in the ListBox.
dragBoxFromMouseDown = Rectangle.Empty;

}

private void ListDragSource_MouseUp(object sender,
System.Windows.Forms.MouseEventArgs e)
{
// Reset the drag rectangle when the mouse button is raised.
dragBoxFromMouseDown = Rectangle.Empty;
}

private void ListDragSource_MouseMove(object sender,
System.Windows.Forms.MouseEventArgs e)
{

if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{

// If the mouse moves outside the rectangle, start the drag.
if (dragBoxFromMouseDown != Rectangle.Empty &&
!dragBoxFromMouseDown.Contains(e.X, e.Y))
{

// Create custom cursors for the drag-and-drop operation.
try
{
MyNormalCursor = new Cursor("3dwarro.cur");
MyNoDropCursor = new Cursor("3dwno.cur");

}
catch
{
// An error occurred while attempting to load the cursors, so use
// standard cursors.
UseCustomCursorsCheck.Checked = false;
}
finally
{

// The screenOffset is used to account for any desktop bands
// that may be at the top or left side of the screen when
// determining when to cancel the drag drop operation.
screenOffset = SystemInformation.WorkingArea.Location;

// Proceed with the drag and drop, passing in the list item.

DragDropEffects dropEffect =
ListDragSource.DoDragDrop(ListDragSource.Items[indexOfItemUnderMouseToDrag],
DragDropEffects.All | DragDropEffects.Link);

// If the drag operation was a move then remove the item.
if (dropEffect == DragDropEffects.Move)
{
ListDragSource.Items.RemoveAt(indexOfItemUnderMous eToDrag);

// Selects the previous item in the list as long as the list has an
item.
if (indexOfItemUnderMouseToDrag > 0)
ListDragSource.SelectedIndex = indexOfItemUnderMouseToDrag -1;

else if (ListDragSource.Items.Count > 0)
// Selects the first item.
ListDragSource.SelectedIndex =0;
}

// Dispose of the cursors since they are no longer needed.
if (MyNormalCursor != null)
MyNormalCursor.Dispose();

if (MyNoDropCursor != null)
MyNoDropCursor.Dispose();
}
}
}
}
private void ListDragSource_GiveFeedback(object sender,
System.Windows.Forms.GiveFeedbackEventArgs e)
{
// Use custom cursors if the check box is checked.
if (UseCustomCursorsCheck.Checked)
{

// Sets the custom cursor based upon the effect.
e.UseDefaultCursors = false;
if ((e.Effect & DragDropEffects.Move) == DragDropEffects.Move)
Cursor.Current = MyNormalCursor;
else
Cursor.Current = MyNoDropCursor;
}

}
private void ListDragTarget_DragOver(object sender,
System.Windows.Forms.DragEventArgs e)
{

// Determine whether string data exists in the drop data. If not, then
// the drop effect reflects that the drop cannot occur.
if (!e.Data.GetDataPresent(typeof(System.String)))
{

e.Effect = DragDropEffects.None;
DropLocationLabel.Text = "None - no string data.";
return;
}

// Set the effect based upon the KeyState.
if ((e.KeyState & (8+32)) == (8+32) &&
(e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link)
{
// KeyState 8 + 32 = CTL + ALT

// Link drag and drop effect.
e.Effect = DragDropEffects.Link;

}
else if ((e.KeyState & 32) == 32 &&
(e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link)
{

// ALT KeyState for link.
e.Effect = DragDropEffects.Link;

}
else if ((e.KeyState & 4) == 4 &&
(e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
{

// SHIFT KeyState for move.
e.Effect = DragDropEffects.Move;

}
else if ((e.KeyState & 8) == 8 &&
(e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
{

// CTL KeyState for copy.
e.Effect = DragDropEffects.Copy;

}
else if ((e.AllowedEffect & DragDropEffects.Move) ==
DragDropEffects.Move)
{

// By default, the drop action should be move, if allowed.
e.Effect = DragDropEffects.Move;

}
else
e.Effect = DragDropEffects.None;

// Get the index of the item the mouse is below.

// The mouse locations are relative to the screen, so they must be
// converted to client coordinates.

indexOfItemUnderMouseToDrop =
ListDragTarget.IndexFromPoint(ListDragTarget.Point ToClient(new
Point(e.X, e.Y)));

// Updates the label text.
if (indexOfItemUnderMouseToDrop != ListBox.NoMatches)
{

DropLocationLabel.Text = "Drops before item #" +
(indexOfItemUnderMouseToDrop + 1);
}
else
DropLocationLabel.Text = "Drops at the end.";

}
private void ListDragTarget_DragDrop(object sender,
System.Windows.Forms.DragEventArgs e)
{
// Ensure that the list item index is contained in the data.
if (e.Data.GetDataPresent(typeof(System.String)))
{

Object item = (object)e.Data.GetData(typeof(System.String));

// Perform drag and drop, depending upon the effect.
if (e.Effect == DragDropEffects.Copy ||
e.Effect == DragDropEffects.Move)
{

// Insert the item.
if (indexOfItemUnderMouseToDrop != ListBox.NoMatches)
ListDragTarget.Items.Insert(indexOfItemUnderMouseT oDrop, item);
else
ListDragTarget.Items.Add(item);

}
}
// Reset the label text.
DropLocationLabel.Text = "None";
}
private void ListDragSource_QueryContinueDrag(object sender,
System.Windows.Forms.QueryContinueDragEventArgs e)
{
// Cancel the drag if the mouse moves off the form.
ListBox lb = sender as ListBox;

if (lb != null)
{

Form f = lb.FindForm();

// Cancel the drag if the mouse moves off the form. The screenOffset
// takes into account any desktop bands that may be at the top or left
// side of the screen.
if (((Control.MousePosition.X - screenOffset.X) < f.DesktopBounds.Left)
||
((Control.MousePosition.X - screenOffset.X) > f.DesktopBounds.Right) ||
((Control.MousePosition.Y - screenOffset.Y) < f.DesktopBounds.Top) ||
((Control.MousePosition.Y - screenOffset.Y) > f.DesktopBounds.Bottom))
{

e.Action = DragAction.Cancel;
}
}
}
private void ListDragTarget_DragEnter(object sender,
System.Windows.Forms.DragEventArgs e)
{
// Reset the label text.
DropLocationLabel.Text = "None";
}
private void ListDragTarget_DragLeave(object sender, System.EventArgs e)
{
// Reset the label text.
DropLocationLabel.Text = "None";
}
}
}

Mohamed Mahfouz
MEA Developer Support Center
ITworx on behalf of Microsoft EMEA GTSC

Nov 16 '05 #2

Hi..
Thanks a lot for the working example. My code works now.
Rgds,
Ajay
*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Nov 16 '05 #3
Great :)
Mohamed Mahfouz
MEA Developer Support Center
ITworx on behalf of Microsoft EMEA GTSC

Nov 16 '05 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: NewSun | last post by:
How can i drag a datarow from a datagrid to a other control? e.g. Drag a datarow from a datagrid to a TextBox,Then display one colnumn' value of the datarow . Or Drag a cell's value to a controll...
5
by: Clyde | last post by:
I am trying to implement the user feedback provided by Windows Explorer when draggng a filename from one place to another. I have the drag and drop action worked out but have had no luck in...
3
by: Benny | last post by:
Hello Experts, Currently I am working on a windows-based project using asp.net with C#. One of the project tasks is to create a scheduler. For example I have two datagrids with one rows each:...
1
by: Adam Klobukowski | last post by:
Hello I'm trying to do basic drag and drop from DataGrid control. The problem is that after I start DoDragDrop, items in DataGrid will become unselected. I wish them to remian selected. I hav...
2
by: Ken Loomis | last post by:
Hello: I have spent two days on drag and drop now and I'm getting no where. I am trying to drag an item from a listbox and load it into a datagrid (actually a child of the datagrid, but I'll be...
4
by: sonu | last post by:
I want to drag rows from one datagrid and drop that rows in other datagrid. when we drop rows into 2nd datagrid the rows will be deleted from first datagrid i want this functionality in...
3
by: Demetri | last post by:
If one were to develop a web server control (web control library), which enhances the datagrid by implementing a class that inherits from the DataGrid class, and give it drag and drop capability. ...
1
by: sunil | last post by:
Hi there, I am trying to implement the task in which i have a datagrid filled with data extracted from the database and a combobox in which i have populated some data. Now what i want to do is...
6
by: Neelesh2007 | last post by:
Hi to all. I m having project with VB6.0 as front End and Access-2003 as backend. In one of my code I m having Datagrid with ADODC as datasource. I want Drag & Drop Functionality in Datagrid as like...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.