X-Git-Url: https://mograsim.net/gitweb/?a=blobdiff_plain;ds=inline;f=plugins%2Fnet.mograsim.plugin.core%2Fsrc%2Fnet%2Fmograsim%2Fplugin%2Fnature%2FMachineContext.java;h=147b2441ccfcbd929e1e8959b1e490b5e7b2e3b8;hb=c356c613955c3ea57d2379fb76f9bd07f1e30170;hp=2e02e31dff0c0dfb7914718aef1174851d4768a1;hpb=15020b7263b6edd100d4b0a5de317e9eaff05c27;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 2e02e31d..147b2441 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,6 +16,7 @@ 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;
@@ -15,23 +25,36 @@ 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()
@@ -49,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;
}
/**
@@ -89,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()
@@ -105,15 +142,110 @@ 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);
+ updateStatus();
ProjectMachineContext.notifyListeners(new ProjectContextEvent(this, ProjectContextEventType.MACHINE_DEFINITION_CHANGE));
}
@@ -121,30 +253,55 @@ public class MachineContext
{
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)
{
- observers.add(ob);
- ob.setMachine(activeMachine);
+ machineListeners.forEach(ob -> ob.setMachine(oldMachine, newMachine));
}
- public void deregisterObserver(ActiveMachineListener ob)
+ @Deprecated(forRemoval = true)
+ public void addActiveMachineListener(ActiveMachineListener ob)
{
- observers.remove(ob);
+ machineListeners.add(ob);
+ ob.setMachine(Optional.empty(), activeMachine);
}
- private void notifyObservers()
+ @Deprecated(forRemoval = true)
+ public void removeActiveMachineListener(ActiveMachineListener ob)
{
- observers.forEach(ob -> ob.setMachine(activeMachine));
+ machineListeners.remove(ob);
+ }
+
+ private void notifyMachineContextStatusListeners(MachineContextStatus oldStatus)
+ {
+ MachineContextStatus newStatus = status;
+ stateListeners.forEach(ob -> ob.updateStatus(oldStatus, newStatus));
+ }
+
+ public void addMachineContextStatusListener(MachineContextStatusListener ob)
+ {
+ 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