From: Christian Femers Date: Thu, 19 Sep 2019 14:56:37 +0000 (+0200) Subject: Restructured Mograsim project nature and introduced project context X-Git-Url: https://mograsim.net/gitweb/?a=commitdiff_plain;h=f919efc362c3de5c94d894dc8fc7fe22c03fc865;p=Mograsim.git Restructured Mograsim project nature and introduced project context --- diff --git a/features/net.mograsim.feature/feature.xml b/features/net.mograsim.feature/feature.xml index 7e121014..2aeb3dc7 100644 --- a/features/net.mograsim.feature/feature.xml +++ b/features/net.mograsim.feature/feature.xml @@ -690,11 +690,10 @@ exception as provided by Oracle in the LICENSE file that accompanied this code.& - - - - + + + installedMachines = new HashMap<>(); + private static final Map installedMachines = new HashMap<>(); - public static void reload() + private static void reload() { + installedMachines.clear(); IExtensionRegistry registry = Platform.getExtensionRegistry(); System.out.println(Arrays.toString(registry.getExtensionPoints("net.mograsim.machine"))); IConfigurationElement[] config = registry.getConfigurationElementsFor(MACHINE_EXT_ID); @@ -45,8 +48,45 @@ public class MachineRegistry } } - public static Map getinstalledMachines() + public static void initialize() + { + reload(); + Platform.getExtensionRegistry().addListener(new IRegistryEventListener() + { + + @Override + public void removed(IExtensionPoint[] extensionPoints) + { + // nothing? + } + + @Override + public void removed(IExtension[] extensions) + { + reload(); + } + + @Override + public void added(IExtensionPoint[] extensionPoints) + { + // nothing? + } + + @Override + public void added(IExtension[] extensions) + { + reload(); + } + }, MACHINE_EXT_ID); + } + + public static Map getInstalledMachines() { return Collections.unmodifiableMap(installedMachines); } + + public static MachineDefinition getMachine(String id) + { + return installedMachines.get(id); + } } diff --git a/plugins/net.mograsim.machine/src/net/mograsim/machine/mi/MicroInstructionMemoryParser.java b/plugins/net.mograsim.machine/src/net/mograsim/machine/mi/MicroInstructionMemoryParser.java index 3c13f67b..cea4326f 100644 --- a/plugins/net.mograsim.machine/src/net/mograsim/machine/mi/MicroInstructionMemoryParser.java +++ b/plugins/net.mograsim.machine/src/net/mograsim/machine/mi/MicroInstructionMemoryParser.java @@ -56,7 +56,7 @@ public class MicroInstructionMemoryParser try { MicroInstructionMemoryDefinition def = Objects - .requireNonNull(MachineRegistry.getinstalledMachines().get(machineName), "Unknown machine: " + machineName) + .requireNonNull(MachineRegistry.getMachine(machineName), "Unknown machine: " + machineName) .getMicroInstructionMemoryDefinition(); MicroInstructionMemory memory = new StandardMicroInstructionMemory(def); parseMemory(memory, input); diff --git a/plugins/net.mograsim.plugin.core/META-INF/MANIFEST.MF b/plugins/net.mograsim.plugin.core/META-INF/MANIFEST.MF index 6dfa9547..c3d17e93 100644 --- a/plugins/net.mograsim.plugin.core/META-INF/MANIFEST.MF +++ b/plugins/net.mograsim.plugin.core/META-INF/MANIFEST.MF @@ -8,6 +8,7 @@ Export-Package: net.mograsim.plugin;uses:="org.eclipse.ui.themes,org.eclipse.swt net.mograsim.plugin.asm.editor, net.mograsim.plugin.asm.editor.rules, net.mograsim.plugin.nature, + net.mograsim.plugin.nature.properties, net.mograsim.plugin.tables, net.mograsim.plugin.tables.memory, net.mograsim.plugin.tables.mi, @@ -28,7 +29,9 @@ Require-Bundle: org.eclipse.core.runtime, javax.annotation;bundle-version="1.0.0", net.mograsim.preferences;bundle-version="0.1.0", net.mograsim.machine, - net.mograsim.plugin.core + net.mograsim.plugin.core, + org.eclipse.core.expressions, + org.eclipse.ui.ide Bundle-RequiredExecutionEnvironment: JavaSE-11 Automatic-Module-Name: net.mograsim.plugin.core Bundle-Vendor: %Bundle-Vendor.0 diff --git a/plugins/net.mograsim.plugin.core/OSGI-INF/l10n/bundle.properties b/plugins/net.mograsim.plugin.core/OSGI-INF/l10n/bundle.properties index 26d588f2..04c03e1a 100644 --- a/plugins/net.mograsim.plugin.core/OSGI-INF/l10n/bundle.properties +++ b/plugins/net.mograsim.plugin.core/OSGI-INF/l10n/bundle.properties @@ -9,10 +9,9 @@ view.name = Sample AsmOpsEdit e4view.name = Simulation und Visualisierung extension.name = Mograsim Project Builder extension.name.0 = Mograsim Project Nature -category.name.0 = Mograsim Project Nature commands -command.name = Add/RemoveMograsim Project Nature -command.label = Disable Sample builder -command.label.0 = Enable Sample builder +category.name.0 = Mograsim +command.name = Convert to Mograsim Project +command.label = Convert to Mograsim Project extension.name.1 = XML Problem decorator.label = Resource Decorator themeElementCategory.label = Mograsim diff --git a/plugins/net.mograsim.plugin.core/plugin.xml b/plugins/net.mograsim.plugin.core/plugin.xml index 03348a3f..38f64cbe 100644 --- a/plugins/net.mograsim.plugin.core/plugin.xml +++ b/plugins/net.mograsim.plugin.core/plugin.xml @@ -1,6 +1,19 @@ + + + + + + + + @@ -21,6 +34,38 @@ priority="high"> + + + + + + + + + + + + + + + + + + + + @@ -126,87 +171,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + name="Mograsim"> + + + + + + + + + + + + + + + + + + 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 2e7a9c1d..9da121a2 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 @@ -24,7 +24,7 @@ public class MachineContext { instance = new MachineContext(); // TODO don't hardcode the Am2900 - instance.setMachine(MachineRegistry.getinstalledMachines().get("Am2900").createNew()); + instance.setMachine(MachineRegistry.getMachine("Am2900").createNew()); } return instance; } diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/MograsimActivator.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/MograsimActivator.java index 2d8e8e67..b3340dad 100644 --- a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/MograsimActivator.java +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/MograsimActivator.java @@ -13,7 +13,7 @@ public final class MograsimActivator extends AbstractUIPlugin if (instance != null) throw new IllegalStateException("MograsimActivator already created!"); instance = this; - MachineRegistry.reload(); + MachineRegistry.initialize(); } public static MograsimActivator instance() 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 new file mode 100644 index 00000000..3941b1d2 --- /dev/null +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/AddMograsimNatureHandler.java @@ -0,0 +1,89 @@ +package net.mograsim.plugin.nature; + +import java.util.Iterator; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.handlers.HandlerUtil; + +public class AddMograsimNatureHandler extends AbstractHandler +{ + @Override + public Object execute(ExecutionEvent event) throws ExecutionException + { + ISelection selection = HandlerUtil.getCurrentSelection(event); + // + + MultiStatus ms = new MultiStatus("net.mograsim.plugin.core", 42, "MograsimNature Conversion", null); + + if (selection instanceof IStructuredSelection) + { + for (Iterator it = ((IStructuredSelection) selection).iterator(); it.hasNext();) + { + Object element = it.next(); + IProject project = null; + if (element instanceof IProject) + { + project = (IProject) element; + } else if (element instanceof IAdaptable) + { + project = ((IAdaptable) element).getAdapter(IProject.class); + } + if (project != null) + { + try + { + ms.add(toggleNature(project)); + } + catch (CoreException e) + { + // TODO log something + throw new ExecutionException("Failed to toggle nature", e); + } + } + } + } + + return ms.getSeverity(); + } + + /** + * Adds Mograsim nature on a project + * + * @param project to have Mograsim nature + * @return + */ + private IStatus toggleNature(IProject project) throws CoreException + { + IProjectDescription description = project.getDescription(); + String[] natures = description.getNatureIds(); + + // Add the nature + String[] newNatures = new String[natures.length + 1]; + System.arraycopy(natures, 0, newNatures, 0, natures.length); + newNatures[natures.length] = MograsimNature.NATURE_ID; + + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IStatus status = workspace.validateNatureSet(newNatures); + + // only apply new nature, if the status is ok + if (status.getCode() == IStatus.OK) + { + description.setNatureIds(newNatures); + project.setDescription(description, null); + } + + return status; + } +} \ No newline at end of file diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/AddRemoveMograsimNatureHandler.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/AddRemoveMograsimNatureHandler.java deleted file mode 100644 index e8b38e99..00000000 --- a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/AddRemoveMograsimNatureHandler.java +++ /dev/null @@ -1,85 +0,0 @@ -package net.mograsim.plugin.nature; - -import java.util.Iterator; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectDescription; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.handlers.HandlerUtil; - -public class AddRemoveMograsimNatureHandler extends AbstractHandler -{ - @Override - public Object execute(ExecutionEvent event) throws ExecutionException - { - ISelection selection = HandlerUtil.getCurrentSelection(event); - // - if (selection instanceof IStructuredSelection) - { - for (Iterator it = ((IStructuredSelection) selection).iterator(); it.hasNext();) - { - Object element = it.next(); - IProject project = null; - if (element instanceof IProject) - { - project = (IProject) element; - } else if (element instanceof IAdaptable) - { - project = ((IAdaptable) element).getAdapter(IProject.class); - } - if (project != null) - { - try - { - toggleNature(project); - } - catch (CoreException e) - { - // TODO log something - throw new ExecutionException("Failed to toggle nature", e); - } - } - } - } - - return null; - } - - /** - * Toggles sample nature on a project - * - * @param project to have sample nature added or removed - */ - private void toggleNature(IProject project) throws CoreException - { - IProjectDescription description = project.getDescription(); - String[] natures = description.getNatureIds(); - - for (int i = 0; i < natures.length; ++i) - { - if (MograsimNature.NATURE_ID.equals(natures[i])) - { - // Remove the nature - String[] newNatures = new String[natures.length - 1]; - System.arraycopy(natures, 0, newNatures, 0, i); - System.arraycopy(natures, i + 1, newNatures, i, natures.length - i - 1); - description.setNatureIds(newNatures); - project.setDescription(description, null); - return; - } - } - - // Add the nature - String[] newNatures = new String[natures.length + 1]; - System.arraycopy(natures, 0, newNatures, 0, natures.length); - newNatures[natures.length] = MograsimNature.NATURE_ID; - description.setNatureIds(newNatures); - project.setDescription(description, null); - } -} \ No newline at end of file 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 new file mode 100644 index 00000000..b434ec97 --- /dev/null +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContext.java @@ -0,0 +1,120 @@ +package net.mograsim.plugin.nature; + +import java.io.IOException; +import java.util.Objects; +import java.util.Optional; + +import org.eclipse.core.resources.IProject; +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; + +public class MachineContext +{ + IProject owner; + ScopedPreferenceStore prefs; + Optional machineId; + Optional machineDefinition; + Optional activeMachine; + + public MachineContext(IProject owner) + { + this.owner = Objects.requireNonNull(owner); + prefs = ProjectMachineContext.getProjectPrefs(owner); + prefs.addPropertyChangeListener(this::preferenceListener); + machineId = ProjectMachineContext.getMachineIdFrom(prefs); + updateDefinition(); + } + + public final IProject getProject() + { + return owner; + } + + public final ScopedPreferenceStore getPreferences() + { + return prefs; + } + + /** + * Returns true if the project configuration is valid in the current environment + */ + public final boolean isCurrentyValid() + { + return machineDefinition.isPresent(); + } + + /** + * Returns true if the persisted project configuration itself is intact + */ + public final boolean isIntact() + { + return machineId.isPresent(); + } + + /** + * Returns true if a machine is instantiated and (possibly) running + */ + public final boolean isActive() + { + return activeMachine.isPresent(); + } + + /** + * Sets the projects machineId. Will likely break things, if the {@link MachineContext} {@link #isActive()}. + */ + public final boolean setMachineId(String machineId) + { + prefs.setValue(ProjectMachineContext.MACHINE_PROPERTY, machineId); + try + { + prefs.save(); + } + catch (IOException e) + { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * Sets the active machine in the {@link MachineContext}'s project scope. + */ + public final void setActiveMachine(Machine machine) + { + activeMachine = Optional.ofNullable(machine); + } + + public final Optional getMachineId() + { + return machineId; + } + + public final Optional getMachineDefinition() + { + return machineDefinition; + } + + public final Optional getActiveMachine() + { + return activeMachine; + } + + final void updateDefinition() + { + machineDefinition = machineId.map(MachineRegistry::getMachine); + } + + private void preferenceListener(PropertyChangeEvent changeEvent) + { + if (changeEvent.getProperty().equals(ProjectMachineContext.MACHINE_PROPERTY)) + { + machineId = Optional.ofNullable((String) changeEvent.getNewValue()); + updateDefinition(); + } + } +} \ No newline at end of file diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MograsimNature.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MograsimNature.java index 5422731e..4ffd62e7 100644 --- a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MograsimNature.java +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MograsimNature.java @@ -12,7 +12,7 @@ public class MograsimNature implements IProjectNature /** * ID of this project nature */ - public static final String NATURE_ID = "net.mograsim"; + public static final String NATURE_ID = "net.mograsim.plugin.core.mograsimNature"; private IProject project; 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 new file mode 100644 index 00000000..0e6185c4 --- /dev/null +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/ProjectMachineContext.java @@ -0,0 +1,91 @@ +package net.mograsim.plugin.nature; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ProjectScope; +import org.eclipse.core.runtime.Adapters; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ui.preferences.ScopedPreferenceStore; + +public class ProjectMachineContext +{ + private static Map projectMachineContexts = Collections.synchronizedMap(new HashMap<>()); + + public static final String MOGRASIM_PROJECT_PREFS_NODE = "net.mograsim"; + public static final String MACHINE_PROPERTY = "net.mograsim.projectMachineId"; + + public static MachineContext getMachineContextOf(IProject project) + { + MachineContext mc = projectMachineContexts.get(project); + if (mc != null) + return mc; + validateMograsimNatureProject(project); + mc = new MachineContext(project); + projectMachineContexts.put(project, mc); + return mc; + } + + public static MachineContext getMachineContextOf(IAdaptable mograsimProjectAdapable) + { + IProject project = Adapters.adapt(mograsimProjectAdapable, IProject.class, true); + Objects.requireNonNull(project, "project was null / no project found for " + mograsimProjectAdapable); + return getMachineContextOf(project); + } + + static ScopedPreferenceStore getProjectPrefs(IProject mograsimProject) + { + return new ScopedPreferenceStore(new ProjectScope(mograsimProject), MOGRASIM_PROJECT_PREFS_NODE); + } + + static IProject validateMograsimNatureProject(IAdaptable mograsimProjectAdapable) + { + IProject project; + if (mograsimProjectAdapable instanceof IProject) + { + project = (IProject) mograsimProjectAdapable; + } else + { + project = Adapters.adapt(mograsimProjectAdapable, IProject.class, true); + Objects.requireNonNull(project, () -> mograsimProjectAdapable + " is not adaptable to IProject"); + } + try + { + if (!project.isNatureEnabled(MograsimNature.NATURE_ID)) + throw new IllegalArgumentException(mograsimProjectAdapable + "is not (in) a Mograsim project"); + } + catch (CoreException e) + { + e.printStackTrace(); + throw new IllegalArgumentException(mograsimProjectAdapable + " project nature could not be evaluated", e); + } + return project; + } + + static boolean hasMograsimNature(IProject project) + { + if (project == null) + return false; + try + { + return project.isNatureEnabled(MograsimNature.NATURE_ID); + } + catch (CoreException e) + { + e.printStackTrace(); + return false; + } + } + + static Optional getMachineIdFrom(ScopedPreferenceStore preferenceStore) + { + if (preferenceStore.contains(MACHINE_PROPERTY)) + return Optional.of(preferenceStore.getString(MACHINE_PROPERTY)); + return Optional.empty(); + } +} diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/properties/MograsimNaturePropertyPage.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/properties/MograsimNaturePropertyPage.java new file mode 100644 index 00000000..edf07e2c --- /dev/null +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/properties/MograsimNaturePropertyPage.java @@ -0,0 +1,137 @@ +package net.mograsim.plugin.nature.properties; + +import java.util.Optional; + +import org.eclipse.jface.preference.PreferencePage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.dialogs.PropertyPage; + +import net.mograsim.machine.MachineRegistry; +import net.mograsim.plugin.nature.MachineContext; +import net.mograsim.plugin.nature.ProjectMachineContext; + +public class MograsimNaturePropertyPage extends PropertyPage +{ + + private static final String WARNING = "Changing the Mograsim machine can completely break your project. Be careful."; + private static final String MACHINE_LABEL = "Machine ID"; + private static final String MACHINE_PROPERTY = "net.mograsim.projectMachineId"; + private static final String DEFAULT_MACHINE = "Am2900"; + + private Combo machineSelect; + private String defaultId; + + private MachineContext machineContext; + + /** + * Constructor for SamplePropertyPage. + */ + public MograsimNaturePropertyPage() + { + super(); + } + + private void addFirstSection(Composite parent) + { + Composite composite = createDefaultComposite(parent); + + // Label for path field + Label pathLabel = new Label(composite, SWT.NONE); + pathLabel.setText(WARNING); + } + + private void addSeparator(Composite parent) + { + Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); + GridData gridData = new GridData(); + gridData.horizontalAlignment = GridData.FILL; + gridData.grabExcessHorizontalSpace = true; + separator.setLayoutData(gridData); + } + + private void addSecondSection(Composite parent) + { + Composite composite = createDefaultComposite(parent); + + // Label for machine + Label ownerLabel = new Label(composite, SWT.NONE); + ownerLabel.setText(MACHINE_LABEL); + + // Machine choice + machineSelect = new Combo(parent, SWT.BORDER); + GridData gd = new GridData(); + machineSelect.setLayoutData(gd); + + Optional currentId = machineContext.getMachineId(); + + if (currentId.isPresent()) + machineSelect.add(currentId.get()); + + for (String machineId : MachineRegistry.getInstalledMachines().keySet()) + { + if (currentId.isPresent() && currentId.get().equals(machineId)) + continue; + machineSelect.add(machineId); + } + + defaultId = currentId.orElse(DEFAULT_MACHINE); + + machineSelect.select(machineSelect.indexOf(defaultId)); + } + + /** + * @see PreferencePage#createContents(Composite) + */ + protected Control createContents(Composite parent) + { + machineContext = ProjectMachineContext.getMachineContextOf(getElement()); + + Composite composite = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + composite.setLayout(layout); + GridData data = new GridData(GridData.FILL); + data.grabExcessHorizontalSpace = true; + composite.setLayoutData(data); + + addFirstSection(composite); + addSeparator(composite); + addSecondSection(composite); + return composite; + } + + private Composite createDefaultComposite(Composite parent) + { + Composite composite = new Composite(parent, SWT.NULL); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + composite.setLayout(layout); + + GridData data = new GridData(); + data.verticalAlignment = GridData.FILL; + data.horizontalAlignment = GridData.FILL; + composite.setLayoutData(data); + + return composite; + } + + protected void performDefaults() + { + super.performDefaults(); + // Populate the owner text field with the default value + machineSelect.select(machineSelect.indexOf(DEFAULT_MACHINE)); + } + + public boolean performOk() + { + int selected = machineSelect.getSelectionIndex(); + String newId = machineSelect.getItem(selected); + return machineContext.setMachineId(newId); + } + +} \ No newline at end of file