1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.adt.internal.editors.layout.gle2; 18 19 import static com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor.DEPRECATED_CATEGORY; 20 21 import org.eclipse.jface.action.IStatusLineManager; 22 import org.eclipse.swt.SWT; 23 import org.eclipse.swt.events.MouseAdapter; 24 import org.eclipse.swt.events.MouseEvent; 25 import org.eclipse.swt.graphics.Color; 26 import org.eclipse.swt.graphics.GC; 27 import org.eclipse.swt.graphics.Point; 28 import org.eclipse.swt.graphics.Rectangle; 29 import org.eclipse.swt.layout.FillLayout; 30 import org.eclipse.swt.widgets.Composite; 31 import org.eclipse.swt.widgets.Display; 32 import org.eclipse.swt.widgets.Event; 33 import org.eclipse.swt.widgets.Label; 34 import org.eclipse.swt.widgets.Listener; 35 import org.eclipse.swt.widgets.Shell; 36 import org.eclipse.swt.widgets.Tree; 37 import org.eclipse.swt.widgets.TreeItem; 38 import org.eclipse.ui.IActionBars; 39 import org.eclipse.ui.views.properties.IPropertySheetEntry; 40 import org.eclipse.ui.views.properties.PropertySheetEntry; 41 import org.eclipse.ui.views.properties.PropertySheetSorter; 42 43 /** 44 * A customized property sheet page for the graphical layout editor v2. 45 * <p/> 46 * Currently it just provides a custom tooltip to display attributes javadocs. 47 * <p/> 48 * The property sheet is linked to the current site's selection service. 49 * <p/> 50 * Note: this is an exact copy of GLE1's UiPropertySheetPage implementation. 51 * The idea is that eventually GLE1 will go away and we'll upgrade this to be 52 * a more robust property editor (it currently lacks on so many levels, it's not 53 * even worth listing the flaws.) 54 * 55 * @since GLE2 56 */ 57 public class PropertySheetPage extends org.eclipse.ui.views.properties.PropertySheetPage { 58 private static final String MISC_CATEGORY = "Misc"; 59 60 public PropertySheetPage() { 61 super(); 62 63 setSorter(new PropertySheetSorter() { 64 @Override 65 public int compareCategories(String categoryA, String categoryB) { 66 // Sort the "Deprecated" category to the bottom, and the "Misc" 67 // category second to last. 68 if (categoryA.equals(DEPRECATED_CATEGORY)) { 69 return 1; 70 } else if (categoryB.equals(DEPRECATED_CATEGORY)) { 71 return -1; 72 } 73 if (categoryA.equals(MISC_CATEGORY)) { 74 return 1; 75 } else if (categoryB.equals(MISC_CATEGORY)) { 76 return -1; 77 } 78 79 return super.compareCategories(categoryA, categoryB); 80 } 81 }); 82 } 83 84 @Override 85 public void createControl(Composite parent) { 86 super.createControl(parent); 87 88 setupTooltip(); 89 90 // Override parent class' "set status message" behavior. The parent will set 91 // the status message to the property's "getDescription()" field. That field 92 // may contain newlines, which means the text gets cut off. We want to instead 93 // show ALL the text, fit on a single line, and since we don't get to subclass 94 // the viewer we will just replace the status message with our own, which works 95 // since our mouse listener is registered later so runs later. 96 final Tree tree = (Tree) getControl(); 97 tree.addMouseListener(new MouseAdapter() { 98 @Override 99 public void mouseDown(MouseEvent event) { 100 Point pt = new Point(event.x, event.y); 101 TreeItem item = tree.getItem(pt); 102 if (item != null) { 103 Object object = item.getData(); 104 if (object instanceof IPropertySheetEntry) { 105 IPropertySheetEntry entry = (IPropertySheetEntry) object; 106 String help = entry.getDescription(); 107 if (help != null) { 108 // Strip out newlines to make this a single line entry 109 help = help.replace('\n', ' '); 110 // Remove repeated spaces in case there were trailing spaces 111 help = help.replaceAll(" ", " "); //$NON-NLS-1$ //$NON-NLS-2$ 112 IActionBars actionBars = getSite().getActionBars(); 113 IStatusLineManager status = actionBars.getStatusLineManager(); 114 status.setMessage(help); 115 } 116 } 117 } 118 } 119 }); 120 121 // Fix the selection background. In Eclipse 3.5 and 3.6, the selection color 122 // is white, painted on top of a white or light blue background (table striping), 123 // which is practically unreadable. This is fixed in 3.7M3, but we need a workaround 124 // for earlier releases. This just paints a solid color under the current line in 125 // the left column. 126 tree.addListener(SWT.EraseItem, new Listener() { 127 public void handleEvent(Event event) { 128 if ((event.detail & SWT.SELECTED) != 0 && event.index == 0) { 129 GC gc = event.gc; 130 Rectangle rect = event.getBounds(); 131 Color background = gc.getBackground(); 132 Display display = tree.getDisplay(); 133 gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_SELECTION)); 134 gc.fillRectangle(rect.x, rect.y, rect.width, rect.height); 135 gc.setBackground(background); 136 } 137 } 138 }); 139 } 140 141 /** 142 * Sets up a custom tooltip when hovering over tree items. 143 * <p/> 144 * The tooltip will display the element's javadoc, if any, or the item's getText otherwise. 145 */ 146 private void setupTooltip() { 147 final Tree tree = (Tree) getControl(); 148 149 /* 150 * Reference: 151 * http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet125.java?view=markup 152 */ 153 154 final Listener listener = new Listener() { 155 Shell tip = null; 156 Label label = null; 157 158 public void handleEvent(Event event) { 159 switch(event.type) { 160 case SWT.Dispose: 161 case SWT.KeyDown: 162 case SWT.MouseExit: 163 case SWT.MouseDown: 164 case SWT.MouseMove: 165 if (tip != null) { 166 tip.dispose(); 167 tip = null; 168 label = null; 169 } 170 break; 171 case SWT.MouseHover: 172 if (tip != null) { 173 tip.dispose(); 174 tip = null; 175 label = null; 176 } 177 178 String tooltip = null; 179 180 TreeItem item = tree.getItem(new Point(event.x, event.y)); 181 if (item != null) { 182 Object data = item.getData(); 183 if (data instanceof PropertySheetEntry) { 184 tooltip = ((PropertySheetEntry) data).getDescription(); 185 } 186 187 if (tooltip == null) { 188 tooltip = item.getText(); 189 } else { 190 tooltip = item.getText() + ":\r" + tooltip; 191 } 192 193 if (tooltip != null) { 194 Shell shell = tree.getShell(); 195 Display display = tree.getDisplay(); 196 197 tip = new Shell(shell, SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL); 198 tip.setBackground(display .getSystemColor(SWT.COLOR_INFO_BACKGROUND)); 199 FillLayout layout = new FillLayout(); 200 layout.marginWidth = 2; 201 tip.setLayout(layout); 202 label = new Label(tip, SWT.NONE); 203 label.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); 204 label.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); 205 label.setData("_TABLEITEM", item); 206 label.setText(tooltip); 207 label.addListener(SWT.MouseExit, this); 208 label.addListener(SWT.MouseDown, this); 209 Point size = tip.computeSize(SWT.DEFAULT, SWT.DEFAULT); 210 Rectangle rect = item.getBounds(0); 211 // Display the tooltip on the same line as the property, 212 // but offset to the right of wherever the mouse cursor was, 213 // such that it does not obscure the list of properties. 214 Point pt = tree.toDisplay(event.x + 15, rect.y); 215 tip.setBounds(pt.x, pt.y, size.x, size.y); 216 tip.setVisible(true); 217 } 218 } 219 } 220 } 221 }; 222 223 tree.addListener(SWT.Dispose, listener); 224 tree.addListener(SWT.KeyDown, listener); 225 tree.addListener(SWT.MouseMove, listener); 226 tree.addListener(SWT.MouseHover, listener); 227 228 } 229 230 } 231