1 19 20 package org.openide.src.nodes; 21 22 23 import java.awt.Component ; 24 import java.awt.datatransfer.Transferable ; 25 import java.beans.*; 26 import java.io.IOException ; 27 import java.lang.reflect.Modifier ; 28 import java.util.*; 29 import org.netbeans.api.java.classpath.ClassPath; 30 31 import org.openide.*; 32 import org.openide.src.*; 33 import org.openide.nodes.*; 34 import org.openide.cookies.SourceCookie; 35 import org.openide.filesystems.FileObject; 36 import org.openide.loaders.DataObject; 37 import org.openide.util.*; 38 import org.openide.util.datatransfer.NewType; 39 import org.openide.util.datatransfer.PasteType; 40 import org.openide.util.datatransfer.ExTransferable; 41 42 47 class SourceEditSupport { 48 49 static final ResourceBundle bundle = NbBundle.getBundle(SourceEditSupport.class); 50 51 static final String [] MENU_NAMES = { 52 bundle.getString("MENU_CREATE_BLOCK"), bundle.getString("MENU_CREATE_VARIABLE"), 53 bundle.getString("MENU_CREATE_CONSTRUCTOR"), bundle.getString("MENU_CREATE_METHOD"), 54 bundle.getString("MENU_CREATE_CLASS"), bundle.getString("MENU_CREATE_INTERFACE") 55 }; 56 57 61 public static NewType[] createNewTypes(ClassElement element) { 62 if (element.isClass()) { 63 return new NewType[] { 65 new ElementNewType(element, (byte) 0), 66 new ElementNewType(element, (byte) 1), 67 new ElementNewType(element, (byte) 2), 68 new ElementNewType(element, (byte) 3), 69 new ElementNewType(element, (byte) 4), 70 new ElementNewType(element, (byte) 5) 71 }; 72 } 73 else { 74 return new NewType[] { 76 new ElementNewType(element, (byte) 1), 77 new ElementNewType(element, (byte) 3), 78 new ElementNewType(element, (byte) 4), 79 new ElementNewType(element, (byte) 5) 80 }; 81 } 82 } 83 84 85 static class ElementNewType extends NewType { 86 87 ClassElement element; 88 89 92 ClassElement proxy; 93 94 95 byte kind; 96 97 101 public ElementNewType(ClassElement element, byte kind) { 102 this.element = element; 103 proxy = new ClassElement(); 104 try { 105 proxy.setName(Identifier.create("Default")); proxy.setClassOrInterface(element.isClassOrInterface()); 107 } catch (SourceException ex) { 108 } 110 this.kind = kind; 111 } 112 113 116 public String getName() { 117 return MENU_NAMES[kind]; 118 } 119 120 121 public org.openide.util.HelpCtx getHelpCtx() { 122 return new org.openide.util.HelpCtx (SourceEditSupport.class.getName () + ".newElement" + kind); } 124 125 126 public void create () throws IOException { 127 final Identifier outerName = element.getName(); 128 final boolean outerIsClass = element.isClass(); 129 130 Element newElement = null; 131 132 try { 133 switch (kind) { 134 case 0: 135 { 136 InitializerElement e = new InitializerElement(); 138 e.setStatic(true); 139 e.setBody("\n"); newElement = e; 141 break; 142 } 143 case 1: 144 { 145 FieldElement e = new FieldElement(); 147 e.setType(Type.INT); 148 e.setName(Identifier.create("newField")); e.setModifiers(Modifier.PRIVATE + (outerIsClass ? 0 : Modifier.STATIC)); 150 proxy.addField(e); 151 e = proxy.getFields()[0]; 152 FieldCustomizer cust = new FieldCustomizer(e); 153 if (openCustomizer(cust, "TIT_NewField") && cust.isOK()) newElement = e; 155 break; 156 } 157 case 2: 158 { 159 ConstructorElement e = new ConstructorElement(); 161 e.setName(Identifier.create(((ClassElement)element).getName().getName())); 162 e.setModifiers(Modifier.PUBLIC); 163 e.setBody("\n"); MethodCustomizer cust = new MethodCustomizer(e); 165 if (openCustomizer(cust, "TIT_NewConstructor") && cust.isOK()) newElement = e; 167 break; 168 } 169 case 3: 170 { 171 MethodElement e = new MethodElement(); 173 e.setReturn(Type.VOID); 174 e.setName(Identifier.create("newMethod")); e.setModifiers(Modifier.PUBLIC); 176 e.setBody(outerIsClass ? "\n" : null); proxy.addMethod(e); 178 e = proxy.getMethods()[0]; 179 MethodCustomizer cust = new MethodCustomizer(e); 180 if (openCustomizer(cust, "TIT_NewMethod") && cust.isOK()) { if ((e.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) > 0) { 182 e.setBody(null); 184 } 185 newElement = e; 186 } 187 break; 188 } 189 case 4: 190 { 191 ClassElement e = new ClassElement(); 193 e.setName(Identifier.create(outerName.getFullName() + ".InnerClass", "InnerClass")); e.setModifiers(Modifier.PUBLIC); 195 e.setClassOrInterface(true); 196 proxy.addClass(e); 197 e = proxy.getClasses()[0]; 198 ClassCustomizer cust = new ClassCustomizer(e); 199 if (openCustomizer(cust, "TIT_NewClass") && cust.isOK()) newElement = e; 201 break; 202 } 203 case 5: 204 { 205 ClassElement e = new ClassElement(); 207 e.setName(Identifier.create(outerName.getFullName() + ".InnerInterface", "InnerInterface")); e.setModifiers(Modifier.PUBLIC); 209 e.setClassOrInterface(false); 210 proxy.addClass(e); 211 e = proxy.getClasses()[0]; 212 ClassCustomizer cust = new ClassCustomizer(e); 213 if (openCustomizer(cust, "TIT_NewInterface") && cust.isOK()) newElement = e; 215 break; 216 } 217 } 218 } 219 catch (SourceException exc) { 220 } 223 224 if (newElement == null) 225 return; 226 227 final Element addingElement = newElement; 228 SourceEditSupport.invokeAtomicAsUser(element, new SourceEditSupport.ExceptionalRunnable() { 229 public void run() throws SourceException { 230 switch (kind) { 231 case 0: 232 ((ClassElement)element).addInitializer((InitializerElement)addingElement); 233 return; 234 case 1: 235 ((ClassElement)element).addField((FieldElement)addingElement); 236 return; 237 case 2: 238 ((ClassElement)element).addConstructor((ConstructorElement)addingElement); 239 return; 240 case 3: 241 ((ClassElement)element).addMethod((MethodElement)addingElement); 242 return; 243 case 4: 244 case 5: 245 element.addClass((ClassElement)addingElement); 246 return; 247 } 248 } 249 }); 250 } 251 } 252 253 259 static boolean openCustomizer(Component customizer, String titleKey) { 260 NotifyDescriptor desriptor = new NotifyDescriptor( 261 customizer, 262 ElementNode.bundle.getString(titleKey), 263 NotifyDescriptor.OK_CANCEL_OPTION, 264 NotifyDescriptor.PLAIN_MESSAGE, 265 null, null); 266 267 Object ret = DialogDisplayer.getDefault().notify(desriptor); 268 return (ret == NotifyDescriptor.OK_OPTION); 269 } 270 271 276 static void invokeAtomicAsUser(Element element, final ExceptionalRunnable exRun) throws IOException { 277 try { 278 runAsUser(element, exRun); 279 } catch (SourceException.IO e) { 280 ErrorManager.getDefault().annotate(e.getReason(), 281 ErrorManager.USER, null, null, null, null); 282 throw e.getReason(); 283 } 284 catch (SourceException e) { 285 if (Boolean.getBoolean("netbeans.debug.exceptions")) e.printStackTrace(); 287 IOException x = new IOException (e.getMessage()); 288 ErrorManager.getDefault().annotate(x, 290 ErrorManager.USER, null, null, e, null); 291 throw x; 292 } 293 } 294 295 static void runAsUser(Element ref, final ExceptionalRunnable exRun) throws SourceException { 296 final SourceException ex[] = { null }; 297 SourceElement src = findSource(ref); 298 boolean retry = false; 299 do { 300 ex[0] = null; 301 if (src == null) { 302 exRun.run(); 303 } else { 304 src.runAtomicAsUser(new Runnable () { 305 public void run() { 306 try { 307 exRun.run(); 308 } catch (SourceException e) { 309 ex[0] = e; 310 } 311 } 312 }); 313 } 314 if (ex[0] != null) { 315 if (retry) 316 break; 317 retry = true; 318 if (ex[0] instanceof SourceException.IO) { 319 IOException iex = ((SourceException.IO)ex[0]).getReason(); 320 if (iex instanceof UserQuestionException) { 321 UserQuestionException uex = (UserQuestionException)iex; 322 NotifyDescriptor.Confirmation nc = new NotifyDescriptor.Confirmation(uex.getLocalizedMessage(), 323 bundle.getString("TIT_CannotWriteFile"), NotifyDescriptor.Confirmation.YES_NO_OPTION); 324 Object o = DialogDisplayer.getDefault().notify(nc); 325 if (o == NotifyDescriptor.YES_OPTION) { 326 try { 327 uex.confirmed(); 328 continue; 330 } catch (IOException x) { 331 ex[0] = new SourceException.IO(x); 332 ErrorManager.getDefault().annotate(ex[0], ErrorManager.USER, null, null, x, null); 333 } 334 } else { 335 iex = new IOException ("Cannot write"); ErrorManager.getDefault().annotate(iex, ErrorManager.USER, null, bundle.getString("ERR_CannotWriteFile"), uex, null); 337 ex[0] = new SourceException.IO(iex); 338 ErrorManager.getDefault().annotate(ex[0], ErrorManager.USER, null, bundle.getString("ERR_CannotWriteFile"), iex, null); 339 } 340 } 341 } 342 break; 344 } 345 } while (ex[0] != null); 346 347 if (ex[0] != null) 348 throw ex[0]; 349 } 350 351 355 static interface ExceptionalRunnable { 356 public void run() throws SourceException; 357 } 358 359 static boolean isWriteable(Element element) { 360 SourceElement el = findSource(element); 361 DataObject d = el == null ? null : (DataObject)el.getCookie(DataObject.class); 362 if (d == null) { 363 return true; 364 } 365 return !d.getPrimaryFile().isReadOnly(); 366 } 367 368 371 static SourceElement findSource(Element element) { 372 SourceElement source = null; 373 ClassElement clazz = null; 374 if (element instanceof ClassElement) { 375 clazz = (ClassElement) element; 376 } 377 else if (element instanceof MemberElement) { 378 clazz = ((MemberElement) element).getDeclaringClass(); 379 } 380 else if (element instanceof InitializerElement) { 381 clazz = ((InitializerElement) element).getDeclaringClass(); 382 } 383 else if (element instanceof SourceElement) { 384 return (SourceElement) element; 385 } 386 if (clazz != null) { 387 source = clazz.getSource(); 388 } 389 return source; 390 } 391 392 static void createJavaFile(ClassElement clazz, FileObject target) throws SourceException, IOException { 393 DataObject targetObject; 394 String name = clazz.getName().getSourceName(); 395 FileObject newFile; 396 ClassPath cp = ClassPath.getClassPath(target, ClassPath.SOURCE); 397 if (cp == null) { 398 throw new IOException ("No known package source root for " + target); } 400 String packageName = cp.getResourceName(target, '.', true); 401 String newName; 402 403 if ("".equals(packageName)) packageName = null; 405 newName = org.openide.filesystems.FileUtil.findFreeFileName(target, name, "java"); newFile = target.createData(name, "java"); SourceElement newSrc; 408 SourceCookie cookie; 409 try { 410 targetObject = DataObject.find(newFile); 411 } catch (org.openide.loaders.DataObjectNotFoundException e) { 412 throw (IOException )ErrorManager.getDefault().annotate( 413 new IOException (e.getMessage()), 414 ErrorManager.EXCEPTION, "Data object can't be created", bundle.getString("EXC_CREATE_SOURCE_FILE"), 416 e, null 417 ); 418 } 419 cookie = (SourceCookie)targetObject.getCookie(SourceCookie.class); 420 if (cookie == null) { 421 throw (SourceException)ErrorManager.getDefault().annotate( 423 new SourceException("Source element cannot be found"), bundle.getString("EXC_CREATE_SOURCE_FILE") 425 ); 426 } 427 if (packageName != null) cookie.getSource().setPackage(Identifier.create(packageName)); 429 cookie.getSource().addClass(clazz); 430 431 ClassElement targetC = cookie.getSource().getClass(Identifier.create(clazz.getName().getSourceName())); 432 int mods = targetC.getModifiers() & ~Modifier.STATIC; 433 if ((mods & (Modifier.PROTECTED | Modifier.PRIVATE)) > 0) { 434 mods = (mods & ~(Modifier.PROTECTED | Modifier.PRIVATE)) | Modifier.PUBLIC; 435 } 436 targetC.setModifiers(mods); 437 } 438 439 static void removeClass(ClassElement clazz) throws SourceException { 440 if (clazz.getDeclaringClass() != null) { 441 clazz.getDeclaringClass().removeClass(clazz); 442 } else { 443 SourceElement src = SourceEditSupport.findSource(clazz); 444 if (src == null) { 445 throw (SourceException)ErrorManager.getDefault().annotate( 446 new SourceException("Element has no source"), bundle.getString("EXC_NO_SOURCE") 448 ); 449 } 450 src.removeClass(clazz); 451 } 452 } 453 454 static class PackagePaste implements NodeTransfer.Paste { 455 private static PasteType[] EMPTY_TYPES = new PasteType[0]; 456 458 private boolean deleteSelf; 459 460 462 private ClassElement element; 463 464 PackagePaste(ClassElement cls, boolean deleteSelf) { 465 this.deleteSelf = deleteSelf; 466 this.element = cls; 467 } 468 469 public PasteType[] types(Node target) { 470 DataObject obj = (DataObject)target.getCookie(DataObject.class); 471 if (element == null || obj == null) 472 return EMPTY_TYPES; 473 FileObject fob = obj.getPrimaryFile(); 474 if (!fob.isFolder()) { 475 return EMPTY_TYPES; 476 } 477 return new PasteType[] { 478 new Type(fob) 479 }; 480 } 481 482 private class Type extends PasteType { 483 485 private FileObject target; 486 487 Type(FileObject target) { 488 this.target = target; 489 } 490 491 public String getName() { 492 return bundle.getString("MENU_PASTE_AS_FILE"); 493 } 494 495 public org.openide.util.HelpCtx getHelpCtx() { 496 return super.getHelpCtx(); 497 } 498 499 public Transferable paste() throws IOException { 500 final ClassElement clazz = PackagePaste.this.element; 501 final boolean del = PackagePaste.this.deleteSelf; 502 503 try { 504 createJavaFile(clazz, target); 505 } catch (SourceException ex) { 506 IOException x = new IOException (ex.getMessage()); 507 ErrorManager.getDefault().annotate(x, ex); 508 throw x; 509 } 510 if (del) { 511 final SourceException ex[] = { null }; 512 SourceEditSupport.invokeAtomicAsUser(clazz, new SourceEditSupport.ExceptionalRunnable() { 513 public void run() throws SourceException { 514 try { 515 removeClass(clazz); 516 } catch (SourceException e) { 517 ex[0] = e; 518 } 519 } 520 }); 521 if (ex[0] != null) { 522 IOException x = new IOException (ex[0].getMessage()); 523 ErrorManager.getDefault().annotate(x, ex[0]); 524 throw x; 525 } 526 PackagePaste.this.element = null; 527 return ExTransferable.EMPTY; 528 } else { 529 return null; 530 } 531 } 532 } 533 } 534 535 static class ClassMultiPasteType extends PasteType { 536 ClassElementNode target; 537 Collection members; 538 boolean delete; 539 540 ClassMultiPasteType(ClassElementNode target, Collection members, boolean delete) { 541 this.target = target; 542 this.members = members; 543 this.delete = delete; 544 } 545 546 public Transferable paste() throws IOException { 547 for (Iterator it = members.iterator(); it.hasNext(); ) { 548 target.pasteElement((Element)it.next(), delete); 549 } 550 if (delete) 551 return ExTransferable.EMPTY; 552 else 553 return null; 554 } 555 } 556 } 557 | Popular Tags |