1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.dnd.TreeDragSourceEffect;
14 
15 import java.lang.all;
16 
17 
18 import org.eclipse.swt.SWT;
19 import org.eclipse.swt.graphics.Image;
20 import org.eclipse.swt.internal.gtk.OS;
21 import org.eclipse.swt.widgets.Display;
22 import org.eclipse.swt.widgets.Tree;
23 import org.eclipse.swt.dnd.DragSourceEffect;
24 import org.eclipse.swt.dnd.DragSourceEvent;
25 
26 
27 /**
28  * This class provides default implementations to display a source image
29  * when a drag is initiated from a <code>Tree</code>.
30  *
31  * <p>Classes that wish to provide their own source image for a <code>Tree</code> can
32  * extend <code>TreeDragSourceEffect</code> class and override the <code>TreeDragSourceEffect.dragStart</code>
33  * method and set the field <code>DragSourceEvent.image</code> with their own image.</p>
34  *
35  * Subclasses that override any methods of this class must call the corresponding
36  * <code>super</code> method to get the default drag under effect implementation.
37  *
38  * @see DragSourceEffect
39  * @see DragSourceEvent
40  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
41  *
42  * @since 3.3
43  */
44 public class TreeDragSourceEffect : DragSourceEffect {
45     Image dragSourceImage = null;
46 
47     /**
48      * Creates a new <code>TreeDragSourceEffect</code> to handle drag effect
49      * from the specified <code>Tree</code>.
50      *
51      * @param tree the <code>Tree</code> that the user clicks on to initiate the drag
52      */
53     public this(Tree tree) {
54         super(tree);
55     }
56 
57     /**
58      * This implementation of <code>dragFinished</code> disposes the image
59      * that was created in <code>TreeDragSourceEffect.dragStart</code>.
60      *
61      * Subclasses that override this method should call <code>super.dragFinished(event)</code>
62      * to dispose the image in the default implementation.
63      *
64      * @param event the information associated with the drag finished event
65      */
66     public override void dragFinished(DragSourceEvent event) {
67         if (dragSourceImage !is null) dragSourceImage.dispose();
68         dragSourceImage = null;
69     }
70 
71     /**
72      * This implementation of <code>dragStart</code> will create a default
73      * image that will be used during the drag. The image should be disposed
74      * when the drag is completed in the <code>TreeDragSourceEffect.dragFinished</code>
75      * method.
76      *
77      * Subclasses that override this method should call <code>super.dragStart(event)</code>
78      * to use the image from the default implementation.
79      *
80      * @param event the information associated with the drag start event
81      */
82     public override void dragStart(DragSourceEvent event) {
83         event.image = getDragSourceImage(event);
84     }
85 
86     Image getDragSourceImage(DragSourceEvent event) {
87         if (dragSourceImage !is null) dragSourceImage.dispose();
88         dragSourceImage = null;
89 
90         Tree tree = cast(Tree) control;
91         if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) return null;
92         //TEMPORARY CODE
93         if (tree.isListening(SWT.EraseItem) || tree.isListening (SWT.PaintItem)) return null;
94         /*
95         * Bug in GTK.  gtk_tree_selection_get_selected_rows() segmentation faults
96         * in versions smaller than 2.2.4 if the model is NULL.  The fix is
97         * to give a valid pointer instead.
98         */
99         auto handle = tree.handle;
100         auto selection = OS.gtk_tree_view_get_selection (handle);
101         ptrdiff_t dummy;
102         void* model = OS.GTK_VERSION < OS.buildVERSION (2, 2, 4) ? &dummy : null;
103         auto list = OS.gtk_tree_selection_get_selected_rows (selection, &model);
104         if (list is null) return null;
105         ptrdiff_t count = Math.min(10, OS.g_list_length (list));
106 
107         Display display = tree.getDisplay();
108         if (count is 1) {
109             auto path = OS.g_list_nth_data (list, 0);
110             auto pixmap = OS.gtk_tree_view_create_row_drag_icon(handle, path);
111             dragSourceImage =  Image.gtk_new(display, SWT.ICON, pixmap, null);
112         } else {
113             int width = 0, height = 0;
114             int w , h;
115             int[] yy = new int[count], hh = new int[count];
116             GdkDrawable* [] pixmaps = new GdkDrawable*[count];
117             GdkRectangle rect;
118             for (int i=0; i<count; i++) {
119                 auto path = OS.g_list_nth_data (list, i);
120                 OS.gtk_tree_view_get_cell_area (handle, path, null, &rect);
121                 pixmaps[i] = OS.gtk_tree_view_create_row_drag_icon(handle, path);
122                 OS.gdk_drawable_get_size(pixmaps[i], &w, &h);
123                 width = Math.max(width, w);
124                 height = rect.y + h - yy[0];
125                 yy[i] = rect.y;
126                 hh[i] = h;
127             }
128             auto source = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, -1);
129             auto gcSource = OS.gdk_gc_new(source);
130             auto mask = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, 1);
131             auto gcMask = OS.gdk_gc_new(mask);
132             GdkColor color;
133             color.pixel = 0;
134             OS.gdk_gc_set_foreground(gcMask, &color);
135             OS.gdk_draw_rectangle(mask, gcMask, 1, 0, 0, width, height);
136             color.pixel = 1;
137             OS.gdk_gc_set_foreground(gcMask, &color);
138             for (int i=0; i<count; i++) {
139                 OS.gdk_draw_drawable(source, gcSource, pixmaps[i], 0, 0, 0, yy[i] - yy[0], -1, -1);
140                 OS.gdk_draw_rectangle(mask, gcMask, 1, 0, yy[i] - yy[0], width, hh[i]);
141                 OS.g_object_unref(pixmaps[i]);
142             }
143             OS.g_object_unref(gcSource);
144             OS.g_object_unref(gcMask);
145             dragSourceImage  = Image.gtk_new(display, SWT.ICON, source, mask);
146         }
147         OS.g_list_free (list);
148 
149         return dragSourceImage;
150     }
151 }