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