1 /******************************************************************************* 2 * Copyright (c) 2011 Google, Inc. 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 * Google, Inc. - initial API and implementation 10 *******************************************************************************/ 11 package org.eclipse.wb.internal.core.model.property.editor.presentation; 12 13 import com.google.common.collect.Maps; 14 15 import org.eclipse.swt.SWT; 16 import org.eclipse.swt.graphics.Rectangle; 17 import org.eclipse.swt.widgets.Button; 18 import org.eclipse.swt.widgets.Control; 19 import org.eclipse.swt.widgets.Event; 20 import org.eclipse.swt.widgets.Listener; 21 import org.eclipse.wb.internal.core.model.property.Property; 22 import org.eclipse.wb.internal.core.model.property.table.PropertyTable; 23 import org.eclipse.wb.internal.core.utils.Pair; 24 25 import java.util.Map; 26 27 /** 28 * Internal implementation of {@link PropertyEditorPresentation} for displaying {@link Button}. 29 * 30 * @author scheglov_ke 31 * @author mitin_aa 32 * @coverage core.model.property.editor 33 */ 34 class ButtonPropertyEditorPresentationImpl extends PropertyEditorPresentation { 35 protected final PropertyToControlMap m_propertyToControl = new PropertyToControlMap(); 36 private final ButtonPropertyEditorPresentation m_presentation; 37 38 //////////////////////////////////////////////////////////////////////////// 39 // 40 // Constructor 41 // 42 //////////////////////////////////////////////////////////////////////////// 43 public ButtonPropertyEditorPresentationImpl(ButtonPropertyEditorPresentation presentation) { 44 m_presentation = presentation; 45 } 46 47 //////////////////////////////////////////////////////////////////////////// 48 // 49 // PropertyEditorPresentation 50 // 51 //////////////////////////////////////////////////////////////////////////// 52 @Override 53 public final void hide(PropertyTable propertyTable, Property property) { 54 Control control = m_propertyToControl.remove(propertyTable, property); 55 if (control != null) { 56 control.dispose(); 57 } 58 } 59 60 @Override 61 public final int show(PropertyTable propertyTable, 62 Property property, 63 int x, 64 int y, 65 int width, 66 int height) { 67 // prepare control 68 Control control = m_propertyToControl.get(propertyTable, property); 69 if (control == null) { 70 control = createControl(propertyTable, property); 71 } 72 // set bounds 73 final int controlWidth = height; 74 final int controlX = x + width - controlWidth; 75 setBounds(control, controlX, y, controlWidth, height); 76 return controlWidth; 77 } 78 79 /** 80 * Finds and select the appropriate {@link Control} belonging to given property. 81 */ 82 public void setSelection(PropertyTable propertyTable, Property property, boolean selected) { 83 Button button = (Button) m_propertyToControl.get(propertyTable, property); 84 if (button != null) { 85 button.setSelection(selected); 86 } 87 } 88 89 //////////////////////////////////////////////////////////////////////////// 90 // 91 // Control 92 // 93 //////////////////////////////////////////////////////////////////////////// 94 /** 95 * Creates the control for given property and initializes newly created control. 96 */ 97 private Control createControl(final PropertyTable propertyTable, final Property property) { 98 Control control = createControlImpl(propertyTable, property); 99 m_propertyToControl.put(propertyTable, property, control); 100 // when Control disposed, remove Control/Property from map to avoid memory leak 101 control.addListener(SWT.Dispose, new Listener() { 102 @Override 103 public void handleEvent(Event e) { 104 m_propertyToControl.remove(propertyTable, property); 105 } 106 }); 107 // activate property on mouse down 108 control.addListener(SWT.MouseDown, new Listener() { 109 @Override 110 public void handleEvent(Event event) { 111 propertyTable.deactivateEditor(true); 112 propertyTable.setActiveProperty(property); 113 } 114 }); 115 // return focus on propertyTable after click 116 control.addListener(SWT.MouseUp, new Listener() { 117 @Override 118 public void handleEvent(Event event) { 119 propertyTable.forceFocus(); 120 } 121 }); 122 // handle selection 123 control.addListener(SWT.Selection, new Listener() { 124 @Override 125 public void handleEvent(Event event) { 126 try { 127 getPresentation().onClick(propertyTable, property); 128 } catch (Throwable e) { 129 propertyTable.deactivateEditor(false); 130 propertyTable.handleException(e); 131 } 132 } 133 }); 134 return control; 135 } 136 137 /** 138 * Creates the {@link Control} instance. By default, {@link Button} instance created. 139 */ 140 protected Control createControlImpl(final PropertyTable propertyTable, final Property property) { 141 Button button = new Button(propertyTable, getPresentation().getStyle()); 142 button.setImage(getPresentation().getImage()); 143 button.setToolTipText(getPresentation().getTooltip()); 144 return button; 145 } 146 147 //////////////////////////////////////////////////////////////////////////// 148 // 149 // Access 150 // 151 //////////////////////////////////////////////////////////////////////////// 152 /** 153 * @return the 'parent' presentation. Internal usage only. 154 */ 155 protected final ButtonPropertyEditorPresentation getPresentation() { 156 return m_presentation; 157 } 158 159 //////////////////////////////////////////////////////////////////////////// 160 // 161 // Utils 162 // 163 //////////////////////////////////////////////////////////////////////////// 164 /** 165 * Sets new bounds for {@link Control}, optimizing when possible. 166 */ 167 private static void setBounds(Control control, int newX, int newY, int newWidth, int newHeight) { 168 // check, may be Control is invisible, so no reason to change bounds 169 { 170 // is in negative zone 171 if (newY + newHeight < 0) { 172 control.setVisible(false); 173 return; 174 } 175 // is out of client area height 176 Rectangle parentArea = control.getParent().getClientArea(); 177 if (newY > parentArea.height) { 178 control.setVisible(false); 179 return; 180 } 181 } 182 // well, now we sure that Control is visible 183 if (!control.getVisible()) { 184 control.setVisible(true); 185 } 186 // prepare old size, remember new 187 Integer oldWidthObject = (Integer) control.getData("oldWidth"); 188 Integer oldHeightObject = (Integer) control.getData("oldHeight"); 189 control.setData("oldWidth", newWidth); 190 control.setData("oldHeight", newHeight); 191 // check, may be same size 192 if (oldWidthObject != null) { 193 int oldWidth = oldWidthObject.intValue(); 194 int oldHeight = oldHeightObject.intValue(); 195 if (oldWidth == newWidth && oldHeight == newHeight) { 196 control.setLocation(newX, newY); 197 return; 198 } 199 } 200 // no any optimization possible, just set bounds 201 control.setBounds(newX, newY, newWidth, newHeight); 202 } 203 204 //////////////////////////////////////////////////////////////////////////// 205 // 206 // Controls map 207 // 208 //////////////////////////////////////////////////////////////////////////// 209 protected static final class PropertyToControlMap { 210 private final Map<Pair<PropertyTable, Property>, Control> m_map = Maps.newHashMap(); 211 212 void put(PropertyTable propertyTable, Property property, Control control) { 213 m_map.put(Pair.create(propertyTable, property), control); 214 } 215 216 Control remove(PropertyTable propertyTable, Property property) { 217 return m_map.remove(Pair.create(propertyTable, property)); 218 } 219 220 Control get(PropertyTable propertyTable, Property property) { 221 return m_map.get(Pair.create(propertyTable, property)); 222 } 223 } 224 } 225