X-Git-Url: https://mograsim.net/gitweb/?a=blobdiff_plain;f=plugins%2Fnet.mograsim.plugin.core%2Fsrc%2Fnet%2Fmograsim%2Fplugin%2Fnature%2FMachineContext.java;h=f3965f2a3976874e22a8f25de0273937adcff4a3;hb=161ecd36b6dcfe0e38cee3fd6ea8ad42d0705777;hp=c65a95e16a35dfa8ed4e3f990ea258bf819f5f16;hpb=f4c2b2357f708fce0b1a15d7d9de32fbf509e0eb;p=Mograsim.git diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContext.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContext.java index c65a95e1..f3965f2a 100644 --- a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContext.java +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContext.java @@ -1,5 +1,14 @@ package net.mograsim.plugin.nature; +import static net.mograsim.plugin.nature.MachineContextStatus.ACTIVE; +import static net.mograsim.plugin.nature.MachineContextStatus.ACTIVE_CHANGED; +import static net.mograsim.plugin.nature.MachineContextStatus.BROKEN; +import static net.mograsim.plugin.nature.MachineContextStatus.CLOSED; +import static net.mograsim.plugin.nature.MachineContextStatus.DEAD; +import static net.mograsim.plugin.nature.MachineContextStatus.INTACT; +import static net.mograsim.plugin.nature.MachineContextStatus.READY; +import static net.mograsim.plugin.nature.MachineContextStatus.UNKOWN; + import java.io.IOException; import java.util.HashSet; import java.util.Objects; @@ -7,30 +16,45 @@ import java.util.Optional; import java.util.Set; import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.ui.preferences.ScopedPreferenceStore; import net.mograsim.machine.Machine; import net.mograsim.machine.MachineDefinition; import net.mograsim.machine.MachineRegistry; +import net.mograsim.plugin.nature.ProjectContextEvent.ProjectContextEventType; +/** + * A MachineContext is a project specific context for the Mograsim machine associated to them. + *

