/*******************************************************************************
* Copyright (c) 2010 protos software gmbh (http://www.protos.de).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* CONTRIBUTORS:
* Thomas Schuetz and Henrik Rentz-Reichert (initial contribution)
*
*******************************************************************************/
package org.eclipse.etrice.ui.structure.dialogs;
import java.util.ArrayList;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.etrice.core.validation.ValidationUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.etrice.core.room.ActorClass;
import org.eclipse.etrice.core.room.ActorContainerClass;
import org.eclipse.etrice.core.room.ExternalPort;
import org.eclipse.etrice.core.room.Port;
import org.eclipse.etrice.core.room.ProtocolClass;
import org.eclipse.etrice.core.room.RoomFactory;
import org.eclipse.etrice.core.room.RoomModel;
import org.eclipse.etrice.core.room.RoomPackage;
import org.eclipse.etrice.core.room.SubSystemClass;
import org.eclipse.etrice.ui.common.dialogs.AbstractPropertyDialog;
import org.eclipse.etrice.ui.structure.Activator;
public class PortPropertyDialog extends AbstractPropertyDialog {
class NameValidator implements IValidator {
@Override
public IStatus validate(Object value) {
if (value instanceof String) {
String name = (String) value;
if (name.isEmpty())
return ValidationStatus.error("name must not be empty");
// TODOHRR: check valid identifier
// TODOHRR: use ValidationUtil
if (acc instanceof ActorClass) {
if (nameExists((ActorClass) acc, name))
return ValidationStatus.error("name already exists");
}
else if (acc instanceof SubSystemClass) {
SubSystemClass ssc = (SubSystemClass) acc;
for (Port p : ssc.getRelayPorts()) {
if (p!=port && p.getName().equals(name))
return ValidationStatus.error("name already exists");
}
}
else {
assert(false): "unexpected type";
}
return Status.OK_STATUS;
}
return Status.OK_STATUS;
}
private boolean nameExists(ActorClass ac, String name) {
for (Port p : ac.getIfPorts()) {
if (p!=port && p.getName().equals(name))
return true;
}
for (Port p : ac.getIntPorts()) {
if (p!=port && p.getName().equals(name))
return true;
}
if (ac.getBase()!=null)
return nameExists(ac.getBase(), name);
return false;
}
}
class ProtocolValidator implements IValidator {
@Override
public IStatus validate(Object value) {
if (value==null)
return ValidationStatus.error("select a protocol");
return Status.OK_STATUS;
}
}
class MultiplicityValidator implements IValidator {
private boolean mayChange;
private int old;
public MultiplicityValidator(boolean mayChange, int old) {
this.mayChange = mayChange;
this.old = old;
}
@Override
public IStatus validate(Object value) {
if (value instanceof Integer) {
int m = (Integer) value;
if (m<=0)
return ValidationStatus.error("multiplicity must be positive");
if (!mayChange) {
if (old==1 && m>1)
return ValidationStatus.error("cannot make connected port replicated");
if (old>1 && m==1)
return ValidationStatus.error("cannot make connected port not replicated");
}
}
return Status.OK_STATUS;
}
}
private Port port;
private ActorContainerClass acc;
private boolean newPort;
private boolean refitem;
private boolean internal;
private Button relayCheck = null;
private boolean relay;
public PortPropertyDialog(Shell shell, Port port, ActorContainerClass acc, boolean newPort, boolean refitem, boolean internal) {
super(shell, "Edit Port");
this.port = port;
this.acc = acc;
this.newPort = newPort;
this.refitem = refitem;
this.internal = internal;
relay = isPortRelay();
}
private boolean isPortRelay() {
if (newPort)
return false;
if (internal)
return false;
if (acc instanceof SubSystemClass)
return true;
else if (acc instanceof ActorClass) {
for (ExternalPort xp : ((ActorClass) acc).getExtPorts()) {
if (xp.getIfport()==port)
return false;
}
return true;
}
return false;
}
@Override
protected void initializeBounds() {
getShell().setSize(300, 300);
}
@Override
protected void createContent(IManagedForm mform, Composite body, DataBindingContext bindingContext) {
boolean connected = ValidationUtil.isConnected(port, null, acc);
NameValidator nv = new NameValidator();
ProtocolValidator pv = new ProtocolValidator();
MultiplicityValidator mv = new MultiplicityValidator(newPort || !connected, port.getMultiplicity());
ArrayList<ProtocolClass> protocols = new ArrayList<ProtocolClass>();
if (acc.eResource()!=null) {
for (Resource r: acc.eResource().getResourceSet().getResources()) {
if (!r.getContents().isEmpty()) {
if (r.getContents().get(0) instanceof RoomModel) {
protocols.addAll(((RoomModel)r.getContents().get(0)).getProtocolClasses());
}
}
}
}
Text name = createText(body, "Name:", port, RoomPackage.eINSTANCE.getInterfaceItem_Name(), nv);
Combo protocol = createCombo(body, "Protocol:", port, ProtocolClass.class, RoomPackage.eINSTANCE.getInterfaceItem_Protocol(), protocols, RoomPackage.eINSTANCE.getRoomClass_Name(), pv);
Button conj = createCheck(body, "Conjugated:", port, RoomPackage.eINSTANCE.getPort_Conjugated());
if (!internal && !refitem && (acc instanceof ActorClass))
createRelayCheck(body, mform.getToolkit());
Text multi = createText(body, "Multiplicity:", port, RoomPackage.eINSTANCE.getPort_Multiplicity(), mv);
if (!newPort) {
// TODOHRR: check whether port is used externally?
if (connected) {
protocol.setEnabled(false);
conj.setEnabled(false);
if (port.getMultiplicity()==1)
multi.setEnabled(false);
}
if (refitem) {
name.setEnabled(false);
protocol.setEnabled(false);
conj.setEnabled(false);
multi.setEnabled(false);
}
}
createDecorator(name, "invalid name");
createDecorator(protocol, "no protocol selected");
createDecorator(multi, "multiplicity must be greater 1");
name.setFocus();
}
private void createRelayCheck(Composite parent, FormToolkit toolkit) {
Label l = toolkit.createLabel(parent, "Is Relay Port:", SWT.NONE);
l.setLayoutData(new GridData(SWT.NONE));
relayCheck = toolkit.createButton(parent, "", SWT.CHECK);
relayCheck.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
relayCheck.setSelection(relay);
if (ValidationUtil.isConnected(port, null, acc))
relayCheck.setEnabled(false);
}
@Override
protected void okPressed() {
if (relayCheck!=null) {
if (relay!=relayCheck.getSelection()) {
relay = relayCheck.getSelection();
// we know it's an ActorClass if we created the relayCheck in the first place
ActorClass ac = (ActorClass) acc;
if (relay) {
for (ExternalPort xp : ac.getExtPorts()) {
if (xp.getIfport()==port) {
ac.getExtPorts().remove(xp);
break;
}
}
}
else {
ExternalPort xp = RoomFactory.eINSTANCE.createExternalPort();
xp.setIfport(port);
ac.getExtPorts().add(xp);
}
}
}
super.okPressed();
}
@Override
protected Image getImage() {
return Activator.getImage("icons/Structure.gif");
}
}