From: Daniel Kirschten Date: Tue, 24 Sep 2019 09:26:59 +0000 (+0200) Subject: Merge remote-tracking branch 'origin/development' into development X-Git-Url: https://mograsim.net/gitweb/?a=commitdiff_plain;h=cb96c0334c0b477ec692ec8d11dd65c1bbbf72a6;hp=424226156a244e05c560248efeabdf6f8eccc181;p=Mograsim.git Merge remote-tracking branch 'origin/development' into development --- diff --git a/plugins/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/machine/Am2900MachineDefinition.java b/plugins/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/machine/Am2900MachineDefinition.java index e75c79a9..1ed03720 100644 --- a/plugins/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/machine/Am2900MachineDefinition.java +++ b/plugins/net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/am2900/machine/Am2900MachineDefinition.java @@ -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; } + } diff --git a/plugins/net.mograsim.machine/src/net/mograsim/machine/MachineDefinition.java b/plugins/net.mograsim.machine/src/net/mograsim/machine/MachineDefinition.java index 02cf3757..8f1ee265 100644 --- a/plugins/net.mograsim.machine/src/net/mograsim/machine/MachineDefinition.java +++ b/plugins/net.mograsim.machine/src/net/mograsim/machine/MachineDefinition.java @@ -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 diff --git a/plugins/net.mograsim.machine/src/net/mograsim/machine/MachineRegistry.java b/plugins/net.mograsim.machine/src/net/mograsim/machine/MachineRegistry.java index 28e79216..ca52eaea 100644 --- a/plugins/net.mograsim.machine/src/net/mograsim/machine/MachineRegistry.java +++ b/plugins/net.mograsim.machine/src/net/mograsim/machine/MachineRegistry.java @@ -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 installedMachines = new HashMap<>(); + private static final Map installedMachines = Collections.synchronizedMap(new HashMap<>()); + private static final Set 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 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 installedMachines); + } } diff --git a/plugins/net.mograsim.plugin.core/plugin.xml b/plugins/net.mograsim.plugin.core/plugin.xml index e9c762a3..76a21618 100644 --- a/plugins/net.mograsim.plugin.core/plugin.xml +++ b/plugins/net.mograsim.plugin.core/plugin.xml @@ -143,7 +143,7 @@ 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"> diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/MachineContext.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/MachineContext.java index 9da121a2..c22c1c74 100644 --- a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/MachineContext.java +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/MachineContext.java @@ -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; diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/AddMograsimNatureHandler.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/AddMograsimNatureHandler.java index f4d03577..aa5d5d61 100644 --- a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/AddMograsimNatureHandler.java +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/AddMograsimNatureHandler.java @@ -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(); 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..2e02e31d 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 @@ -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 index 00000000..9c0ad0b3 --- /dev/null +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContextSwtTools.java @@ -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 INSTALLED_MACHINES = MachineRegistry.getInstalledMachines(); + private static final Map 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 + { + final ComboViewer combo; + private Set> listeners; + + public AdvancedCombo(Composite parent, Function labelProvider) + { + this(parent, SWT.NONE, labelProvider); + } + + public AdvancedCombo(Composite parent, int style, Function 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 listener) + { + listeners.add(listener); + } + + public final void removeListener(Consumer listener) + { + listeners.remove(listener); + } + + public void refreshContent() + { + Display.getDefault().asyncExec(combo::refresh); + } + } + + public static class MachineCombo extends AdvancedCombo + { + private static final Set 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 + { + private static final Set 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 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 index 00000000..059b3eae --- /dev/null +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectContextEvent.java @@ -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 index 00000000..f7366bc3 --- /dev/null +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectContextListener.java @@ -0,0 +1,7 @@ +package net.mograsim.plugin.nature; + +@FunctionalInterface +public interface ProjectContextListener +{ + void onProjectContextChange(ProjectContextEvent projectContextEvent); +} \ No newline at end of file diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectMachineContext.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectMachineContext.java index 0e6185c4..86b9df6f 100644 --- a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectMachineContext.java +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectMachineContext.java @@ -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 projectMachineContexts = Collections.synchronizedMap(new HashMap<>()); + private static final Set 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 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)); + } } diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/views/LogicUIPart.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/views/LogicUIPart.java index 8825ba98..cf883d2c 100644 --- a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/views/LogicUIPart.java +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/views/LogicUIPart.java @@ -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);