Home | History | Annotate | Download | only in editors
      1 /*
      2  * Copyright (C) 2011 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 package com.android.ide.eclipse.traceview.editors;
     17 
     18 import com.android.ide.eclipse.ddms.JavaSourceRevealer;
     19 import com.android.ide.eclipse.traceview.TraceviewPlugin;
     20 import com.android.traceview.ColorController;
     21 import com.android.traceview.DmTraceReader;
     22 import com.android.traceview.MethodData;
     23 import com.android.traceview.ProfileView;
     24 import com.android.traceview.ProfileView.MethodHandler;
     25 import com.android.traceview.SelectionController;
     26 import com.android.traceview.TimeLineView;
     27 import com.android.traceview.TraceReader;
     28 import com.android.traceview.TraceUnits;
     29 
     30 import org.eclipse.core.filesystem.EFS;
     31 import org.eclipse.core.filesystem.IFileStore;
     32 import org.eclipse.core.filesystem.URIUtil;
     33 import org.eclipse.core.resources.IFile;
     34 import org.eclipse.core.resources.IWorkspace;
     35 import org.eclipse.core.resources.IWorkspaceRoot;
     36 import org.eclipse.core.resources.ResourcesPlugin;
     37 import org.eclipse.core.runtime.CoreException;
     38 import org.eclipse.core.runtime.IPath;
     39 import org.eclipse.core.runtime.IProgressMonitor;
     40 import org.eclipse.core.runtime.IStatus;
     41 import org.eclipse.core.runtime.Status;
     42 import org.eclipse.jface.dialogs.IDialogConstants;
     43 import org.eclipse.jface.dialogs.IMessageProvider;
     44 import org.eclipse.jface.dialogs.MessageDialog;
     45 import org.eclipse.jface.window.Window;
     46 import org.eclipse.swt.SWT;
     47 import org.eclipse.swt.custom.SashForm;
     48 import org.eclipse.swt.graphics.Color;
     49 import org.eclipse.swt.layout.GridData;
     50 import org.eclipse.swt.layout.GridLayout;
     51 import org.eclipse.swt.widgets.Composite;
     52 import org.eclipse.swt.widgets.Display;
     53 import org.eclipse.swt.widgets.FileDialog;
     54 import org.eclipse.swt.widgets.Label;
     55 import org.eclipse.swt.widgets.Shell;
     56 import org.eclipse.ui.IEditorInput;
     57 import org.eclipse.ui.IEditorSite;
     58 import org.eclipse.ui.PartInitException;
     59 import org.eclipse.ui.dialogs.SaveAsDialog;
     60 import org.eclipse.ui.ide.FileStoreEditorInput;
     61 import org.eclipse.ui.part.EditorPart;
     62 import org.eclipse.ui.part.FileEditorInput;
     63 
     64 import java.io.File;
     65 import java.io.IOException;
     66 import java.net.URI;
     67 
     68 public class TraceviewEditor extends EditorPart implements MethodHandler {
     69 
     70     private Composite mParent;
     71     private String mFilename;
     72     private Composite mContents;
     73 
     74     @Override
     75     public void doSave(IProgressMonitor monitor) {
     76         // We do not modify the file
     77     }
     78 
     79     /*
     80      * Copied from org.eclipse.ui.texteditor.AbstractDecoratedTextEditor.
     81      */
     82     /**
     83      * Checks whether there given file store points to a file in the workspace.
     84      * Only returns a workspace file if there's a single match.
     85      *
     86      * @param fileStore the file store
     87      * @return the <code>IFile</code> that matches the given file store
     88      */
     89     private IFile getWorkspaceFile(IFileStore fileStore) {
     90         IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
     91         IFile[] files = workspaceRoot.findFilesForLocationURI(fileStore.toURI());
     92         if (files != null && files.length == 1)
     93             return files[0];
     94         return null;
     95     }
     96 
     97     /*
     98      * Based on the performSaveAs() method defined in class
     99      * org.eclipse.ui.texteditor.AbstractDecoratedTextEditor of the
    100      * org.eclipse.ui.editors plugin.
    101      */
    102     @Override
    103     public void doSaveAs() {
    104         Shell shell = getSite().getShell();
    105         final IEditorInput input = getEditorInput();
    106 
    107         final IEditorInput newInput;
    108 
    109         if (input instanceof FileEditorInput) {
    110             // the file is part of the current workspace
    111             FileEditorInput fileEditorInput = (FileEditorInput) input;
    112             SaveAsDialog dialog = new SaveAsDialog(shell);
    113 
    114             IFile original = fileEditorInput.getFile();
    115             if (original != null) {
    116                 dialog.setOriginalFile(original);
    117             }
    118 
    119             dialog.create();
    120 
    121             if (original != null && !original.isAccessible()) {
    122                 String message = String.format(
    123                         "The original file ''%s'' has been deleted or is not accessible.",
    124                         original.getName());
    125                 dialog.setErrorMessage(null);
    126                 dialog.setMessage(message, IMessageProvider.WARNING);
    127             }
    128 
    129             if (dialog.open() == Window.CANCEL) {
    130                 return;
    131             }
    132 
    133             IPath filePath = dialog.getResult();
    134             if (filePath == null) {
    135                 return;
    136             }
    137 
    138             IWorkspace workspace = ResourcesPlugin.getWorkspace();
    139             IFile file = workspace.getRoot().getFile(filePath);
    140 
    141             if (copy(shell, fileEditorInput.getURI(), file.getLocationURI()) == null) {
    142                 return;
    143             }
    144 
    145             try {
    146                 file.refreshLocal(IFile.DEPTH_ZERO, null);
    147             } catch (CoreException e) {
    148                 // TODO Auto-generated catch block
    149                 e.printStackTrace();
    150             }
    151             newInput = new FileEditorInput(file);
    152             setInput(newInput);
    153             setPartName(newInput.getName());
    154         } else if (input instanceof FileStoreEditorInput) {
    155             // the file is not part of the current workspace
    156             FileStoreEditorInput fileStoreEditorInput = (FileStoreEditorInput) input;
    157             FileDialog dialog = new FileDialog(shell, SWT.SAVE);
    158             IPath oldPath = URIUtil.toPath(fileStoreEditorInput.getURI());
    159             if (oldPath != null) {
    160                 dialog.setFileName(oldPath.lastSegment());
    161                 dialog.setFilterPath(oldPath.toOSString());
    162             }
    163 
    164             String path = dialog.open();
    165             if (path == null) {
    166                 return;
    167             }
    168 
    169             // Check whether file exists and if so, confirm overwrite
    170             final File localFile = new File(path);
    171             if (localFile.exists()) {
    172                 MessageDialog overwriteDialog = new MessageDialog(
    173                         shell,
    174                         "Save As",
    175                         null,
    176                         String.format(
    177                                 "%s already exists.\nDo you want to replace it?"
    178                                 , path),
    179                         MessageDialog.WARNING,
    180                         new String[] {
    181                                 IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL
    182                         }, 1); // 'No' is the default
    183                 if (overwriteDialog.open() != Window.OK) {
    184                     return;
    185                 }
    186             }
    187 
    188             IFileStore destFileStore = copy(shell, fileStoreEditorInput.getURI(), localFile.toURI());
    189             if (destFileStore != null) {
    190                 IFile file = getWorkspaceFile(destFileStore);
    191                 if (file != null) {
    192                     newInput = new FileEditorInput(file);
    193                 } else {
    194                     newInput = new FileStoreEditorInput(destFileStore);
    195                 }
    196                 setInput(newInput);
    197                 setPartName(newInput.getName());
    198             }
    199         }
    200     }
    201 
    202     private IFileStore copy(Shell shell, URI source, URI dest) {
    203         IFileStore destFileStore = null;
    204         IFileStore sourceFileStore = null;
    205         try {
    206             destFileStore = EFS.getStore(dest);
    207             sourceFileStore = EFS.getStore(source);
    208             sourceFileStore.copy(destFileStore, EFS.OVERWRITE, null);
    209         } catch (CoreException ex) {
    210             String title = "Problems During Save As...";
    211             String msg = String.format("Save could not be completed. %s",
    212                     ex.getMessage());
    213             MessageDialog.openError(shell, title, msg);
    214             return null;
    215         }
    216         return destFileStore;
    217     }
    218 
    219     @Override
    220     public void init(IEditorSite site, IEditorInput input) throws PartInitException {
    221         // The contract of init() mentions we need to fail if we can't
    222         // understand the input.
    223         if (input instanceof FileEditorInput) {
    224             // We try to open a file that is part of the current workspace
    225             FileEditorInput fileEditorInput = (FileEditorInput) input;
    226             mFilename = fileEditorInput.getPath().toOSString();
    227             setSite(site);
    228             setInput(input);
    229             setPartName(input.getName());
    230         } else if (input instanceof FileStoreEditorInput) {
    231             // We try to open a file that is not part of the current workspace
    232             FileStoreEditorInput fileStoreEditorInput = (FileStoreEditorInput) input;
    233             mFilename = fileStoreEditorInput.getURI().getPath();
    234             setSite(site);
    235             setInput(input);
    236             setPartName(input.getName());
    237         } else {
    238             throw new PartInitException("Input is not of type FileEditorInput " + //$NON-NLS-1$
    239                     "nor FileStoreEditorInput: " + //$NON-NLS-1$
    240                     input == null ? "null" : input.toString()); //$NON-NLS-1$
    241         }
    242     }
    243 
    244     @Override
    245     public boolean isDirty() {
    246         return false;
    247     }
    248 
    249     @Override
    250     public boolean isSaveAsAllowed() {
    251         return true;
    252     }
    253 
    254     @Override
    255     public void createPartControl(Composite parent) {
    256         mParent = parent;
    257         try {
    258             TraceReader reader = new DmTraceReader(mFilename, false);
    259             reader.getTraceUnits().setTimeScale(TraceUnits.TimeScale.MilliSeconds);
    260 
    261             mContents = new Composite(mParent, SWT.NONE);
    262 
    263             Display display = mContents.getDisplay();
    264             ColorController.assignMethodColors(display, reader.getMethods());
    265             SelectionController selectionController = new SelectionController();
    266 
    267             GridLayout gridLayout = new GridLayout(1, false);
    268             gridLayout.marginWidth = 0;
    269             gridLayout.marginHeight = 0;
    270             gridLayout.horizontalSpacing = 0;
    271             gridLayout.verticalSpacing = 0;
    272             mContents.setLayout(gridLayout);
    273 
    274             Color darkGray = display.getSystemColor(SWT.COLOR_DARK_GRAY);
    275 
    276             // Create a sash form to separate the timeline view (on top)
    277             // and the profile view (on bottom)
    278             SashForm sashForm1 = new SashForm(mContents, SWT.VERTICAL);
    279             sashForm1.setBackground(darkGray);
    280             sashForm1.SASH_WIDTH = 3;
    281             GridData data = new GridData(GridData.FILL_BOTH);
    282             sashForm1.setLayoutData(data);
    283 
    284             // Create the timeline view
    285             new TimeLineView(sashForm1, reader, selectionController);
    286 
    287             // Create the profile view
    288             new ProfileView(sashForm1, reader, selectionController).setMethodHandler(this);
    289         } catch (IOException e) {
    290             Label l = new Label(parent, 0);
    291             l.setText("Failed to read the stack trace.");
    292 
    293             Status status = new Status(IStatus.ERROR, TraceviewPlugin.PLUGIN_ID,
    294                     "Failed to read the stack trace.", e);
    295             TraceviewPlugin.getDefault().getLog().log(status);
    296         }
    297 
    298         mParent.layout();
    299     }
    300 
    301     @Override
    302     public void setFocus() {
    303         mParent.setFocus();
    304     }
    305 
    306     // ---- MethodHandler methods
    307 
    308     @Override
    309     public void handleMethod(MethodData method) {
    310         String methodName = method.getMethodName();
    311         String className = method.getClassName().replaceAll("/", ".");  //$NON-NLS-1$ //$NON-NLS-2$
    312         String fqmn = className + "." + methodName; //$NON-NLS-1$
    313 
    314         JavaSourceRevealer.revealMethod(fqmn, null, -1, null);
    315     }
    316 }
    317