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