/******************************************************************************* | |
* Copyright (C) 2020 | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v2.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v20.html | |
******************************************************************************/ | |
package org.polarsys.chess.cdo.pages; | |
import java.util.ArrayList; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Set; | |
import org.eclipse.core.runtime.IStatus; | |
import org.eclipse.core.runtime.Status; | |
import org.eclipse.emf.cdo.CDOElement; | |
import org.eclipse.emf.cdo.eresource.CDOResource; | |
import org.eclipse.emf.cdo.eresource.CDOResourceFolder; | |
import org.eclipse.emf.cdo.eresource.CDOResourceLeaf; | |
import org.eclipse.emf.cdo.eresource.CDOResourceNode; | |
import org.eclipse.emf.cdo.explorer.CDOExplorerUtil; | |
import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout; | |
import org.eclipse.emf.cdo.explorer.ui.checkouts.CDOCheckoutContentProvider; | |
import org.eclipse.emf.cdo.view.CDOView; | |
import org.eclipse.emf.common.notify.Adapter; | |
import org.eclipse.emf.common.util.ECollections; | |
import org.eclipse.emf.common.util.EList; | |
import org.eclipse.emf.common.util.URI; | |
import org.eclipse.emf.ecore.EObject; | |
import org.eclipse.emf.ecore.resource.Resource; | |
import org.eclipse.emf.ecore.util.EcoreUtil; | |
import org.eclipse.jface.layout.GridDataFactory; | |
import org.eclipse.jface.viewers.ISelectionChangedListener; | |
import org.eclipse.jface.viewers.IStructuredSelection; | |
import org.eclipse.jface.viewers.SelectionChangedEvent; | |
import org.eclipse.jface.viewers.StructuredSelection; | |
import org.eclipse.jface.viewers.TreeViewer; | |
import org.eclipse.jface.wizard.WizardPage; | |
import org.eclipse.osgi.util.NLS; | |
import org.eclipse.papyrus.uml.diagram.wizards.Activator; | |
import org.eclipse.swt.SWT; | |
import org.eclipse.swt.events.ModifyEvent; | |
import org.eclipse.swt.events.ModifyListener; | |
import org.eclipse.swt.layout.GridData; | |
import org.eclipse.swt.layout.GridLayout; | |
import org.eclipse.swt.widgets.Composite; | |
import org.eclipse.swt.widgets.Label; | |
import org.eclipse.swt.widgets.Text; | |
import com.google.common.base.Strings; | |
import com.google.common.eventbus.EventBus; | |
/** | |
* This is the NewCHESSModelPage type. Enjoy. | |
*/ | |
public class NewCHESSModelPage extends WizardPage { | |
public static final String PAGE_ID = "NewCDOModel"; //$NON-NLS-1$ | |
private String resourceType = "model"; | |
private Text folderText; | |
private TreeViewer folderViewer; | |
private Text nameText; | |
private boolean synchronizingFolderSelection; | |
private Object selectedElement; | |
private boolean selectedElementRevealed; | |
private URI newModelResourceURI; | |
private String folderRelativePath; | |
private String projectName; | |
public NewCHESSModelPage(IStructuredSelection selection, EventBus bus, String modelKindName) { | |
super(PAGE_ID); | |
setTitle(NLS.bind("New CHESS Model", modelKindName)); | |
setDescription(NLS.bind("Create a new CHESS model", modelKindName)); | |
setSelection(selection); | |
bus.register(this); | |
} | |
@Override | |
public void createControl(Composite parentControl) { | |
Composite container = new Composite(parentControl, SWT.NONE); | |
GridDataFactory.fillDefaults().grab(true, true).applyTo(container); | |
container.setLayout(new GridLayout(2, false)); | |
Label label = new Label(container, SWT.NONE); | |
label.setText("Enter or select the parent folder:"); | |
GridDataFactory.swtDefaults().span(2, 1).applyTo(label); | |
folderText = new Text(container, SWT.BORDER); | |
GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(folderText); | |
updateFolderText(); | |
folderViewer = CDOCheckoutContentProvider.createTreeViewer(container); | |
folderViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); | |
folderViewer.addSelectionChangedListener(new ISelectionChangedListener() { | |
@Override | |
public void selectionChanged(SelectionChangedEvent event) { | |
if (selectedElementRevealed) { | |
IStructuredSelection selection = (IStructuredSelection) event.getSelection(); | |
setSelection(selection); | |
} | |
validatePage(); | |
} | |
}); | |
new Label(container, SWT.NONE).setText("Resource name:"); | |
nameText = new Text(container, SWT.BORDER); | |
GridDataFactory.fillDefaults().grab(true, false).applyTo(nameText); | |
nameText.setText(getUniqueName("di")); //$NON-NLS-1$ | |
setControl(container); | |
folderText.addModifyListener(new ModifyListener() { | |
@Override | |
public void modifyText(ModifyEvent e) { | |
// TODO: set parent then revealParent() | |
validatePage(); | |
} | |
}); | |
folderViewer.addSelectionChangedListener(new ISelectionChangedListener() { | |
@Override | |
public void selectionChanged(SelectionChangedEvent event) { | |
IStructuredSelection selection = (IStructuredSelection) event.getSelection(); | |
setSelection(selection); | |
updateFolderText(); | |
validatePage(); | |
} | |
}); | |
nameText.addModifyListener(new ModifyListener() { | |
@Override | |
public void modifyText(ModifyEvent e) { | |
validatePage(); | |
} | |
}); | |
parentControl.getShell().getDisplay().asyncExec(new Runnable() { | |
@Override | |
public void run() { | |
revealSelectedElement(); | |
validatePage(); | |
} | |
}); | |
} | |
public String getNewResourceName() { | |
return (nameText == null) ? null : nameText.getText().trim(); | |
} | |
public URI createNewModelResourceURI() { | |
return newModelResourceURI; | |
} | |
public URI createSelectedElementURI() { | |
if (selectedElement instanceof CDOCheckout) { | |
CDOCheckout checkout = (CDOCheckout) selectedElement; | |
return checkout.getURI(); | |
} | |
if (selectedElement instanceof CDOResourceNode) { | |
CDOResourceNode resourceNode = (CDOResourceNode) selectedElement; | |
return resourceNode.getURI(); | |
} | |
return null; | |
} | |
/** | |
* Diagram extension changed. | |
* | |
* @param newExtension | |
* the new extension | |
* @return result of validation of the new extension | |
*/ | |
public IStatus diagramExtensionChanged(String newExtension) { | |
String currentExtension = getExtension(); | |
if (!newExtension.equals(currentExtension)) { | |
String oldFileName = getNewResourceName(); | |
String base = oldFileName; | |
if (currentExtension != null) { | |
// take one off for the '.' | |
base = base.substring(0, base.length() - currentExtension.length() - 1); | |
} | |
String newFileName = getUniqueName(newExtension); | |
setNewResourceName(newFileName); | |
String message1 = org.eclipse.papyrus.uml.diagram.wizards.Messages.NewModelFilePage_new_diagram_category_needs_specific_extension; | |
String message2 = NLS.bind(org.eclipse.papyrus.uml.diagram.wizards.Messages.NewModelFilePage_diagram_file_was_renamed, oldFileName, newFileName); | |
String message = message1 + message2; | |
Status resultStatus = new Status(IStatus.INFO, Activator.PLUGIN_ID, message); | |
String errorMessage = getErrorMessage(); | |
if (errorMessage != null) { | |
resultStatus = new Status(IStatus.ERROR, Activator.PLUGIN_ID, errorMessage); | |
} | |
return resultStatus; | |
} | |
return Status.OK_STATUS; | |
} | |
protected void setNewResourceName(String newName) { | |
nameText.setText(newName.trim()); | |
} | |
protected void validatePage() { | |
newModelResourceURI = null; | |
setMessage(null, NONE); | |
setPageComplete(true); | |
String folder = folderText.getText().trim(); | |
if (Strings.isNullOrEmpty(folder)) { | |
setPageComplete(false); | |
return; | |
} | |
String[] segments = getSegments(folder); | |
CDOCheckout checkout = CDOExplorerUtil.getCheckoutManager().getCheckoutByLabel(segments[0]); | |
if (checkout == null) { | |
setMessage(NLS.bind("The selected checkout does not exist.", segments[0]), ERROR); | |
setPageComplete(false); | |
return; | |
} | |
CDOView view = checkout.getView(); | |
String path = ""; | |
SegmentType segmentType = SegmentType.FOLDER; // The checkout is treated like a folder. | |
for (int i = 1; i < segments.length; i++) { | |
String segment = segments[i]; | |
path += "/"; | |
path += segment; | |
segmentType = SegmentType.of(view, path); | |
if (segmentType == SegmentType.OTHER) { | |
setMessage("The specified folder cannot be created.", ERROR); | |
setPageComplete(false); | |
return; | |
} | |
} | |
String name = getNewResourceName(); | |
if (Strings.isNullOrEmpty(name)) { | |
setMessage("The new model resource name is required.", ERROR); | |
setPageComplete(false); | |
return; | |
} | |
if (segmentType != SegmentType.MISSING) { | |
String fullPath = path + "/" + name; | |
if (SegmentType.of(view, fullPath) != SegmentType.MISSING) { | |
setMessage(NLS.bind("The resource already exists.", fullPath), ERROR); | |
setPageComplete(false); | |
return; | |
} | |
} | |
//TODO work in progress!! | |
String folderName = name.substring(0, name.lastIndexOf(".")); | |
path = path.concat("/" + folderName.substring(0, 1).toUpperCase() + folderName.substring(1)); | |
newModelResourceURI = checkout.createResourceURI(path).appendSegment(name); | |
folderRelativePath = path; | |
projectName = folderName; | |
if (segmentType == SegmentType.MISSING) { | |
setMessage("The specified folder does not exist and will be created.", WARNING); | |
} | |
} | |
private String[] getSegments(String folder) { | |
while (folder.startsWith("/")) { | |
folder = folder.substring(1); | |
} | |
while (folder.endsWith("/")) { | |
folder = folder.substring(0, folder.length() - 1); | |
} | |
return folder.split("/"); | |
} | |
private String getExtension() { | |
String result = null; | |
String name = getNewResourceName(); | |
if (name != null) { | |
// the proper extension is whatever follows the *last* '.', | |
// but for our purposes we need e.g. "profile.uml" to be | |
// an extension | |
int dot = name.indexOf('.'); | |
if (dot >= 0) { | |
result = name.substring(dot + 1); | |
} | |
} | |
return result; | |
} | |
private void setSelection(IStructuredSelection selection) { | |
selectedElement = null; | |
if (!selection.isEmpty()) { | |
Object element = selection.getFirstElement(); | |
if (element instanceof CDOElement) { | |
element = ((CDOElement) element).getDelegate(); | |
} | |
if (element instanceof CDOCheckout) { | |
selectedElement = element; | |
} else if (element instanceof CDOResourceLeaf) { | |
selectedElement = ((CDOResourceLeaf) element).getFolder(); | |
} else if (element instanceof CDOResourceFolder) { | |
selectedElement = (CDOResourceFolder) element; | |
} else if (element instanceof EObject) { | |
Resource resource = ((EObject) element).eResource(); | |
if (resource instanceof CDOResource) { | |
selectedElement = ((CDOResource) resource).getFolder(); | |
} | |
} | |
} | |
} | |
private void updateFolderText() { | |
if (!synchronizingFolderSelection) { | |
synchronizingFolderSelection = true; | |
try { | |
if (selectedElement == null) { | |
folderText.setText(""); //$NON-NLS-1$ | |
} else { | |
StringBuilder builder = new StringBuilder(); | |
for (Object node : getSelectedSegments()) { | |
builder.append('/'); | |
builder.append(CDOExplorerUtil.getName(node)); | |
} | |
String path = builder.toString(); | |
folderText.setText(path); | |
} | |
} finally { | |
synchronizingFolderSelection = false; | |
} | |
} | |
} | |
private void revealSelectedElement() { | |
if (selectedElement != null) { | |
List<Object> segments = getSelectedSegments(); | |
for (int i = 0; i < segments.size() - 1; i++) { | |
Object segment = segments.get(i); | |
folderViewer.setExpandedState(segment, true); | |
} | |
selectedElementRevealed = true; | |
folderViewer.setSelection(new StructuredSelection(selectedElement), true); | |
} | |
} | |
private List<Object> getSelectedSegments() { | |
List<Object> segments = new ArrayList<Object>(); | |
fillSegments(segments, selectedElement); | |
return segments; | |
} | |
private void fillSegments(List<Object> segments, Object element) { | |
if (element instanceof CDOCheckout) { | |
segments.add(element); | |
return; | |
} | |
if (element instanceof CDOResourceFolder) { | |
CDOResourceFolder folder = (CDOResourceFolder) element; | |
Adapter adapter = EcoreUtil.getAdapter(folder.eAdapters(), CDOCheckout.class); | |
if (adapter != null) { | |
fillSegments(segments, adapter); | |
} else { | |
Object parent = folder.getFolder(); | |
if (parent == null) { | |
parent = EcoreUtil.getAdapter(folder.cdoView().getRootResource().eAdapters(), CDOCheckout.class); | |
} | |
fillSegments(segments, parent); | |
} | |
} | |
segments.add(element); | |
} | |
private EList<EObject> getChildrenOfSelectedElement() { | |
if (selectedElement instanceof CDOCheckout) { | |
CDOCheckout checkout = (CDOCheckout) selectedElement; | |
return checkout.getRootObject().eContents(); | |
} | |
if (selectedElement instanceof CDOResourceFolder) { | |
CDOResourceFolder folder = (CDOResourceFolder) selectedElement; | |
return folder.eContents(); | |
} | |
return ECollections.emptyEList(); | |
} | |
private String getUniqueName(String extension) { | |
Set<String> names = new HashSet<String>(); | |
for (EObject eObject : getChildrenOfSelectedElement()) { | |
if (eObject instanceof CDOResourceNode) { | |
CDOResourceNode node = (CDOResourceNode) eObject; | |
String name = node.getName(); | |
if (name.startsWith(resourceType)) { | |
names.add(name); | |
} | |
} | |
} | |
for (int i = 1; i < Integer.MAX_VALUE; i++) { | |
String name = resourceType + (i > 1 ? i : "") + "." + extension; | |
if (!names.contains(name)) { | |
return name; | |
} | |
} | |
throw new IllegalStateException("Too many children"); | |
} | |
/** | |
* @author Stepper | |
*/ | |
private enum SegmentType { | |
MISSING, FOLDER, OTHER; | |
public static SegmentType of(CDOView view, String path) { | |
CDOResourceNode resourceNode; | |
try { | |
resourceNode = view.getResourceNode(path); | |
if (resourceNode != null) { | |
if (resourceNode instanceof CDOResourceFolder) { | |
return SegmentType.FOLDER; | |
} | |
return SegmentType.OTHER; | |
} | |
} catch (Exception ex) { | |
//$FALL-THROUGH$ | |
} | |
return SegmentType.MISSING; | |
} | |
private static SegmentType of(CDOResourceNode resourceNode) { | |
if (resourceNode == null) { | |
return SegmentType.MISSING; | |
} | |
if (resourceNode instanceof CDOResourceFolder) { | |
return SegmentType.FOLDER; | |
} | |
return SegmentType.OTHER; | |
} | |
} | |
public String getFolderRelativePath() { | |
return folderRelativePath; | |
} | |
public String getProjectName() { | |
return projectName; | |
} | |
} |