Merge remote-tracking branch 'origin/development' into development
authorDaniel Kirschten <daniel.kirschten@gmx.de>
Tue, 24 Sep 2019 09:26:59 +0000 (11:26 +0200)
committerDaniel Kirschten <daniel.kirschten@gmx.de>
Tue, 24 Sep 2019 09:26:59 +0000 (11:26 +0200)
12 files changed:
plugins/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/machine/Am2900MachineDefinition.java
plugins/net.mograsim.machine/src/net/mograsim/machine/MachineDefinition.java
plugins/net.mograsim.machine/src/net/mograsim/machine/MachineRegistry.java
plugins/net.mograsim.plugin.core/plugin.xml
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/MachineContext.java
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/AddMograsimNatureHandler.java
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContext.java
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContextSwtTools.java [new file with mode: 0644]
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectContextEvent.java [new file with mode: 0644]
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectContextListener.java [new file with mode: 0644]
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectMachineContext.java
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/views/LogicUIPart.java

index e75c79a..1ed0372 100644 (file)
@@ -11,6 +11,14 @@ import net.mograsim.machine.Register;
 //(used for detecting installed machines in plugin.core)
 public class Am2900MachineDefinition implements MachineDefinition
 {
+       public static final String AM2900_MACHINE_ID = "Am2900";
+
+       @Override
+       public String getId()
+       {
+               return AM2900_MACHINE_ID;
+       }
+
        @Override
        public Am2900Machine createNew()
        {
@@ -65,4 +73,5 @@ public class Am2900MachineDefinition implements MachineDefinition
        {
                return Am2900MicroInstructionMemoryDefinition.instance;
        }
+
 }
index 02cf375..8f1ee26 100644 (file)
@@ -6,6 +6,14 @@ import net.mograsim.machine.mi.MicroInstructionMemoryDefinition;
 
 public interface MachineDefinition
 {
+       /**
+        * This returns the MachineDefinitions ID. This must be consistent and coherent with the id in the extension point (Eclipse plugin xml)
+        * providing the definition.
+        * 
+        * @return a human readable, unique id representing the specified machine.
+        * @author Christian Femers
+        */
+       String getId();
 
        /**
         * Creates a new instance of the machine
index 28e7921..ca52eae 100644 (file)
@@ -3,7 +3,11 @@ package net.mograsim.machine;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IConfigurationElement;
 import org.eclipse.core.runtime.IExtension;
@@ -14,9 +18,11 @@ import org.eclipse.core.runtime.Platform;
 
 public class MachineRegistry
 {
+
        private static final String MACHINE_EXT_ID = "net.mograsim.machine.machine_definition";
 
-       private static final Map<String, MachineDefinition> installedMachines = new HashMap<>();
+       private static final Map<String, MachineDefinition> installedMachines = Collections.synchronizedMap(new HashMap<>());
+       private static final Set<MachineRegistryListener> listeners = Collections.synchronizedSet(new HashSet<>());
 
        private static void reload()
        {
@@ -35,7 +41,11 @@ public class MachineRegistry
                                if (o instanceof MachineDefinition)
                                {
                                        System.out.println("Found " + id);
-                                       installedMachines.put(id, (MachineDefinition) o);
+                                       MachineDefinition md = (MachineDefinition) o;
+                                       if (Objects.equals(id, md.getId()))
+                                               installedMachines.put(id, md);
+                                       else
+                                               System.err.println("Machine definition ids to not match: " + id + " and " + md.getId());
                                } else
                                {
                                        System.err.println("Invalid machine definition: " + o + "(id=" + id + "");
@@ -46,6 +56,7 @@ public class MachineRegistry
                {
                        System.out.println(ex.getMessage());
                }
+               notifyListeners();
        }
 
        public static void initialize()
@@ -89,4 +100,26 @@ public class MachineRegistry
        {
                return installedMachines.get(id);
        }
+
+       private static void notifyListeners()
+       {
+               Map<String, MachineDefinition> unmodMachines = getInstalledMachines();
+               listeners.forEach(l -> l.onReload(unmodMachines));
+       }
+
+       public static void addMachineRegistryListener(MachineRegistryListener listener)
+       {
+               listeners.add(listener);
+       }
+
+       public static void removeMachineRegistryListener(MachineRegistryListener listener)
+       {
+               listeners.remove(listener);
+       }
+
+       @FunctionalInterface
+       public interface MachineRegistryListener
+       {
+               void onReload(Map<String, MachineDefinition> installedMachines);
+       }
 }
index e9c762a..76a2161 100644 (file)
             category="net.mograsim.plugin"
             class="net.mograsim.plugin.views.LogicUIPart"
             icon="icons/mograsim/blue-orange/icon_blue-orange_16.png"
-            id="net.mograsim.plugin.core.view1"
+            id="net.mograsim.plugin.core.simulationView"
             inject="true"
             name="%view.name.0"
             restorable="true">
index 9da121a..c22c1c7 100644 (file)
@@ -6,7 +6,12 @@ import java.util.Set;
 
 import net.mograsim.machine.Machine;
 import net.mograsim.machine.MachineRegistry;
+import net.mograsim.plugin.nature.ProjectMachineContext;
 
+/**
+ * @deprecated use the {@link ProjectMachineContext} instead to make the context project dependent.
+ */
+@Deprecated(forRemoval = true)
 public class MachineContext
 {
        private Machine machine;
index f4d0357..aa5d5d6 100644 (file)
@@ -43,7 +43,7 @@ public class AddMograsimNatureHandler extends AbstractHandler
                                {
                                        try
                                        {
-                                               ms.add(toggleNature(project));
+                                               ms.add(addNature(project));
                                        }
                                        catch (CoreException e)
                                        {
@@ -63,7 +63,7 @@ public class AddMograsimNatureHandler extends AbstractHandler
         * @param project to have Mograsim nature
         * @return
         */
-       private IStatus toggleNature(IProject project) throws CoreException
+       public static IStatus addNature(IProject project) throws CoreException
        {
                IProjectDescription description = project.getDescription();
                String[] natures = description.getNatureIds();
index c65a95e..2e02e31 100644 (file)
@@ -13,6 +13,7 @@ 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;
 
 public class MachineContext
 {
@@ -113,6 +114,7 @@ public class MachineContext
        {
                machineDefinition = machineId.map(MachineRegistry::getMachine);
                machineDefinition.ifPresent(md -> setActiveMachine(md.createNew()));
+               ProjectMachineContext.notifyListeners(new ProjectContextEvent(this, ProjectContextEventType.MACHINE_DEFINITION_CHANGE));
        }
 
        private void preferenceListener(PropertyChangeEvent changeEvent)
diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContextSwtTools.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContextSwtTools.java
new file mode 100644 (file)
index 0000000..9c0ad0b
--- /dev/null
@@ -0,0 +1,199 @@
+package net.mograsim.plugin.nature;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+
+import net.mograsim.machine.MachineDefinition;
+import net.mograsim.machine.MachineRegistry;
+import net.mograsim.plugin.nature.ProjectContextEvent.ProjectContextEventType;
+
+public final class MachineContextSwtTools
+{
+       private static final Map<String, MachineDefinition> INSTALLED_MACHINES = MachineRegistry.getInstalledMachines();
+       private static final Map<IProject, MachineContext> PROJECT_MACHINE_CONTEXTS = ProjectMachineContext.getAllProjectMachineContexts();
+
+       private MachineContextSwtTools()
+       {
+               // not instantiable
+       }
+
+       public static MachineCombo createMachineSelector(Composite parent, int style)
+       {
+               return new MachineCombo(parent, style);
+       }
+
+       public static MograsimProjectCombo createMograsimProjectSelector(Composite parent, int style)
+       {
+               return new MograsimProjectCombo(parent, style);
+       }
+
+       public abstract static class AdvancedCombo<T>
+       {
+               final ComboViewer combo;
+               private Set<Consumer<T>> listeners;
+
+               public AdvancedCombo(Composite parent, Function<T, String> labelProvider)
+               {
+                       this(parent, SWT.NONE, labelProvider);
+               }
+
+               public AdvancedCombo(Composite parent, int style, Function<T, String> labelProvider)
+               {
+                       listeners = Collections.synchronizedSet(new HashSet<>());
+                       combo = new ComboViewer(parent, style);
+                       combo.addSelectionChangedListener(e -> updateSelection());
+                       combo.setComparator(new ViewerComparator());
+                       combo.setLabelProvider(new LabelProvider()
+                       {
+                               @SuppressWarnings("unchecked")
+                               @Override
+                               public String getText(Object element)
+                               {
+                                       try
+                                       {
+                                               return labelProvider.apply((T) element);
+                                       }
+                                       catch (ClassCastException e)
+                                       {
+                                               return "Invalid Element: " + e.getLocalizedMessage();
+                                       }
+                               }
+                       });
+               }
+
+               public final ComboViewer getCombo()
+               {
+                       return combo;
+               }
+
+               @SuppressWarnings("unchecked")
+               public T getSelection()
+               {
+                       return (T) combo.getStructuredSelection().getFirstElement();
+               }
+
+               private void updateSelection()
+               {
+                       T active = getSelection();
+                       listeners.forEach(l -> l.accept(active));
+               }
+
+               public final void addListener(Consumer<T> listener)
+               {
+                       listeners.add(listener);
+               }
+
+               public final void removeListener(Consumer<T> listener)
+               {
+                       listeners.remove(listener);
+               }
+
+               public void refreshContent()
+               {
+                       Display.getDefault().asyncExec(combo::refresh);
+               }
+       }
+
+       public static class MachineCombo extends AdvancedCombo<MachineDefinition>
+       {
+               private static final Set<MachineCombo> machineComboListeners = Collections.synchronizedSet(new HashSet<>());
+
+               static
+               {
+                       MachineRegistry.addMachineRegistryListener(newMap -> machineComboListeners.forEach(AdvancedCombo::refreshContent));
+               }
+
+               public MachineCombo(Composite parent)
+               {
+                       this(parent, SWT.NONE);
+               }
+
+               public MachineCombo(Composite parent, int style)
+               {
+                       super(parent, style, MachineDefinition::getId);
+                       combo.setContentProvider(new IStructuredContentProvider()
+                       {
+                               @Override
+                               public void dispose()
+                               {
+                                       machineComboListeners.remove(MachineCombo.this);
+                               }
+
+                               @Override
+                               public Object[] getElements(Object inputElement)
+                               {
+                                       return INSTALLED_MACHINES.values().toArray();
+                               }
+                       });
+                       combo.setInput(this);
+                       machineComboListeners.add(this);
+               }
+       }
+
+       public static class MograsimProjectCombo extends AdvancedCombo<IProject>
+       {
+               private static final Set<MograsimProjectCombo> projectComboListeners = Collections.synchronizedSet(new HashSet<>());
+
+               static
+               {
+                       ProjectMachineContext.addProjectContextListener(projectEvent ->
+                       {
+                               if (projectEvent.getEventType() != ProjectContextEventType.OTHER_CHANGE)
+                                       projectComboListeners.forEach(AdvancedCombo::refreshContent);
+                       });
+               }
+
+               public MograsimProjectCombo(Composite parent)
+               {
+                       this(parent, SWT.NONE);
+               }
+
+               public MograsimProjectCombo(Composite parent, int style)
+               {
+                       super(parent, style, IProject::getName);
+                       combo.setContentProvider(new IStructuredContentProvider()
+                       {
+                               @Override
+                               public void dispose()
+                               {
+                                       projectComboListeners.remove(MograsimProjectCombo.this);
+                               }
+
+                               @Override
+                               public Object[] getElements(Object inputElement)
+                               {
+                                       return PROJECT_MACHINE_CONTEXTS.values().stream().filter(mc -> mc.getProject().isOpen() && mc.isCurrentyValid())
+                                                       .map(MachineContext::getProject).toArray();
+                               }
+                       });
+                       combo.setInput(this);
+                       projectComboListeners.add(this);
+               }
+       }
+
+       /**
+        * XXX: of no use?
+        */
+       static Optional<String> getSelection(Combo c)
+       {
+               int selectionIndex = c.getSelectionIndex();
+               if (selectionIndex == -1)
+                       return Optional.empty();
+               return Optional.of(c.getItem(selectionIndex));
+       }
+}
diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectContextEvent.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectContextEvent.java
new file mode 100644 (file)
index 0000000..059b3ea
--- /dev/null
@@ -0,0 +1,53 @@
+package net.mograsim.plugin.nature;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResourceChangeEvent;
+
+public class ProjectContextEvent
+{
+       private final MachineContext machineContext;
+       private final ProjectContextEventType eventType;
+
+       public ProjectContextEvent(MachineContext machineContext, ProjectContextEventType eventType)
+       {
+               this.machineContext = machineContext;
+               this.eventType = eventType;
+       }
+
+       public final MachineContext getMachineContext()
+       {
+               return machineContext;
+       }
+
+       public final ProjectContextEventType getEventType()
+       {
+               return eventType;
+       }
+
+       public final IProject getProject()
+       {
+               return machineContext.getProject();
+       }
+
+       public enum ProjectContextEventType
+       {
+               NEW, MACHINE_DEFINITION_CHANGE, OTHER_CHANGE, REFRESH, CLOSE, DELETE;
+
+               static ProjectContextEventType ofResourceChangeEvent(int id)
+               {
+                       switch (id)
+                       {
+                       case IResourceChangeEvent.POST_CHANGE:
+                               return OTHER_CHANGE;
+                       case IResourceChangeEvent.PRE_CLOSE:
+                               return CLOSE;
+                       case IResourceChangeEvent.PRE_DELETE:
+                               return DELETE;
+                       case IResourceChangeEvent.PRE_REFRESH:
+                               return REFRESH;
+                       default:
+                               return null;
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectContextListener.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectContextListener.java
new file mode 100644 (file)
index 0000000..f7366bc
--- /dev/null
@@ -0,0 +1,7 @@
+package net.mograsim.plugin.nature;
+
+@FunctionalInterface
+public interface ProjectContextListener
+{
+       void onProjectContextChange(ProjectContextEvent projectContextEvent);
+}
\ No newline at end of file
index 0e6185c..86b9df6 100644 (file)
@@ -2,20 +2,27 @@ package net.mograsim.plugin.nature;
 
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.Set;
 
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResourceChangeEvent;
 import org.eclipse.core.resources.ProjectScope;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.Adapters;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.ui.preferences.ScopedPreferenceStore;
 
+import net.mograsim.plugin.nature.ProjectContextEvent.ProjectContextEventType;
+
 public class ProjectMachineContext
 {
        private static Map<IProject, MachineContext> projectMachineContexts = Collections.synchronizedMap(new HashMap<>());
+       private static final Set<ProjectContextListener> listeners = Collections.synchronizedSet(new HashSet<>());
 
        public static final String MOGRASIM_PROJECT_PREFS_NODE = "net.mograsim";
        public static final String MACHINE_PROPERTY = "net.mograsim.projectMachineId";
@@ -28,6 +35,7 @@ public class ProjectMachineContext
                validateMograsimNatureProject(project);
                mc = new MachineContext(project);
                projectMachineContexts.put(project, mc);
+               notifyListeners(new ProjectContextEvent(mc, ProjectContextEventType.NEW));
                return mc;
        }
 
@@ -38,6 +46,11 @@ public class ProjectMachineContext
                return getMachineContextOf(project);
        }
 
+       public static Map<IProject, MachineContext> getAllProjectMachineContexts()
+       {
+               return Collections.unmodifiableMap(projectMachineContexts);
+       }
+
        static ScopedPreferenceStore getProjectPrefs(IProject mograsimProject)
        {
                return new ScopedPreferenceStore(new ProjectScope(mograsimProject), MOGRASIM_PROJECT_PREFS_NODE);
@@ -88,4 +101,39 @@ public class ProjectMachineContext
                        return Optional.of(preferenceStore.getString(MACHINE_PROPERTY));
                return Optional.empty();
        }
+
+       static void notifyListeners(ProjectContextEvent projectContextEvent)
+       {
+               listeners.forEach(l -> l.onProjectContextChange(projectContextEvent));
+       }
+
+       public static void addProjectContextListener(ProjectContextListener listener)
+       {
+               listeners.add(listener);
+       }
+
+       public static void removeProjectContextListener(ProjectContextListener listener)
+       {
+               listeners.remove(listener);
+       }
+
+       static
+       {
+               ResourcesPlugin.getWorkspace().addResourceChangeListener(ProjectMachineContext::resourceChanged);
+       }
+
+       private static void resourceChanged(IResourceChangeEvent event)
+       {
+//             System.out.println(((ResourceChangeEvent) event).toDebugString());
+               ProjectContextEventType eventType = ProjectContextEventType.ofResourceChangeEvent(event.getType());
+               if (eventType == null)
+                       return;
+               if (event.getResource() == null || event.getResource().getProject() == null)
+                       return;
+               MachineContext mc = projectMachineContexts.get(event.getResource().getProject());
+               if (mc == null)
+                       return;
+//             System.out.println("  " + eventType + " - " + mc.getProject());
+               notifyListeners(new ProjectContextEvent(mc, eventType));
+       }
 }
index 8825ba9..cf883d2 100644 (file)
@@ -23,6 +23,9 @@ import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
 import net.mograsim.plugin.EclipsePreferences;
 import net.mograsim.plugin.MachineContext;
 import net.mograsim.plugin.MograsimActivator;
+import net.mograsim.plugin.nature.MachineContextSwtTools;
+import net.mograsim.plugin.nature.MachineContextSwtTools.MachineCombo;
+import net.mograsim.plugin.nature.MachineContextSwtTools.MograsimProjectCombo;
 import net.mograsim.plugin.tables.DisplaySettings;
 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
 import net.mograsim.plugin.tables.mi.InstructionTable;
@@ -90,7 +93,11 @@ public class LogicUIPart extends ViewPart
        private void addSimulationControlWidgets(Composite parent)
        {
                Composite c = new Composite(parent, SWT.NONE);
-               c.setLayout(new GridLayout(4, false));
+               c.setLayout(new GridLayout(6, false));
+
+               MograsimProjectCombo projectCombo = MachineContextSwtTools.createMograsimProjectSelector(c, SWT.NONE);
+               MachineCombo machineCombo = MachineContextSwtTools.createMachineSelector(c, SWT.NONE);
+
                Button pauseButton = new Button(c, SWT.TOGGLE);
                pauseButton.setSelection(true);
                setPauseText(pauseButton, false);