package bluej.classmgr;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.MissingResourceException;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.util.StringConverter;
import bluej.prefmgr.PrefMgrDialog;
import bluej.utility.Utility;
import bluej.utility.javafx.JavaFXUtil;
import bluej.utility.javafx.NoMultipleSelectionModel;
import threadchecker.OnThread;
import threadchecker.Tag;
import bluej.Config;
import bluej.pkgmgr.Project;
import bluej.prefmgr.PrefPanelListener;
import bluej.utility.DialogManager;
import bluej.utility.FileUtility;
| A PrefPanel subclass to allow the user to interactively add a new library
| to the browser. The new library can be specified as a file (ZIP or JAR
| archive) with an associated description.
|
| @author Andrew Patterson
|
@OnThread(Tag.FXPlatform)
public class ClassMgrPrefPanel
extends VBox
implements PrefPanelListener{
private static final String userlibPrefix = "bluej.userlibrary";
| The user libraries are referenced cross-project, so someone needs to a hold
| a static reference to keep track of them. This class seems as good a place
| as any.
|
@OnThread(value = Tag.Any, requireSynchronized = true)
private static List<ClassPathEntry> savedUserLibraries = null;
private ListView<ClassPathEntry> userLibrariesListView = null;
private ObservableList<ClassPathEntry> editingUserLibraries;
private boolean classPathModified = false;
| Setup the UI for the dialog and event handlers for the dialog's buttons.
|
public ClassMgrPrefPanel()
{
JavaFXUtil.addStyleClass(this, "prefmgr-pref-panel", "prefmgr-library-panel");
loadSavedUserLibraries();
List<ClassPathEntry> userlibExtLibrariesList =
Project.getUserlibContent().stream()
.map(url -> { try {return new ClassPathEntry(new File(url.toURI()), "");
} catch (URISyntaxException e){ return null;
}
})
.filter(f -> f != null)
.distinct().collect(Collectors.toList());
BorderPane userLibPane = new BorderPane();
{
JavaFXUtil.addStyleClass(userLibPane, "prefmgr-library-userlib-hbox");
editingUserLibraries = FXCollections.observableArrayList();
editingUserLibraries.setAll(savedUserLibraries);
userLibrariesListView = makeClassPathEntryListView(editingUserLibraries);
userLibrariesListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
Pane buttonPane = new VBox();
{
JavaFXUtil.addStyleClass(buttonPane, "prefmgr-library-userlib-buttons");
Button addFileButton = new Button(Config.getString("classmgr.addFile"));
addFileButton.setOnAction(e -> addUserLibraryFile());
Button deleteButton = new Button(Config.getString("classmgr.delete"));
deleteButton.setOnAction(e -> deleteUserLibrary());
deleteButton.disableProperty().bind(userLibrariesListView.getSelectionModel().selectedItemProperty().isNull());
buttonPane.getChildren().addAll(addFileButton, deleteButton);
}
userLibPane.setCenter(userLibrariesListView);
userLibPane.setRight(buttonPane);
}
ListView userlibExtLibrariesListView = makeClassPathEntryListView(FXCollections.observableArrayList(userlibExtLibrariesList));
userlibExtLibrariesListView.setSelectionModel(new NoMultipleSelectionModel());
userlibExtLibrariesListView.setFocusTraversable(false);
String userlibLocation = Config.getString("classmgr.userliblibraries")
+ " " + Config.getBlueJLibDir() + File.separator + "userlib";
getChildren().add(PrefMgrDialog.headedVBox("classmgr.userlibraries", Arrays.asList(userLibPane)));
getChildren().add(PrefMgrDialog.headedVBoxTranslated(userlibLocation, Arrays.asList(userlibExtLibrariesListView)));
}
@OnThread(Tag.Any)
private static synchronized void loadSavedUserLibraries()
{
if (savedUserLibraries == null)
{
savedUserLibraries = new ArrayList<>();
addConfigEntries(savedUserLibraries, userlibPrefix);
}
}
private ListView makeClassPathEntryListView(ObservableList<ClassPathEntry> userlibExtLibrariesList)
{
ListView userlibExtLibrariesListView = new ListView<>(userlibExtLibrariesList);
JavaFXUtil.addStyleClass(userlibExtLibrariesListView, "prefmgr-library-listview");
userlibExtLibrariesListView.setCellFactory(lv -> {
return new TextFieldListCell<>(new StringConverter<ClassPathEntry>()
{
@Override
public ClassPathEntry fromString(String string)
{
return null;
}
@Override
public String toString(ClassPathEntry cpe)
{
return cpe.getCanonicalPathNoException() + " (" + cpe.getStatusString() + ")";
}
});
});
userlibExtLibrariesListView.setEditable(false);
return userlibExtLibrariesListView;
}
| Returns an ArrayList of URLS holding jars that the user wish to be added to
| the Project classloader.
| @return a non null but possibly empty arrayList of URL.
|
@OnThread(Tag.Any)
public synchronized static List getUserConfigContent()
{
loadSavedUserLibraries();
return Utility.mapList(savedUserLibraries, ClassPathEntry::safeGetURL);
}
| Retrieve from the system wide Config entries corresponding to classpath
| entries. The entries to retrieve start with prefix and have 1.location,
| 2.location etc appended to them until an entry is not found.
|
| @param prefix the prefix of the property names to look up
|
@OnThread(Tag.Any)
private static void addConfigEntries(List<ClassPathEntry> cp, String prefix)
{
int resourceID = 1;
try {
while (true){
String location = Config.getPropString(prefix + resourceID + ".location", null);
if (location == null)
break;
try {
StringTokenizer st = new StringTokenizer(location, File.pathSeparator);
while (st.hasMoreTokens()) {
String entry = st.nextToken();
ClassPathEntry cpentry = new ClassPathEntry(entry, "");
if (!cp.contains(cpentry))
cp.add(cpentry);
}
}
catch(Exception e) {
e.printStackTrace();
}
resourceID++;
}
} catch (MissingResourceException mre) {
}
}
@Override
public void beginEditing(Project project)
{
}
public synchronized void revertEditing(Project project)
{
editingUserLibraries.setAll(savedUserLibraries);
}
@Override
public void commitEditing(Project project)
{
if (classPathModified) {
DialogManager.showMessageFX(null, "classmgr-changes-no-effect");
classPathModified = false;
}
saveUserLibraries();
}
| Save user classpath entries into the system wide Config properties object.
| The entries stored start with prefix and have 1.location,
| 2.location etc appended to them.
|
private synchronized void saveUserLibraries()
{
savedUserLibraries.clear();
savedUserLibraries.addAll(editingUserLibraries);
String r1;
int resourceID = 1;
while (true) {
r1 = Config.removeProperty(userlibPrefix + resourceID + ".location");
if (r1 == null)
break;
resourceID++;
}
Iterator<ClassPathEntry> it = savedUserLibraries.iterator();
resourceID = 1;
while (it.hasNext()){
ClassPathEntry nextEntry = it.next();
Config.putPropString(userlibPrefix + resourceID + ".location",
nextEntry.getPath());
resourceID++;
}
}
| Pop up a dialog to allow the user to add a library
| to their user library classpath.
|
private void addUserLibraryFile()
{
List<File> files = FileUtility.getOpenFilesFX(getScene().getWindow(), Config.getString("prefmgr.misc.addLibTitle"),
Arrays.asList(new FileChooser.ExtensionFilter(Config.getString("prefmgr.misc.libFileFilter"), "*.zip", "*.jar")), false);
if (files != null) {
for (File file : files)
{
editingUserLibraries.add(new ClassPathEntry(file.getAbsolutePath(), "", true));
}
classPathModified = true;
}
}
| Delete the currently selected row (if there is one)
| of the user library table from the user library
| classpath.
|
private void deleteUserLibrary()
{
int which = userLibrariesListView.getSelectionModel().getSelectedIndex();
if (which != -1) {
classPathModified = true;
editingUserLibraries.remove(which);
}
}
}
top,
use,
map,
class ClassMgrPrefPanel
. ClassMgrPrefPanel
. loadSavedUserLibraries
. makeClassPathEntryListView
. fromString
. toString
. getUserConfigContent
. addConfigEntries
. beginEditing
. revertEditing
. commitEditing
. saveUserLibraries
. addUserLibraryFile
. deleteUserLibrary
316 neLoCode
+ 23 LoComm