/******************************************************************************* * Copyright 2016 Jalian Systems Pvt. Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package net.sourceforge.marathon.runtime.fx.api; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.util.Enumeration; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.logging.Logger; import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Node; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.ComboBox; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.control.TabPane.TabClosingPolicy; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import javafx.util.Callback; import net.sourceforge.marathon.fx.api.FXUIUtils; import net.sourceforge.marathon.fx.api.ModalDialog; import net.sourceforge.marathon.fx.projectselection.FormPane; import net.sourceforge.marathon.runtime.api.PlugInModelInfo; public abstract class CompositeLayout implements IPropertiesLayout { public static final Logger LOGGER = Logger.getLogger(CompositeLayout.class.getName()); private ComboBox<PlugInModelInfo> optionBox = new ComboBox<>(); private TabPane optionTabpane = new TabPane(); private ObservableList<PlugInModelInfo> model; protected ModalDialog<?> parent; private ISubPropertiesLayout[] layouts; public CompositeLayout(ModalDialog<?> parent) { this.parent = parent; this.model = createComboBoxModel(getResourceName()); initComponents(); } private void initComponents() { optionBox.setItems(model); optionBox.getSelectionModel().selectedItemProperty().addListener((observableValue, oldValue, newValue) -> { if (newValue != null) { updateTabPane(); } }); optionBox.setCellFactory(new Callback<ListView<PlugInModelInfo>, ListCell<PlugInModelInfo>>() { @Override public ListCell<PlugInModelInfo> call(ListView<PlugInModelInfo> param) { return new LauncherCell(); } }); optionTabpane.setId("CompositeTabPane"); optionTabpane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE); optionTabpane.getStyleClass().add(TabPane.STYLE_CLASS_FLOATING); VBox.setVgrow(optionTabpane, Priority.ALWAYS); } protected abstract String getResourceName(); @Override public Node getContent() { VBox content = new VBox(); content.setId("CompositeLayout"); content.getStyleClass().add("composite-layout"); FormPane form = new FormPane("composite-layout-form", 2); form.addFormField(getOptionFieldName(), optionBox); content.getChildren().addAll(form, optionTabpane); return content; } private void updateTabPane() { optionTabpane.getTabs().clear(); layouts = getLauncherLayouts(); for (ISubPropertiesLayout p : layouts) { Node content = p.getContent(); if (Boolean.getBoolean("marathon.show.id")) { parent.addToolTips(content); } String name = p.getName(); Tab tab = new Tab(name, content); tab.setId(name); tab.setGraphic(p.getIcon()); optionTabpane.getTabs().add(tab); } } public ISubPropertiesLayout[] getLauncherLayouts() { String selectedLauncher = getClassName(); if (selectedLauncher == null) { return new ISubPropertiesLayout[] {}; } try { ISublayoutProvider model = getLauncherModel(selectedLauncher); if (model != null) { return model.getSublayouts(parent); } } catch (ClassNotFoundException e) { e.printStackTrace(); FXUIUtils.showMessageDialog(parent.getStage(), "Could not find launcher: " + selectedLauncher, "Error", AlertType.ERROR); } catch (InstantiationException e) { e.printStackTrace(); FXUIUtils.showMessageDialog(parent.getStage(), "Could not find launcher: " + selectedLauncher, "Error", AlertType.ERROR); } catch (IllegalAccessException e) { e.printStackTrace(); FXUIUtils.showMessageDialog(parent.getStage(), "Could not find launcher: " + selectedLauncher, "Error", AlertType.ERROR); } return new ISubPropertiesLayout[] {}; } private ObservableList<PlugInModelInfo> createComboBoxModel(String pluginName) { ObservableList<PlugInModelInfo> model = FXCollections.observableArrayList(); Enumeration<URL> systemResources = null; try { systemResources = ClassLoader.getSystemResources(pluginName); } catch (IOException e) { FXUIUtils.showMessageDialog(parent.getStage(), "No resource found for " + pluginName + ".", "No " + pluginName + " Support", AlertType.ERROR); e.printStackTrace(); System.exit(1); } while (systemResources.hasMoreElements()) { Properties props = new Properties(); try { URL url = systemResources.nextElement(); props.load(url.openStream()); Set<Entry<Object, Object>> entries = props.entrySet(); for (Entry<Object, Object> entry : entries) { model.add(new PlugInModelInfo((String) entry.getValue(), (String) entry.getKey())); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } if (model.size() == 0) { FXUIUtils.showMessageDialog(parent.getStage(), "No Marathon " + pluginName + " found.", "No " + pluginName + " Support", AlertType.ERROR); System.exit(1); } return model; } protected ISublayoutProvider getLauncherModel(String launcher) throws ClassNotFoundException, InstantiationException, IllegalAccessException { if (launcher == null || launcher.equals("")) { return null; } Class<?> klass = Class.forName(launcher); return (ISublayoutProvider) klass.newInstance(); } public String getClassName() { if (optionBox.getSelectionModel().getSelectedItem() == null) { return ""; } return optionBox.getSelectionModel().getSelectedItem().className; } protected abstract String getOptionFieldName(); @Override public boolean isValidInput(boolean showAlert) { if (optionBox.getSelectionModel().getSelectedItem() == null) { errorMessage(); Platform.runLater(() -> optionBox.requestFocus()); return false; } for (ISubPropertiesLayout p : layouts) { if (!p.isValidInput(showAlert)) { return false; } } return true; } @Override public void getProperties(Properties props) { props.setProperty(getClassProperty(), getClassName()); for (ISubPropertiesLayout p : layouts) { p.getProperties(props); } } abstract protected String getClassProperty(); @Override public void setProperties(Properties props) { setPlugInSelection(optionBox, props, getClassProperty()); updateTabPane(); for (IPropertiesLayout p : layouts) { p.setProperties(props); } } private void setPlugInSelection(ComboBox<PlugInModelInfo> comboBox, Properties props, String key) { String model = (String) props.get(key); if (model == null) { comboBox.getSelectionModel().select(findFirstValidModel()); } else { comboBox.getSelectionModel().select(getPluginModel(model)); if (!isSelectable()) { comboBox.setDisable(true); } } } private int findFirstValidModel() { int n = model.size(); for (int i = 0; i < n; i++) { PlugInModelInfo elementAt = model.get(i); try { getLauncherModel(elementAt.className); return i; } catch (Throwable t) { } } return 0; } protected boolean isSelectable() { return true; } public PlugInModelInfo getPluginModel(String className) { for (int i = 0; i < model.size(); i++) { if (model.get(i).className.equals(className)) { return model.get(i); } } return null; } protected abstract void errorMessage(); public class LauncherCell extends ListCell<PlugInModelInfo> { @Override protected void updateItem(PlugInModelInfo item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) { try { setText(item.toString()); getLauncherModel(item.className); } catch (Throwable t) { setDisable(true); } } else { setText(null); } } } }