437 lines
13 KiB
Java
Executable File
437 lines
13 KiB
Java
Executable File
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<String> usedXmiIds;
|
|
private boolean includeSuperClasses=false;
|
|
private boolean includeSubClasses=false;
|
|
private Map<EObject, String> modelXmiDict;
|
|
|
|
private List<Element> nodeToDeleteList;
|
|
private List<Element> usedModelElements;
|
|
|
|
public EditViewWizard(Shell parentShell, Model model, UMLResource resource, IProject project, IFile confFile, String viewName, Map<EObject, String>modelXmiDict) {
|
|
super();
|
|
this.model = model;
|
|
this.resource = resource;
|
|
this.project = project;
|
|
this.confFile = confFile;
|
|
this.viewName = viewName;
|
|
this.modelXmiDict = modelXmiDict;
|
|
this.usedModelElements = new Vector<Element>();
|
|
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>();
|
|
|
|
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<Element>();
|
|
|
|
if (partsPage.viewNameField != null)
|
|
this.usedXmiIds= new Vector<String>();
|
|
|
|
removeUnmarkedNodes(this.model);
|
|
|
|
List<Classifier> 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<Generalization> 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<Type> 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<Element> packageList = new Vector<Element>();
|
|
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("(.*<element xmi:type=\"uml:Package\" href=\"file:[^#]*#)([^\"]*)(\"/>.*)");
|
|
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<Classifier> getClassListFromModel(Element node) {
|
|
Vector<Classifier> classList = new Vector<Classifier>();
|
|
if (node instanceof Classifier) {
|
|
Classifier cl = (Classifier) node;
|
|
classList.add(cl);
|
|
} else {
|
|
EList<Element> 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<Type> getPackagedElementsFromModel(Element node) {
|
|
|
|
Vector<Type> elList = new Vector<Type>();
|
|
if (node instanceof Classifier) {
|
|
Classifier cl = (Classifier) node;
|
|
elList.add(cl);
|
|
elList.addAll(cl.getAssociations());
|
|
} else {
|
|
EList<Element> children = node.getOwnedElements();
|
|
for (Element child : children) {
|
|
elList.addAll(getPackagedElementsFromModel(child));
|
|
}
|
|
}
|
|
return elList;
|
|
}
|
|
|
|
public SelectViewElementsPage getPartsPage() {
|
|
return partsPage;
|
|
}
|
|
} |