Last modified 16 years ago
Last modified on 07/13/09 13:13:52
Analysis
Overview
General Scripting overview:
The users should be able to type and execute custom scripts.
- A script is a resource.
- Execute button should be present inside the resource pallete.
- Scripts could be edited inside a document window. Again execute button should be available. While editing the resource is saved automatically.
- Scripts could also be executed via links.
- The resource preview for scripts should allow editing.
- There should be ability to import/export script files.
- The user could create/edit/delete scripts.
Task requirements
Create prototype for scripting that includes the following functionality:
- Ability to add/edit/delete script files.
- Add 'Insert Script File' button inside 'Insert' menu
- Create 'Insert Script' button inside 'Insert' menu that creates new resource.
- Provide document window that allows editing for scripts as well as executing them.
- Add 'Execute' button inside resource details pallete, that is visible only when script resource is selected.
- Create 'Hello world' example via scripting in Sophie.
- OPTIONAL: Provide functionality that allows scripts to be evoked from links.
- Provide functionality that allows for script resource to be exported to files. Again in the resource pallete. Also while editing it from the file menu save and save as should be functional. (NOTE: Saving the resource should be automatically, but exporting it to file is not).
Task result
- The result should be code.
Implementation idea
- Use the Rhino library: http://www.mozilla.org/rhino/.
- The output for the script could be Eclipse console or popup window.
Related
(Add links to related tasks that could be useful or helpful.)
How to demo
- Click Insert -> Script. A new window should be opened.
- Write a JavaScript code that outputs "Hello world".
- Click the Run button.
Design
- Create a Sophie module org.sophie2.extra.func.scripting.
- Create a class org.sophie2.extra.func.scripting.ScriptingModule that extends SophieModule.
- Create subpackages model, view and logic.
- model:
- class ScriptResource that extends Resource.
- kind is "script"
- RwProp<String> scriptText - the javascript source code text
- subpackage persistence
- class ScriptResPersister extends Persister<String, Storage>
- schema "resource:script|storage|r3"
- the storage should have one child for the script text
- this persister is needed when the parent book is persisted.
- register the persister as an extension
- class ScriptResPersister extends Persister<String, Storage>
- class ScriptResource that extends Resource.
- view:
- menu items InsertScriptItem and InsertScriptFileItem in Insert menu
- enum EventIds that contains the identifiers of all events that can be fired by any UI component in this package
- INSERT_SCRIPT
- INSERT_SCRIPT_FILE
- RUN_SCRIPT
- TEXT_CHANGED
- OPEN_WINDOW
- document window for resource viewing, editing and running:
- class ScriptDocumentWindow extends DefaultDocumentWindow implements DocumentView
- In DocumentWindow add Prop<ResourceRef> modelDocument()
- RwProp<ResourceRef> modelDocument - the script resource that is displayed
- resource property swingFrameSync that adds the following components to swingComponent:
- a text area that fires TEXT_CHANGED
- "Run" LogicR3Button that fires RUN_SCRIPT
- a text area for the script result or error messages
- class ScriptDocumentWindowProvider implements DocumentWindowProvider (see last section)
- getWindow should return a new ScriptDocumentWindow for the given script resource
- register it as an extension
- resource preview of scripts (in Resource Preview Palette):
- class ScriptResourcePreviewProvider implements ResourcePreviewProvider
- getResourceKind() should return the kind in ScriptResource
- filterKind() should return "Script"
- nested static class ScriptResourcePreview which is a SwingVisualElement
- constructor with argument of type ScriptResource
- in swingComponent create a new JPanel with:
- read-only JTextArea that displays the script content
- "Open" LogicR3Button that fires OPEN_WINDOW
- getVisualElement(Resource element) should return a new instance of ScriptResourcePreview
- In ResourceDetailsPalette create a property RwProp<SwingVisualElement> previewVisualElement
- use @Own annotation because the parent is required in the logic of OPEN_WINDOW
- register the class as an extension
- class ScriptResourcePreviewProvider implements ResourcePreviewProvider
- logic:
- enum ScriptingLogic that implements OperationDef:
- all of the following items should listen for an event with the corresponding id
- INSERT_SCRIPT
- listens for the event in InsertScriptItem
- creates a new empty ScriptResource in current book (use CurrentBookUtil.getCurrentBook)
- adds it to App.documents (see last section for details)
- sets it as current
- INSERT_SCRIPT_FILE
- listens for the event in InsertScriptFileItem
- displays a file dialog for "JavaScript files (*.js)" with "Insert" button
- using the persisters, creates a new ScriptResource in current book
- adds it to App.documents (see last section)
- sets it as current
- RUN_SCRIPT
- write the following temporary solution:
- create a new context using Context cx = Context.enter();
- initialize the standard objects (Object, Function, etc.) using Scriptable scope = cx.initStandardObjects();
- evaluate the resource's text: Object result = cx.evaluateString(scope, s, "<cmd>", 1, null);
- display the result in the result text area.
- if org.mozilla.javascript.EcmaError or org.mozilla.javascript.EvaluatorException is thrown, display the message in the result text area
- exit from the context with Context.exit();. Call this from a finally block.
- write the following temporary solution:
- TEXT_CHANGED
- the following solution can be optimized:
- create a new AutoChange that changes the text in the resource with that from the text area. Register the change to the script resource.
- the following solution can be optimized:
- OPEN_WINDOW
- get the source which is of type ScriptResourcePreview
- add its model to the list App.documents, but only if it is not already added
- set the document as current
- register the enum as an extension
- enum ScriptingLogic that implements OperationDef:
- Currently all open documents are books. Sophie's main window should display also images, scripts and so on.
- Rename the books property in App to documents.
- Create an interface org.sophie2.main.app.commons.windows.DocumentWindowProvider
- String getResourceKind() - Gets the resource kind of the resource for which this provider should create appropriate document window.
- DocumentWindowProvider getWindowProvider(ResourceRef ref) - Creates a new concrete implementation of DocumentWindowProvider for the given resource.
- Create an extension point in MainAppModule for document window providers
- Class org.sophie2.main.app.commons.windows.BookDocumentWindowProvider implements DocumentWindowProvider and creates book document windows
- Register it as an extension
- Class org.sophie2.main.app.commons.windows.DocumentWindowProviderFactory
- static DocumentWindowProvider getWindowProvider(ResourceRef ref)
- iterates over all extensions in the extension point
- if an appropriate provider is found, returns it
- static DocumentWindowProvider getWindowProvider(ResourceRef ref)
- Refactor AppDocumentsDesktop.windows:
- create a class DocumentInfo that has two fields - ResourceRef ref and DocumentWindowProvider provider
- create a hash map with keys of type DocumentInfo and values of type DocumentWindow
- override equals and hashCode methods
- create a hashCode in ResourceRef too
- replace the TrackingProList with ComposingProList
- iterate over all open documents and use the factory to find the appropriate provider
- if the cache (the hash map) contains DocumentInfo with these resource reference and provider, return the window
- if not, create a new window with the factory and store it in the cache
- Source code: branches/private/deni/scripting/
Implementation
- Source code: branches/private/deni/scripting/
Merged in revision [4185] to the trunk.
Testing
(Place the testing results here.)
Comments
- The goal of this task is mainly to provide interface for scripting