package pyUML.views; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.wizard.IWizard; import org.eclipse.jface.wizard.Wizard; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IEditorPart; import org.eclipse.uml2.uml.Classifier; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Generalization; import org.eclipse.uml2.uml.Model; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.Relationship; import org.eclipse.uml2.uml.Type; import org.eclipse.uml2.uml.resource.UMLResource; import pyUML.backend.EclipseHelperMethods; import pyUML.backend.GlobalConstants; import pyUML.backend.UMLToolsHelperMethods; import pyUML.listeners.ViewChangeListener; /** * This wizard lets the user edit a view. Classes * and Packages can be selected; super- or child classes * can be used creating a view. */ public class EditViewWizard extends Wizard implements IWizard{ private Model model; private UMLResource resource; private IProject project; private IFile confFile; private String viewName; private SelectViewElementsPage partsPage; private List usedXmiIds; private boolean includeSuperClasses=false; private boolean includeSubClasses=false; private Map modelXmiDict; private List nodeToDeleteList; private List usedModelElements; public EditViewWizard(Shell parentShell, Model model, UMLResource resource, IProject project, IFile confFile, String viewName, MapmodelXmiDict) { super(); this.model = model; this.resource = resource; this.project = project; this.confFile = confFile; this.viewName = viewName; this.modelXmiDict = modelXmiDict; this.usedModelElements = new Vector(); this.setWindowTitle("Create UML View"); this.readConfFile(); } @Override public void addPages() { this.partsPage = new SelectViewElementsPage("Select Model Elements for this View", this.model, this.usedXmiIds, this.modelXmiDict, this.viewName, this.includeSuperClasses, this.includeSubClasses); addPage(partsPage); } /** * Reads the CONF file of this view (e.g. used classes+packages) */ public void readConfFile(){ this.usedXmiIds = new Vector(); String[] confContent = EclipseHelperMethods.iFileToString(confFile).split("\n"); boolean xmiSectionFound=false; for (String line:confContent) { if(xmiSectionFound) { this.usedXmiIds.add(line); } if (line.matches("CONF_INCLUDE_SUPERCLASSES:.*")) { this.includeSuperClasses= line.replaceAll("CONF_INCLUDE_SUPERCLASSES:", "") .equals("TRUE"); } if (line.matches("CONF_INCLUDE_SUBCLASSES:.*")) { this.includeSubClasses= line.replaceAll("CONF_INCLUDE_SUBCLASSES:", "") .equals("TRUE"); } if (line.matches("XMI_SECTION")) xmiSectionFound=true; } } @Override public boolean performFinish() { return performFinish(true); } /** * * @param openAfterFinish if true, the created view will be * opened immediately * @return true on success */ public boolean performFinish(boolean openAfterFinish) { //generate new model as part of old one String oldViewName = viewName; String viewName = this.viewName; if (this.partsPage.viewNameField != null) viewName = this.partsPage.getViewNameField().getText(); IFile umlFile = this.project.getWorkspace().getRoot() .getFile(this.project.getFullPath() .append(GlobalConstants.getPyUmlDir()) .append(oldViewName+GlobalConstants.getViewUmlExtension())); IFile diagramFile = this.project.getWorkspace().getRoot() .getFile(this.project.getFullPath() .append(GlobalConstants.getPyUmlDir()) .append(oldViewName+GlobalConstants.getDiagramExtension())); boolean editorChangedNameAndWasOpen =true; // if view name changed, move all files to new name if (!viewName.equals(oldViewName)) { // compute new file names with changed view name IPath newConfFilePath = this.project.getFullPath() .append(GlobalConstants.getPyUmlDir()) .append(viewName+GlobalConstants.getViewConfExtension()); IPath newViewUmlPath = this.project.getFullPath() .append(GlobalConstants.getPyUmlDir()) .append(viewName+GlobalConstants.getViewUmlExtension()); IPath newDiagramFilePath = this.project.getFullPath() .append(GlobalConstants.getPyUmlDir()) .append(viewName+GlobalConstants.getDiagramExtension()); // close editor, if it is open EclipseHelperMethods.closeEditorByName(project, diagramFile.getName()); editorChangedNameAndWasOpen = true; try { // now really move view files this.confFile.move(newConfFilePath, true, null); if (umlFile.exists()) umlFile.move(newViewUmlPath, true, null); if (diagramFile.exists()) diagramFile.move(newDiagramFilePath, true, null); this.confFile = project.getFile(newConfFilePath.removeFirstSegments(1)); umlFile = project.getFile(newViewUmlPath.removeFirstSegments(1)); diagramFile = project.getFile(newDiagramFilePath.removeFirstSegments(1)); } catch (CoreException e) { System.out.println("error moving view file to new view name!"); } } //model.setName(viewName); this.nodeToDeleteList = new Vector(); if (partsPage.viewNameField != null) this.usedXmiIds= new Vector(); removeUnmarkedNodes(this.model); List classList; classList = getClassListFromModel(this.model); // if "include superclasses" was checked: // remove all superclasses of selected items from 'classes to remove' list if (this.partsPage.getButtInclSuperClasses() != null) this.includeSuperClasses = this.partsPage.getButtInclSuperClasses().getSelection(); if (this.partsPage.getButtInclSubClasses() != null) this.includeSubClasses = this.partsPage.getButtInclSubClasses().getSelection(); if (includeSuperClasses) { boolean superClassFound; do { superClassFound = false; for (Classifier cl:classList) { EList gens = cl.getGeneralizations(); for (Generalization gen : gens) { if (nodeToDeleteList.contains(gen.getGeneral()) && (! nodeToDeleteList.contains(cl))) { nodeToDeleteList.remove(gen.getGeneral()); superClassFound = true; } } } } while (superClassFound); } // exclude subclasses from nodeToDeleteList for every class in list // if includeSubClasses was set in gui if (includeSubClasses) { boolean subClassFound; do { subClassFound = false; for (Classifier cl:classList) { for (Relationship rel : cl.getRelationships()) { if (rel instanceof Generalization) { Generalization gen = (Generalization) rel; if (gen.getOwner() == cl) continue; if (nodeToDeleteList.contains(gen.getOwner()) && (! nodeToDeleteList.contains(cl))) { nodeToDeleteList.remove(gen.getOwner()); subClassFound = true; } } } } } while (subClassFound); } List elList = getPackagedElementsFromModel(this.model); Package viewPack = model.createNestedPackage("View_"+viewName); // make model "flat", setting parent of all classes to model root for(Type el : elList) { if (! this.nodeToDeleteList.contains(el)) el.setPackage(viewPack); } // remove elements in nodeToDeleteList /*for (Element e:this.nodeToDeleteList) { e.destroy(); } */ /* //remove all package entries of model List packageList = new Vector(); for (Element e: model.getOwnedElements()) { if (e instanceof Package) { packageList.add(e); } } for (Element e: packageList) { //e.destroy(); }*/ //save new "view"-model try { // if model was renamed, rename old model String umlFileName=project.getLocation(). append(GlobalConstants.getPyUmlDir()). append(viewName + GlobalConstants.getViewUmlExtension()).toOSString(); resource.setURI(URI.createFileURI(umlFileName)); resource.save(null); EclipseHelperMethods.updateFile(umlFile); System.out.println(("Saving view file "+umlFileName+" done.")); } catch (IOException ioe) { MessageDialog.openError(null,"IOException", "Error saving uml file: \n" + ioe.getMessage()); } //save configuration String confFileContents="CONF_INCLUDE_SUPERCLASSES:" +( includeSuperClasses ? "TRUE" : "FALSE" ) + "\n"; confFileContents+="CONF_INCLUDE_SUBCLASSES:" +( includeSubClasses ? "TRUE" : "FALSE" ) + "\n"; confFileContents += "XMI_SECTION\n"; for (String id: this.usedXmiIds) { confFileContents += id + "\n"; } EclipseHelperMethods.StringToIFile(confFile, confFileContents); // create graphical diagram, if it does not already exist // create diagram, if it does not exist; after creation, open it // (diagram should not be opened when "edit" was pressed) if (! diagramFile.exists() || editorChangedNameAndWasOpen) { // create and open diagram, if it was created as new if (! diagramFile.exists()) UMLToolsHelperMethods.createModelDiagram(viewPack, diagramFile); else { String oldDiagramContent = EclipseHelperMethods.iFileToString(diagramFile); Pattern pattern = Pattern.compile("(.*.*)"); String viewId = resource.getID(viewPack); // get old view package id Matcher matcher = pattern.matcher(oldDiagramContent); String oldViewId = null; if (matcher.find()) { oldViewId = matcher.group(2); } else return false; // replace all old IDs to the new ID oldDiagramContent = oldDiagramContent.replace(oldViewId, viewId); EclipseHelperMethods.StringToIFile(diagramFile, oldDiagramContent); } if (openAfterFinish) UMLToolsHelperMethods.openDiagram(project, diagramFile, umlFile.getName() ,true); } else { // refresh editor, if it was open if (null != EclipseHelperMethods.lookForOpenEditorByName(diagramFile.getName())) { IEditorPart newPage = UMLToolsHelperMethods.refreshDiagramEditor(project, diagramFile, false); newPage.addPropertyListener(new ViewChangeListener(this.project)); } } EclipseHelperMethods.updateFile(diagramFile); return true; } /** * Recursive Helper method to add the nodes that were not * selected to the nodeToDeletelist * If a package node is selected, all children will be selected, implicitely. * If a package node is not selected, a recursion on the children is started. * @param node */ private void removeUnmarkedNodes(Element node) { TreeItem assignedItem =this.partsPage.getNodeCheckboxDict().get(node); if (assignedItem != null && (assignedItem.getChecked())) this.usedXmiIds.add(this.modelXmiDict.get(node)); if (node instanceof Relationship) { return; } if (node instanceof org.eclipse.uml2.uml.Classifier) { assignedItem =this.partsPage.getNodeCheckboxDict().get(node); if (assignedItem == null) { if (this.usedXmiIds.contains(modelXmiDict.get(node))) { this.usedModelElements.add(node); } else { this.nodeToDeleteList.add(node); } }else if (! assignedItem.getChecked()) { // add node to remove list if it is not marked. this.nodeToDeleteList.add(node); return; } else { this.usedModelElements.add(node); this.usedXmiIds.add(this.modelXmiDict.get(node)); } } else if (node instanceof Package) { for (Element childNode : node.getOwnedElements()) { assignedItem =this.partsPage.getNodeCheckboxDict().get(node); if (assignedItem == null) { } else if (assignedItem.getChecked()) this.usedXmiIds.add(this.modelXmiDict.get(node)); removeUnmarkedNodes(childNode); } } } /** * return all classes in model * @param node */ private Vector getClassListFromModel(Element node) { Vector classList = new Vector(); if (node instanceof Classifier) { Classifier cl = (Classifier) node; classList.add(cl); } else { EList children = node.getOwnedElements(); for (Element child : children) { classList.addAll(getClassListFromModel(child)); } } return classList; } /** * get all child elements of a package * that are Types (direct successors of packages) * * @param node The node where the search is to be started * @return the list of Types */ private Vector getPackagedElementsFromModel(Element node) { Vector elList = new Vector(); if (node instanceof Classifier) { Classifier cl = (Classifier) node; elList.add(cl); elList.addAll(cl.getAssociations()); } else { EList children = node.getOwnedElements(); for (Element child : children) { elList.addAll(getPackagedElementsFromModel(child)); } } return elList; } public SelectViewElementsPage getPartsPage() { return partsPage; } }