001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.uml.codegen.action;
043:
044: import java.io.File;
045: import java.util.ArrayList;
046: import java.util.HashMap;
047: import java.util.List;
048: import javax.swing.JButton;
049:
050: import org.netbeans.api.project.Project;
051: import org.netbeans.modules.uml.codegen.CodeGenUtil;
052: import org.netbeans.modules.uml.codegen.action.ui.GenerateCodePanel;
053: import org.netbeans.modules.uml.codegen.dataaccess.DomainTemplatesRetriever;
054:
055: import org.netbeans.modules.uml.core.metamodel.core.constructs.IClass;
056: import org.netbeans.modules.uml.core.metamodel.core.constructs.IEnumeration;
057: import org.netbeans.modules.uml.core.metamodel.core.foundation.IElement;
058: import org.netbeans.modules.uml.core.metamodel.core.foundation.INamedElement;
059: import org.netbeans.modules.uml.core.metamodel.core.foundation.INamespace;
060: import org.netbeans.modules.uml.core.metamodel.core.foundation.IPackage;
061: import org.netbeans.modules.uml.core.metamodel.core.foundation.IVersionableElement;
062: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IInterface;
063: import org.netbeans.modules.uml.core.metamodel.structure.IProject;
064: import org.netbeans.modules.uml.core.support.umlutils.ETArrayList;
065: import org.netbeans.modules.uml.core.support.umlutils.ETList;
066: import org.netbeans.modules.uml.core.support.umlutils.ElementLocator;
067: import org.netbeans.modules.uml.core.support.umlutils.IElementLocator;
068: import org.netbeans.modules.uml.project.ProjectUtil;
069: import org.netbeans.modules.uml.project.UMLProject;
070: import org.netbeans.modules.uml.project.UMLProjectHelper;
071: import org.netbeans.modules.uml.project.ui.customizer.UMLProjectProperties;
072: import org.netbeans.modules.uml.util.AbstractNBTask;
073:
074: import org.openide.DialogDescriptor;
075: import org.openide.DialogDisplayer;
076: import org.openide.NotifyDescriptor;
077: import org.openide.awt.Mnemonics;
078: import org.openide.filesystems.FileObject;
079: import org.openide.filesystems.FileUtil;
080: import org.openide.nodes.Node;
081: import org.openide.util.HelpCtx;
082: import org.openide.util.NbBundle;
083: import org.openide.util.RequestProcessor;
084: import org.openide.util.actions.CookieAction;
085:
086: /**
087: *
088: * @author Craig Conover, craig.conover@sun.com
089: */
090: public class GenerateCodeAction extends CookieAction {
091: private final static int GC_NODE_PROJECT = 1;
092: private final static int GC_NODE_NAMESPACES = 2;
093: private final static int GC_NODE_CODEGENS = 4;
094:
095: private IProject parentProject = null;
096:
097: /**
098: * Creates a new instance of GenerateCodeAction
099: */
100: public GenerateCodeAction() {
101: }
102:
103: protected void performAction(Node[] nodes) {
104: int genCodeNodeType = 0;
105:
106: final ETArrayList<IElement> elements = new ETArrayList<IElement>();
107: ArrayList<IPackage> pkgList = new ArrayList<IPackage>();
108:
109: // get the parent UML IProject
110: IElement element = nodes[0].getCookie(IElement.class);
111:
112: if (element == null) {
113: parentProject = lookupProject(nodes[0]);
114: element = parentProject;
115: }
116:
117: else
118: parentProject = getParentProject(nodes[0]);
119:
120: if (nodes.length == 1) {
121: if (element instanceof IProject) {
122: genCodeNodeType = GC_NODE_PROJECT;
123: element.addElement(element);
124: }
125:
126: else if (element instanceof IPackage) {
127: genCodeNodeType = GC_NODE_NAMESPACES;
128: pkgList.add((IPackage) element);
129: }
130:
131: else // code gen capable element
132: {
133: genCodeNodeType = GC_NODE_CODEGENS;
134: elements.add(element);
135: }
136: }
137:
138: else {
139: for (Node curNode : nodes) {
140: IElement curElement = curNode.getCookie(IElement.class);
141:
142: if (curElement != null) {
143: if (curElement instanceof IPackage) {
144: genCodeNodeType |= GC_NODE_NAMESPACES;
145:
146: // need to save these to reteive children and possibly
147: // "recursive" children based on dialog selections
148: pkgList.add((IPackage) curElement);
149: }
150:
151: // we only want to add the non-Package elements
152: else {
153: genCodeNodeType |= GC_NODE_CODEGENS;
154: elements.add(curElement);
155: }
156: } // if curElement !null
157: } // for
158: } // else - more than one node selected
159:
160: UMLProjectProperties prjProps = retrieveUMLProject()
161: .getUMLProjectProperties();
162:
163: String targetFolderName = prjProps.getCodeGenFolderLocation();
164: boolean hasTargetJavaPrj = true;
165:
166: if (targetFolderName == null || targetFolderName.length() == 0) {
167: hasTargetJavaPrj = false;
168: }
169:
170: else {
171: FileObject targetSrcFolderFO = FileUtil
172: .toFileObject(new File(targetFolderName));
173:
174: if (targetSrcFolderFO == null
175: || !targetSrcFolderFO.isValid()) {
176: hasTargetJavaPrj = false;
177: }
178: }
179:
180: // if (!hasTargetJavaPrj)
181:
182: boolean templatesEnabled = CodeGenUtil
183: .areTemplatesEnabled(prjProps
184: .getCodeGenTemplatesArray());
185:
186: if (prjProps.isCodeGenShowDialog() || !hasTargetJavaPrj
187: || !templatesEnabled) {
188: // display gen code options dialog
189: GenerateCodePanel gcPanel = new GenerateCodePanel(
190: // retrieveExportFolderDefault(nodes[0]),
191: true, retrieveUMLProject()
192: .getUMLProjectProperties(),
193: retrieveUMLProject());
194:
195: gcPanel.requestFocus();
196:
197: if (!displayDialogDescriptor(gcPanel, hasTargetJavaPrj,
198: templatesEnabled)) {
199: return;
200: }
201:
202: gcPanel.storeProjectProperties();
203: }
204:
205: ETList<IElement> selElements = new ETArrayList<IElement>();
206:
207: // action invoked from Project node
208: if ((genCodeNodeType & GC_NODE_PROJECT) == GC_NODE_PROJECT)
209: selElements = retrieveNamespaceElements(parentProject, true);
210:
211: // action not invoked from Project node
212: else {
213: // action invocation included at least one selected non-Package node
214: if ((genCodeNodeType & GC_NODE_CODEGENS) == GC_NODE_CODEGENS)
215: selElements.addThese(elements);
216:
217: // action invocation included at least one selected Package node
218: if ((genCodeNodeType & GC_NODE_NAMESPACES) == GC_NODE_NAMESPACES) {
219: // iterate through all selected package nodes and get
220: // the code gen capable elements - recursively if requested
221: for (IPackage pkg : pkgList) {
222: ETList<IElement> selected = retrieveNamespaceElements(
223: (INamespace) pkg, true);
224:
225: if (selected != null && selected.size() > 0)
226: selElements.addThese(selected);
227: }
228: }
229: }
230:
231: if (selElements == null || selElements.size() == 0) {
232: DialogDisplayer.getDefault().notify(
233: new NotifyDescriptor.Message(NbBundle.getMessage(
234: GenerateCodeAction.class,
235: "MSG_NoElementsFound"), // NOI18N
236: NotifyDescriptor.ERROR_MESSAGE));
237:
238: return;
239: }
240:
241: else
242: selElements = removeImportedElements(selElements);
243:
244: final ETList<IElement> ecElements = selElements;
245:
246: RequestProcessor processor = new RequestProcessor(
247: "uml/ExportCode"); // NOI18N
248:
249: HashMap<String, Object> settings = new HashMap<String, Object>();
250:
251: settings.put(AbstractNBTask.SETTING_KEY_TASK_NAME, NbBundle
252: .getMessage(GenerateCodeAction.class,
253: "CTL_ExportCodeActionName")); // NOI18N
254:
255: settings.put(AbstractNBTask.SETTING_KEY_TOTAL_ITEMS,
256: new Integer(selElements.size()));
257:
258: final String destFolderName = prjProps
259: .getCodeGenFolderLocation();
260: final boolean backupSources = prjProps.isCodeGenBackupSources();
261: final boolean generateMarkers = prjProps.isCodeGenUseMarkers();
262: final boolean addMarkers = prjProps.isCodeGenAddMarkers();
263: final boolean showGCDialog = prjProps.isCodeGenShowDialog();
264:
265: GenerateCodeTask task = new GenerateCodeTask(settings,
266: selElements, parentProject.getName(), destFolderName,
267: backupSources, generateMarkers, addMarkers,
268: showGCDialog);
269:
270: processor.post(task);
271: }
272:
273: private final static String COLON_COLON = "::"; // NOI18N
274:
275: private ETList<IElement> removeImportedElements(
276: ETList<IElement> elements) {
277: String parentProjectName = parentProject.getName();
278: ETList<IElement> noImports = new ETArrayList<IElement>();
279:
280: for (IElement ele : elements) {
281: String eleName = ((INamedElement) ele)
282: .getFullyQualifiedName(true);
283:
284: int end = eleName.indexOf(COLON_COLON);
285: String realPrjOwner = eleName;
286:
287: if (end != -1)
288: realPrjOwner = eleName.substring(0, end);
289:
290: if (realPrjOwner.equals(parentProjectName))
291: noImports.add(ele);
292: }
293:
294: return noImports;
295: }
296:
297: private boolean displayDialogDescriptor(GenerateCodePanel gcPanel,
298: boolean hasTargetJavaPrj, boolean templatesEnabled) {
299: JButton detailsButton = new JButton();
300: detailsButton.setActionCommand("TEMPLATES"); // NOI18N
301: detailsButton.getAccessibleContext().setAccessibleDescription(
302: NbBundle.getMessage(GenerateCodeAction.class,
303: "ACSD_DetailsButton")); // NOI18N
304:
305: if (templatesEnabled) {
306: Mnemonics.setLocalizedText(detailsButton, NbBundle
307: .getMessage(GenerateCodeAction.class,
308: "LBL_TemplatesShowButton")); // NOI18N
309: }
310:
311: else {
312: Mnemonics.setLocalizedText(detailsButton, NbBundle
313: .getMessage(GenerateCodeAction.class,
314: "LBL_TemplatesHideButton")); // NOI18N
315: }
316:
317: Object[] buttonOptions = { DialogDescriptor.OK_OPTION,
318: DialogDescriptor.CANCEL_OPTION, detailsButton };
319:
320: Object[] closeOptions = { DialogDescriptor.OK_OPTION,
321: DialogDescriptor.CANCEL_OPTION,
322: DialogDescriptor.DEFAULT_OPTION };
323:
324: GenerateCodeDescriptor gcd = new GenerateCodeDescriptor(
325: gcPanel, // inner pane
326: NbBundle.getMessage(GenerateCodeAction.class,
327: "LBL_GenerateCodeDialog_Title"), // NOI18N
328: true, // modal flag
329: buttonOptions, // button option type
330: NotifyDescriptor.OK_OPTION, // default button
331: DialogDescriptor.DEFAULT_ALIGN, // button alignment
332: new HelpCtx("uml_diagrams_generating_code"), // NOI18N
333: gcPanel, // button action listener
334: false); // isLeaf
335:
336: gcPanel.getAccessibleContext().setAccessibleName(
337: NbBundle.getMessage(GenerateCodeAction.class,
338: "ACSN_CodeGenDialog")); // NOI18N
339: gcPanel.getAccessibleContext().setAccessibleDescription(
340: NbBundle.getMessage(GenerateCodeAction.class,
341: "ACSD_CodeGenDialog")); // NOI18N
342: gcPanel.requestFocus();
343:
344: gcd.setClosingOptions(closeOptions);
345:
346: return (DialogDisplayer.getDefault().notify(gcd) == NotifyDescriptor.OK_OPTION);
347: }
348:
349: protected Class[] cookieClasses() {
350: return new Class[] { UMLProject.class, IElement.class };
351: }
352:
353: protected int mode() {
354: return MODE_ALL;
355: }
356:
357: @Override
358: protected boolean enable(Node[] nodes) {
359: if (nodes == null || nodes.length == 0)
360: return false;
361:
362: IElement element = nodes[0].getCookie(IElement.class);
363:
364: IProject parentPrj = null;
365: if (element == null) {
366: parentPrj = lookupProject(nodes[0]);
367: element = parentPrj;
368: }
369:
370: // we may have a UML project node and it doesn't hold IElement
371: // as a cookie so it won't pass the automated IElement mode test
372: // so we need to verify that it is indeed a UML project (IProject)
373: // and if it is, then it is 'enabled'
374: boolean checkSuperEnable = nodes.length > 1
375: || parentPrj == null;
376:
377: if (checkSuperEnable && !super .enable(nodes))
378: return false;
379:
380: // get the parent UML IProject
381: if (parentPrj == null)
382: parentPrj = getParentProject(nodes[0]);
383:
384: Project assocProject = ProjectUtil
385: .findNetBeansProjectForModel(parentPrj);
386: if (assocProject instanceof UMLProject) {
387: UMLProject umlProject = (UMLProject) assocProject;
388: UMLProjectProperties props = umlProject
389: .getUMLProjectProperties();
390:
391: if (props != null) {
392: String mode = props.getProjectMode();
393: if (mode != null) {
394: if (mode
395: .equals(UMLProject.PROJECT_MODE_ANALYSIS_STR)) {
396: return false;
397: }
398: }
399: }
400: }
401:
402: else {
403: return false;
404: }
405:
406: // single node selection criteria is a little different/easier/faster
407: // than multi-node selection criteria
408: if (nodes.length == 1) {
409: // node has to be Project, Package,
410: // or CodeGenType (see enum defined at top of this class)
411: if (element instanceof IProject
412: || element instanceof IPackage) {
413: return true;
414: }
415:
416: else if (isCodeGenElement(element))
417: return true;
418:
419: else
420: return false;
421: }
422:
423: // multiple nodes were selected - all must meet certain conditions
424: // for this action to be available
425:
426: for (Node curNode : nodes) {
427: IElement curEle = curNode.getCookie(IElement.class);
428:
429: // UML project node can't be part of a multi-node selection
430: if (curEle instanceof IProject)
431: return false;
432:
433: // all selected elements must be from same UML project
434: if (curEle == null || getParentProject(curEle) != parentPrj)
435: return false;
436:
437: // all selected nodes must be of type package or code gen capable
438: if ((curEle instanceof IPackage)
439: || isCodeGenElement(curEle))
440: continue;
441: else
442: return false;
443: } // for-each curNode/nodes
444:
445: return true;
446: }
447:
448: private boolean isCodeGenElement(IElement element) {
449: try {
450: CodeGenType cgType = CodeGenType.valueOf(element
451: .getElementType());
452: if (cgType == null)
453: return false;
454:
455: if (element.toString().equalsIgnoreCase(
456: getUnnamedElementPreference())) {
457: return false;
458: }
459:
460: // if the element is an inner element, then we
461: // do not enable this action
462: IElement owner = element.getOwner();
463: if (owner instanceof IClass
464: || owner instanceof IEnumeration
465: || owner instanceof IInterface) {
466: return false;
467: }
468:
469: return true;
470: }
471:
472: catch (IllegalArgumentException ex) {
473: return false;
474: }
475: }
476:
477: @Override
478: protected boolean asynchronous() {
479: return false;
480: }
481:
482: public HelpCtx getHelpCtx() {
483: return null;
484: }
485:
486: public String getName() {
487: return NbBundle.getMessage(GenerateCodeAction.class,
488: "CTL_ExportCodeActionName"); // NOI18N
489: }
490:
491: // helper methods
492:
493: private IProject getParentProject(Node node) {
494: IElement element = node.getCookie(IElement.class);
495: if (element == null)
496: return null;
497:
498: return (getParentProject(element));
499: }
500:
501: private IProject getParentProject(IElement element) {
502: return element.getProject();
503: }
504:
505: private IProject lookupProject(Node node) {
506: UMLProject umlProject = node.getLookup().lookup(
507: UMLProject.class);
508:
509: if (umlProject != null) {
510: UMLProjectHelper helper = umlProject.getLookup().lookup(
511: UMLProjectHelper.class);
512:
513: return helper.getProject();
514: }
515: return null;
516: }
517:
518: private UMLProject retrieveUMLProject() {
519: return (UMLProject) ProjectUtil
520: .findNetBeansProjectForModel(parentProject);
521: }
522:
523: // private final static String BASE_QUERY =
524: // "//*[name() = \'UML:Class\'" + // NOI18N
525: // " or name() = \'UML:Interface\'" + // NOI18N
526: // " or name() = \'UML:Enumeration\'" + // NOI18N
527: // " or name() = \'UML:Actor\'" + // NOI18N
528: // " or name() = \'UML:UseCase\'" + // NOI18N
529: // " or name() = \'UML:Component\'" + // NOI18N
530: // " or name() = \'UML:Invocation\'" + // NOI18N
531: // " or name() = \'UML:Lifeline\'" + // NOI18N
532: // " or name() = \'UML:Node\'" + // NOI18N
533: // " or name() = \'UML:SimpleState\'" + // NOI18N
534: // " or name() = \'UML:AbortedFinalState\'" + // NOI18N
535: // " or name() = \'UML:ActivityFinalNode\'" + // NOI18N
536: // " or name() = \'UML:ChoicePseudoState\'" + // NOI18N
537: // " or name() = \'UML:CombinedFragment\'" + // NOI18N
538: // " or name() = \'UML:Comment\'" + // NOI18N
539: // " or name() = \'UML:CompositeState\'" + // NOI18N
540: // " or name() = \'UML:DataStore\'" + // NOI18N
541: // " or name() = \'UML:Decision\'" + // NOI18N
542: // " or name() = \'UML:DeepHistoryState\'" + // NOI18N
543: // " or name() = \'UML:DeploymentSpecification\'" + // NOI18N
544: // " or name() = \'UML:DerivationClassifier\'" + // NOI18N
545: // " or name() = \'UML:EntryPointState\'" + // NOI18N
546: // " or name() = \'UML:FinalState\'" + // NOI18N
547: // " or name() = \'UML:FlowFinal\'" + // NOI18N
548: // " or name() = \'UML:InitialNode\'" + // NOI18N
549: // " or name() = \'UML:JunctionState\'" + // NOI18N
550: // " or name() = \'UML:Package\'" + // NOI18N
551: // " or name() = \'UML:ParameterUsage\'" + // NOI18N
552: // " or name() = \'UML:ShallowHistoryState\'" + // NOI18N
553: // " or name() = \'UML:Signal\'" + // NOI18N
554: // " or name() = \'UML:SubmachineState\'" + // NOI18N
555: // " or name() = \'UML:TemplateClass\']"; // NOI18N
556:
557: public ETList<IElement> retrieveNamespaceElements(
558: INamespace nsElement, boolean recursiveSearch) {
559: String query = null;
560: IElementLocator elementLocator = new ElementLocator();
561:
562: if (nsElement instanceof IProject) {
563: return elementLocator.findElementsByDeepQuery(nsElement,
564: getQuery((UMLProject) ProjectUtil
565: .findElementOwner(nsElement)));
566: }
567:
568: else // package scoped
569: {
570: org.dom4j.Node node = ((IVersionableElement) nsElement)
571: .getNode();
572:
573: query = node.getUniquePath()
574: + getQuery((UMLProject) ProjectUtil
575: .findElementOwner(nsElement));
576:
577: if (recursiveSearch)
578: return elementLocator.findElementsByDeepQuery(
579: nsElement, query);
580:
581: else
582: return elementLocator.findElementsByQuery(nsElement,
583: query);
584: }
585: }
586:
587: private String getQuery(UMLProject umlProject) {
588: DomainTemplatesRetriever.clear();
589: DomainTemplatesRetriever.load(umlProject);
590:
591: List<String> elementTypes = DomainTemplatesRetriever
592: .retrieveProjectEnabledModelElements();
593:
594: StringBuffer query = new StringBuffer("//*["); // NOI18N
595:
596: for (String eleType : elementTypes) {
597: query.append("name()=" + "\'UML:" + eleType + "\' or "); // NOI18N
598: }
599:
600: int lastindex = query.length() - 1;
601: query.delete(lastindex - 3, lastindex);
602: query.append("]"); // NOI18N
603:
604: // System.out.println();
605: // System.out.println("Gen Code query: " + query.toString());
606: // System.out.println();
607: return query.toString();
608: }
609:
610: private String getUnnamedElementPreference() {
611: //Kris Richards - returning the default value.
612: return "Unnamed"; // NOI18N
613: }
614:
615: public enum CodeGenType {
616: Class, Interface, Enumeration, UseCase, Actor, Component, Datatype, Invocation, Lifeline, Node, SimpleState, AbortedFinalState, ActivityFinalNode, ChoicePseudoState, CombinedFragment, Comment, CompositeState, DataStore, Decision, DeepHistoryState, DeploymentSpecification, DerivationClassifier, EntryPointState, FinalState, FlowFinal, InitialNode, JunctionState, Package, ParameterUsage, ShallowHistoryState, Signal, SubmachineState, TemplateClass
617: };
618: }
|