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.table; 12 13 import org.eclipse.swt.SWT; 14 import org.eclipse.swt.graphics.Point; 15 import org.eclipse.swt.widgets.Control; 16 import org.eclipse.swt.widgets.Display; 17 import org.eclipse.swt.widgets.Event; 18 import org.eclipse.swt.widgets.Listener; 19 import org.eclipse.swt.widgets.Shell; 20 import org.eclipse.wb.internal.core.EnvironmentUtils; 21 import org.eclipse.wb.internal.core.model.property.Property; 22 import org.eclipse.wb.internal.core.utils.ui.GridLayoutFactory; 23 24 /** 25 * Helper class for displaying tooltips. 26 * 27 * @author scheglov_ke 28 * @coverage core.model.property.table 29 */ 30 class PropertyTableTooltipHelper implements IPropertyTooltipSite { 31 private final PropertyTable m_table; 32 private Shell m_tooltip; 33 34 //////////////////////////////////////////////////////////////////////////// 35 // 36 // Constructor 37 // 38 //////////////////////////////////////////////////////////////////////////// 39 public PropertyTableTooltipHelper(PropertyTable table) { 40 m_table = table; 41 m_table.addListener(SWT.MouseHover, new Listener() { 42 @Override 43 public void handleEvent(Event event) { 44 if (event.stateMask == 0) { 45 showTooltip(); 46 } 47 } 48 }); 49 m_table.addListener(SWT.MouseExit, new Listener() { 50 @Override 51 public void handleEvent(Event event) { 52 // check, may be cursor is now on tooltip, so ignore this MouseExit 53 { 54 Control control = Display.getCurrent().getCursorControl(); 55 while (control != null) { 56 if (control == m_tooltip) { 57 return; 58 } 59 control = control.getParent(); 60 } 61 } 62 // no, we should hide tooltip 63 hideTooltip(); 64 } 65 }); 66 } 67 68 //////////////////////////////////////////////////////////////////////////// 69 // 70 // Access 71 // 72 //////////////////////////////////////////////////////////////////////////// 73 private Property m_property; 74 private boolean m_onTitle; 75 private boolean m_onValue; 76 private int m_beginX; 77 private int m_endX; 78 private int m_y; 79 private int m_rowHeight; 80 81 /** 82 * {@link PropertyTable} call this method to inform that cursor location was changed. 83 */ 84 public void update(Property property, 85 boolean onTitle, 86 boolean onValue, 87 int beginX, 88 int endX, 89 int y, 90 int rowHeight) { 91 m_property = property; 92 m_onTitle = onTitle; 93 m_onValue = onValue; 94 m_beginX = beginX; 95 m_endX = endX; 96 m_y = y; 97 m_rowHeight = rowHeight; 98 } 99 100 //////////////////////////////////////////////////////////////////////////// 101 // 102 // IPropertyTooltipSite 103 // 104 //////////////////////////////////////////////////////////////////////////// 105 @Override 106 public PropertyTable getTable() { 107 return m_table; 108 } 109 110 @Override 111 public void hideTooltip() { 112 if (m_tooltip != null && !m_tooltip.isDisposed()) { 113 m_tooltip.dispose(); 114 } 115 m_tooltip = null; 116 } 117 118 //////////////////////////////////////////////////////////////////////////// 119 // 120 // Showing tooltip 121 // 122 //////////////////////////////////////////////////////////////////////////// 123 private void showTooltip() { 124 hideTooltip(); 125 // check for property 126 if (m_property == null) { 127 return; 128 } 129 // 130 if (m_onTitle) { 131 showTooltip(m_property.getAdapter(PropertyTooltipProvider.class), m_beginX, m_endX); 132 } 133 if (m_onValue) { 134 showTooltip(m_property.getEditor().getAdapter(PropertyTooltipProvider.class), 135 m_beginX, m_endX); 136 } 137 } 138 139 private void showTooltip(PropertyTooltipProvider provider, int startX, int endX) { 140 if (provider == null) { 141 return; 142 } 143 // create Shell 144 { 145 m_tooltip = new Shell(m_table.getShell(), SWT.NO_FOCUS | SWT.ON_TOP | SWT.TOOL | SWT.SINGLE); 146 configureColors(m_tooltip); 147 GridLayoutFactory.create(m_tooltip).noMargins(); 148 } 149 // prepare control 150 Control control = provider.createTooltipControl(m_property, m_tooltip, endX - startX, this); 151 if (control == null) { 152 hideTooltip(); 153 return; 154 } 155 // show Shell 156 { 157 // prepare tooltip location 158 Point tooltipLocation; 159 if (provider.getTooltipPosition() == PropertyTooltipProvider.ON) { 160 tooltipLocation = m_table.toDisplay(new Point(startX, m_y)); 161 } else { 162 tooltipLocation = m_table.toDisplay(new Point(startX, m_y + m_rowHeight)); 163 } 164 // set location/size and open 165 m_tooltip.setLocation(tooltipLocation.x, tooltipLocation.y); 166 // for non-windows systems the tooltip may have invalid tooltip bounds 167 // because some widget's API functions may fail if tooltip content is not visible 168 // ex., on MacOSX tree widget's items has zero bounds since they are not yet visible. 169 // the workaround is to preset tooltip size to big values before any computeSize called. 170 if (!EnvironmentUtils.IS_WINDOWS) { 171 m_tooltip.setSize(1000, 1000); 172 } 173 m_tooltip.setSize(m_tooltip.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 174 provider.show(m_tooltip); 175 } 176 } 177 178 //////////////////////////////////////////////////////////////////////////// 179 // 180 // Utils 181 // 182 //////////////////////////////////////////////////////////////////////////// 183 /** 184 * Sets given {@link Control} correct background/foreground for tooltips. 185 */ 186 private void configureColors(Control control) { 187 Display display = Display.getCurrent(); 188 control.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); 189 control.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); 190 } 191 } 192