|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
|
2 // Use of this source code is governed by a BSD-style license that can be |
|
3 // found in the LICENSE file. |
|
4 |
|
5 package org.chromium.debug.ui.actions; |
|
6 |
|
7 import java.util.ArrayList; |
|
8 import java.util.List; |
|
9 |
|
10 import org.chromium.debug.core.model.DebugTargetImpl; |
|
11 import org.chromium.debug.core.model.VmResource; |
|
12 import org.chromium.debug.core.util.ChromiumDebugPluginUtil; |
|
13 import org.chromium.sdk.JavascriptVm; |
|
14 import org.eclipse.core.resources.IFile; |
|
15 import org.eclipse.core.resources.IResource; |
|
16 import org.eclipse.core.resources.IResourceVisitor; |
|
17 import org.eclipse.core.resources.mapping.ResourceMapping; |
|
18 import org.eclipse.core.runtime.CoreException; |
|
19 import org.eclipse.jface.action.IAction; |
|
20 import org.eclipse.jface.viewers.ISelection; |
|
21 import org.eclipse.jface.viewers.IStructuredSelection; |
|
22 import org.eclipse.swt.widgets.Event; |
|
23 import org.eclipse.ui.IActionDelegate2; |
|
24 import org.eclipse.ui.IObjectActionDelegate; |
|
25 import org.eclipse.ui.IWorkbenchPart; |
|
26 |
|
27 /** |
|
28 * A base class for all LiveEdit actions that are scoped to a working file from user workspace. |
|
29 * It makes all necessary checks and prepares data in form of {@link FilePair} class. |
|
30 * The concrete actions implement the {@link #execute(FilePair)} method. |
|
31 */ |
|
32 abstract class V8ScriptAction implements IObjectActionDelegate, IActionDelegate2 { |
|
33 private Runnable currentRunnable = null; |
|
34 |
|
35 public void setActivePart(IAction action, IWorkbenchPart targetPart) { |
|
36 } |
|
37 |
|
38 public void run(IAction action) { |
|
39 if (currentRunnable == null) { |
|
40 return; |
|
41 } |
|
42 currentRunnable.run(); |
|
43 currentRunnable = null; |
|
44 } |
|
45 |
|
46 public void selectionChanged(IAction action, ISelection selection) { |
|
47 currentRunnable = createRunnable(selection); |
|
48 action.setEnabled(currentRunnable != null); |
|
49 } |
|
50 |
|
51 private Runnable createRunnable(ISelection selection) { |
|
52 if (selection instanceof IStructuredSelection == false) { |
|
53 return null; |
|
54 } |
|
55 IStructuredSelection structured = (IStructuredSelection) selection; |
|
56 if (structured.size() != 1) { |
|
57 return null; |
|
58 } |
|
59 |
|
60 Object firstElement = structured.getFirstElement(); |
|
61 if (firstElement instanceof ResourceMapping == false) { |
|
62 return null; |
|
63 } |
|
64 ResourceMapping resourceMapping = (ResourceMapping) firstElement; |
|
65 final List<IResource> resourceList = new ArrayList<IResource>(1); |
|
66 IResourceVisitor visitor = new IResourceVisitor() { |
|
67 public boolean visit(IResource resource) throws CoreException { |
|
68 resourceList.add(resource); |
|
69 return false; |
|
70 } |
|
71 }; |
|
72 try { |
|
73 resourceMapping.accept(null, visitor, null); |
|
74 } catch (CoreException e) { |
|
75 throw new RuntimeException(e); |
|
76 } |
|
77 if (resourceList.size() != 1) { |
|
78 return null; |
|
79 } |
|
80 if (resourceList.get(0) instanceof IFile == false) { |
|
81 return null; |
|
82 } |
|
83 final IFile file = (IFile) resourceList.get(0); |
|
84 if (!filterFileName(file.getName())) { |
|
85 return null; |
|
86 } |
|
87 return new Runnable() { |
|
88 public void run() { |
|
89 try { |
|
90 execute(file); |
|
91 } catch (RuntimeException e) { |
|
92 // TODO(peter.rybin): Handle it. |
|
93 throw e; |
|
94 } |
|
95 } |
|
96 }; |
|
97 } |
|
98 |
|
99 private void execute(IFile file) { |
|
100 List<? extends FilePair> filePairList = getFilePairs(file); |
|
101 FilePair filePair = getSingleFilePair(filePairList); |
|
102 execute(filePair); |
|
103 } |
|
104 |
|
105 protected abstract void execute(FilePair filePair); |
|
106 |
|
107 /** |
|
108 * A temporary method that excludes all cases when there are more than one file pair for a |
|
109 * user file. The proper solution ought to provide a UI for user so that he could review |
|
110 * which debug sessions should be included in action. |
|
111 */ |
|
112 private static FilePair getSingleFilePair(List<? extends FilePair> pairs) { |
|
113 if (pairs.size() == 0) { |
|
114 throw new RuntimeException("File is not associated with any V8 VM"); |
|
115 } |
|
116 if (pairs.size() != 1) { |
|
117 throw new RuntimeException( |
|
118 "File is associated with several V8 VMs, this is not supported yet."); |
|
119 } |
|
120 return pairs.get(0); |
|
121 } |
|
122 |
|
123 /** |
|
124 * Finds all file pairs for a user working file. One working file may correspond to several |
|
125 * scripts if there are more than one debug sessions. |
|
126 */ |
|
127 private static List<? extends FilePair> getFilePairs(IFile localFile) { |
|
128 List<DebugTargetImpl> targetList = DebugTargetImpl.getAllDebugTargetImpls(); |
|
129 ArrayList<FilePair> result = new ArrayList<FilePair>(targetList.size()); |
|
130 |
|
131 for (DebugTargetImpl target : targetList) { |
|
132 VmResource script; |
|
133 try { |
|
134 script = target.getVmResource(localFile); |
|
135 } catch (CoreException e) { |
|
136 throw new RuntimeException("Failed to resolve script from the file " + localFile, e); |
|
137 } |
|
138 if (script == null) { |
|
139 continue; |
|
140 } |
|
141 result.add(new FilePair(localFile, script, target)); |
|
142 } |
|
143 return result; |
|
144 } |
|
145 |
|
146 protected static class FilePair { |
|
147 private final IFile file; |
|
148 private final VmResource vmResource; |
|
149 private final DebugTargetImpl debugTargetImpl; |
|
150 |
|
151 FilePair(IFile file, VmResource vmResource, DebugTargetImpl debugTargetImpl) { |
|
152 this.file = file; |
|
153 this.vmResource = vmResource; |
|
154 this.debugTargetImpl = debugTargetImpl; |
|
155 } |
|
156 protected IFile getFile() { |
|
157 return file; |
|
158 } |
|
159 protected VmResource getVmResource() { |
|
160 return vmResource; |
|
161 } |
|
162 protected JavascriptVm getJavascriptVm() { |
|
163 return debugTargetImpl.getJavascriptEmbedder().getJavascriptVm(); |
|
164 } |
|
165 protected DebugTargetImpl getDebugTarget() { |
|
166 return debugTargetImpl; |
|
167 } |
|
168 } |
|
169 |
|
170 /** |
|
171 * @return true if action should be enabled for this file name |
|
172 */ |
|
173 private boolean filterFileName(String name) { |
|
174 for (String suffix : ChromiumDebugPluginUtil.SUPPORTED_EXTENSIONS_SUFFIX_LIST) { |
|
175 if (name.endsWith(suffix)) { |
|
176 return true; |
|
177 } |
|
178 } |
|
179 return false; |
|
180 } |
|
181 |
|
182 public void dispose() { |
|
183 currentRunnable = null; |
|
184 } |
|
185 |
|
186 public void init(IAction action) { |
|
187 } |
|
188 |
|
189 public void runWithEvent(IAction action, Event event) { |
|
190 run(action); |
|
191 } |
|
192 } |
|
193 |