source: trunk/org.modelica.mdt/src/org/modelica/mdt/NewClassWizard.java @ 61

Last change on this file since 61 was 61, checked in by boris, 19 years ago
  • added copyright notice to all source files
File size: 17.2 KB
Line 
1/*
2 * This file is part of Modelica Development Tooling.
3 *
4 * Copyright (c) 2005, Linköpings universitet, Department of
5 * Computer and Information Science, PELAB
6 *
7 * All rights reserved.
8 *
9 * (The new BSD license, see also
10 * http://www.opensource.org/licenses/bsd-license.php)
11 *
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are
15 * met:
16 *
17 * * Redistributions of source code must retain the above copyright
18 *   notice, this list of conditions and the following disclaimer.
19 *
20 * * Redistributions in binary form must reproduce the above copyright
21 *   notice, this list of conditions and the following disclaimer in
22 *   the documentation and/or other materials provided with the
23 *   distribution.
24 *
25 * * Neither the name of Linköpings universitet nor the names of its
26 *   contributors may be used to endorse or promote products derived from
27 *   this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
42package org.modelica.mdt;
43
44
45import java.io.ByteArrayInputStream;
46import java.io.IOException;
47import java.io.InputStream;
48import java.lang.reflect.InvocationTargetException;
49import java.util.regex.Pattern;
50
51import org.eclipse.core.resources.IContainer;
52import org.eclipse.core.resources.IFile;
53import org.eclipse.core.resources.IResource;
54import org.eclipse.core.resources.IWorkspaceRoot;
55import org.eclipse.core.resources.ResourcesPlugin;
56import org.eclipse.core.runtime.CoreException;
57import org.eclipse.core.runtime.IPath;
58import org.eclipse.core.runtime.IProgressMonitor;
59import org.eclipse.core.runtime.IStatus;
60import org.eclipse.core.runtime.Path;
61import org.eclipse.core.runtime.Status;
62import org.eclipse.jface.dialogs.DialogPage;
63import org.eclipse.jface.dialogs.ErrorDialog;
64import org.eclipse.jface.dialogs.MessageDialog;
65import org.eclipse.jface.operation.IRunnableWithProgress;
66import org.eclipse.jface.viewers.IStructuredSelection;
67import org.eclipse.jface.wizard.Wizard;
68import org.eclipse.jface.wizard.WizardPage;
69import org.eclipse.swt.SWT;
70import org.eclipse.swt.events.ModifyEvent;
71import org.eclipse.swt.events.ModifyListener;
72import org.eclipse.swt.events.SelectionAdapter;
73import org.eclipse.swt.events.SelectionEvent;
74import org.eclipse.swt.events.SelectionListener;
75import org.eclipse.swt.layout.GridData;
76import org.eclipse.swt.layout.GridLayout;
77import org.eclipse.swt.widgets.Combo;
78import org.eclipse.swt.widgets.Composite;
79import org.eclipse.swt.widgets.Label;
80import org.eclipse.swt.widgets.Text;
81import org.eclipse.swt.widgets.Button;
82import org.eclipse.ui.INewWizard;
83import org.eclipse.ui.IWorkbench;
84import org.eclipse.ui.IWorkbenchPage;
85import org.eclipse.ui.PartInitException;
86import org.eclipse.ui.PlatformUI;
87import org.eclipse.ui.dialogs.ContainerSelectionDialog;
88import org.eclipse.ui.ide.IDE;
89
90public class NewClassWizard extends Wizard implements INewWizard
91{
92   
93    public class NewClassPage extends WizardPage
94    {
95        private Text sourceFolder;
96        private Text className;
97        private Combo classType;
98        private Button initialEquation;
99        private Button partialClass;
100        private Button externalBody;
101   
102        private IPath selection = null;
103       
104       
105        /* regexp pattern of a valid modelica class name */
106        //TODO add complete regexp for modelcia class name
107        // see modelica specification page 9 (and perhaps some other pages as well)
108        // http://www.modelica.org/documents/ModelicaSpec22.pdf
109        Pattern classNamePattern = Pattern.compile("[a-zA-Z]\\w*");
110       
111        private boolean classNameValid = false;
112        private boolean sourceFolderValid = false;     
113       
114        public NewClassPage()
115        {
116            super("");
117        }
118
119        public void createControl(Composite parent)
120        {
121            setPageComplete(false);
122            /*
123             * configure description of this page
124             */
125            setTitle("Modelica Class");
126            setDescription("Create a new Modelica class.");
127           
128            // TODO set image descriptor           
129            //setImageDescriptor(...);
130           
131            /*
132             * setup widgets for this page
133             */
134            Composite composite= new Composite(parent, SWT.NONE);
135            setControl(composite);
136            composite.setFont(parent.getFont());
137           
138            GridLayout layout = new GridLayout();
139            layout.numColumns = 3;
140            composite.setLayout(layout);
141           
142            GridData gd;
143
144            /* source folder field */
145            Label l = new Label(composite, SWT.LEFT | SWT.WRAP);
146            l.setText("Source folder:");
147            gd = new GridData();
148            gd.horizontalAlignment = GridData.BEGINNING;
149            l.setLayoutData(gd);
150           
151            sourceFolder = new Text(composite, SWT.SINGLE | SWT.BORDER);
152            gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
153            sourceFolder.setLayoutData(gd);
154            setSourceFolder(selection);
155           
156            sourceFolder.addModifyListener(new ModifyListener()
157            {
158                    /* check if entered path exists */
159                    public void modifyText(ModifyEvent e)
160                    {
161                        sourceFolderChanged();
162                    }
163            });
164
165
166            Button b = new Button(composite, SWT.PUSH);
167            b.setText("Browse...");
168            gd = new GridData();
169            gd.horizontalAlignment = GridData.END;
170            b.setLayoutData(gd);
171            b.addSelectionListener(new SelectionAdapter()
172            {
173                public void widgetSelected(SelectionEvent e)
174                {
175                    handleBrowse();
176                }
177            });
178
179           
180            /* class name field */
181            l = new Label(composite, SWT.LEFT | SWT.WRAP);
182            l.setText("Name:");
183            gd = new GridData();
184            gd.horizontalAlignment = GridData.BEGINNING;
185            l.setLayoutData(gd);
186           
187            className = new Text(composite,  SWT.SINGLE | SWT.BORDER);
188            gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
189            gd.horizontalSpan = 2;
190            className.setLayoutData(gd);
191
192            className.addModifyListener(new ModifyListener()
193            {
194                /* check if entered classname is valid */
195                public void modifyText(ModifyEvent e)
196                {
197                    if (!isLegalClassName(className.getText()))
198                    {
199                        classNameValid  = false;
200                        updateStatus("Class name is not valid. Illegal identifier.",
201                                    DialogPage.WARNING);
202                    }
203                    else
204                    {
205                        classNameValid  = true;
206                        updateStatus(null, DialogPage.NONE);
207                    }
208                }
209            });
210            className.setFocus();
211
212            /* class type field */
213            l = new Label(composite, SWT.LEFT | SWT.WRAP);
214            l.setText("Type:");
215            gd = new GridData();
216            gd.horizontalAlignment = GridData.BEGINNING;
217            l.setLayoutData(gd);
218           
219            classType = new Combo(composite, SWT.READ_ONLY);
220            classType.setItems(new String [] {"model", "class", "connector", "record",
221                    "block", "type", "function"});
222            classType.setVisibleItemCount(7);
223            classType.select(0);           
224                   
225            gd = new GridData();
226            gd.horizontalAlignment = GridData.BEGINNING;
227            classType.setLayoutData(gd);
228           
229            classType.addSelectionListener(new SelectionListener()
230            {
231
232                public void widgetSelected(SelectionEvent e)
233                {
234                    /*
235                     * update state of the modifiers checkboxes
236                     */
237                    initialEquation.setEnabled
238                    (NewClassWizard.classTypeHaveEquations(classType.getText()));
239                   
240                    partialClass.setEnabled
241                    (NewClassWizard.canBePartial(classType.getText()));
242                   
243                    externalBody.setEnabled(classType.getText().equals("function"));
244
245                }
246
247                public void widgetDefaultSelected(SelectionEvent e)
248                {}
249               
250            });
251           
252            /* fill upp 'empty' space */
253            new Label(composite, SWT.NONE);
254
255           
256            /* create separator */
257            l = new Label(composite, SWT.HORIZONTAL | SWT.SEPARATOR);
258            gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
259            gd.horizontalSpan = 3;
260            l.setLayoutData(gd);
261           
262           
263            /* modifiers section */
264            l = new Label(composite, SWT.NONE);
265            l.setText("Modifiers:");
266           
267            /* initial equation block */
268            initialEquation = new Button(composite, SWT.CHECK);
269            initialEquation.setText("include initial equation block");
270           
271            gd = new GridData();
272            gd.horizontalAlignment = GridData.BEGINNING;
273            gd.horizontalSpan = 2;
274            initialEquation.setLayoutData(gd);
275           
276            /* partial class */
277            new Label(composite, SWT.NONE); /* empty label for padding */
278            partialClass = new Button(composite, SWT.CHECK);
279            partialClass.setText("is partial class");
280           
281            gd = new GridData();
282            gd.horizontalAlignment = GridData.BEGINNING;
283            gd.horizontalSpan = 2;
284            partialClass.setLayoutData(gd);
285
286            /* external body */
287            new Label(composite, SWT.NONE); /* empty label for padding */
288            externalBody = new Button(composite, SWT.CHECK);
289            externalBody.setText("have external body");
290            externalBody.setEnabled(false);
291           
292            gd = new GridData();
293            gd.horizontalAlignment = GridData.BEGINNING;
294            gd.horizontalSpan = 2;
295            externalBody.setLayoutData(gd);
296           
297
298        }
299
300        private void sourceFolderChanged()
301        {
302            IResource container = ResourcesPlugin.getWorkspace().getRoot()
303                    .findMember(new Path(sourceFolder.getText()));
304
305            sourceFolderValid = false;
306            if (sourceFolder.getText().length() == 0) {
307                updateStatus("File container must be specified", DialogPage.ERROR);
308                return;
309            }
310            if (container == null
311                    || (container.getType() & (IResource.PROJECT | IResource.FOLDER)) == 0) {
312                updateStatus("File container must exist", DialogPage.ERROR);
313                return;
314            }
315            if (!container.isAccessible()) {
316                updateStatus("Project must be writable", DialogPage.ERROR);
317                return;
318            }
319            sourceFolderValid = true;
320            updateStatus(null, DialogPage.NONE);
321        }
322
323        /**
324         * @return true if name is a valid modelica class name
325         */
326        protected boolean isLegalClassName(String name)
327        {
328            return classNamePattern.matcher(name).matches();
329        }
330       
331        public void init(IStructuredSelection selection)
332        {
333            if (selection == null || selection.size() != 1)
334            {
335                return;
336            }
337            if (!(selection.getFirstElement() instanceof IResource))
338            {
339                return;
340            }
341           
342            /*
343             * now we know that a single element of type IResource is selected
344             */
345            IResource sel = (IResource) selection.getFirstElement();
346
347            this.selection = sel.getFullPath();
348            if (sel.getType() == IResource.FILE)
349            {
350                this.selection = this.selection.removeLastSegments(1);
351            }
352        }
353       
354        private void handleBrowse()
355        {
356            ContainerSelectionDialog dialog =
357                new ContainerSelectionDialog(
358                    getShell(), ResourcesPlugin.getWorkspace().getRoot(), false,
359                    "Choose a source folder:");
360           
361            if (dialog.open() == ContainerSelectionDialog.OK)
362            {
363                Object[] result = dialog.getResult();
364                if (result.length == 1)
365                {
366                    setSourceFolder((IPath) result[0]);
367                }
368            }
369        }
370       
371        private void updateStatus(String message, int messageType)
372        {
373            setMessage(message, messageType);
374            setPageComplete((classNameValid && sourceFolderValid));
375        }
376
377
378        public void setSourceFolder(IPath path)
379        {
380            if (path != null)
381            {               
382                sourceFolder.setText(path.makeRelative().toString());
383                setPageComplete(isPageComplete());
384                sourceFolderValid = true;
385            }                       
386        }
387
388    }
389
390
391    private NewClassPage classPage = new NewClassPage();
392
393    public NewClassWizard()
394    {
395        super();
396    }
397
398    /**
399     * @param classType name of the class type, e.g. 'record'
400     * @return false if class type can't have equations, e.g.
401     * false is returned for record
402     */
403    public static boolean classTypeHaveEquations(String classType)
404    {
405        return 
406        !(classType.equals("record") 
407                || classType.equals("type")
408                || classType.equals("connector") 
409                || classType.equals("function"));
410    }
411   
412    /**
413     * @param classType name of the class type, e.g. 'record'
414     * @return false if class type can't have equations, e.g.
415     * false is returned for type
416     */
417    public static boolean canBePartial(String classType)
418    {
419        return 
420        (!(classType.equals("type") 
421                || classType.equals("function"))); 
422    }
423
424   
425    @Override
426    public boolean performFinish()
427    {
428        final String sourceFolder = classPage.sourceFolder.getText();
429        final String className = classPage.className.getText();
430        final String classType = classPage.classType.getText();
431        final boolean initialEquationBlock = 
432            classPage.initialEquation.getSelection();
433        final boolean partialClass = 
434            classPage.partialClass.getSelection();
435        final boolean externalBody = 
436            classPage.externalBody.getSelection();
437
438       
439        IRunnableWithProgress op = new IRunnableWithProgress() {
440            public void run(IProgressMonitor monitor) 
441                                throws InvocationTargetException
442             {
443                try 
444                {
445                    doFinish(sourceFolder, className, classType, 
446                            initialEquationBlock, partialClass, externalBody, monitor);
447                } 
448                catch (CoreException e)
449                {
450                    throw new InvocationTargetException(e);
451                }
452                finally 
453                {
454                    monitor.done();
455                }
456            }
457        };
458        try
459        {
460            getContainer().run(true, false, op);
461        }
462        catch (InterruptedException e)
463        {
464            return false;
465        }
466        catch (InvocationTargetException e)
467        {
468            Throwable realException = e.getTargetException();
469            MessageDialog.openError(getShell(), "Error", realException.getMessage());
470            return false;
471        }
472        return true;
473    }
474
475    protected void doFinish(String sourceFolder, String className, 
476            String classType, boolean initialEquationBlock, boolean partialClass, 
477            boolean haveExternalBody, IProgressMonitor monitor)
478    throws CoreException
479    {
480        // create a sample file
481        monitor.beginTask("Creating " + className, 2);
482       
483        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
484        IResource resource = root.findMember(new Path(sourceFolder));
485       
486        IContainer container = (IContainer) resource;
487       
488        final IFile file = container.getFile(new Path(className+".mo"));
489       
490        try
491        {
492            String contents = generateClassContentes(className, classType, 
493                    initialEquationBlock, partialClass, haveExternalBody);
494            InputStream stream = 
495                new ByteArrayInputStream(contents.getBytes());
496            if (file.exists())
497            {
498                file.appendContents(stream, true, true, monitor);
499            }
500            else
501            {
502                file.create(stream, true, monitor);
503            }
504            stream.close();
505        } 
506        catch (IOException e)
507        {
508            /* ignored */
509        }
510        monitor.worked(1);
511        monitor.setTaskName("Opening file for editing...");
512        getShell().getDisplay().asyncExec(new Runnable() 
513        {
514            public void run()
515            {
516                IWorkbenchPage page =
517                    PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
518                try 
519                {
520                    IDE.openEditor(page, file, true);
521                }
522                catch (PartInitException e) 
523                {
524                    ErrorDialog.openError(null, "Error", 
525                            "Could not open class filer in an editor.",(new Status(IStatus.ERROR, 
526                            MdtPlugin.getSymbolicName(), 0, 
527                            "error starting editor for " + file.getName(), e)));
528                }
529            }
530        });
531        monitor.worked(1);
532
533    }
534
535    private String generateClassContentes(String className, String classType, 
536            boolean initialEquationBlock, boolean partialClass, boolean haveExternalBody) 
537    {
538        /*
539         * the gory logic of generating a skeleton for a modelica class
540         */
541        String contents = "";
542
543        if (canBePartial(classType) && partialClass)
544        {
545            contents += "partial ";
546        }
547       
548        contents += classType + " " + className;
549       
550        if (classTypeHaveEquations(classType))
551        {
552            contents += "\n\nequation\n";
553            if (initialEquationBlock)
554            {
555                contents += "\ninitial equation\n";
556            }
557        }
558       
559        if (classType.equals("function"))
560        {
561            if (haveExternalBody)
562            {
563                contents += "\nexternal";
564            }
565            else
566            {   
567                contents += "\nalgorithm\n";
568            }
569        }
570
571        if (!classType.equals("type"))
572        {
573            contents += "\nend " + className;
574        }
575
576        contents += ";";
577        return contents ;
578    }
579
580    public void init(IWorkbench workbench, IStructuredSelection selection)
581    {
582        classPage.init(selection);
583        setWindowTitle("New Modelica Class");
584    }
585
586    @Override
587    public void addPages()
588    {
589        addPage(classPage);
590    }
591}
Note: See TracBrowser for help on using the repository browser.