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=1be6b2aa5ce674736af4654d6a19c23d30968eea;hb=a873ef940ba160f284ba6fa3fee1b9704bf68858;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..1be6b2aa 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,43 @@ 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();
+ Optional activeMachine = Optional.empty();
+
+ private MachineContextStatus status = UNKOWN;
- private final Set observers = new HashSet<>();
+ 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,15 +70,17 @@ 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;
}
/**
@@ -64,7 +88,15 @@ public class MachineContext
*/
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;
}
/**
@@ -91,7 +123,8 @@ public class MachineContext
public final void setActiveMachine(Machine machine)
{
activeMachine = Optional.ofNullable(machine);
- notifyObservers();
+ updateStatus();
+ notifyActiveMachineListeners();
}
public final Optional getMachineId()
@@ -106,38 +139,144 @@ public class MachineContext
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
+ */
+ 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.
+ */
+ 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;
+ }
+
+ private void doPostStatusChangedAction()
+ {
+ if ((status == DEAD || status == CLOSED) && activeMachine.isPresent())
+ {
+ activeMachine = Optional.empty();
+ notifyActiveMachineListeners();
+ }
+ }
+
+ 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));
}
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)
+ private void notifyActiveMachineListeners()
{
- observers.add(ob);
+ machineListeners.forEach(ob -> ob.setMachine(activeMachine));
+ }
+
+ public void addActiveMachineListener(ActiveMachineListener ob)
+ {
+ machineListeners.add(ob);
ob.setMachine(activeMachine);
}
- public void deregisterObserver(ActiveMachineListener ob)
+ public void removeActiveMachineListener(ActiveMachineListener ob)
{
- observers.remove(ob);
+ machineListeners.remove(ob);
}
- private void notifyObservers()
+ private void notifyMachineContextStatusListeners(MachineContextStatus oldStatus)
{
- observers.forEach(ob -> ob.setMachine(activeMachine));
+ 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
@@ -145,4 +284,10 @@ public class MachineContext
{
void setMachine(Optional machine);
}
+
+ @FunctionalInterface
+ public static interface MachineContextStatusListener
+ {
+ void updateStatus(MachineContextStatus oldStatus, MachineContextStatus newStatus);
+ }
}
\ No newline at end of file