+ * It stores the {@link MachineDefinition#getId() machine id}, the {@link MachineDefinition} if applicable and an active machine if present. + * {@link ActiveMachineListener}s and {@link MachineContextStatusListener}s can be used to track the state of the MachineContext. + * + * @author Christian Femers + * + */ public class MachineContext { - IProject owner; - ScopedPreferenceStore prefs; - Optional machineId; - Optional machineDefinition; - Optional activeMachine; + final IProject owner; + final ScopedPreferenceStore prefs; + Optional machineId = Optional.empty(); + Optional machineDefinition = Optional.empty(); + @Deprecated(forRemoval = true) + Optional activeMachine = Optional.empty(); + + private MachineContextStatus status = UNKOWN; - private final Set observers = new HashSet<>(); + @Deprecated(forRemoval = true) + private final Set machineListeners = new HashSet<>(); + private final Set stateListeners = new HashSet<>(); public MachineContext(IProject owner) { this.owner = Objects.requireNonNull(owner); prefs = ProjectMachineContext.getProjectPrefs(owner); prefs.addPropertyChangeListener(this::preferenceListener); - machineId = ProjectMachineContext.getMachineIdFrom(prefs); - updateDefinition(); + updateDefinition(ProjectMachineContext.getMachineIdFrom(prefs)); } public final IProject getProject() @@ -48,23 +72,34 @@ public class MachineContext */ public final boolean isCurrentyValid() { - return machineDefinition.isPresent(); + return status == READY || isActive(); } /** * Returns true if the persisted project configuration itself is intact + * + * @see MachineContextStatus#INTACT */ public final boolean isIntact() { - return machineId.isPresent(); + return isCurrentyValid() || status == INTACT; } /** * Returns true if a machine is instantiated and (possibly) running */ + @Deprecated(forRemoval = true) public final boolean isActive() { - return activeMachine.isPresent(); + return status == ACTIVE || status == ACTIVE_CHANGED; + } + + /** + * Returns the current status of this machine context + */ + public final MachineContextStatus getStatus() + { + return status; } /** @@ -88,10 +123,13 @@ public class MachineContext /** * Sets the active machine in the {@link MachineContext}'s project scope. */ + @Deprecated(forRemoval = true) public final void setActiveMachine(Machine machine) { + Optional oldMachine = activeMachine; activeMachine = Optional.ofNullable(machine); - notifyObservers(); + updateStatus(); + notifyActiveMachineListeners(oldMachine, activeMachine); } public final Optional getMachineId() @@ -104,45 +142,171 @@ public class MachineContext return machineDefinition; } + @Deprecated(forRemoval = true) public final Optional getActiveMachine() { +// activateMachine(); // TODO is this the best way to deal with this? return activeMachine; } - final void updateDefinition() + /** + * Tries to activate the associated machine. This will not succeed if the project is not {@link MachineContextStatus#READY}. If the + * status is {@link MachineContextStatus#ACTIVE}, this method has no effect. + * + * @return true if the activation was successful + */ + @Deprecated(forRemoval = true) + public final boolean activateMachine() { - machineDefinition = machineId.map(MachineRegistry::getMachine); + if (status == ACTIVE) + return true; machineDefinition.ifPresent(md -> setActiveMachine(md.createNew())); + updateStatus(); + return isActive(); + } + + /** + * This changes the internal status to a newly evaluated one and calls the {@link MachineContextStatusListener}s if this caused the + * status to change. + * + * @see #reevaluateStatus() + * @see #getStatus() + */ + public final void updateStatus() + { + MachineContextStatus newStatus = reevaluateStatus(); + forceUpdateStatus(newStatus); + } + + final void forceUpdateStatus(MachineContextStatus newStatus) + { + MachineContextStatus oldStatus = status; + if (oldStatus == newStatus) + return; + status = newStatus; + doPostStatusChangedAction(); + notifyMachineContextStatusListeners(oldStatus); + } + + /** + * This method reevaluates the status but does not change/update it.
+ * To update the status of the {@link MachineContext}, use {@link #updateStatus()}. + * + * @return the raw status of the project at the time of the call. + */ + @SuppressWarnings("removal") + public final MachineContextStatus reevaluateStatus() + { + if (!owner.exists()) + return DEAD; + if (!owner.isOpen()) + return CLOSED; + if (hasInvaildMograsimProject()) + return BROKEN; + if (machineDefinition.isEmpty()) + return INTACT; + if (activeMachine.isEmpty()) + return READY; + if (!activeMachine.get().getDefinition().getId().equals(machineDefinition.get().getId())) + return ACTIVE_CHANGED; + return ACTIVE; + } + + @Deprecated(forRemoval = true) + private void doPostStatusChangedAction() + { + if ((status == DEAD || status == CLOSED) && activeMachine.isPresent()) + { + Optional oldMachine = activeMachine; + activeMachine = Optional.empty(); + notifyActiveMachineListeners(oldMachine, activeMachine); + } + } + + private boolean hasInvaildMograsimProject() + { + try + { + if (!owner.isNatureEnabled(MograsimNature.NATURE_ID)) + return true; + return machineId.isEmpty(); + } + catch (CoreException e) + { + // cannot happen, because this method is called after the exceptional states were checked. + e.printStackTrace(); + return false; + } + } + + final void updateDefinition(Optional newMachineDefinitionId) + { + if (newMachineDefinitionId.equals(machineId)) + return; + machineId = newMachineDefinitionId; + machineDefinition = machineId.map(MachineRegistry::getMachine); + if (machineDefinition.isEmpty() && newMachineDefinitionId.isPresent()) + { + // TODO open a dialog + System.err.println("Machine definition for ID " + newMachineDefinitionId.get() + " not found"); + } + updateStatus(); + ProjectMachineContext.notifyListeners(new ProjectContextEvent(this, ProjectContextEventType.MACHINE_DEFINITION_CHANGE)); } private void preferenceListener(PropertyChangeEvent changeEvent) { if (changeEvent.getProperty().equals(ProjectMachineContext.MACHINE_PROPERTY)) { - machineId = Optional.ofNullable((String) changeEvent.getNewValue()); - updateDefinition(); + updateDefinition(Optional.ofNullable((String) changeEvent.getNewValue())); } } - public void registerObserver(ActiveMachineListener ob) + @Deprecated(forRemoval = true) + private void notifyActiveMachineListeners(Optional oldMachine, Optional newMachine) + { + machineListeners.forEach(ob -> ob.setMachine(oldMachine, newMachine)); + } + + @Deprecated(forRemoval = true) + public void addActiveMachineListener(ActiveMachineListener ob) + { + machineListeners.add(ob); + ob.setMachine(Optional.empty(), activeMachine); + } + + @Deprecated(forRemoval = true) + public void removeActiveMachineListener(ActiveMachineListener ob) { - observers.add(ob); - ob.setMachine(activeMachine); + machineListeners.remove(ob); } - public void deregisterObserver(ActiveMachineListener ob) + private void notifyMachineContextStatusListeners(MachineContextStatus oldStatus) { - observers.remove(ob); + MachineContextStatus newStatus = status; + stateListeners.forEach(ob -> ob.updateStatus(oldStatus, newStatus)); } - private void notifyObservers() + public void addMachineContextStatusListener(MachineContextStatusListener ob) { - observers.forEach(ob -> ob.setMachine(activeMachine)); + stateListeners.add(ob); + } + + public void removeMachineContextStatusListener(MachineContextStatusListener ob) + { + stateListeners.remove(ob); } @FunctionalInterface + @Deprecated(forRemoval = true) public static interface ActiveMachineListener { - void setMachine(Optional machine); + void setMachine(Optional oldMachine, Optional newMachine); + } + + @FunctionalInterface + public static interface MachineContextStatusListener + { + void updateStatus(MachineContextStatus oldStatus, MachineContextStatus newStatus); } } \ No newline at end of file