The user can now specify a RAM file (but doesn't have to)
[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.Group;
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
41 //a big part of this class is stolen from org.eclipse.jdt.debug.ui
42 public class MainMachineLaunchConfigTab extends AbstractLaunchConfigurationTab
43 {
44         private Text projSelText;
45         private Text mpmFileSelText;
46         private Text initialRAMFileSelText;
47
48         @Override
49         public void createControl(Composite parent)
50         {
51                 parent.setLayout(new FillLayout());
52                 Composite innerParent = new Composite(parent, SWT.NONE);
53                 setControl(innerParent);
54
55                 innerParent.setLayout(new GridLayout());
56
57                 this.projSelText = createResourceSelectorGroup(innerParent, "&Project:", this::chooseMograsimProject);
58
59                 this.mpmFileSelText = createResourceSelectorGroup(innerParent, "&MPM:", this::chooseMPMFile);
60
61                 this.initialRAMFileSelText = createResourceSelectorGroup(innerParent, "Initial &RAM (optional):", this::chooseInitialRAMFile);
62         }
63
64         private Text createResourceSelectorGroup(Composite innerParent, String groupName, Supplier<String> chooser)
65         {
66                 Group group = new Group(innerParent, SWT.NONE);
67                 group.setLayout(new GridLayout(2, false));
68                 group.setText(groupName);
69                 group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
70
71                 Text text = new Text(group, SWT.BORDER);
72                 text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
73                 text.addModifyListener(e -> updateLaunchConfigurationDialog());
74
75                 Button browseButton = new Button(group, SWT.PUSH);
76                 GridData projSelButtonData = new GridData();
77                 projSelButtonData.widthHint = calculateWidthHint(browseButton);
78                 projSelButtonData.horizontalAlignment = SWT.FILL;
79                 browseButton.setLayoutData(projSelButtonData);
80                 browseButton.setText("&Browse...");
81                 browseButton.addListener(SWT.Selection, e ->
82                 {
83                         String chosen = chooser.get();
84                         if (chosen != null)
85                                 text.setText(chosen);
86                 });
87                 return text;
88         }
89
90         private static int calculateWidthHint(Control c)
91         {
92                 int wHint = new PixelConverter(c).convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
93                 return Math.max(wHint, c.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
94         }
95
96         private String chooseMograsimProject()
97         {
98                 WorkbenchLabelProvider renderer = new WorkbenchLabelProvider()
99                 {
100                         @Override
101                         protected ImageDescriptor decorateImage(ImageDescriptor input, Object element)
102                         {
103                                 return new ImageDescriptorWithMargins(input, new Point(22, 16));
104                         }
105                 };
106                 ElementListSelectionDialog dialog = new ElementListSelectionDialog(getShell(), renderer);
107                 dialog.setTitle("Project Selection");
108                 dialog.setMessage("Select a Mograsim project");
109                 dialog.setElements(filterOpenMograsimProjects(ResourcesPlugin.getWorkspace().getRoot().getProjects()));
110                 if (dialog.open() == Window.OK)
111                         return ((IProject) dialog.getFirstResult()).getName();
112                 return null;
113         }
114
115         private String chooseMPMFile()
116         {
117                 WorkbenchLabelProvider renderer = new WorkbenchLabelProvider()
118                 {
119                         @Override
120                         protected ImageDescriptor decorateImage(ImageDescriptor input, Object element)
121                         {
122                                 return new ImageDescriptorWithMargins(input, new Point(22, 16));
123                         }
124                 };
125                 ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), renderer, new WorkbenchContentProvider());
126                 dialog.setTitle("MPM Selection");
127                 dialog.setMessage("Select a MPM file");
128                 dialog.setInput(getSelectedProject());
129                 dialog.addFilter(new FileExtensionViewerFilter("mpm"));
130
131                 if (dialog.open() == Window.OK)
132                         return ((IResource) dialog.getResult()[0]).getProjectRelativePath().toPortableString();
133                 return null;
134         }
135
136         private String chooseInitialRAMFile()
137         {
138                 WorkbenchLabelProvider renderer = new WorkbenchLabelProvider()
139                 {
140                         @Override
141                         protected ImageDescriptor decorateImage(ImageDescriptor input, Object element)
142                         {
143                                 return new ImageDescriptorWithMargins(input, new Point(22, 16));
144                         }
145                 };
146                 ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), renderer, new WorkbenchContentProvider());
147                 dialog.setTitle("Initial RAM Selection");
148                 dialog.setMessage("Select a RAM file");
149                 dialog.setInput(getSelectedProject());
150                 dialog.addFilter(new FileExtensionViewerFilter("mem"));
151
152                 if (dialog.open() == Window.OK)
153                         return ((IResource) dialog.getResult()[0]).getProjectRelativePath().toPortableString();
154                 return null;
155         }
156
157         private IProject getSelectedProject()
158         {
159                 String projName = projSelText.getText().trim();
160                 IWorkspace workspace = ResourcesPlugin.getWorkspace();
161                 if (workspace.validateName(projName, IResource.PROJECT).isOK())
162                         return workspace.getRoot().getProject(projName);
163                 return null;
164         }
165
166         private static IProject[] filterOpenMograsimProjects(IProject[] projects)
167         {
168                 return Arrays.stream(projects).filter(p ->
169                 {
170                         try
171                         {
172                                 return p.isAccessible() && p.hasNature(MograsimNature.NATURE_ID);
173                         }
174                         catch (CoreException e)
175                         {
176                                 throw new RuntimeException(e);
177                         }
178                 }).toArray(IProject[]::new);
179         }
180
181         @Override
182         public void setDefaults(ILaunchConfigurationWorkingCopy configuration)
183         {
184                 // TODO don't let the user have to specify everything
185         }
186
187         @Override
188         public void initializeFrom(ILaunchConfiguration configuration)
189         {
190                 projSelText.setText(getStringAttribSafe(configuration, MachineLaunchConfigType.PROJECT_ATTR, ""));
191                 mpmFileSelText.setText(getStringAttribSafe(configuration, MachineLaunchConfigType.MPM_FILE_ATTR, ""));
192                 initialRAMFileSelText.setText(getStringAttribSafe(configuration, MachineLaunchConfigType.INITIAL_RAM_FILE_ATTR, ""));
193         }
194
195         private String getStringAttribSafe(ILaunchConfiguration configuration, String attrib, String defaultValue)
196         {
197                 try
198                 {
199                         return configuration.getAttribute(attrib, defaultValue);
200                 }
201                 catch (CoreException e)
202                 {
203                         setErrorMessage(e.getStatus().getMessage());
204                 }
205                 return defaultValue;
206         }
207
208         @Override
209         public void performApply(ILaunchConfigurationWorkingCopy configuration)
210         {
211                 String projName = projSelText.getText().trim();
212                 String mpmFileName = mpmFileSelText.getText().trim();
213                 String initialRAMFileName = initialRAMFileSelText.getText().trim();
214
215                 Set<IResource> associatedResources = new HashSet<>();
216                 IWorkspace workspace = ResourcesPlugin.getWorkspace();
217                 if (workspace.validateName(projName, IResource.PROJECT).isOK())
218                 {
219                         IProject project = workspace.getRoot().getProject(projName);
220                         try
221                         {
222                                 if (project != null && project.isAccessible() && project.hasNature(MograsimNature.NATURE_ID))
223                                 {
224                                         associatedResources.add(project);
225
226                                         IResource mpmFile = project.findMember(mpmFileName);
227                                         if (mpmFile != null && mpmFile.exists() && mpmFile.getType() == IResource.FILE)
228                                                 associatedResources.add(mpmFile);
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.INITIAL_RAM_FILE_ATTR, initialRAMFileName);
244         }
245
246         @Override
247         public boolean isValid(ILaunchConfiguration launchConfig)
248         {
249                 setErrorMessage(null);
250                 setMessage(null);
251                 String projName = projSelText.getText().trim();
252                 if (projName.length() == 0)
253                         return setErrorAndReturnFalse("No project specified");
254
255                 IWorkspace workspace = ResourcesPlugin.getWorkspace();
256                 IStatus status = workspace.validateName(projName, IResource.PROJECT);
257                 if (!status.isOK())
258                         return setErrorAndReturnFalse("Illegal project name: {0}: {1}", projName, status.getMessage());
259
260                 IProject project = workspace.getRoot().getProject(projName);
261                 if (!project.exists())
262                         return setErrorAndReturnFalse("Project {0} does not exist", projName);
263                 if (!project.isOpen())
264                         return setErrorAndReturnFalse("Project {0} is closed", projName);
265                 try
266                 {
267                         if (!project.hasNature(MograsimNature.NATURE_ID))
268                                 return setErrorAndReturnFalse("Project {0} is not a Mograsim project", projName);
269                 }
270                 catch (CoreException e)
271                 {
272                         return setErrorAndReturnFalse(e.getStatus().getMessage());
273                 }
274
275                 String mpmFileName = mpmFileSelText.getText().trim();
276                 if (mpmFileName.length() == 0)
277                         return setErrorAndReturnFalse("No MPM file specified");
278                 IResource mpmResource = project.findMember(mpmFileName);
279                 if (mpmResource == null || !mpmResource.exists())
280                         return setErrorAndReturnFalse("MPM file {0} does not exist", mpmFileName);
281                 if (mpmResource.getType() != IResource.FILE)
282                         return setErrorAndReturnFalse("MPM file {0} is not a file", mpmFileName);
283
284                 String initialRAMFileName = initialRAMFileSelText.getText().trim();
285                 if (initialRAMFileName.length() > 0)
286                 {
287                         IResource initialRAMResource = project.findMember(initialRAMFileName);
288                         if (initialRAMResource == null || !initialRAMResource.exists())
289                                 return setErrorAndReturnFalse("Initial RAM file {0} does not exist", initialRAMFileName);
290                         if (initialRAMResource.getType() != IResource.FILE)
291                                 return setErrorAndReturnFalse("Initial RAM file {0} is not a file", initialRAMFileName);
292                 }
293
294                 return true;
295         }
296
297         private boolean setErrorAndReturnFalse(String message, String... params)
298         {
299                 setErrorMessage(NLS.bind(message, params));
300                 return false;
301         }
302
303         @Override
304         public String getName()
305         {
306                 return "testlaunchconfigtabname";
307         }
308 }