package nl.fontys.sofa.limo.view.widget; import java.awt.Color; import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.border.TitledBorder; import javax.swing.event.UndoableEditEvent; import javax.swing.undo.UndoManager; import nl.fontys.sofa.limo.api.service.provider.EventService; import nl.fontys.sofa.limo.api.service.provider.ProcedureService; import nl.fontys.sofa.limo.domain.component.event.Event; import nl.fontys.sofa.limo.domain.component.hub.Hub; import nl.fontys.sofa.limo.domain.component.procedure.Procedure; import nl.fontys.sofa.limo.view.action.DeleteAction; import nl.fontys.sofa.limo.view.chain.ChainGraphScene; import nl.fontys.sofa.limo.view.node.bean.HubNode; import nl.fontys.sofa.limo.view.util.LIMOResourceBundle; import nl.fontys.sofa.limo.view.util.undoable.events.EventUndoableEdit; import nl.fontys.sofa.limo.view.util.undoable.widget.hub.DeleteHubWidgetUndoableEdit; import nl.fontys.sofa.limo.view.wizard.hub.HubWizardAction; import org.netbeans.api.visual.action.ActionFactory; import org.netbeans.api.visual.action.PopupMenuProvider; import org.netbeans.api.visual.layout.LayoutFactory; import org.netbeans.api.visual.widget.LabelWidget; import org.netbeans.api.visual.widget.Scene; import org.netbeans.api.visual.widget.SeparatorWidget; import org.netbeans.api.visual.widget.Widget; import org.netbeans.api.visual.widget.general.IconNodeWidget; import org.openide.util.Lookup; /** * HubWidget which represents a Hub in the GraphScene. It holds HubNode which * contains a Hub. * * @author Sebastiaan Heijmann */ public final class HubWidget extends IconNodeWidget implements BasicWidget { private final int widgetWidth = 140; private final int widgetHeight = 170; private final Color backgroundColor = new Color(0, 0, 0, 0); private final HubNode hubNode; private Widget containerWidget; private LabelWidget eventLabelWidget; private LabelWidget procedureLabelWidget; private final Widget startFlagWidget; private Scene scene; /** * Constructor sets up the widget by setting the display name and image. * * @param scene - the scene to display the Widget on. * @param beanNode - the beanNode belonging to this widget. */ public HubWidget(Scene scene, HubNode beanNode) throws IOException { super(scene); this.hubNode = beanNode; setPreferredBounds(new Rectangle(widgetWidth, widgetHeight)); setPreferredSize(new Dimension(widgetWidth, widgetHeight)); setToolTipText(hubNode.getName()); setOpaque(false); startFlagWidget = new StartWidget(scene); startFlagWidget.setVisible(false); setImage(getHub().getIcon().getImage()); setLabel(beanNode.getName()); addSeparator(); addChildren(); beanNode.addPropertyChangeListener((PropertyChangeEvent evt) -> { listeners.forEach((PropertyChangeListener t) -> { t.propertyChange(evt); updateLabels(); }); }); hubNode.getLookup().lookup(Hub.class).addPropertyChangeListener((evt) -> { updateLabels(); }); this.scene = scene; } @Override public void addActions(ChainGraphScene scene) { getActions().addAction(scene.getSelectAction()); getActions().addAction(scene.createObjectHoverAction()); getActions().addAction(scene.getConnectAction()); getActions().addAction(scene.getMoveAlignAction()); getActions().addAction(ActionFactory.createPopupMenuAction(new WidgetPopupMenu())); } private List<PropertyChangeListener> listeners = new ArrayList<>(); public void addPropertyChangeListener(PropertyChangeListener listener) { listeners.add(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { listeners.remove(listener); } /** * Add the children to this widget. */ private void addChildren() { containerWidget = new Widget(getScene()); containerWidget.setLayout(LayoutFactory.createHorizontalFlowLayout()); addChild(containerWidget); procedureLabelWidget = new LabelWidget(getScene(), "Procedures: " + getHub().getProcedures().size()); procedureLabelWidget.getActions().addAction(ActionFactory.createPopupMenuAction(new WidgetPopupMenu())); this.addChild(procedureLabelWidget); eventLabelWidget = new LabelWidget(getScene()); eventLabelWidget.getActions().addAction(ActionFactory.createPopupMenuAction(new WidgetPopupMenu())); if (getHub().getEvents() != null && !getHub().getEvents().isEmpty()) { eventLabelWidget = new LabelWidget(getScene(), "Events: " + getHub().getEvents().size()); } this.addChild(eventLabelWidget); addChild(startFlagWidget); } /** * Add a separator to this widget. */ private void addSeparator() { SeparatorWidget separatorWidget = new SeparatorWidget(getScene(), SeparatorWidget.Orientation.HORIZONTAL); separatorWidget.setThickness(10); addChild(separatorWidget); } /** * Create a border around this widget. */ private void createBorder() { setBorder(BorderFactory.createCompoundBorder( new TitledBorder( BorderFactory.createEmptyBorder(), hubNode.getName(), TitledBorder.CENTER, TitledBorder.ABOVE_TOP), BorderFactory.createLineBorder(backgroundColor))); } @Override public boolean drop(ChainGraphScene scene, Widget widget, Point point) { this.setPreferredLocation(point); if (scene.getStartWidget() == null) { scene.setStartWidget(this); } scene.addHubWidget(this); repaint(); return true; } /** * Get the hub which belongs to this widget. * * @return */ public Hub getHub() { return hubNode.getLookup().lookup(Hub.class); } public HubWidget getHubWidget() { return this; } /** * Update the widgets properties and hide or show the procedures or events * icon. * * @param pce the event. */ @Override public void propertyChange(PropertyChangeEvent pce) { Hub hub = getHub(); setImage(hub.getIcon().getImage()); setLabel(hub.getName()); setToolTipText(hub.getName()); if (pce != null && pce.getPropertyName().equals("events")) { ChainGraphScene scene = (ChainGraphScene) getScene(); UndoManager manager = scene.getLookup().lookup(UndoManager.class); manager.undoableEditHappened(new UndoableEditEvent(this, new EventUndoableEdit(hubNode, scene, eventLabelWidget))); } updateLabels(); } public void updateLabels() { procedureLabelWidget.setLabel("Procedures: " + getHub().getProcedures().size()); if (getHub().getEvents().isEmpty()) { eventLabelWidget.setLabel(""); } else { eventLabelWidget.setLabel("Events: " + getHub().getEvents().size()); } scene.validate(); } /** * Set the start flag visible for this HubWidget. * * @param startFlag - true if start flag should be visible. */ public void setStartFlag(boolean startFlag) { startFlagWidget.setVisible(startFlag); } @Override public void delete() { ChainGraphScene scene = (ChainGraphScene) getScene(); UndoManager manager = scene.getLookup().lookup(UndoManager.class); // add a new UndoableEditEvent to the undoManager of the ChainGraphScene when the undoManager exists if (manager != null) { manager.undoableEditHappened(new UndoableEditEvent(HubWidget.this, new DeleteHubWidgetUndoableEdit(scene, HubWidget.this))); } scene.removeHubWidget(HubWidget.this); scene.removeNodeWithEdges(hubNode); propertyChange(null); } /** * The pop up menu when right clicked on this widget. The offered actions * are the selection of the widget to be a start hub or deleting the widget. */ private class WidgetPopupMenu implements PopupMenuProvider { @Override public JPopupMenu getPopupMenu(Widget widget, Point localLocation) { JPopupMenu popup = new JPopupMenu(); popup.add(new AbstractAction(LIMOResourceBundle.getString("SET_START_HUB")) { @Override public void actionPerformed(ActionEvent ae) { ChainGraphScene scene = (ChainGraphScene) getScene(); scene.setStartWidget(HubWidget.this); } }); popup.add(new AbstractAction(LIMOResourceBundle.getString("EDIT")) { @Override public void actionPerformed(ActionEvent ae) { HubWizardAction wiz = new HubWizardAction(); wiz.setUpdate(getHub()); wiz.actionPerformed(ae); propertyChange(null); } }); popup.add(new DeleteAction()); JMenu procedureMenu = new JMenu("Proceduren"); ProcedureService procedureService = Lookup.getDefault().lookup(ProcedureService.class); List<Procedure> procedureList = procedureService.findAll(); procedureList.stream().forEach((procedure) -> { procedureMenu.add(new AbstractAction(procedure.getName()) { @Override public void actionPerformed(ActionEvent ae) { List<Procedure> procedureListOfHub = HubWidget.this.getHub().getProcedures(); Procedure selected = procedureService.findById(procedure.getId()); selected.setId(null); procedureListOfHub.add(selected); HubWidget.this.getHub().setProcedures(procedureListOfHub); updateLabels(); } }); }); JMenu eventMenu = new JMenu("Events"); EventService eventService = Lookup.getDefault().lookup(EventService.class); List<Event> eventList = eventService.findAll(); eventList.stream().forEach((event) -> { eventMenu.add(new AbstractAction(event.getName()) { @Override public void actionPerformed(ActionEvent ae) { List<Event> eventListOfHub = HubWidget.this.getHub().getEvents(); Event selected = eventService.findById(event.getId()); selected.setId(null); eventListOfHub.add(selected); HubWidget.this.getHub().setEvents(eventListOfHub); updateLabels(); } }); }); popup.add(procedureMenu); popup.add(eventMenu); return popup; } } }