Marked MPROM as optional in MainMachineLaunchConfigTab
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / launch / MainMachineLaunchConfigTab.java
1 package net.mograsim.plugin.launch;
2
3 import java.util.Arrays;
4 import java.util.HashSet;
5 import java.util.Set;
6 import java.util.function.Supplier;
7
8 import org.eclipse.core.resources.IProject;
9 import org.eclipse.core.resources.IResource;
10 import org.eclipse.core.resources.IWorkspace;
11 import org.eclipse.core.resources.ResourcesPlugin;
12 import org.eclipse.core.runtime.CoreException;
13 import org.eclipse.core.runtime.IStatus;
14 import org.eclipse.debug.core.ILaunchConfiguration;
15 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
16 import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
17 import org.eclipse.jface.dialogs.IDialogConstants;
18 import org.eclipse.jface.layout.PixelConverter;
19 import org.eclipse.jface.resource.ImageDescriptor;
20 import org.eclipse.jface.window.Window;
21 import org.eclipse.osgi.util.NLS;
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.graphics.Point;
24 import org.eclipse.swt.layout.FillLayout;
25 import org.eclipse.swt.layout.GridData;
26 import org.eclipse.swt.layout.GridLayout;
27 import org.eclipse.swt.widgets.Button;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.swt.widgets.Label;
31 import org.eclipse.swt.widgets.Text;
32 import org.eclipse.ui.dialogs.ElementListSelectionDialog;
33 import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
34 import org.eclipse.ui.model.WorkbenchContentProvider;
35 import org.eclipse.ui.model.WorkbenchLabelProvider;
36
37 import net.mograsim.plugin.nature.MograsimNature;
38 import net.mograsim.plugin.util.FileExtensionViewerFilter;
39 import net.mograsim.plugin.util.ImageDescriptorWithMargins;
40 import net.mograsim.plugin.util.ProjectViewerFilter;
41
42 //a big part of this class is stolen from org.eclipse.jdt.debug.ui
43 public class MainMachineLaunchConfigTab extends AbstractLaunchConfigurationTab
44 {
45         private Text projSelText;
46         private Text mpmFileSelText;
47         private Text mpromFileSelText;
48         private Text initialRAMFileSelText;
49
50         @Override
51         public void createControl(Composite parent)
52         {
53                 parent.setLayout(new FillLayout());
54                 Composite innerParent = new Composite(parent, SWT.NONE);
55                 setControl(innerParent);
56
57                 innerParent.setLayout(new GridLayout(3, false));
58
59                 this.projSelText = addResourceSelector(innerParent, "P&roject:", this::chooseMograsimProject);
60
61                 this.mpmFileSelText = addResourceSelector(innerParent, "&MPM:", this::chooseMPMFile);
62
63                 this.mpromFileSelText = addResourceSelector(innerParent, "M&PROM (optional):", this::chooseMPROMFile);
64
65                 this.initialRAMFileSelText = addResourceSelector(innerParent, "Initial &RAM (optional):", this::chooseInitialRAMFile);
66         }
67
68         private Text addResourceSelector(Composite innerParent, String label, Supplier<String> chooser)
69         {
70                 Label swtLabel = new Label(innerParent, SWT.NONE);
71                 swtLabel.setText(label);
72                 swtLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
73
74                 Text text = new Text(innerParent, SWT.BORDER);
75                 text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
76                 text.addModifyListener(e -> updateLaunchConfigurationDialog());
77
78                 swtLabel.addListener(SWT.FocusIn, e -> text.setFocus());
79
80                 Button browseButton = new Button(innerParent, SWT.PUSH);
81                 GridData projSelButtonData = new GridData();
82                 projSelButtonData.widthHint = calculateWidthHint(browseButton);
83                 projSelButtonData.horizontalAlignment = SWT.FILL;
84                 browseButton.setLayoutData(projSelButtonData);
85                 browseButton.setText("&Browse...");
86                 browseButton.addListener(SWT.Selection, e ->
87                 {
88                         String chosen = chooser.get();
89                         if (chosen != null)
90                                 text.setText(chosen);
91                 });
92                 return text;
93         }
94
95         private static int calculateWidthHint(Control c)
96         {
97                 int wHint = new PixelConverter(c).convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
98                 return Math.max(wHint, c.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
99         }
100
101         private String chooseMograsimProject()
102         {
103                 // TODO this seems very ugly, especially hardcoded width/height
104                 WorkbenchLabelProvider renderer = new WorkbenchLabelProvider()
105                 {
106                         @Override
107                         protected ImageDescriptor decorateImage(ImageDescriptor input, Object element)
108                         {
109                                 return new ImageDescriptorWithMargins(input, new Point(20, 16));
110                         }
111                 };
112                 ElementListSelectionDialog dialog = new ElementListSelectionDialog(getShell(), renderer);
113                 dialog.setTitle("Project Selection");
114                 dialog.setMessage("Select a Mograsim project");
115                 dialog.setElements(filterOpenMograsimProjects(ResourcesPlugin.getWorkspace().getRoot().getProjects()));
116                 if (dialog.open() == Window.OK)
117                         return ((IProject) dialog.getFirstResult()).getName();
118                 return null;
119         }
120
121         private String chooseMPMFile()
122         {
123                 return chooseFile("MPM", "mpm");
124         }
125
126         private String chooseMPROMFile()
127         {
128                 return chooseFile("MPROM", "mprom");
129         }
130
131         private String chooseInitialRAMFile()
132         {
133                 return chooseFile("Initial RAM", "mem");
134         }
135
136         private String chooseFile(String type, String fileext)
137         {
138                 ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(),
139                                 new WorkbenchContentProvider());
140                 dialog.setTitle(type + " Selection");
141                 dialog.setMessage("Select a ." + fileext + " file");
142                 dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
143                 dialog.addFilter(new FileExtensionViewerFilter(fileext));
144                 dialog.addFilter(new ProjectViewerFilter(getSelectedProject()));
145
146                 if (dialog.open() == Window.OK)
147                         return ((IResource) dialog.getResult()[0]).getProjectRelativePath().toPortableString();
148                 return null;
149         }
150
151         private IProject getSelectedProject()
152         {
153                 String projName = projSelText.getText().trim();
154                 IWorkspace workspace = ResourcesPlugin.getWorkspace();
155                 if (workspace.validateName(projName, IResource.PROJECT).isOK())
156                         return workspace.getRoot().getProject(projName);
157                 return null;
158         }
159
160         private static IProject[] filterOpenMograsimProjects(IProject[] projects)
161         {
162                 return Arrays.stream(projects).filter(p ->
163                 {
164                         try
165                         {
166                                 return p.isAccessible() && p.hasNature(MograsimNature.NATURE_ID);
167                         }
168                         catch (CoreException e)
169                         {
170                                 throw new RuntimeException(e);
171                         }
172                 }).toArray(IProject[]::new);
173         }
174
175         @Override
176         public void setDefaults(ILaunchConfigurationWorkingCopy configuration)
177         {
178                 // TODO don't let the user have to specify everything
179         }
180
181         @Override
182         public void initializeFrom(ILaunchConfiguration configuration)
183         {
184                 projSelText.setText(getStringAttribSafe(configuration, MachineLaunchConfigType.PROJECT_ATTR, ""));
185                 mpmFileSelText.setText(getStringAttribSafe(configuration, MachineLaunchConfigType.MPM_FILE_ATTR, ""));
186                 mpromFileSelText.setText(getStringAttribSafe(configuration, MachineLaunchConfigType.MPROM_FILE_ATTR, ""));
187                 initialRAMFileSelText.setText(getStringAttribSafe(configuration, MachineLaunchConfigType.INITIAL_RAM_FILE_ATTR, ""));
188         }
189
190         private String getStringAttribSafe(ILaunchConfiguration configuration, String attrib, String defaultValue)
191         {
192                 try
193                 {
194                         return configuration.getAttribute(attrib, defaultValue);
195                 }
196                 catch (CoreException e)
197                 {
198                         setErrorMessage(e.getStatus().getMessage());
199                 }
200                 return defaultValue;
201         }
202
203         @Override
204         public void performApply(ILaunchConfigurationWorkingCopy configuration)
205         {
206                 String projName = projSelText.getText().trim();
207                 String mpmFileName = mpmFileSelText.getText().trim();
208                 String mpromFileName = mpromFileSelText.getText().trim();
209                 String initialRAMFileName = initialRAMFileSelText.getText().trim();
210
211                 Set<IResource> associatedResources = new HashSet<>();
212                 IWorkspace workspace = ResourcesPlugin.getWorkspace();
213                 if (workspace.validateName(projName, IResource.PROJECT).isOK())
214                 {
215                         IProject project = workspace.getRoot().getProject(projName);
216                         try
217                         {
218                                 if (project != null && project.isAccessible() && project.hasNature(MograsimNature.NATURE_ID))
219                                 {
220                                         associatedResources.add(project);
221
222                                         IResource mpmFile = project.findMember(mpmFileName);
223                                         if (mpmFile != null && mpmFile.exists() && mpmFile.getType() == IResource.FILE)
224                                                 associatedResources.add(mpmFile);
225
226                                         IResource mpromFile = project.findMember(mpromFileName);
227                                         if (mpromFile != null && mpromFile.exists() && mpromFile.getType() == IResource.FILE)
228                                                 associatedResources.add(mpromFile);
229
230                                         IResource ramFile = project.findMember(initialRAMFileName);
231                                         if (ramFile != null && ramFile.exists() && ramFile.getType() == IResource.FILE)
232                                                 associatedResources.add(ramFile);
233                                 }
234                         }
235                         catch (CoreException e)
236                         {
237                                 setErrorMessage(e.getStatus().getMessage());
238                         }
239                 }
240                 configuration.setMappedResources(associatedResources.toArray(IResource[]::new));
241                 configuration.setAttribute(MachineLaunchConfigType.PROJECT_ATTR, projName);
242                 configuration.setAttribute(MachineLaunchConfigType.MPM_FILE_ATTR, mpmFileName);
243                 configuration.setAttribute(MachineLaunchConfigType.MPROM_FILE_ATTR, mpromFileName);
244                 configuration.setAttribute(MachineLaunchConfigType.INITIAL_RAM_FILE_ATTR, initialRAMFileName);
245         }
246
247         @Override
248         public boolean isValid(ILaunchConfiguration launchConfig)
249         {
250                 setErrorMessage(null);
251                 setMessage(null);
252                 String projName = projSelText.getText().trim();
253                 if (projName.length() == 0)
254                         return setErrorAndReturnFalse("No project specified");
255
256                 IWorkspace workspace = ResourcesPlugin.getWorkspace();
257                 IStatus status = workspace.validateName(projName, IResource.PROJECT);
258                 if (!status.isOK())
259                         return setErrorAndReturnFalse("Illegal project name: {0}: {1}", projName, status.getMessage());
260
261                 IProject project = workspace.getRoot().getProject(projName);
262                 if (!project.exists())
263                         return setErrorAndReturnFalse("Project {0} does not exist", projName);
264                 if (!project.isOpen())
265                         return setErrorAndReturnFalse("Project {0} is closed", projName);
266                 try
267                 {
268                         if (!project.hasNature(MograsimNature.NATURE_ID))
269                                 return setErrorAndReturnFalse("Project {0} is not a Mograsim project", projName);
270                 }
271                 catch (CoreException e)
272                 {
273                         return setErrorAndReturnFalse(e.getStatus().getMessage());
274                 }
275
276                 String mpmFileName = mpmFileSelText.getText().trim();
277                 if (mpmFileName.length() == 0)
278                         return setErrorAndReturnFalse("No MPM file specified");
279                 IResource mpmResource = project.findMember(mpmFileName);
280                 if (mpmResource == null || !mpmResource.exists())
281                         return setErrorAndReturnFalse("MPM file {0} does not exist", mpmFileName);
282                 if (mpmResource.getType() != IResource.FILE)
283                         return setErrorAndReturnFalse("MPM file {0} is not a file", mpmFileName);
284
285                 String mpromFileName = mpromFileSelText.getText().trim();
286                 if (mpromFileName.length() > 0)
287                 {
288                         IResource mpromResource = project.findMember(mpromFileName);
289                         if (mpromResource == null || !mpromResource.exists())
290                                 return setErrorAndReturnFalse("MPROM file {0} does not exist", mpromFileName);
291                         if (mpromResource.getType() != IResource.FILE)
292                                 return setErrorAndReturnFalse("MPROM file {0} is not a file", mpromFileName);
293                 }
294
295                 String initialRAMFileName = initialRAMFileSelText.getText().trim();
296                 if (initialRAMFileName.length() > 0)
297                 {
298                         IResource initialRAMResource = project.findMember(initialRAMFileName);
299                         if (initialRAMResource == null || !initialRAMResource.exists())
300                                 return setErrorAndReturnFalse("Initial RAM file {0} does not exist", initialRAMFileName);
301                         if (initialRAMResource.getType() != IResource.FILE)
302                                 return setErrorAndReturnFalse("Initial RAM file {0} is not a file", initialRAMFileName);
303                 }
304
305                 return true;
306         }
307
308         private boolean setErrorAndReturnFalse(String message, String... params)
309         {
310                 setErrorMessage(NLS.bind(message, params));
311                 return false;
312         }
313
314         @Override
315         public String getName()
316         {
317                 return "Main";
318         }
319 }