2 // DragAndDropTest.cs: tests for general drag and drop operations.
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 // Carlos Alberto Cortez <ccortes@novell.com>
26 // (C) 2008 Novell, Inc. (http://www.novell.com)
28 // NOTE: Since this is an interactive set of tests, I didn't include it as part
29 // of the MWF test suite build. You will need to build it by yourself and then
30 // use nunit-console, since the nunit GUI has some problems with DND (basically a COM
36 using System.Reflection;
37 using System.Windows.Forms;
39 using NUnit.Framework;
41 namespace MonoTests.System.Windows.Forms
44 public class DragAndDropTest
47 public void DropCancelledByEsc ()
49 DNDForm form = new DNDForm ();
50 form.Text = MethodBase.GetCurrentMethod ().Name;
51 form.InstructionsText =
52 "Instructions:" + Environment.NewLine + Environment.NewLine +
53 "1. Click with left button on the control on the left, holding it." + Environment.NewLine +
54 "2. Move mouse pointer to the control in the right. " + Environment.NewLine +
55 "3. While still pressing the mouse button, press ESC." + Environment.NewLine +
57 form.DragControl.DragData = "hello";
58 form.DragControl.AllowedEffects = DragDropEffects.All;
59 form.DropControl.DropEffect = DragDropEffects.Copy;
61 Application.Run (form);
63 Assert.AreEqual (DragDropEffects.None, form.DragControl.PerformedEffect, "A1");
64 Assert.AreEqual (1, form.DropControl.EnterFiredCount, "A2");
65 Assert.AreEqual (1, form.DropControl.LeaveFiredCount, "A3");
66 Assert.AreEqual (0, form.DropControl.DropFiredCount, "A4");
70 public void DropCancelledByQuery ()
72 DNDForm form = new DNDForm ();
73 form.Text = MethodBase.GetCurrentMethod ().Name;
74 form.InstructionsText =
75 "Instructions:" + Environment.NewLine + Environment.NewLine +
76 "1. Click with left button on the control on the left, holding it." + Environment.NewLine +
77 "2. Move mouse pointer to the control in the right. " + Environment.NewLine +
78 "3. The drop should be cancelled after some seconds." + Environment.NewLine +
80 form.DragControl.DragData = "hello";
81 form.DragControl.AllowedEffects = DragDropEffects.All;
82 form.DropControl.DropEffect = DragDropEffects.Copy;
85 form.DragControl.QueryContinueDrag += new QueryContinueDragEventHandler (DragControl_QueryContinueDrag);
87 Application.Run (form);
89 Assert.AreEqual (DragDropEffects.None, form.DragControl.PerformedEffect, "A1");
90 Assert.AreEqual (1, form.DropControl.EnterFiredCount, "A2");
91 Assert.AreEqual (1, form.DropControl.LeaveFiredCount, "A3");
92 Assert.AreEqual (0, form.DropControl.DropFiredCount, "A4");
95 int query_counter = 0;
97 void DragControl_QueryContinueDrag (object sender, QueryContinueDragEventArgs e)
99 DragDropControl c = (DragDropControl)sender;
100 DNDForm f = (DNDForm)c.Parent;
101 if (f.DropControl.EnterFiredCount == 0)
104 // Cancel dnd operation AFTER we have reached the drop control
105 if (query_counter++ >= 32)
106 e.Action = DragAction.Cancel;
110 public void EventsAfterDrop ()
112 DNDForm form = new DNDForm ();
113 form.Text = MethodBase.GetCurrentMethod ().Name;
114 form.InstructionsText =
115 "Instructions:" + Environment.NewLine + Environment.NewLine +
116 "1. Click with left button on the control on the left, holding it." + Environment.NewLine +
117 "2. Move mouse pointer to the control in the right. " + Environment.NewLine +
118 "3. Move the pointer around and then release the mouse button." + Environment.NewLine +
119 "4. Close the form.";
120 form.DragControl.DragData = "hello";
121 form.DragControl.AllowedEffects = DragDropEffects.All;
122 form.DropControl.DropEffect = DragDropEffects.Copy;
124 // These should clear the event counters AND
125 // thus the event counters should remain at 0 after drop occurred
126 // AND we should get any MouseUp event.
127 mouse_up_counter = 0;
128 form.DropControl.DragDrop += new DragEventHandler (DropControl_DragDrop);
129 form.DropControl.MouseUp += new MouseEventHandler (DropControl_MouseUp);
131 Application.Run (form);
133 Assert.AreEqual (DragDropEffects.Copy, form.DragControl.PerformedEffect, "A1");
134 Assert.AreEqual (0, form.DropControl.EnterFiredCount, "A2");
135 Assert.AreEqual (0, form.DropControl.LeaveFiredCount, "A3");
136 Assert.AreEqual (0, form.DropControl.DropFiredCount, "A4");
137 Assert.AreEqual (0, form.DropControl.DragOverFiredCount, "A5");
138 Assert.AreEqual (0, mouse_up_counter, "A6");
141 void DropControl_DragDrop (object sender, DragEventArgs e)
143 DragDropControl c = (DragDropControl)sender;
144 c.ResetEventCounters ();
147 int mouse_up_counter;
149 void DropControl_MouseUp (object sender, MouseEventArgs e)
155 public void SimpleDragDrop ()
157 DNDForm form = new DNDForm ();
158 form.Text = MethodBase.GetCurrentMethod ().Name;
159 form.InstructionsText =
160 "Instructions:" + Environment.NewLine + Environment.NewLine +
161 "1. Click with left button on the control on the left, holding it." + Environment.NewLine +
162 "2. Move mouse pointer to the control in the right. " + Environment.NewLine +
163 "3. Drop on the right control." + Environment.NewLine +
164 "4. Close the form.";
165 form.DragControl.DragData = "SimpleDragDropMessage";
166 form.DragControl.AllowedEffects = DragDropEffects.Copy;
167 form.DropControl.DropEffect = DragDropEffects.Copy;
169 Application.Run (form);
171 Assert.AreEqual (DragDropEffects.Copy, form.DragControl.PerformedEffect, "A1");
172 Assert.IsTrue (form.DropControl.Data != null, "A2");
173 Assert.AreEqual (true, form.DropControl.Data.GetDataPresent (typeof (string)), "A3");
174 Assert.AreEqual ("SimpleDragDropMessage", form.DropControl.Data.GetData (typeof (string)), "A4");
178 public void SimpleLeave ()
180 DNDForm form = new DNDForm ();
181 form.Text = MethodBase.GetCurrentMethod ().Name;
182 form.InstructionsText =
183 "Instructions:" + Environment.NewLine + Environment.NewLine +
184 "1. Click with left button on the control on the left, holding it." + Environment.NewLine +
185 "2. Move mouse pointer to the control in the right. " + Environment.NewLine +
186 "3. Move the mouse pointer outside the drop control." + Environment.NewLine +
187 "5. Release mouse button." + Environment.NewLine +
188 "6. Close the form.";
189 form.DragControl.DragData = "hello";
190 form.DragControl.AllowedEffects = DragDropEffects.All;
191 form.DropControl.DropEffect = DragDropEffects.Copy;
193 Application.Run (form);
195 Assert.AreEqual (DragDropEffects.None, form.DragControl.PerformedEffect, "A1");
196 Assert.AreEqual (1, form.DropControl.EnterFiredCount, "A2");
197 Assert.AreEqual (1, form.DropControl.LeaveFiredCount, "A3");
198 Assert.AreEqual (0, form.DropControl.DropFiredCount, "A4");
202 public void NotAllowedDropEffect ()
204 DNDForm form = new DNDForm ();
205 form.Text = MethodBase.GetCurrentMethod ().Name;
206 form.InstructionsText =
207 "Instructions:" + Environment.NewLine + Environment.NewLine +
208 "1. Click with left button on the control on the left, holding it." + Environment.NewLine +
209 "2. Move mouse pointer to the control in the right. " + Environment.NewLine +
210 "3. Drop on the right control." + Environment.NewLine +
211 "4. Close the form.";
212 form.DragControl.DragData = "SimpleDragDropMessage";
213 form.DragControl.AllowedEffects = DragDropEffects.Copy;
214 form.DropControl.DropEffect = DragDropEffects.Move;
216 Application.Run (form);
218 Assert.AreEqual (DragDropEffects.None, form.DragControl.PerformedEffect, "A1");
219 Assert.AreEqual (1, form.DropControl.EnterFiredCount, "A2");
220 Assert.AreEqual (0, form.DropControl.DropFiredCount, "A3");
221 Assert.AreEqual (1, form.DropControl.LeaveFiredCount, "A4");
224 // This test should probably include a 'log' check
226 public void SequentialOperations ()
228 DNDForm form = new DNDForm ();
229 form.Text = MethodBase.GetCurrentMethod ().Name;
230 form.InstructionsText =
231 "Instructions:" + Environment.NewLine + Environment.NewLine +
232 "1. Click with left button on the control on the left, holding it." + Environment.NewLine +
233 "2. Drag on the control on the right. " + Environment.NewLine + Environment.NewLine +
234 "3. Click with left button on the control on the left again, holding it." + Environment.NewLine +
235 "4. Move the mouse pointer to the control in the right." + Environment.NewLine +
236 "5. Move the mouse pointer outside the drop control." + Environment.NewLine +
237 "6. Release mouse button." + Environment.NewLine + Environment.NewLine +
238 "7. Click with left button on the control on the left again, holding it." + Environment.NewLine +
239 "8. Drag on the control on the right. " + Environment.NewLine + Environment.NewLine +
240 "9. Close the form.";
241 form.DragControl.DragData = "SimpleDragDropMessage";
242 form.DragControl.AllowedEffects = DragDropEffects.Move;
243 form.DropControl.DropEffect = DragDropEffects.Move;
245 Application.Run (form);
247 Assert.AreEqual (2, form.DropControl.DropFiredCount, "A1");
248 Assert.AreEqual (1, form.DropControl.LeaveFiredCount, "A2");
249 Assert.AreEqual (DragDropEffects.Move, form.DragControl.PerformedEffect, "A3");
253 public void DropWithoutMovement ()
255 DNDForm form = new DNDForm ();
256 form.Text = MethodBase.GetCurrentMethod ().Name;
257 form.InstructionsText =
258 "Instructions:" + Environment.NewLine + Environment.NewLine +
259 "1. Click with left button on the control on the left, holding it, WITHOUT MOVING IT." + Environment.NewLine +
260 "2. Release the button." + Environment.NewLine +
261 "3. Close the form.";
262 form.DragControl.DragData = "no movement";
263 form.DragControl.AllowDrop = true;
264 form.DragControl.AllowedEffects = DragDropEffects.Move;
265 form.DragControl.DropEffect = DragDropEffects.Move;
267 // Force to automatically do a dnd operation when mouse is pressed,
268 // instead of waiting for movement
269 form.DragControl.MouseDown += new MouseEventHandler (DragControl_MouseDown);
271 Application.Run (form);
273 Assert.AreEqual (1, form.DragControl.EnterFiredCount, "A1");
274 Assert.AreEqual (0, form.DragControl.LeaveFiredCount, "A2");
275 Assert.AreEqual (1, form.DragControl.DropFiredCount, "A3");
276 Assert.AreEqual (0, form.DragControl.DragOverFiredCount, "A4");
277 Assert.AreEqual (true, form.DragControl.Data != null, "A5");
278 // The assertion below is weird: We had a successfully drop, but the returned value is None
279 Assert.AreEqual (DragDropEffects.None, form.DragControl.PerformedEffect, "A6");
282 void DragControl_MouseDown (object sender, MouseEventArgs e)
284 DragDropControl ctrl = (DragDropControl)sender;
285 ctrl.DoDragDrop (ctrl.DragData, ctrl.AllowedEffects);
289 public void DragDropInSameControl ()
291 DNDForm form = new DNDForm ();
292 form.Text = MethodBase.GetCurrentMethod ().Name;
293 form.InstructionsText =
294 "Instructions:" + Environment.NewLine + Environment.NewLine +
295 "1. Click with left button on the control on the left, holding it." + Environment.NewLine +
296 "2. Move the mouse inside left control. " + Environment.NewLine +
297 "3. Drop on left control (same)." + Environment.NewLine + Environment.NewLine +
298 "4. Click with left button on the control on the left again, holding it." + Environment.NewLine +
299 "5. Move the mouse inside the left control. " + Environment.NewLine +
300 "6. Press ESC, release mouse button and move mouse pointer outside control." + Environment.NewLine +
301 "7. Close the form.";
302 form.DragControl.DragData = "SameControl";
303 form.DragControl.AllowDrop = true;
304 form.DragControl.AllowedEffects = DragDropEffects.Copy;
307 drag_enter_count = drag_leave_count = 0;
308 form.DragControl.DragEnter += new DragEventHandler (DragDropInSameControl_DragEnter);
309 form.DragControl.DragLeave += new EventHandler (DragDropInSameControl_DragLeave);
310 form.DragControl.DragDrop += new DragEventHandler (DragDropInSameControl_DragDrop);
312 Application.Run (form);
314 Assert.AreEqual (2, drag_enter_count, "A1");
315 Assert.AreEqual (1, drag_leave_count, "A2");
316 Assert.AreEqual (1, drag_drop_count, "A3");
317 Assert.AreEqual ("SameControl", data, "A4");
320 int drag_enter_count;
321 int drag_leave_count;
325 void DragDropInSameControl_DragDrop (object sender, DragEventArgs e)
328 data = e.Data.GetData (typeof (string));
331 void DragDropInSameControl_DragLeave (object sender, EventArgs e)
336 void DragDropInSameControl_DragEnter (object sender, DragEventArgs e)
338 e.Effect = DragDropEffects.Copy;
343 public class DNDForm : Form
345 DragDropControl drag_control;
346 DragDropControl drop_control;
347 TextBox instructions_tb;
352 test_name = new Label ();
353 test_name.Location = new Point (5, 5);
354 test_name.AutoSize = true;
355 test_name.Font = new Font (Font, FontStyle.Bold | Font.Style);
356 test_name.Text = Text;
358 instructions_tb = new TextBox ();
359 instructions_tb.Multiline = true;
360 instructions_tb.ScrollBars = ScrollBars.Vertical;
361 instructions_tb.Location = new Point (5, test_name.Bottom + 5);
362 instructions_tb.Size = new Size (460, 180);
364 drag_control = new DragDropControl ();
365 drag_control.Location = new Point (5, instructions_tb.Bottom + 10);
366 drag_control.Size = new Size (220, 180);
367 drag_control.BackColor = Color.LightYellow;
368 drag_control.DragDropColor = Color.Yellow;
369 drag_control.Text = "Drag Control";
370 drag_control.DoDrag = true;
372 drop_control = new DragDropControl ();
373 drop_control.Location = new Point (drag_control.Right + 20, instructions_tb.Bottom + 10);
374 drop_control.Size = new Size (220, 180);
375 drop_control.BackColor = Color.LightGreen;
376 drop_control.DragDropColor = Color.Green;
377 drop_control.Text = "Drop Control";
378 drop_control.AllowDrop = true;
380 Controls.AddRange (new Control [] { test_name, instructions_tb, drag_control, drop_control });
382 Size = new Size (480, 440);
385 public string InstructionsText {
387 return instructions_tb.Text;
390 instructions_tb.Text = value;
394 public DragDropControl DragControl {
400 public DragDropControl DropControl {
406 protected override void OnTextChanged (EventArgs args)
408 base.OnTextChanged (args);
409 test_name.Text = Text;
413 public class DragDropControl : Control
415 DragDropEffects effect;
416 DragDropEffects allowed_effects;
417 DragDropEffects performed_effect;
425 int drop_fired_count;
426 int leave_fired_count;
427 int drag_over_fired_count;
428 int enter_fired_count;
430 public DragDropControl ()
432 drag_rect = new Rectangle (new Point (-1, -1), SystemInformation.DragSize);
435 // to call or not DoDragDrop when mouse movement is detected. Only handle dnd events otherwise.
445 // Color of the control when an operation is having place
446 public Color DragDropColor {
455 // Data to pass to Control.DoDragDrop
456 public object DragData {
465 // Effects passed to Control.DoDragDrop
466 public DragDropEffects AllowedEffects {
468 return allowed_effects;
471 allowed_effects = value;
475 // Effect returned by Control.DoDragDrop
476 public DragDropEffects PerformedEffect {
478 return performed_effect;
482 // The value DragEventArgs.Effect gets in DragEnter event
483 public DragDropEffects DropEffect {
492 // The value in DragEventArgs.Data
493 public IDataObject Data {
499 public int DropFiredCount {
501 return drop_fired_count;
505 public int EnterFiredCount {
507 return enter_fired_count;
511 public int LeaveFiredCount {
513 return leave_fired_count;
517 public int DragOverFiredCount {
519 return drag_over_fired_count;
523 public void ResetEventCounters ()
525 drop_fired_count = enter_fired_count = leave_fired_count = drag_over_fired_count = 0;
528 protected override void OnDragEnter (DragEventArgs drgevent)
531 prev_color = BackColor;
532 BackColor = drop_color;
536 drgevent.Effect = effect;
538 base.OnDragEnter (drgevent);
541 protected override void OnDragOver (DragEventArgs drgevent)
543 drag_over_fired_count++;
545 base.OnDragOver (drgevent);
548 protected override void OnDragLeave (EventArgs e)
554 BackColor = prev_color;
556 base.OnDragLeave (e);
559 protected override void OnDragDrop (DragEventArgs drgevent)
561 data = drgevent.Data;
565 BackColor = prev_color;
567 base.OnDragDrop (drgevent);
570 protected override void OnMouseMove (MouseEventArgs e)
572 base.OnMouseMove (e);
577 if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right) {
579 if (drag_rect.X == -1 && drag_rect.Y == -1)
580 drag_rect.Location = new Point (e.X, e.Y);
582 if (!drag_rect.Contains (new Point (e.X, e.Y))) {
583 Color prev_color = BackColor;
584 BackColor = drop_color;
586 performed_effect = DoDragDrop (drag_data, allowed_effects);
588 drag_rect.Location = new Point (-1, -1);
589 BackColor = prev_color;
596 protected override void OnPaint (PaintEventArgs e)
600 Graphics g = e.Graphics;
602 StringFormat sf = new StringFormat ();
603 sf.Alignment = StringAlignment.Center;
604 sf.LineAlignment = StringAlignment.Center;
606 g.DrawString (Text, SystemFonts.DefaultFont, SystemBrushes.ControlDark,
607 ClientRectangle, sf);