1 19 20 package org.netbeans.modules.junit; 21 22 import com.sun.source.tree.Tree; 23 import com.sun.source.util.TreePath; 24 import java.awt.EventQueue ; 25 import java.io.IOException ; 26 import java.util.Collections ; 27 import java.util.logging.Level ; 28 import java.util.logging.Logger ; 29 import javax.lang.model.element.Element; 30 import javax.swing.Action ; 31 import javax.swing.JEditorPane ; 32 import javax.swing.text.Document ; 33 import org.netbeans.api.java.classpath.ClassPath; 34 import org.netbeans.api.java.project.JavaProjectConstants; 35 import org.netbeans.api.java.queries.UnitTestForSourceQuery; 36 import org.netbeans.api.java.source.CancellableTask; 37 import org.netbeans.api.java.source.ClasspathInfo; 38 import org.netbeans.api.java.source.CompilationController; 39 import org.netbeans.api.java.source.JavaSource; 40 import org.netbeans.api.java.source.JavaSource.Phase; 41 import org.netbeans.api.project.FileOwnerQuery; 42 import org.netbeans.api.project.Project; 43 import org.netbeans.api.project.ProjectUtils; 44 import org.netbeans.api.project.SourceGroup; 45 import org.netbeans.modules.junit.plugin.JUnitPlugin; 46 import org.netbeans.modules.junit.plugin.JUnitPlugin.Location; 47 import org.netbeans.spi.java.classpath.support.ClassPathSupport; 48 import org.openide.NotifyDescriptor; 49 import org.openide.filesystems.FileObject; 50 import org.openide.loaders.DataObject; 51 import org.openide.nodes.Node; 52 import org.openide.text.CloneableEditorSupport; 53 import org.openide.util.HelpCtx; 54 import org.openide.util.NbBundle; 55 import org.openide.util.RequestProcessor; 56 import org.openide.util.actions.CallableSystemAction; 57 import org.openide.windows.TopComponent; 58 59 69 @SuppressWarnings ("serial") 70 public final class GoToOppositeAction extends CallableSystemAction { 71 72 75 public GoToOppositeAction() { 76 super(); 77 putValue("noIconInMenu", Boolean.TRUE); String trimmedName = NbBundle.getMessage( 79 getClass(), 80 "LBL_Action_GoToTest_trimmed"); putValue("PopupMenuText", trimmedName); putValue("trimmed-text", trimmedName); } 84 85 87 @Override 88 public void performAction() { 89 assert EventQueue.isDispatchThread(); 90 91 TopComponent comp; 92 JEditorPane editorPane; 93 FileObject fileObj; 94 ClassPath srcCP; 95 FileObject fileObjRoot; 96 Project project; 97 98 boolean sourceToTest = true; 99 comp = TopComponent.getRegistry().getActivated(); 100 if (comp == null) { 101 return; 102 } 103 104 if (comp instanceof CloneableEditorSupport.Pane) { 105 editorPane = ((CloneableEditorSupport.Pane) comp).getEditorPane(); 106 if (editorPane == null) { 107 return; 108 } 109 110 fileObj = getFileObject(editorPane.getDocument()); 111 } else { 112 editorPane = null; 113 114 Node[] selectedNodes = comp.getActivatedNodes(); 115 if ((selectedNodes == null) || (selectedNodes.length != 1)) { 116 return; 117 } 118 119 DataObject dataObj = selectedNodes[0].getLookup().lookup(DataObject.class); 120 if (dataObj == null) { 121 return; 122 } 123 124 fileObj = dataObj.getPrimaryFile(); 125 } 126 127 boolean isJavaFile = false; 128 if ((fileObj == null) 129 || !fileObj.isFolder() && !(isJavaFile = TestUtil.isJavaFile(fileObj)) 130 || ((srcCP = ClassPath.getClassPath(fileObj, ClassPath.SOURCE)) == null) 131 || ((fileObjRoot = srcCP.findOwnerRoot(fileObj)) == null) 132 || ((project = FileOwnerQuery.getOwner(fileObjRoot)) == null) 133 || (UnitTestForSourceQuery.findUnitTests(fileObjRoot).length == 0) 134 && !(sourceToTest = false) && (!isJavaFile || (UnitTestForSourceQuery.findSources(fileObjRoot).length == 0))) { 136 return; 137 } 138 139 JUnitPlugin plugin = TestUtil.getPluginForProject(project); 140 assert plugin != null; 141 142 SourceGroup[] srcGroups; 143 FileObject[] srcRoots; 144 srcGroups = ProjectUtils.getSources(project) 145 .getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); 146 srcRoots = new FileObject[srcGroups.length]; 147 for (int i = 0; i < srcGroups.length; i++) { 148 srcRoots[i] = srcGroups[i].getRootFolder(); 149 } 150 ClassPath srcClassPath = ClassPathSupport.createClassPath(srcRoots); 151 152 172 RequestProcessor.getDefault().post( 173 new ActionImpl(plugin, 174 new Location(fileObj), 175 sourceToTest, 176 srcClassPath)); 177 } 178 179 182 private class ElementFinder implements CancellableTask<CompilationController> { 183 184 185 private final int caretPosition; 186 187 private volatile boolean cancelled; 188 189 private Element element = null; 190 191 193 private ElementFinder(int caretPosition) { 194 this.caretPosition = caretPosition; 195 } 196 197 199 public void run(CompilationController controller) throws IOException { 200 controller.toPhase(Phase.RESOLVED); if (cancelled) { 202 return; 203 } 204 205 TreePath treePath = controller.getTreeUtilities() 206 .pathFor(caretPosition); 207 if (treePath != null) { 208 if (cancelled) { 209 return; 210 } 211 212 TreePath parent = treePath.getParentPath(); 213 while (parent != null) { 214 Tree.Kind parentKind = parent.getLeaf().getKind(); 215 if ((parentKind == Tree.Kind.CLASS) 216 || (parentKind == Tree.Kind.COMPILATION_UNIT)) { 217 break; 218 } 219 treePath = parent; 220 parent = treePath.getParentPath(); 221 } 222 223 } 224 225 if (treePath != null) { 226 if (cancelled) { 227 return; 228 } 229 230 try { 231 element = controller.getTrees().getElement(treePath); 232 } catch (IllegalArgumentException ex) { 233 Logger.getLogger("global").log(Level.WARNING, null, ex); 234 } 235 } 236 } 237 238 240 public void cancel() { 241 cancelled = true; 242 } 243 244 246 Element getElement() { 247 return element; 248 } 249 250 } 251 252 255 private class ActionImpl implements Runnable { 256 257 private final JUnitPlugin plugin; 258 private final Location currLocation; 259 private final boolean sourceToTest; 260 private final ClassPath srcClassPath; 261 262 private Location oppoLocation; 263 264 ActionImpl(JUnitPlugin plugin, 265 Location currLocation, 266 boolean sourceToTest, 267 ClassPath srcClassPath) { 268 this.plugin = plugin; 269 this.currLocation = currLocation; 270 this.sourceToTest = sourceToTest; 271 this.srcClassPath = srcClassPath; 272 } 273 274 public void run() { 275 if (!EventQueue.isDispatchThread()) { 276 findOppositeLocation(); 277 if ((oppoLocation != null) || sourceToTest) { 278 EventQueue.invokeLater(this); 279 } 280 } else { 281 if (oppoLocation != null) { 282 goToOppositeLocation(); 283 } else if (sourceToTest) { 284 displayNoOppositeLocationFound(); 285 } 286 } 287 } 288 289 291 private void findOppositeLocation() { 292 oppoLocation = sourceToTest 293 ? JUnitPluginTrampoline.DEFAULT.getTestLocation(plugin, 294 currLocation) 295 : JUnitPluginTrampoline.DEFAULT.getTestedLocation(plugin, 296 currLocation); 297 } 298 299 301 private void goToOppositeLocation() { 302 assert oppoLocation != null; 303 assert oppoLocation.getFileObject() != null; 304 305 final FileObject oppoFile = oppoLocation.getFileObject(); 306 OpenTestAction.openFile(oppoFile); 312 } 314 315 317 private void displayNoOppositeLocationFound() { 318 String sourceClsName; 319 FileObject fileObj = currLocation.getFileObject(); 320 sourceClsName = srcClassPath.getResourceName(fileObj, '.', false); 321 String msgKey = !fileObj.isFolder() 322 ? "MSG_test_class_not_found" : (sourceClsName.length() != 0) 324 ? "MSG_testsuite_class_not_found" : "MSG_testsuite_class_not_found_def_pkg"; TestUtil.notifyUser( 327 NbBundle.getMessage(getClass(), msgKey, sourceClsName), 328 NotifyDescriptor.INFORMATION_MESSAGE); 329 } 330 331 } 332 333 335 @Override 336 public boolean isEnabled() { 337 assert EventQueue.isDispatchThread(); 338 339 return checkDirection() != null; 340 } 341 342 344 public String getName() { 345 return NbBundle.getMessage(getClass(), 346 checkDirection() == Boolean.FALSE 347 ? "LBL_Action_GoToSource" : "LBL_Action_GoToTest"); } 350 351 361 private Boolean checkDirection() { 362 TopComponent comp = TopComponent.getRegistry().getActivated(); 363 if (comp == null) { 364 return null; 365 } 366 367 FileObject fileObj = null; 368 369 if (comp instanceof CloneableEditorSupport.Pane) { 370 JEditorPane editorPane = ((CloneableEditorSupport.Pane) comp).getEditorPane(); 371 if (editorPane != null) { 372 fileObj = getFileObject(editorPane.getDocument()); 373 } 374 } else { 375 Node[] selectedNodes = comp.getActivatedNodes(); 376 if ((selectedNodes != null) && (selectedNodes.length == 1)) { 377 DataObject dataObj = selectedNodes[0].getLookup().lookup(DataObject.class); 378 if (dataObj != null) { 379 fileObj = dataObj.getPrimaryFile(); 380 } 381 } 382 } 383 384 ClassPath srcCP; 385 FileObject fileObjRoot; 386 387 boolean isJavaFile = false; 388 boolean sourceToTest = true; 389 boolean enabled = (fileObj != null) 390 && (fileObj.isFolder() || (isJavaFile = TestUtil.isJavaFile(fileObj))) 391 && ((srcCP = ClassPath.getClassPath(fileObj, ClassPath.SOURCE)) != null) 392 && ((fileObjRoot = srcCP.findOwnerRoot(fileObj)) != null) 393 && ((UnitTestForSourceQuery.findUnitTests(fileObjRoot).length != 0) 394 || (sourceToTest = false) || isJavaFile && (UnitTestForSourceQuery.findSources(fileObjRoot).length != 0)); 396 397 return enabled ? Boolean.valueOf(sourceToTest) 398 : null; 399 } 400 401 403 public HelpCtx getHelpCtx() { 404 return HelpCtx.DEFAULT_HELP; 405 } 406 407 409 protected void initialize () { 410 super.initialize (); 411 putProperty(Action.SHORT_DESCRIPTION, 412 NbBundle.getMessage(getClass(), 413 "HINT_Action_GoToTest")); } 415 416 418 @Override 419 protected boolean asynchronous() { 420 return false; 421 } 422 423 425 private static FileObject getFileObject(Document document) { 426 427 428 429 Object sdp = document.getProperty(Document.StreamDescriptionProperty); 430 if (sdp instanceof FileObject) { 431 return (FileObject) sdp; 432 } 433 if (sdp instanceof DataObject) { 434 return ((DataObject) sdp).getPrimaryFile(); 435 } 436 return null; 437 } 438 439 } 440 | Popular Tags |