1 /* 2 * Copyright (C) 2007 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.ui; 18 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.AndroidConstants; 21 import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResourceItem; 22 import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; 23 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFile; 24 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; 25 import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IResourceEventListener; 26 import com.android.ide.eclipse.adt.io.IFileWrapper; 27 import com.android.sdklib.io.IAbstractFile; 28 29 import org.eclipse.core.resources.IFile; 30 import org.eclipse.core.resources.IProject; 31 import org.eclipse.core.resources.IResource; 32 import org.eclipse.core.runtime.CoreException; 33 import org.eclipse.core.runtime.IAdaptable; 34 import org.eclipse.jdt.core.IJavaElement; 35 import org.eclipse.jdt.core.IJavaProject; 36 import org.eclipse.jface.preference.IPreferenceStore; 37 import org.eclipse.jface.viewers.DoubleClickEvent; 38 import org.eclipse.jface.viewers.IDoubleClickListener; 39 import org.eclipse.jface.viewers.ISelection; 40 import org.eclipse.jface.viewers.IStructuredSelection; 41 import org.eclipse.jface.viewers.TreeViewer; 42 import org.eclipse.swt.SWT; 43 import org.eclipse.swt.SWTException; 44 import org.eclipse.swt.events.ControlEvent; 45 import org.eclipse.swt.events.ControlListener; 46 import org.eclipse.swt.layout.GridData; 47 import org.eclipse.swt.widgets.Composite; 48 import org.eclipse.swt.widgets.Tree; 49 import org.eclipse.swt.widgets.TreeColumn; 50 import org.eclipse.ui.IEditorInput; 51 import org.eclipse.ui.IEditorPart; 52 import org.eclipse.ui.IFileEditorInput; 53 import org.eclipse.ui.ISelectionListener; 54 import org.eclipse.ui.IWorkbenchPage; 55 import org.eclipse.ui.IWorkbenchPart; 56 import org.eclipse.ui.PartInitException; 57 import org.eclipse.ui.ide.IDE; 58 import org.eclipse.ui.part.ViewPart; 59 60 import java.util.Iterator; 61 62 /** 63 * Resource Explorer View. 64 * <p/> 65 * This contains a basic Tree view, and uses a TreeViewer to handle the data. 66 * <p/> 67 * The view listener to change in selection in the workbench, and update to show the resource 68 * of the project of the current selected item (either item in the package explorer, or of the 69 * current editor). 70 * 71 * @see ResourceContentProvider 72 */ 73 public class ResourceExplorerView extends ViewPart implements ISelectionListener, 74 IResourceEventListener { 75 76 // Note: keep using the obsolete AndroidConstants.EDITORS_NAMESPACE (which used 77 // to be the Editors Plugin ID) to keep existing preferences functional. 78 private final static String PREFS_COLUMN_RES = 79 AndroidConstants.EDITORS_NAMESPACE + "ResourceExplorer.Col1"; //$NON-NLS-1$ 80 private final static String PREFS_COLUMN_2 = 81 AndroidConstants.EDITORS_NAMESPACE + "ResourceExplorer.Col2"; //$NON-NLS-1$ 82 83 private Tree mTree; 84 private TreeViewer mTreeViewer; 85 86 private IProject mCurrentProject; 87 ResourceExplorerView()88 public ResourceExplorerView() { 89 } 90 91 @Override createPartControl(Composite parent)92 public void createPartControl(Composite parent) { 93 mTree = new Tree(parent, SWT.SINGLE | SWT.VIRTUAL); 94 mTree.setLayoutData(new GridData(GridData.FILL_BOTH)); 95 mTree.setHeaderVisible(true); 96 mTree.setLinesVisible(true); 97 98 final IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 99 100 // create 2 columns. The main one with the resources, and an "info" column. 101 createTreeColumn(mTree, "Resources", SWT.LEFT, 102 "abcdefghijklmnopqrstuvwxz", -1, PREFS_COLUMN_RES, store); //$NON-NLS-1$ 103 createTreeColumn(mTree, "Info", SWT.LEFT, 104 "0123456789", -1, PREFS_COLUMN_2, store); //$NON-NLS-1$ 105 106 // create the jface wrapper 107 mTreeViewer = new TreeViewer(mTree); 108 109 mTreeViewer.setContentProvider(new ResourceContentProvider(true /* fullLevels */)); 110 mTreeViewer.setLabelProvider(new ResourceLabelProvider()); 111 112 // listen to selection change in the workbench. 113 IWorkbenchPage page = getSite().getPage(); 114 115 page.addSelectionListener(this); 116 117 // init with current selection 118 selectionChanged(getSite().getPart(), page.getSelection()); 119 120 // add support for double click. 121 mTreeViewer.addDoubleClickListener(new IDoubleClickListener() { 122 public void doubleClick(DoubleClickEvent event) { 123 ISelection sel = event.getSelection(); 124 125 if (sel instanceof IStructuredSelection) { 126 IStructuredSelection selection = (IStructuredSelection) sel; 127 128 if (selection.size() == 1) { 129 Object element = selection.getFirstElement(); 130 131 // if it's a resourceFile, we directly open it. 132 if (element instanceof ResourceFile) { 133 try { 134 IAbstractFile iAbstractFile = ((ResourceFile)element).getFile(); 135 if (iAbstractFile instanceof IFileWrapper) { 136 IDE.openEditor(getSite().getWorkbenchWindow().getActivePage(), 137 ((IFileWrapper)iAbstractFile).getIFile()); 138 } 139 } catch (PartInitException e) { 140 } 141 } else if (element instanceof ProjectResourceItem) { 142 // if it's a ResourceItem, we open the first file, but only if 143 // there's no alternate files. 144 ProjectResourceItem item = (ProjectResourceItem)element; 145 146 if (item.isEditableDirectly()) { 147 ResourceFile[] files = item.getSourceFileArray(); 148 if (files[0] != null) { 149 try { 150 IAbstractFile iAbstractFile = files[0].getFile(); 151 if (iAbstractFile instanceof IFileWrapper) { 152 IDE.openEditor( 153 getSite().getWorkbenchWindow().getActivePage(), 154 ((IFileWrapper)iAbstractFile).getIFile()); 155 } 156 } catch (PartInitException e) { 157 } 158 } 159 } 160 } 161 } 162 } 163 } 164 }); 165 166 // set up the resource manager to send us resource change notification 167 AdtPlugin.getDefault().getResourceMonitor().addResourceEventListener(this); 168 } 169 170 @Override dispose()171 public void dispose() { 172 AdtPlugin.getDefault().getResourceMonitor().removeResourceEventListener(this); 173 174 super.dispose(); 175 } 176 177 @Override setFocus()178 public void setFocus() { 179 mTree.setFocus(); 180 } 181 182 /** 183 * Processes a new selection. 184 */ selectionChanged(IWorkbenchPart part, ISelection selection)185 public void selectionChanged(IWorkbenchPart part, ISelection selection) { 186 // first we test if the part is an editor. 187 if (part instanceof IEditorPart) { 188 // if it is, we check if it's a file editor. 189 IEditorInput input = ((IEditorPart)part).getEditorInput(); 190 191 if (input instanceof IFileEditorInput) { 192 // from the file editor we can get the IFile object, and from it, the IProject. 193 IFile file = ((IFileEditorInput)input).getFile(); 194 195 // get the file project 196 IProject project = file.getProject(); 197 198 handleProjectSelection(project); 199 } 200 } else if (selection instanceof IStructuredSelection) { 201 // if it's not an editor, we look for structured selection. 202 for (Iterator<?> it = ((IStructuredSelection) selection).iterator(); 203 it.hasNext();) { 204 Object element = it.next(); 205 IProject project = null; 206 207 // if we are in the navigator or package explorer, the selection could contain a 208 // IResource object. 209 if (element instanceof IResource) { 210 project = ((IResource) element).getProject(); 211 } else if (element instanceof IJavaElement) { 212 // if we are in the package explorer on a java element, we handle that too. 213 IJavaElement javaElement = (IJavaElement)element; 214 IJavaProject javaProject = javaElement.getJavaProject(); 215 if (javaProject != null) { 216 project = javaProject.getProject(); 217 } 218 } else if (element instanceof IAdaptable) { 219 // finally we try to get a project object from IAdaptable. 220 project = (IProject) ((IAdaptable) element) 221 .getAdapter(IProject.class); 222 } 223 224 // if we found a project, handle it, and return. 225 if (project != null) { 226 if (handleProjectSelection(project)) { 227 return; 228 } 229 } 230 } 231 } 232 } 233 234 /** 235 * Handles a project selection. 236 * @param project the new selected project 237 * @return true if the project could be processed. 238 */ handleProjectSelection(IProject project)239 private boolean handleProjectSelection(IProject project) { 240 try { 241 // if it's an android project, then we get its resources, and feed them 242 // to the tree viewer. 243 if (project.hasNature(AndroidConstants.NATURE_DEFAULT)) { 244 if (mCurrentProject != project) { 245 ProjectResources projRes = ResourceManager.getInstance().getProjectResources( 246 project); 247 if (projRes != null) { 248 mTreeViewer.setInput(projRes); 249 mCurrentProject = project; 250 return true; 251 } 252 } 253 } 254 } catch (CoreException e) { 255 } 256 257 return false; 258 } 259 260 /** 261 * Create a TreeColumn with the specified parameters. If a 262 * <code>PreferenceStore</code> object and a preference entry name String 263 * object are provided then the column will listen to change in its width 264 * and update the preference store accordingly. 265 * 266 * @param parent The Table parent object 267 * @param header The header string 268 * @param style The column style 269 * @param sample_text A sample text to figure out column width if preference 270 * value is missing 271 * @param fixedSize a fixed size. If != -1 the column is non resizable 272 * @param pref_name The preference entry name for column width 273 * @param prefs The preference store 274 */ createTreeColumn(Tree parent, String header, int style, String sample_text, int fixedSize, final String pref_name, final IPreferenceStore prefs)275 public void createTreeColumn(Tree parent, String header, int style, 276 String sample_text, int fixedSize, final String pref_name, 277 final IPreferenceStore prefs) { 278 279 // create the column 280 TreeColumn col = new TreeColumn(parent, style); 281 282 if (fixedSize != -1) { 283 col.setWidth(fixedSize); 284 col.setResizable(false); 285 } else { 286 // if there is no pref store or the entry is missing, we use the sample 287 // text and pack the column. 288 // Otherwise we just read the width from the prefs and apply it. 289 if (prefs == null || prefs.contains(pref_name) == false) { 290 col.setText(sample_text); 291 col.pack(); 292 293 // init the prefs store with the current value 294 if (prefs != null) { 295 prefs.setValue(pref_name, col.getWidth()); 296 } 297 } else { 298 col.setWidth(prefs.getInt(pref_name)); 299 } 300 301 // if there is a pref store and a pref entry name, then we setup a 302 // listener to catch column resize to put the new width value into the store. 303 if (prefs != null && pref_name != null) { 304 col.addControlListener(new ControlListener() { 305 public void controlMoved(ControlEvent e) { 306 } 307 308 public void controlResized(ControlEvent e) { 309 // get the new width 310 int w = ((TreeColumn)e.widget).getWidth(); 311 312 // store in pref store 313 prefs.setValue(pref_name, w); 314 } 315 }); 316 } 317 } 318 319 // set the header 320 col.setText(header); 321 } 322 323 /** 324 * Processes a start in a resource event change. 325 */ resourceChangeEventStart()326 public void resourceChangeEventStart() { 327 // pass 328 } 329 330 /** 331 * Processes the end of a resource change event. 332 */ resourceChangeEventEnd()333 public void resourceChangeEventEnd() { 334 try { 335 mTree.getDisplay().asyncExec(new Runnable() { 336 public void run() { 337 if (mTree.isDisposed() == false) { 338 mTreeViewer.refresh(); 339 } 340 } 341 }); 342 } catch (SWTException e) { 343 // display is disposed. nothing to do. 344 } 345 } 346 } 347