1 19 20 package org.netbeans.modules.ant.freeform; 21 22 import java.awt.event.ActionEvent ; 23 import java.io.File ; 24 import java.io.IOException ; 25 import java.text.MessageFormat ; 26 import java.util.ArrayList ; 27 import java.util.Arrays ; 28 import java.util.Collection ; 29 import java.util.Collections ; 30 import java.util.HashMap ; 31 import java.util.HashSet ; 32 import java.util.Iterator ; 33 import java.util.LinkedHashSet ; 34 import java.util.List ; 35 import java.util.Map ; 36 import java.util.Properties ; 37 import java.util.Set ; 38 import java.util.logging.Level ; 39 import java.util.logging.Logger ; 40 import java.util.regex.Pattern ; 41 import java.util.regex.PatternSyntaxException ; 42 import javax.swing.AbstractAction ; 43 import javax.swing.Action ; 44 import org.apache.tools.ant.module.api.support.ActionUtils; 45 import org.netbeans.modules.ant.freeform.spi.support.Util; 46 import org.netbeans.modules.ant.freeform.ui.ProjectNodeWrapper; 47 import org.netbeans.modules.ant.freeform.ui.UnboundTargetAlert; 48 import org.netbeans.spi.project.ActionProvider; 49 import org.netbeans.spi.project.support.ant.AntProjectHelper; 50 import org.netbeans.spi.project.ui.support.CommonProjectActions; 51 import org.netbeans.spi.project.ui.support.DefaultProjectOperations; 52 import org.netbeans.spi.project.ui.support.ProjectSensitiveActions; 53 import org.openide.DialogDisplayer; 54 import org.openide.ErrorManager; 55 import org.openide.NotifyDescriptor; 56 import org.openide.actions.FindAction; 57 import org.openide.actions.ToolsAction; 58 import org.openide.filesystems.FileObject; 59 import org.openide.filesystems.FileUtil; 60 import org.openide.loaders.DataObject; 61 import org.openide.util.Lookup; 62 import org.openide.util.NbBundle; 63 import org.openide.util.actions.SystemAction; 64 import org.w3c.dom.Element ; 65 66 70 public final class Actions implements ActionProvider { 71 72 private static final Logger LOG = Logger.getLogger(Actions.class.getName()); 73 74 78 private static final Set <String > COMMON_IDE_GLOBAL_ACTIONS = new HashSet <String >(Arrays.asList( 79 ActionProvider.COMMAND_DEBUG, 80 ActionProvider.COMMAND_DELETE, 81 ActionProvider.COMMAND_COPY, 82 ActionProvider.COMMAND_MOVE, 83 ActionProvider.COMMAND_RENAME)); 84 90 private static final Set <String > COMMON_NON_IDE_GLOBAL_ACTIONS = new HashSet <String >(Arrays.asList( 91 ActionProvider.COMMAND_BUILD, 92 ActionProvider.COMMAND_CLEAN, 93 ActionProvider.COMMAND_REBUILD, 94 ActionProvider.COMMAND_RUN, 95 ActionProvider.COMMAND_TEST, 96 "javadoc", "redeploy")); 102 private final FreeformProject project; 103 104 108 public Actions(FreeformProject project) { 109 this.project = project; 110 } 111 112 public String [] getSupportedActions() { 113 Element genldata = project.getPrimaryConfigurationData(); 114 Element actionsEl = Util.findElement(genldata, "ide-actions", FreeformProjectType.NS_GENERAL); if (actionsEl == null) { 116 return new String [0]; 117 } 118 Set <String > names = new LinkedHashSet <String >(); 120 for (Element actionEl : Util.findSubElements(actionsEl)) { 121 names.add(actionEl.getAttribute("name")); } 123 names.addAll(COMMON_NON_IDE_GLOBAL_ACTIONS); 125 names.add(COMMAND_RENAME); 126 names.add(COMMAND_MOVE); 127 names.add(COMMAND_COPY); 128 names.add(COMMAND_DELETE); 129 return names.toArray(new String [names.size()]); 130 } 131 132 public boolean isActionEnabled(String command, Lookup context) throws IllegalArgumentException { 133 if (COMMAND_DELETE.equals(command)) { 134 return true; 135 } 136 if (COMMAND_COPY.equals(command)) { 137 return true; 138 } 139 if (COMMAND_RENAME.equals(command)) { 140 return true; 141 } 142 if (COMMAND_MOVE.equals(command)) { 143 return true; 144 } 145 146 Element genldata = project.getPrimaryConfigurationData(); 147 Element actionsEl = Util.findElement(genldata, "ide-actions", FreeformProjectType.NS_GENERAL); if (actionsEl == null) { 149 throw new IllegalArgumentException ("No commands supported"); } 151 boolean foundAction = false; 152 for (Element actionEl : Util.findSubElements(actionsEl)) { 153 if (actionEl.getAttribute("name").equals(command)) { foundAction = true; 155 Element contextEl = Util.findElement(actionEl, "context", FreeformProjectType.NS_GENERAL); if (contextEl != null) { 158 Map <String ,FileObject> selection = findSelection(contextEl, context, project); 161 LOG.log(Level.FINE, "detected selection {0} for command {1} in {2}", new Object [] {selection, command, project}); 162 if (selection.size() == 1) { 163 return true; 165 } else if (!selection.isEmpty()) { 166 Element arityEl = Util.findElement(contextEl, "arity", FreeformProjectType.NS_GENERAL); assert arityEl != null : "No <arity> in <context> for " + command; 169 if (Util.findElement(arityEl, "separated-files", FreeformProjectType.NS_GENERAL) != null) { return true; 172 } 173 } 174 } else { 175 return true; 177 } 178 } 179 } 180 if (COMMON_NON_IDE_GLOBAL_ACTIONS.contains(command)) { 181 return true; 183 } 184 if (foundAction) { 185 return false; 187 } else { 188 throw new IllegalArgumentException ("Unrecognized command: " + command); } 190 } 191 192 public void invokeAction(String command, Lookup context) throws IllegalArgumentException { 193 if (COMMAND_DELETE.equals(command)) { 194 DefaultProjectOperations.performDefaultDeleteOperation(project); 195 return ; 196 } 197 if (COMMAND_COPY.equals(command)) { 198 DefaultProjectOperations.performDefaultCopyOperation(project); 199 return ; 200 } 201 if (COMMAND_RENAME.equals(command)) { 202 DefaultProjectOperations.performDefaultRenameOperation(project, null); 203 return ; 204 } 205 if (COMMAND_MOVE.equals(command)) { 206 DefaultProjectOperations.performDefaultMoveOperation(project); 207 return ; 208 } 209 210 Element genldata = project.getPrimaryConfigurationData(); 211 Element actionsEl = Util.findElement(genldata, "ide-actions", FreeformProjectType.NS_GENERAL); if (actionsEl == null) { 213 throw new IllegalArgumentException ("No commands supported"); } 215 boolean foundAction = false; 216 for (Element actionEl : Util.findSubElements(actionsEl)) { 217 if (actionEl.getAttribute("name").equals(command)) { foundAction = true; 219 runConfiguredAction(project, actionEl, context); 220 } 221 } 222 if (!foundAction) { 223 if (COMMON_NON_IDE_GLOBAL_ACTIONS.contains(command)) { 224 if (addGlobalBinding(command)) { 226 invokeAction(command, context); 228 } 229 } else { 230 throw new IllegalArgumentException ("Unrecognized command: " + command); } 232 } 233 } 234 235 241 private static Map <String ,FileObject> findSelection(Element contextEl, Lookup context, FreeformProject project) { 242 Collection <? extends FileObject> files = context.lookupAll(FileObject.class); 243 if (files.isEmpty()) { 244 Collection <? extends DataObject> filesDO = context.lookupAll(DataObject.class); 246 if (filesDO.isEmpty()) { 247 return Collections.emptyMap(); 248 } 249 Collection <FileObject> _files = new ArrayList <FileObject>(filesDO.size()); 250 for (DataObject d : filesDO) { 251 _files.add(d.getPrimaryFile()); 252 } 253 files = _files; 254 } 255 Element folderEl = Util.findElement(contextEl, "folder", FreeformProjectType.NS_GENERAL); assert folderEl != null : "Must have <folder> in <context>"; 257 String rawtext = Util.findText(folderEl); 258 assert rawtext != null : "Must have text contents in <folder>"; 259 String evaltext = project.evaluator().evaluate(rawtext); 260 if (evaltext == null) { 261 return Collections.emptyMap(); 262 } 263 FileObject folder = project.helper().resolveFileObject(evaltext); 264 if (folder == null) { 265 return Collections.emptyMap(); 266 } 267 Pattern pattern = null; 268 Element patternEl = Util.findElement(contextEl, "pattern", FreeformProjectType.NS_GENERAL); if (patternEl != null) { 270 String text = Util.findText(patternEl); 271 assert text != null : "Must have text contents in <pattern>"; 272 try { 273 pattern = Pattern.compile(text); 274 } catch (PatternSyntaxException e) { 275 org.netbeans.modules.ant.freeform.Util.err.annotate(e, ErrorManager.UNKNOWN, "From <pattern> in " + FileUtil.getFileDisplayName(project.getProjectDirectory().getFileObject(AntProjectHelper.PROJECT_XML_PATH)), null, null, null); org.netbeans.modules.ant.freeform.Util.err.notify(e); 277 return Collections.emptyMap(); 278 } 279 } 280 Map <String ,FileObject> result = new HashMap <String ,FileObject>(); 281 for (FileObject file : files) { 282 String path = FileUtil.getRelativePath(folder, file); 283 if (path == null) { 284 return Collections.emptyMap(); 285 } 286 if (pattern != null && !pattern.matcher(path).find()) { 287 return Collections.emptyMap(); 288 } 289 result.put(path, file); 290 } 291 return result; 292 } 293 294 297 private static void runConfiguredAction(FreeformProject project, Element actionEl, Lookup context) { 298 String script; 299 Element scriptEl = Util.findElement(actionEl, "script", FreeformProjectType.NS_GENERAL); if (scriptEl != null) { 301 script = Util.findText(scriptEl); 302 } else { 303 script = "build.xml"; } 305 String scriptLocation = project.evaluator().evaluate(script); 306 FileObject scriptFile = project.helper().resolveFileObject(scriptLocation); 307 if (scriptFile == null) { 308 NotifyDescriptor nd = new NotifyDescriptor.Message(MessageFormat.format(NbBundle.getMessage(Actions.class, "LBL_ScriptFileNotFoundError"), new Object [] {scriptLocation}), NotifyDescriptor.ERROR_MESSAGE); 310 311 DialogDisplayer.getDefault().notify(nd); 312 return; 313 } 314 List <Element > targets = Util.findSubElements(actionEl); 315 List <String > targetNames = new ArrayList <String >(targets.size()); 316 for (Element targetEl : targets) { 317 if (!targetEl.getLocalName().equals("target")) { continue; 319 } 320 targetNames.add(Util.findText(targetEl)); 321 } 322 String [] targetNameArray; 323 if (!targetNames.isEmpty()) { 324 targetNameArray = targetNames.toArray(new String [targetNames.size()]); 325 } else { 326 targetNameArray = null; 328 } 329 Properties props = new Properties (); 330 Element contextEl = Util.findElement(actionEl, "context", FreeformProjectType.NS_GENERAL); if (contextEl != null) { 332 Map <String ,FileObject> selection = findSelection(contextEl, context, project); 333 if (selection.isEmpty()) { 334 return; 335 } 336 String separator = null; 337 if (selection.size() > 1) { 338 Element arityEl = Util.findElement(contextEl, "arity", FreeformProjectType.NS_GENERAL); assert arityEl != null : "No <arity> in <context> for " + actionEl.getAttribute("name"); 341 Element sepFilesEl = Util.findElement(arityEl, "separated-files", FreeformProjectType.NS_GENERAL); if (sepFilesEl == null) { 343 return; 345 } 346 separator = Util.findText(sepFilesEl); 347 } 348 Element formatEl = Util.findElement(contextEl, "format", FreeformProjectType.NS_GENERAL); assert formatEl != null : "No <format> in <context> for " + actionEl.getAttribute("name"); 350 String format = Util.findText(formatEl); 351 StringBuffer buf = new StringBuffer (); 352 Iterator <Map.Entry <String ,FileObject>> it = selection.entrySet().iterator(); 353 while (it.hasNext()) { 354 Map.Entry <String ,FileObject> entry = it.next(); 355 if (format.equals("absolute-path")) { File f = FileUtil.toFile(entry.getValue()); 357 if (f == null) { 358 return; 360 } 361 buf.append(f.getAbsolutePath()); 362 } else if (format.equals("relative-path")) { buf.append(entry.getKey()); 364 } else if (format.equals("absolute-path-noext")) { File f = FileUtil.toFile(entry.getValue()); 366 if (f == null) { 367 return; 369 } 370 String path = f.getAbsolutePath(); 371 int dot = path.lastIndexOf('.'); 372 if (dot > path.lastIndexOf('/')) { 373 path = path.substring(0, dot); 374 } 375 buf.append(path); 376 } else if (format.equals("relative-path-noext")) { String path = entry.getKey(); 378 int dot = path.lastIndexOf('.'); 379 if (dot > path.lastIndexOf('/')) { 380 path = path.substring(0, dot); 381 } 382 buf.append(path); 383 } else { 384 assert format.equals("java-name") : format; 385 String path = entry.getKey(); 386 int dot = path.lastIndexOf('.'); 387 String dotless; 388 if (dot == -1 || dot < path.lastIndexOf('/')) { 389 dotless = path; 390 } else { 391 dotless = path.substring(0, dot); 392 } 393 String javaname = dotless.replace('/', '.'); 394 buf.append(javaname); 395 } 396 if (it.hasNext()) { 397 assert separator != null; 398 buf.append(separator); 399 } 400 } 401 Element propEl = Util.findElement(contextEl, "property", FreeformProjectType.NS_GENERAL); assert propEl != null : "No <property> in <context> for " + actionEl.getAttribute("name"); 403 String prop = Util.findText(propEl); 404 assert prop != null : "Must have text contents in <property>"; 405 props.setProperty(prop, buf.toString()); 406 } 407 for (Element propEl : targets) { 408 if (!propEl.getLocalName().equals("property")) { continue; 410 } 411 String rawtext = Util.findText(propEl); 412 if (rawtext == null) { 413 rawtext = ""; } 416 String evaltext = project.evaluator().evaluate(rawtext); if (evaltext != null) { 418 props.setProperty(propEl.getAttribute("name"), evaltext); } 420 } 421 TARGET_RUNNER.runTarget(scriptFile, targetNameArray, props); 422 } 423 424 429 public static Action [] createContextMenu(FreeformProject p) { 430 List <Action > actions = new ArrayList <Action >(); 431 actions.add(CommonProjectActions.newFileAction()); 432 Element genldata = p.getPrimaryConfigurationData(); 434 Element viewEl = Util.findElement(genldata, "view", FreeformProjectType.NS_GENERAL); if (viewEl != null) { 436 Element contextMenuEl = Util.findElement(viewEl, "context-menu", FreeformProjectType.NS_GENERAL); if (contextMenuEl != null) { 438 actions.add(null); 439 for (Element actionEl : Util.findSubElements(contextMenuEl)) { 440 if (actionEl.getLocalName().equals("ide-action")) { String cmd = actionEl.getAttribute("name"); 442 String displayName; 443 if (COMMON_IDE_GLOBAL_ACTIONS.contains(cmd) || COMMON_NON_IDE_GLOBAL_ACTIONS.contains(cmd)) { 444 displayName = NbBundle.getMessage(Actions.class, "CMD_" + cmd); 445 } else { 446 displayName = cmd; 448 } 449 actions.add(ProjectSensitiveActions.projectCommandAction(cmd, displayName, null)); 450 } else if (actionEl.getLocalName().equals("separator")) { actions.add(null); 452 } else { 453 assert actionEl.getLocalName().equals("action") : actionEl; 454 actions.add(new CustomAction(p, actionEl)); 455 } 456 } 457 } 458 } 459 actions.add(null); 461 actions.add(CommonProjectActions.setAsMainProjectAction()); 462 actions.add(CommonProjectActions.openSubprojectsAction()); 463 actions.add(CommonProjectActions.closeProjectAction()); 464 actions.add(null); 465 actions.add(CommonProjectActions.renameProjectAction()); 466 actions.add(CommonProjectActions.moveProjectAction()); 467 actions.add(CommonProjectActions.copyProjectAction()); 468 actions.add(CommonProjectActions.deleteProjectAction()); 469 actions.add(null); 470 actions.add(SystemAction.get(FindAction.class)); 471 472 actions.add(ProjectNodeWrapper.GENERIC_PROJECTS_ACTIONS_MARKER); 474 475 actions.add(null); 476 actions.add(SystemAction.get(ToolsAction.class)); 477 actions.add(null); 478 actions.add(CommonProjectActions.customizeProjectAction()); 479 return actions.toArray(new Action [actions.size()]); 480 } 481 482 private static final class CustomAction extends AbstractAction { 483 484 private final FreeformProject p; 485 private final Element actionEl; 486 487 public CustomAction(FreeformProject p, Element actionEl) { 488 this.p = p; 489 this.actionEl = actionEl; 490 } 491 492 public void actionPerformed(ActionEvent e) { 493 runConfiguredAction(p, actionEl, Lookup.EMPTY); 494 } 495 496 public boolean isEnabled() { 497 String script; 498 Element scriptEl = Util.findElement(actionEl, "script", FreeformProjectType.NS_GENERAL); if (scriptEl != null) { 500 script = Util.findText(scriptEl); 501 } else { 502 script = "build.xml"; } 504 String scriptLocation = p.evaluator().evaluate(script); 505 return p.helper().resolveFileObject(scriptLocation) != null; 506 } 507 508 public Object getValue(String key) { 509 if (key.equals(Action.NAME)) { 510 Element labelEl = Util.findElement(actionEl, "label", FreeformProjectType.NS_GENERAL); return Util.findText(labelEl); 512 } else { 513 return super.getValue(key); 514 } 515 } 516 517 } 518 519 static TargetRunner TARGET_RUNNER = new TargetRunner(); 521 522 static class TargetRunner { 523 public TargetRunner() {} 524 public void runTarget(FileObject scriptFile, String [] targetNameArray, Properties props) { 525 try { 526 ActionUtils.runTarget(scriptFile, targetNameArray, props); 527 } catch (IOException e) { 528 ErrorManager.getDefault().notify(e); 529 } 530 } 531 } 532 533 542 private boolean addGlobalBinding(String command) { 543 try { 544 return new UnboundTargetAlert(project, command).accepted(); 545 } catch (IOException e) { 546 ErrorManager.getDefault().notify(e); 548 return false; 549 } 550 } 551 552 } 553 | Popular Tags |