Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
[ui] Allow to setup the auxclasspath in the designer #1159
changed the title from
[ui] Allow to setup the auxclasspath in the designer
May 30, 2018
I beg to differ. This screenshot speaks for itself:
Non-scalable UIs are infuriating. On the other hand, a good scalable UI expands what the user would like to expand, such that components won't end up "out of place". You should use anchorpane constraints wisely, so that the ListView expands when the window expands.
I'm guessing you've tried to write
Did you notice that when closing the popup after adding some jars, when you reopen the popup everything is gone?
The problem here is that the AuxClassPathController isn't supposed to manage the ClassLoader or the classpath by itself. It's supposed to be a read/write view of some property of the application, namely the auxclasspath. That is, when you open the popup, it should be initialised with the previous value of that property, and when you close it, the property should be set on the application.
When I say application here, I mean that this property should be managed by some relevant internal division of the application. Since this data is to be used during the parsing stage, which is managed by the SourceEditorController, I think that that controller is the best candidate.
To sum up the required data flow:
- The SourceEditorController should maintains two new properties:
ObservableList<File> auxclasspathFiles. This will contain the up-to-date Files that the auxclasspath references
Var<ClassLoader> auxclasspathClassLoader. This will contain the up-to-date ClassLoader that is used for parsing. This property is purely internal, so private
auxclasspathClassLoaderis bound to
auxclasspathFiles, with a mapping in between. Some extra content validation should make sure every file exist, and the classLoader is never null. This can be four lines of ReactFX
- When the user clicks on the menu item, it's the MainDesignerController that catches the event (like currently). It should ask the SourceEditorController to open the edition popup (calls a public no-arg method on the controller)
- When the SourceEditorController catches that message (body of the method), it creates an AuxclasspathController and hands it the current value of
auxclasspathFilesto initialise the popup.
- The user edits the files in the ListView. Each change modifies the internal list of the ListView so that they're not directly propagated to the SourceEditorController (in case the user wants to cancel his edits, he has a buffer).
- If the user cancels their edits, then the popup closes without doing anything else. Nothing has changed in the core of the app, the controller dies quietly.
- If the user validates their edits, the popup closes, but as it closes it hands the value of the ListView's internal list back to the SourceEditorController. The latter updates its internal
auxclasspathFilesproperty, if it has really changed.
auxclasspathClassLoaderis updated automatically by the binding
This data flow has the advantage that the app doesn't gain a new core component. SourceEditorController is just made marginally more powerful. Moreover, the auxclasspath is made specific to the editor, instead of global to the whole app. One point I kept in mind while designing the app is that we may want to manage several code snippets/ files in different tabs someday. If we decide to do that, multiple SourceEditorControllers will be used concurrently, each one possibly using a different auxclasspath. That's why SourceEditorController should encapsulate the classloader.
This is not all. With what I described, the app maintains a list of Files, but they're not used anywhere yet.
What remains to do:
- When SourceEditorController calls
astManager::updateCompilationUnit, it should pass the ClassLoader as parameter. ASTManager should use this parameter on the relevant lines (indicated in the file).
- SourceEditorController should expose a getter and setter for
auxclasspathFiles, with the getter annotated with
@PersistentProperty. This will persist the auxclasspath between runs.
Some more improvements are in my comments
This is not ready to be merged. In its current state the popup is not connected to the rest of the app and does nothing.
@akshatbahety ClasspathClassloader is pretty explicit. From what you can see in its constructor, we parse a string representing the classpath into an array of files:
But since we already have a collection of files, we don't need to convert to string and back again. So basically you can just create a constructor taking a list of files, convert them to URLs to call the super constructor, then map your Var by doing something like
private final Val<ClassLoader> auxclasspathClassLoader = auxclasspathFiles.map(files -> new ClasspathClassLoader(files, SourceEditorController.class.getClassLoader()));
Only 2 things missing: