1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 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.hierarchyviewerlib.ui; 18 19 import com.android.hierarchyviewerlib.device.ViewNode; 20 import com.android.hierarchyviewerlib.device.ViewNode.Property; 21 import com.android.hierarchyviewerlib.models.TreeViewModel; 22 import com.android.hierarchyviewerlib.models.TreeViewModel.ITreeChangeListener; 23 import com.android.hierarchyviewerlib.ui.util.DrawableViewNode; 24 import com.android.hierarchyviewerlib.ui.util.TreeColumnResizer; 25 26 import org.eclipse.jface.viewers.ILabelProviderListener; 27 import org.eclipse.jface.viewers.ITableLabelProvider; 28 import org.eclipse.jface.viewers.ITreeContentProvider; 29 import org.eclipse.jface.viewers.TreeViewer; 30 import org.eclipse.jface.viewers.Viewer; 31 import org.eclipse.swt.SWT; 32 import org.eclipse.swt.events.ControlAdapter; 33 import org.eclipse.swt.events.ControlEvent; 34 import org.eclipse.swt.events.ControlListener; 35 import org.eclipse.swt.events.DisposeEvent; 36 import org.eclipse.swt.events.DisposeListener; 37 import org.eclipse.swt.graphics.Image; 38 import org.eclipse.swt.layout.FillLayout; 39 import org.eclipse.swt.widgets.Composite; 40 import org.eclipse.swt.widgets.Display; 41 import org.eclipse.swt.widgets.Tree; 42 import org.eclipse.swt.widgets.TreeColumn; 43 44 import java.util.ArrayList; 45 46 public class PropertyViewer extends Composite implements ITreeChangeListener { 47 private TreeViewModel mModel; 48 49 private TreeViewer mTreeViewer; 50 51 private Tree mTree; 52 53 private DrawableViewNode mSelectedNode; 54 55 private class ContentProvider implements ITreeContentProvider, ITableLabelProvider { 56 57 @Override 58 public Object[] getChildren(Object parentElement) { 59 synchronized (PropertyViewer.this) { 60 if (mSelectedNode != null && parentElement instanceof String) { 61 String category = (String) parentElement; 62 ArrayList<Property> returnValue = new ArrayList<Property>(); 63 for (Property property : mSelectedNode.viewNode.properties) { 64 if (category.equals(ViewNode.MISCELLANIOUS)) { 65 if (property.name.indexOf(':') == -1) { 66 returnValue.add(property); 67 } 68 } else { 69 if (property.name.startsWith(((String) parentElement) + ":")) { 70 returnValue.add(property); 71 } 72 } 73 } 74 return returnValue.toArray(new Property[returnValue.size()]); 75 } 76 return new Object[0]; 77 } 78 } 79 80 @Override 81 public Object getParent(Object element) { 82 synchronized (PropertyViewer.this) { 83 if (mSelectedNode != null && element instanceof Property) { 84 if (mSelectedNode.viewNode.categories.size() == 0) { 85 return null; 86 } 87 String name = ((Property) element).name; 88 int index = name.indexOf(':'); 89 if (index == -1) { 90 return ViewNode.MISCELLANIOUS; 91 } 92 return name.substring(0, index); 93 } 94 return null; 95 } 96 } 97 98 @Override 99 public boolean hasChildren(Object element) { 100 synchronized (PropertyViewer.this) { 101 if (mSelectedNode != null && element instanceof String) { 102 String category = (String) element; 103 for (String name : mSelectedNode.viewNode.namedProperties.keySet()) { 104 if (category.equals(ViewNode.MISCELLANIOUS)) { 105 if (name.indexOf(':') == -1) { 106 return true; 107 } 108 } else { 109 if (name.startsWith(((String) element) + ":")) { 110 return true; 111 } 112 } 113 } 114 } 115 return false; 116 } 117 } 118 119 @Override 120 public Object[] getElements(Object inputElement) { 121 synchronized (PropertyViewer.this) { 122 if (mSelectedNode != null && inputElement instanceof TreeViewModel) { 123 if (mSelectedNode.viewNode.categories.size() == 0) { 124 return mSelectedNode.viewNode.properties 125 .toArray(new Property[mSelectedNode.viewNode.properties.size()]); 126 } else { 127 return mSelectedNode.viewNode.categories 128 .toArray(new String[mSelectedNode.viewNode.categories.size()]); 129 } 130 } 131 return new Object[0]; 132 } 133 } 134 135 @Override 136 public void dispose() { 137 // pass 138 } 139 140 @Override 141 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { 142 // pass 143 } 144 145 @Override 146 public Image getColumnImage(Object element, int column) { 147 return null; 148 } 149 150 @Override 151 public String getColumnText(Object element, int column) { 152 synchronized (PropertyViewer.this) { 153 if (mSelectedNode != null) { 154 if (element instanceof String && column == 0) { 155 String category = (String) element; 156 return Character.toUpperCase(category.charAt(0)) + category.substring(1); 157 } else if (element instanceof Property) { 158 if (column == 0) { 159 String returnValue = ((Property) element).name; 160 int index = returnValue.indexOf(':'); 161 if (index != -1) { 162 return returnValue.substring(index + 1); 163 } 164 return returnValue; 165 } else if (column == 1) { 166 return ((Property) element).value; 167 } 168 } 169 } 170 return ""; 171 } 172 } 173 174 @Override 175 public void addListener(ILabelProviderListener listener) { 176 // pass 177 } 178 179 @Override 180 public boolean isLabelProperty(Object element, String property) { 181 // pass 182 return false; 183 } 184 185 @Override 186 public void removeListener(ILabelProviderListener listener) { 187 // pass 188 } 189 } 190 191 public PropertyViewer(Composite parent) { 192 super(parent, SWT.NONE); 193 setLayout(new FillLayout()); 194 mTreeViewer = new TreeViewer(this, SWT.NONE); 195 196 mTree = mTreeViewer.getTree(); 197 mTree.setLinesVisible(true); 198 mTree.setHeaderVisible(true); 199 200 TreeColumn propertyColumn = new TreeColumn(mTree, SWT.NONE); 201 propertyColumn.setText("Property"); 202 TreeColumn valueColumn = new TreeColumn(mTree, SWT.NONE); 203 valueColumn.setText("Value"); 204 205 mModel = TreeViewModel.getModel(); 206 ContentProvider contentProvider = new ContentProvider(); 207 mTreeViewer.setContentProvider(contentProvider); 208 mTreeViewer.setLabelProvider(contentProvider); 209 mTreeViewer.setInput(mModel); 210 mModel.addTreeChangeListener(this); 211 212 addDisposeListener(mDisposeListener); 213 214 new TreeColumnResizer(this, propertyColumn, valueColumn); 215 216 addControlListener(mControlListener); 217 218 treeChanged(); 219 } 220 221 private DisposeListener mDisposeListener = new DisposeListener() { 222 @Override 223 public void widgetDisposed(DisposeEvent e) { 224 mModel.removeTreeChangeListener(PropertyViewer.this); 225 } 226 }; 227 228 // If the window gets too small, hide the data, otherwise SWT throws an 229 // ERROR. 230 231 private ControlListener mControlListener = new ControlAdapter() { 232 private boolean noInput = false; 233 234 private boolean noHeader = false; 235 236 @Override 237 public void controlResized(ControlEvent e) { 238 if (getBounds().height <= 20) { 239 mTree.setHeaderVisible(false); 240 noHeader = true; 241 } else if (noHeader) { 242 mTree.setHeaderVisible(true); 243 noHeader = false; 244 } 245 if (getBounds().height <= 38) { 246 mTreeViewer.setInput(null); 247 noInput = true; 248 } else if (noInput) { 249 mTreeViewer.setInput(mModel); 250 noInput = false; 251 } 252 } 253 }; 254 255 @Override 256 public void selectionChanged() { 257 synchronized (this) { 258 mSelectedNode = mModel.getSelection(); 259 } 260 doRefresh(); 261 } 262 263 @Override 264 public void treeChanged() { 265 synchronized (this) { 266 mSelectedNode = mModel.getSelection(); 267 } 268 doRefresh(); 269 } 270 271 @Override 272 public void viewportChanged() { 273 // pass 274 } 275 276 @Override 277 public void zoomChanged() { 278 // pass 279 } 280 281 private void doRefresh() { 282 Display.getDefault().syncExec(new Runnable() { 283 @Override 284 public void run() { 285 mTreeViewer.refresh(); 286 } 287 }); 288 } 289 } 290