All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.javafx2.project.JFXProjectProperties Maven / Gradle / Ivy

There is a newer version: RELEASE220
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.netbeans.modules.javafx2.project;

import java.awt.Color;
import java.awt.Component;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.UIManager;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableModel;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.java.project.JavaProjectConstants;
import org.netbeans.api.java.project.classpath.ProjectClassPathModifier;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.api.project.ant.AntArtifact;
import org.netbeans.api.project.ant.AntArtifactQuery;
import org.netbeans.modules.java.api.common.project.ProjectProperties;
import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator;
import org.netbeans.modules.javafx2.platform.api.JavaFXPlatformUtils;
import org.netbeans.modules.javafx2.project.ui.JFXApplicationPanel;
import org.netbeans.modules.javafx2.project.ui.JFXPackagingPanel;
import org.netbeans.modules.javafx2.project.ui.JSEDeploymentPanel;
import org.netbeans.spi.project.support.ant.AntProjectHelper;
import org.netbeans.spi.project.support.ant.EditableProperties;
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
import org.netbeans.spi.project.support.ant.PropertyUtils;
import org.netbeans.spi.project.support.ant.ui.StoreGroup;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.Mutex;
import org.openide.util.MutexException;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;

public final class JFXProjectProperties {

    private static final Logger LOG = Logger.getLogger(JFXProjectProperties.class.getName());
    private static final Color INVALID_CELL_CONTENT_COLOR = Color.RED;
    
    public static final String JAVAFX_ENABLED = "javafx.enabled"; // NOI18N
    public static final String JAVAFX_PRELOADER = "javafx.preloader"; // NOI18N
    public static final String JAVAFX_SWING = "javafx.swing"; // NOI18N
    public static final String JAVAFX_DISABLE_AUTOUPDATE = "javafx.disable.autoupdate"; // NOI18N
    public static final String JAVAFX_DISABLE_AUTOUPDATE_NOTIFICATION = "javafx.disable.autoupdate.notification"; // NOI18N
    public static final String JAVAFX_DISABLE_CONCURRENT_RUNS = "javafx.disable.concurrent.runs"; // NOI18N
    public static final String JAVAFX_ENABLE_CONCURRENT_EXTERNAL_RUNS = "javafx.enable.concurrent.external.runs"; // NOI18N
    public static final String JAVAFX_ENDORSED_ANT_CLASSPATH = "endorsed.javafx.ant.classpath"; // NOI18N
    public static final String PLATFORM_ACTIVE = "platform.active"; // NOI18N
    public static final String PLATFORM_ANT_NAME = "platform.ant.name";    //NOI18N
    
    /** The standard extension for FXML source files. */
    public static final String FXML_EXTENSION = "fxml"; // NOI18N    
    
    // copies of private J2SE properties
    public static final String SOURCE_ENCODING = "source.encoding"; // NOI18N
    public static final String JAVADOC_PRIVATE = "javadoc.private"; // NOI18N
    public static final String JAVADOC_NO_TREE = "javadoc.notree"; // NOI18N
    public static final String JAVADOC_USE = "javadoc.use"; // NOI18N
    public static final String JAVADOC_NO_NAVBAR = "javadoc.nonavbar"; // NOI18N
    public static final String JAVADOC_NO_INDEX = "javadoc.noindex"; // NOI18N
    public static final String JAVADOC_SPLIT_INDEX = "javadoc.splitindex"; // NOI18N
    public static final String JAVADOC_AUTHOR = "javadoc.author"; // NOI18N
    public static final String JAVADOC_VERSION = "javadoc.version"; // NOI18N
    public static final String JAVADOC_WINDOW_TITLE = "javadoc.windowtitle"; // NOI18N
    public static final String JAVADOC_ENCODING = "javadoc.encoding"; // NOI18N
    public static final String JAVADOC_ADDITIONALPARAM = "javadoc.additionalparam"; // NOI18N
    public static final String BUILD_SCRIPT = "buildfile"; //NOI18N
    public static final String DIST_JAR = "dist.jar"; // NOI18N

    // Packaging properties
    public static final String JAVAFX_BINARY_ENCODE_CSS = "javafx.binarycss"; // NOI18N
    public static final String JAVAFX_DEPLOY_INCLUDEDT = "javafx.deploy.includeDT"; // NOI18N
    public static final String JAVAFX_DEPLOY_EMBEDJNLP = "javafx.deploy.embedJNLP"; // NOI18N
    public static final String JAVAFX_REBASE_LIBS = "javafx.rebase.libs"; // NOI18N
    
    // FX config properties (Run panel), replicated from ProjectProperties
    public static final String MAIN_CLASS = "javafx.main.class"; // NOI18N
    //public static final String APPLICATION_ARGS = JFXProjectConfigurations.APPLICATION_ARGS;
    //public static final String APP_PARAM_PREFIX = JFXProjectConfigurations.APP_PARAM_PREFIX;
    //public static final String APP_PARAM_SUFFIXES[] = JFXProjectConfigurations.APP_PARAM_SUFFIXES;
    public static final String RUN_JVM_ARGS = ProjectProperties.RUN_JVM_ARGS;
    public static final String FALLBACK_CLASS = "javafx.fallback.class"; // NOI18N
    public static final String SIGNED_JAR = "dist.signed.jar"; // NOI18N
    
    public static final String PRELOADER_ENABLED = "javafx.preloader.enabled"; // NOI18N
    public static final String PRELOADER_TYPE = "javafx.preloader.type"; // NOI18N
    public static final String PRELOADER_PROJECT = "javafx.preloader.project.path"; // NOI18N
    public static final String PRELOADER_CLASS = "javafx.preloader.class"; // NOI18N
    public static final String PRELOADER_JAR_FILENAME = "javafx.preloader.jar.filename"; // NOI18N
    public static final String PRELOADER_JAR_PATH = "javafx.preloader.jar.path"; // NOI18N
    
    public static final String RUN_WORK_DIR = ProjectProperties.RUN_WORK_DIR; // NOI18N
    public static final String RUN_APP_WIDTH = "javafx.run.width"; // NOI18N
    public static final String RUN_APP_HEIGHT = "javafx.run.height"; // NOI18N
    public static final String RUN_IN_HTMLTEMPLATE = "javafx.run.htmltemplate"; // NOI18N
    public static final String RUN_IN_HTMLTEMPLATE_PROCESSED = "javafx.run.htmltemplate.processed"; // NOI18N
    public static final String RUN_IN_BROWSER = "javafx.run.inbrowser"; // NOI18N
    public static final String RUN_IN_BROWSER_PATH = "javafx.run.inbrowser.path"; // NOI18N
    public static final String RUN_IN_BROWSER_ARGUMENTS = "javafx.run.inbrowser.arguments"; // NOI18N
    public static final String RUN_IN_BROWSER_UNDEFINED = "undefined"; // NOI18N
    public static final String RUN_AS = "javafx.run.as"; // NOI18N

    public static final String DEFAULT_APP_WIDTH = "800"; // NOI18N
    public static final String DEFAULT_APP_HEIGHT = "600"; // NOI18N

    // Deployment properties
    public static final String UPDATE_MODE_BACKGROUND = "javafx.deploy.backgroundupdate"; // NOI18N
    public static final String ALLOW_OFFLINE = "javafx.deploy.allowoffline"; // NOI18N
    public static final String INSTALL_PERMANENTLY = "javafx.deploy.installpermanently"; // NOI18N
    public static final String ADD_DESKTOP_SHORTCUT = "javafx.deploy.adddesktopshortcut"; // NOI18N
    public static final String ADD_STARTMENU_SHORTCUT = "javafx.deploy.addstartmenushortcut"; // NOI18N
    public static final String ICON_FILE = "javafx.deploy.icon"; // NOI18N
    public static final String NATIVE_ICON_FILE = "javafx.deploy.icon.native"; // NOI18N
    public static final String SPLASH_IMAGE_FILE = "javafx.deploy.splash"; // NOI18N
    public static final String PERMISSIONS_ELEVATED = "javafx.deploy.permissionselevated"; // NOI18N
    public static final String DISABLE_PROXY = "javafx.deploy.disable.proxy"; // NOI18N
    public static final String REQUEST_RT = "javafx.deploy.request.runtime"; // NOI18N

    // Deployment - signing
    public static final String JAVAFX_SIGNING_ENABLED = "javafx.signing.enabled"; //NOI18N
    public static final String JAVAFX_SIGNING_TYPE = "javafx.signing.type"; //NOI18N
    public static final String JAVAFX_SIGNING_KEYSTORE = "javafx.signing.keystore"; //NOI18N
    public static final String JAVAFX_SIGNING_KEYSTORE_PASSWORD = "javafx.signing.keystore.password"; //NOI18N
    public static final String JAVAFX_SIGNING_KEY = "javafx.signing.keyalias"; //NOI18N
    public static final String JAVAFX_SIGNING_KEY_PASSWORD = "javafx.signing.keyalias.password"; //NOI18N
    public static final String JAVAFX_SIGNING_BLOB = "javafx.signing.blob"; //NOI18N
    
    // Deployment - native packaging
    public static final String NATIVE_BUNDLING_ENABLED = "native.bundling.enabled"; //NOI18N
    public static final String NATIVE_BUNDLING_TYPE = "native.bundling.type"; //NOI18N
    //public static final String JAVASE_NATIVE_BUNDLING_ENABLED = "native.bundling.enabled"; //NOI18N

    //Deloyment - copylibs
    public static final String COPYLIBS_EXCLUDES = "copylibs.excludes"; //NOI18N

    // Deployment - common and SE specific
    public static final String RUN_CP = "run.classpath";    //NOI18N
    public static final String BUILD_CLASSES = "build.classes.dir"; //NOI18N
    public static final String JAVASE_KEEP_JFXRT_ON_CLASSPATH = "keep.javafx.runtime.on.classpath"; //NOI18N
    
    // Deployment - libraries download mode
    public static final String DOWNLOAD_MODE_LAZY_JARS = "download.mode.lazy.jars";   //NOI18N
    private static final String DOWNLOAD_MODE_LAZY_JAR = "download.mode.lazy.jar."; //NOI18N
    private static final String DOWNLOAD_MODE_LAZY_FORMAT = DOWNLOAD_MODE_LAZY_JAR +"%s"; //NOI18N
    
    // Deployment - callbacks
    public static final String JAVASCRIPT_CALLBACK_PREFIX = "javafx.jscallback."; // NOI18N
    
    // Application
    public static final String IMPLEMENTATION_VERSION = "javafx.application.implementation.version"; // NOI18N
    public static final String IMPLEMENTATION_VERSION_DEFAULT = "1.0"; // NOI18N
    
    // folders and files
    public static final String PROJECT_CONFIGS_DIR = JFXProjectConfigurations.PROJECT_CONFIGS_DIR;
    public static final String PROJECT_PRIVATE_CONFIGS_DIR = JFXProjectConfigurations.PROJECT_PRIVATE_CONFIGS_DIR;
    public static final String PROPERTIES_FILE_EXT = JFXProjectConfigurations.PROPERTIES_FILE_EXT;
    public static final String CONFIG_PROPERTIES_FILE = JFXProjectConfigurations.CONFIG_PROPERTIES_FILE;
    public static final String DEFAULT_CONFIG = NbBundle.getBundle("org.netbeans.modules.javafx2.project.ui.Bundle").getString("JFXConfigurationProvider.default.label"); // NOI18N
    public static final String DEFAULT_CONFIG_STANDALONE = NbBundle.getBundle("org.netbeans.modules.javafx2.project.ui.Bundle").getString("JFXConfigurationProvider.standalone.label"); // NOI18N
    public static final String DEFAULT_CONFIG_WEBSTART = NbBundle.getBundle("org.netbeans.modules.javafx2.project.ui.Bundle").getString("JFXConfigurationProvider.webstart.label"); // NOI18N
    public static final String DEFAULT_CONFIG_BROWSER = NbBundle.getBundle("org.netbeans.modules.javafx2.project.ui.Bundle").getString("JFXConfigurationProvider.browser.label"); // NOI18N

    // explicit manifest entries (see #231951, #234231, http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/no_redeploy.html)
    public static final String MANIFEST_CUSTOM_CODEBASE = "manifest.custom.codebase"; // NOI18N
    public static final String MANIFEST_CUSTOM_PERMISSIONS = "manifest.custom.permissions"; // NOI18N
    public static final String PLATFORM_RUNTIME = "platform.runtime";           //NOI18N
    
    // FX RT artifact reference to be kept at compile classpath
    private static final String JFX_EXTENSION_CPREF = "${javafx.classpath.extension}";  //NOI18N

    private StoreGroup fxPropGroup = new StoreGroup();
    
    // Packaging
    JToggleButton.ToggleButtonModel binaryEncodeCSS;
    public JToggleButton.ToggleButtonModel getBinaryEncodeCSSModel() {
        return binaryEncodeCSS;
    }

    private JFXPackagingPanel packagingPanel = null;
    public JFXPackagingPanel getPackagingPanel() {
        if(packagingPanel == null) {
            packagingPanel = new JFXPackagingPanel(this);
        }
        return packagingPanel;
    }

    private JFXApplicationPanel applicationPanel = null;
    public JFXApplicationPanel getApplicationPanel() {
        if(applicationPanel == null) {
            applicationPanel = new JFXApplicationPanel(this);
        }
        return applicationPanel;
    }

    private JSEDeploymentPanel seDeploymentPanel = null;
    public JSEDeploymentPanel getSEDeploymentPanel() {
        if(seDeploymentPanel == null) {
            seDeploymentPanel = new JSEDeploymentPanel(this);
        }
        return seDeploymentPanel;
    }

    // CustomizerRun
    private JFXConfigs CONFIGS = null;
    public JFXConfigs getConfigs() {
        return CONFIGS;
    }

    private Map browserPaths = null;

    public Map getBrowserPaths() {
        return browserPaths;
    }
    public void resetBrowserPaths() {
        this.browserPaths = new HashMap();
    }
    public void setBrowserPaths(Map browserPaths) {
        this.browserPaths = browserPaths;
    }

    // CustomizerRun - Preloader source type
    public enum PreloaderSourceType {
        NONE("none"), // NOI18N
        PROJECT("project"), // NOI18N
        JAR("jar"); // NOI18N
        private final String propertyValue;
        PreloaderSourceType(String propertyValue) {
            this.propertyValue = propertyValue;
        }
        public String getString() {
            return propertyValue;
        }
    }
    
    PreloaderClassComboBoxModel preloaderClassModel;
    public PreloaderClassComboBoxModel getPreloaderClassModel() {
        return preloaderClassModel;
    }

    // CustomizerRun - Run type
    public enum RunAsType {
        STANDALONE("standalone", DEFAULT_CONFIG_STANDALONE), // NOI18N
        ASWEBSTART("webstart", DEFAULT_CONFIG_WEBSTART), // NOI18N
        INBROWSER("embedded", DEFAULT_CONFIG_BROWSER); // NOI18N
        private final String propertyValue;
        private final String defaultConfig;
        RunAsType(String propertyValue, String defaultConfig) {
            this.propertyValue = propertyValue;
            this.defaultConfig = defaultConfig;
        }
        public String getString() {
            return propertyValue;
        }
        public String getDefaultConfig() {
            return defaultConfig;
        }
    }
    JToggleButton.ToggleButtonModel runStandalone;
    JToggleButton.ToggleButtonModel runAsWebStart;
    JToggleButton.ToggleButtonModel runInBrowser;
    
    // Deployment
    JToggleButton.ToggleButtonModel allowOfflineModel;
    public JToggleButton.ToggleButtonModel getAllowOfflineModel() {
        return allowOfflineModel;
    }
    JToggleButton.ToggleButtonModel backgroundUpdateCheck;
    public JToggleButton.ToggleButtonModel getBackgroundUpdateCheckModel() {
        return backgroundUpdateCheck;
    }
    JToggleButton.ToggleButtonModel installPermanently;
    public JToggleButton.ToggleButtonModel getInstallPermanentlyModel() {
        return installPermanently;
    }
    JToggleButton.ToggleButtonModel addDesktopShortcut;
    public JToggleButton.ToggleButtonModel getAddDesktopShortcutModel() {
        return addDesktopShortcut;
    }
    JToggleButton.ToggleButtonModel addStartMenuShortcut;
    public JToggleButton.ToggleButtonModel getAddStartMenuShortcutModel() {
        return addStartMenuShortcut;
    }
    JToggleButton.ToggleButtonModel disableProxy;
    public JToggleButton.ToggleButtonModel getDisableProxyModel() {
        return disableProxy;
    }

    String wsIconPath;
    String splashImagePath;
    String nativeIconPath;
    public String getWSIconPath() {
        return wsIconPath;
    }
    public void setWSIconPath(String path) {
        this.wsIconPath = path;
    }
    public String getSplashImagePath() {
        return splashImagePath;
    }
    public void setSplashImagePath(String path) {
        this.splashImagePath = path;
    }
    public String getNativeIconPath() {
        return nativeIconPath;
    }
    public void setNativeIconPath(String path) {
        this.nativeIconPath = path;
    }
    
    // Deployment - Signing
    public enum SigningType {
        NOSIGN("notsigned"), // NOI18N
        SELF("self"), // NOI18N
        KEY("key"); // NOI18N
        private final String propertyValue;
        SigningType(String propertyValue) {
            this.propertyValue = propertyValue;
        }
        public String getString() {
            return propertyValue;
        }
    }
    boolean signingEnabled;
    boolean signingBlob;
    SigningType signingType;
    String signingKeyStore;
    String signingKeyAlias;
    boolean permissionsElevated;
    char [] signingKeyStorePassword;
    char [] signingKeyPassword;

    public boolean getSigningEnabled() {
        return signingEnabled;
    }
    public void setSigningEnabled(boolean enabled) {
        this.signingEnabled = enabled;
    }
    public boolean getBLOBSigningEnabled() {
        return signingBlob;
    }
    public void setBLOBSigningEnabled(boolean enabled) {
        this.signingBlob = enabled;
    }
    public boolean getPermissionsElevated() {
        return permissionsElevated;
    }
    public void setPermissionsElevated(boolean enabled) {
        this.permissionsElevated = enabled;
    }
    public SigningType getSigningType() {
        return signingType;
    }
    public void setSigningType(SigningType type) {
        this.signingType = type;
    }
    public String getSigningKeyStore() {
        return signingKeyStore;
    }
    public String getSigningKeyAlias() {
        return signingKeyAlias;
    }
    public char[] getSigningKeyStorePassword() {
        return signingKeyStorePassword;
    }
    public char[] getSigningKeyPassword() {
        return signingKeyPassword;
    }
    public void setSigningKeyAlias(String signingKeyAlias) {
        this.signingKeyAlias = signingKeyAlias;
    }
    public void setSigningKeyPassword(char[] signingKeyPassword) {
        this.signingKeyPassword = signingKeyPassword;
    }
    public void setSigningKeyStore(String signingKeyStore) {
        this.signingKeyStore = signingKeyStore;
    }
    public void setSigningKeyStorePassword(char[] signingKeyStorePassword) {
        this.signingKeyStorePassword = signingKeyStorePassword;
    }
    
    // Deployment - Native Packaging (JDK 7u6+)
    public enum BundlingType {
        NONE("none", OS.ALL, "None"), // NOI18N
        ALL("all", OS.ALL, "All Artifacts"), // NOI18N
        IMAGE("image", OS.ALL, "Image Only"), // NOI18N
        INSTALLER("installer", OS.ALL, "All Installers"), // NOI18N
        DEB("deb", OS.LINUX, "DEB Package"), // NOI18N
        RPM("rpm", OS.LINUX, "RPM Package"), // NOI18N
        DMG("dmg", OS.MAC, "DMG Image"), // NOI18N
        EXE("exe", OS.WIN, "EXE Installer"), // NOI18N
        MSI("msi", OS.WIN, "MSI Installer"); // NOI18N
        private final String propertyValue;
        private final String description;
        private final OS extent;
        public enum OS {ALL, WIN, MAC, LINUX, NONE}
        BundlingType(String propertyValue, OS os, String desc) {
            this.propertyValue = propertyValue;
            this.extent = os;
            this.description = desc;
        }
        public String getValue() {
            return propertyValue;
        }
        public OS getExtent() {
            return extent;
        }
        @Override
        public String toString() {
            return description;
        }
    }

    boolean nativeBundlingEnabled;
    public boolean getNativeBundlingEnabled() {
        return nativeBundlingEnabled;
    }
    public void setNativeBundlingEnabled(boolean enabled) {
        this.nativeBundlingEnabled = enabled;
    }
    
    // in SE project - keep jfxrt.jar on classpath
    boolean keepJFXRTonCP;
    public boolean getKeepJFXRTonCP() {
        return keepJFXRTonCP;
    }
    public void setKeepJFXRTonCP(boolean enabled) {
        this.keepJFXRTonCP = enabled;
    }

    // Deployment - Libraries Download Mode
    List runtimeCP;
    List lazyJars;
    boolean lazyJarsChanged;
    public List getRuntimeCP() {
        return runtimeCP;
    }
    public List getLazyJars() {
        return lazyJars;
    }
    public void setLazyJars(List newLazyJars) {
        this.lazyJars = newLazyJars;
    }
    public boolean getLazyJarsChanged() {
        return lazyJarsChanged;
    }
    public void setLazyJarsChanged(boolean changed) {
        this.lazyJarsChanged = changed;
    }
    
    // Deployment - JavaScript Callbacks
    Map jsCallbacks;
    boolean jsCallbacksChanged;
    public Map getJSCallbacks() {
        return jsCallbacks;
    }
    public void setJSCallbacks(Map newCallbacks) {
        jsCallbacks = newCallbacks;
    }
    public boolean getJSCallbacksChanged() {
        return jsCallbacksChanged;
    }
    public void setJSCallbacksChanged(boolean changed) {
        jsCallbacksChanged = changed;
    }
    
    // Deployment - requested RT
    String requestedRT;
    public String getRequestedRT() {
        return requestedRT;
    }
    public void setRequestedRT(String rt) {
        this.requestedRT = rt;
    }
    
    // Application
    String implVersion;
    public String getImplementationVersion() {
        return implVersion;
    }
    public void setImplementationVersion(String implVer) {
        implVersion = implVer;
    }
        
    // Project related references
    private J2SEPropertyEvaluator j2sePropEval;
    private PropertyEvaluator evaluator;
    private Project project;

    public Project getProject() {
        return project;
    }
    public PropertyEvaluator getEvaluator() {
        return evaluator;
    }
    
    /** Keeps singleton instance of JFXProjectProperties for any fx project for which property customizer is opened at once */
    private static Map propInstance = new HashMap();

    /** Keeps set of category markers used to identify validity of JFXProjectProperties instance */
    private Set instanceMarkers = new TreeSet();
    
    public void markInstance(@NonNull String marker) {
        instanceMarkers.add(marker);
    }
    
    public boolean isInstanceMarked(@NonNull String marker) {
        return instanceMarkers.contains(marker);
    }
    
    /** Factory method */
    public static JFXProjectProperties getInstance(Lookup context) {
        Project proj = context.lookup(Project.class);
        String projDir = proj.getProjectDirectory().getPath();
        JFXProjectProperties prop = propInstance.get(projDir);
        if(prop == null) {
            prop = new JFXProjectProperties(context);
            propInstance.put(projDir, prop);
        }
        return prop;
    }

    /** Factory method 
     * This is to prevent reuse of the same instance after the properties dialog
     * has been cancelled. Called by each FX category provider at the time
     * when properties dialog is opened, it checks/stores category-specific marker strings. 
     * Previous existence of marker string indicates that properties dialog had been opened
     * before and ended by Cancel, otherwise this instance would not exist (OK would
     * cause properties to be saved and the instance deleted by a call to JFXProjectProperties.cleanup()).
     * (Note that this is a workaround to avoid adding listener to properties dialog close event.)
     * 
     * @param category marker string to indicate which category provider is calling this
     * @return instance of JFXProjectProperties shared among category panels in the current Project Properties dialog only
     * 
     * @deprecated handle cleanup using ProjectCustomizer.Category.setCloseListener instead
     */
    @Deprecated
    public static JFXProjectProperties getInstancePerSession(Lookup context, String category) {
        Project proj = context.lookup(Project.class);
        String projDir = proj.getProjectDirectory().getPath();
        JFXProjectProperties prop = propInstance.get(projDir);
        if(prop != null) {
            if(prop.isInstanceMarked(category)) {
                // category marked before - create new instance to avoid reuse after Cancel
                prop = null;
            } else {
                prop.markInstance(category);
            }
        }
        if(prop == null) {
            prop = new JFXProjectProperties(context);
            propInstance.put(projDir, prop);
            prop.markInstance(category);
        }
        return prop;
    }
    
    /** Getter method */
    public static JFXProjectProperties getInstanceIfExists(Project proj) {
        assert proj != null;
        String projDir = proj.getProjectDirectory().getPath();
        JFXProjectProperties prop = propInstance.get(projDir);
        if(prop != null) {
            return prop;
        }
        return null;
    }

    /** Getter method */
    public static JFXProjectProperties getInstanceIfExists(Lookup context) {
        Project proj = context.lookup(Project.class);
        return getInstanceIfExists(proj);
    }

    public static void cleanup(Lookup context) {
        Project proj = context.lookup(Project.class);
        String projDir = proj.getProjectDirectory().getPath();
        propInstance.remove(projDir);
    }

    /** Keeps singleton instance of a set of preloader artifact dependencies for any fx project */
    private static Map> prelArtifacts = new HashMap>();
    
    /** Factory method */
    private static Set getPreloaderArtifacts(@NonNull Project proj) {
        String projDir = proj.getProjectDirectory().getPath();
        Set prels = prelArtifacts.get(projDir);
        if(prels == null) {
            prels = new HashSet();
            prelArtifacts.put(projDir, prels);
        }
        return prels;
    }
    
    public String getFXRunTimeJar() {
        assert evaluator != null;
        String active = evaluator.getProperty(PLATFORM_ACTIVE);
        JavaPlatform platform = JavaFXPlatformUtils.findJavaPlatform(active);
        if(platform != null) {
            return JavaFXPlatformUtils.getJavaFXRuntimeJar(platform);
        }
        return null;
    }
    
    /** Creates a new instance of JFXProjectProperties */
    private JFXProjectProperties(Lookup context) {
        
        //defaultInstance = provider.getJFXProjectProperties();
        project = context.lookup(Project.class);
        
        if (project != null) {
            j2sePropEval = project.getLookup().lookup(J2SEPropertyEvaluator.class);
            evaluator = j2sePropEval.evaluator();
            
            // Packaging
            binaryEncodeCSS = fxPropGroup.createToggleButtonModel(evaluator, JAVAFX_BINARY_ENCODE_CSS); // set true by default in JFXProjectGenerator

            // Deployment
            allowOfflineModel = fxPropGroup.createToggleButtonModel(evaluator, ALLOW_OFFLINE); // set true by default in JFXProjectGenerator            
            backgroundUpdateCheck = fxPropGroup.createToggleButtonModel(evaluator, UPDATE_MODE_BACKGROUND); // set true by default in JFXProjectGenerator
            installPermanently = fxPropGroup.createToggleButtonModel(evaluator, INSTALL_PERMANENTLY);
            addDesktopShortcut = fxPropGroup.createToggleButtonModel(evaluator, ADD_DESKTOP_SHORTCUT);
            addStartMenuShortcut = fxPropGroup.createToggleButtonModel(evaluator, ADD_STARTMENU_SHORTCUT);
            disableProxy = fxPropGroup.createToggleButtonModel(evaluator, DISABLE_PROXY);
            
            // CustomizerRun
            CONFIGS = new JFXConfigs();
            CONFIGS.read();
            initPreloaderArtifacts(project, CONFIGS);
            CONFIGS.setActive(evaluator.getProperty(ProjectProperties.PROP_PROJECT_CONFIGURATION_CONFIG));
            preloaderClassModel = new PreloaderClassComboBoxModel();

            initVersion(evaluator);
            initIcons(evaluator);
            initSigning(evaluator);
            initNativeBundling(evaluator);
            initResources(evaluator, project, CONFIGS);
            initJSCallbacks(evaluator);
            initRest(evaluator);
        }
    }
    
    public static boolean isTrue(final String value) {
        return value != null &&
                (value.equalsIgnoreCase("true") ||  //NOI18N
                 value.equalsIgnoreCase("yes") ||   //NOI18N
                 value.equalsIgnoreCase("on"));     //NOI18N
    }

    public static boolean isNonEmpty(String s) {
        return s != null && !s.isEmpty();
    }
            
    public static boolean isEqual(final String s1, final String s2) {
        return (s1 == null && s2 == null) ||
                (s1 != null && s2 != null && s1.equals(s2));
    }                                   

    public static boolean isEqualIgnoreCase(final String s1, final String s2) {
        return (s1 == null && s2 == null) ||
                (s1 != null && s2 != null && s1.equalsIgnoreCase(s2));
    }                                   

    public static boolean isEqualText(final String s1, final String s2) {
        return ((s1 == null || s1.isEmpty()) && (s2 == null || s2.isEmpty())) ||
                (s1 != null && s2 != null && s1.equals(s2));
    }                                   
    
    /**
     * Used to display named and unnamed parameters in table. The point
     * here is to keep consistency by forbidding invalid parameters, i.e.,
     * named parameters with value but without name.
     */
    public static class PropertiesTableModel extends AbstractTableModel {
        
        private List> properties;
        private List> defaultProperties;
        private String propSuffixes[];
        private String columnNames[];
        
        public PropertiesTableModel(List> props, List> defaultProps, String sfxs[], String clmns[]) {
            if (sfxs.length < clmns.length) {
                throw new IllegalArgumentException();
            }
            properties = props;
            defaultProperties = defaultProps;
            propSuffixes = sfxs;
            columnNames = clmns;
        }
        
        public boolean isValid() {
            assert properties != null;
            for(Map map : properties) {
                String left = map.get(propSuffixes[0]);
                if(left == null || left.trim().isEmpty()) {
                    for(int c=1; c last = properties.get(index);
                for(int c=0; c0) {
                String left = properties.get(rowIndex).get(propSuffixes[columnIndex-1]);
                if(left == null || left.isEmpty()) {
                    return false;
                }
            }
            return true;
        }
        
        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            properties.get(rowIndex).put(propSuffixes[columnIndex], (String) aValue);
            fireTableCellUpdated(rowIndex, columnIndex);
        }
        
        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            return properties.get(rowIndex).get(propSuffixes[columnIndex]);
        }
        
        /**
         * restore defaults if defaultProperties exist, otherwise clean
         */
        public void reset() {
            if(defaultProperties != null) {
                properties.clear();
                properties.addAll(defaultProperties);
            } else {
                properties.clear();
            }
            fireTableDataChanged();
        }
        
        /**
         * Indicates whether it makes sense to enable the Default/Clean
         * button, i.e., whether current table contents differ from the default
         * @return true is a call to reset() would modify data
         */
        public boolean isResettable() {
            if(hasDefaultProperties()) {
                return !areEqual(properties, defaultProperties);
            }
            return !properties.isEmpty();
        }
        
        private boolean areEqual(List> list1, List> list2) {
            String s1 = getAsString(list1);
            String s2 = getAsString(list2);
            if(isEqualText(s1, s2)) {
                return true;
            }
            return false;
        }
        
        private String getAsString(List> list) {
            if(list != null) {
                List l = new LinkedList();
                for(Map entry : list) {
                    StringBuilder sb = new StringBuilder();
                    for(int i = 0; i < columnNames.length; i++) {
                        sb.append(propSuffixes[i]);
                        sb.append(entry.get(propSuffixes[i]));
                    }
                    l.add(sb.toString());
                }
                Collections.sort(l);
                return l.toString();
            }
            return null;
        }
        
        public void addRow() {
            Map emptyMap = new HashMap();
            for (String  suffix : propSuffixes) {
                emptyMap.put(suffix, "");
            }
            properties.add(emptyMap);
            fireTableDataChanged();
        }
        
        public void removeRow(int index) {
            properties.remove(index);
            fireTableDataChanged();
        }
        
        private int getEmptyRow() {
            for(int i = 0; i < properties.size(); i++) {
                if(isRowEmpty(i)) {
                    return i;
                }
            }
            return -1;
        }
        
        public void removeEmptyRows() {
            boolean removed = false;
            while(true) {
                int i = getEmptyRow();
                if(i == -1) {
                    if(removed) {
                        fireTableDataChanged();
                    }
                    return;
                }
                removeRow(i);
                removed = true;
            }
        }

    }

    /**
     * May not be necessary but improves user experience - updates OK button state
     * immediately while editing text in table, i.e., not only after cell editing
     * has finished.
     */
    public static class PropertyCellEditor extends DefaultCellEditor implements CellEditorListener {

        private DocumentListener listener = null;
        private Document document = null;

        public PropertyCellEditor() {
            super(new JTextField());
        }

        public void registerCellEditorListener() {
            addCellEditorListener(this);
        }
        
        public void unregisterCellEditorListener() {
            removeCellEditorListener(this);
        }
        
        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            if(document != null) {
                document.removeDocumentListener(listener);
            }
            JTextField editor = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, row, column);
            document = editor.getDocument();
            listener = new CellEditorDocumentListener(table.getModel(), row, column);
            document.addDocumentListener(listener);
            return editor;
        }

        @Override
        public void editingStopped(ChangeEvent e) {
            removeDocumentListenerReference();
        }

        @Override
        public void editingCanceled(ChangeEvent e) {
            removeDocumentListenerReference();
        }

        private void removeDocumentListenerReference() {
            if(document != null) {
                document.removeDocumentListener(listener);
                document = null;
            }
            listener = null;
        }

        private class CellEditorDocumentListener implements DocumentListener {
            private TableModel model;
            private int row;
            private int column;

            private CellEditorDocumentListener(TableModel model, int row, int column) {
                this.model = model;
                this.row = row;
                this.column = column;
            }
            @Override
            public void insertUpdate(DocumentEvent e) {
                update(e);
            }
            @Override
            public void removeUpdate(DocumentEvent e) {
                update(e);
            }
            @Override
            public void changedUpdate(DocumentEvent e) {
                update(e);
            }

            private void update(DocumentEvent e) {
                Document d = e.getDocument();
                try {
                    model.setValueAt(d.getText(0, d.getLength()), row, column);
                } catch (BadLocationException ex) {
                    // can be ignored
                }
            }
        }
    }

    /**
     * Content in invalid cells is rendered in emphasized color.
     */
    public static class PropertyCellRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object o, boolean isSelected, boolean hasFocus, int row, int column) {
            Component cell = super.getTableCellRendererComponent(table, o, isSelected, hasFocus, row, column);
            if(!table.getModel().isCellEditable(row, column)) {
                cell.setForeground(INVALID_CELL_CONTENT_COLOR);
            } else {
                cell.setForeground(UIManager.getColor("textText")); //NOI18N
            }
            return cell;
        }
    }
    
    
    private FileObject getSrcRoot(@NonNull Project project)
    {
        FileObject srcRoot = null;
        for (SourceGroup sg : ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA)) {
            if (!isTest(sg.getRootFolder(),project)) {
                srcRoot = sg.getRootFolder();
                break;
            }
        }
        return srcRoot;
    }

    private void initPreloaderArtifacts(@NonNull Project project, @NonNull JFXConfigs configs) {
        Set prels = getPreloaderArtifacts(project);
        prels.clear();
        try {
            prels.addAll(getPreloaderArtifactsFromConfigs(configs));
        } catch (IOException ex) {
            // can be ignored
        }
    }
    
    public boolean hasPreloaderInAnyConfig() {
        return hasPreloaderInAnyConfig(CONFIGS);
    }
    
    private boolean hasPreloaderInAnyConfig(@NonNull JFXConfigs configs) {
        if(configs != null) {
            for(String config : configs.getConfigNames()) {
                if(isTrue( configs.getProperty(config, PRELOADER_ENABLED))) {
                    return true;
                }
            }
        }
        return false;
    }
    
    private PreloaderArtifact getPreloaderArtifactFromConfig(@NonNull JFXConfigs configs, @NonNull String config, boolean transparent) throws IOException {       
        // check records on any type of preloader from config
        if(configs.hasConfig(config)) {
            
            PreloaderArtifact preloader = null;
            if(!isTrue( transparent ? configs.getPropertyTransparent(config, PRELOADER_ENABLED) : configs.getProperty(config, PRELOADER_ENABLED))) {
                return null;
            }
            String prelTypeString = transparent ? configs.getPropertyTransparent(config, PRELOADER_TYPE) : configs.getProperty(config, PRELOADER_TYPE);
            
            String prelProjDir = transparent ? configs.getPropertyTransparent(config, PRELOADER_PROJECT) : configs.getProperty(config, PRELOADER_PROJECT);
            if (prelProjDir != null && isEqualIgnoreCase(prelTypeString, PreloaderSourceType.PROJECT.getString())) {
                FileObject thisProjDir = project.getProjectDirectory();
                FileObject fo = JFXProjectUtils.getFileObject(thisProjDir, prelProjDir);
                File prelProjDirF = (fo == null) ? null : FileUtil.toFile(fo);                
                if( isTrue(transparent ? configs.getPropertyTransparent(config, PRELOADER_ENABLED) : configs.getProperty(config, PRELOADER_ENABLED)) && prelProjDirF != null && prelProjDirF.exists() ) {
                    FileObject srcRoot = getSrcRoot(getProject());
                    if(srcRoot != null) {
                        prelProjDirF = FileUtil.normalizeFile(prelProjDirF);
                        FileObject prelProjFO = FileUtil.toFileObject(prelProjDirF);
                        final Project proj = ProjectManager.getDefault().findProject(prelProjFO);

                        AntArtifact[] artifacts = proj != null ? AntArtifactQuery.findArtifactsByType(proj, JavaProjectConstants.ARTIFACT_TYPE_JAR) : new AntArtifact[0];
                        List allURI = new ArrayList();
                        for(AntArtifact artifact : artifacts) {
                            allURI.addAll(Arrays.asList(artifact.getArtifactLocations()));
                        }
                        if(!allURI.isEmpty()) {
                            URI[] arrayURI = allURI.toArray(new URI[0]);
                            preloader = new PreloaderProjectArtifact(artifacts, arrayURI, srcRoot, ClassPath.COMPILE, prelProjDirF.getAbsolutePath());
                        }
                    }
                }
            }
            if(preloader == null) {
                String prelJar = transparent ? configs.getPropertyTransparent(config, PRELOADER_JAR_PATH) : configs.getProperty(config, PRELOADER_JAR_PATH);
                if(prelJar != null && isEqualIgnoreCase(prelTypeString, PreloaderSourceType.JAR.getString())) {
                    FileObject thisProjDir = project.getProjectDirectory();
                    FileObject fo = JFXProjectUtils.getFileObject(thisProjDir, prelJar);
                    File prelJarF = (fo == null) ? null : FileUtil.toFile(fo);                
                    if( prelJarF != null && prelJarF.exists() ) {
                        FileObject srcRoot = getSrcRoot(getProject());
                        if(srcRoot != null) {
                            URL[] urls = new URL[1];
                            urls[0] = FileUtil.urlForArchiveOrDir(prelJarF);
                            FileObject[] fos = new FileObject[1];
                            fos[0] = FileUtil.toFileObject(prelJarF);
                            preloader = new PreloaderJarArtifact(urls, fos, srcRoot, ClassPath.COMPILE, urls[0].toString());
                        }
                    }
                }
            }
            return preloader;
        }
        return null;
    }
    
    private Set getPreloaderArtifactsFromConfigs(@NonNull JFXConfigs configs) throws IOException {       
        Set preloaderArtifacts = new HashSet();
        // check records on all preloaders from all configurations
        for(String config : configs.getConfigNames()) {
            PreloaderArtifact preloader = getPreloaderArtifactFromConfig(configs, config, false);
            if(preloader != null) {
                preloaderArtifacts.add(preloader);
            }
        }
        return preloaderArtifacts;
    }

    public void updatePreloaderDependencies() {
        try {
            updatePreloaderDependencies(CONFIGS);
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        }
    }
    
    private void updatePreloaderDependencies(@NonNull final JFXConfigs configs) throws IOException {
        // depeding on the currently (de)selected preloaders update project dependencies,
        // i.e., remove disabled/deleted preloader project dependencies and add enabled/added preloader project dependencies
        Set preloaderArtifacts = getPreloaderArtifacts(getProject());
        for(PreloaderArtifact artifact : preloaderArtifacts) {
            artifact.setValid(false);
        }
        final PreloaderArtifact preloaderActive = getPreloaderArtifactFromConfig(configs, configs.getActive(), true);
        // collect all dependencies from any configuration
        for(final String config : configs.getConfigNames()) {
            final PreloaderArtifact preloader = getPreloaderArtifactFromConfig(configs, config, false);
            if(preloader != null) {
                boolean updated = false;
                for(PreloaderArtifact a : preloaderArtifacts) {
                    if(a.equals(preloader)) {
                        a.setValid(true);
                        updated = true;
                    }
                }
                if(!updated) {
                    preloader.setValid(true);
                    preloaderArtifacts.add(preloader);
                }
            }
        }
        // remove all dependencies not-specified in active configuration (and add the active one)
        Set toRemove = new HashSet();
        for(final PreloaderArtifact artifact : preloaderArtifacts) {
            if(preloaderActive == null || !preloaderActive.equals(artifact)) {
                toRemove.add(artifact);
            }
        }
        if(preloaderActive != null || !toRemove.isEmpty()) {
            final Set toRemoveFinal = Collections.unmodifiableSet(toRemove);
            ProjectManager.mutex().postWriteRequest(new Runnable() {
                @Override
                public void run() {
                    if(preloaderActive != null) {
                        try {
                            preloaderActive.addDependency();
                        } catch(IOException e) {
                            LOG.log(Level.SEVERE, "Preloader dependency addition failed."); // NOI18N
                        }
                    }
                    try {
                        for(final PreloaderArtifact artifact : toRemoveFinal) {
                            artifact.removeDependency();
                        }
                    } catch(IOException e) {
                        LOG.log(Level.SEVERE, "Preloader dependency removal failed."); // NOI18N
                    }
                }
            });
        }
        // remove from preloaderArtifacts those not more present in any config
        toRemove.clear();
        for(final PreloaderArtifact artifact : preloaderArtifacts) {
            if(!artifact.isValid()) {
                toRemove.add(artifact);
            }
        }
        for(PreloaderArtifact artifact : toRemove) {
            preloaderArtifacts.remove(artifact);
        }
    }
    
    private static boolean isTest(final @NonNull FileObject root, final @NonNull Project project) {
        assert root != null;
        assert project != null;
        final ClassPath cp = ClassPath.getClassPath(root, ClassPath.COMPILE);
        for (ClassPath.Entry entry : cp.entries()) {
            final FileObject[] srcRoots = SourceForBinaryQuery.findSourceRoots(entry.getURL()).getRoots();
            for (FileObject srcRoot : srcRoots) {
                if (project.equals(FileOwnerQuery.getOwner(srcRoot))) {
                    return true;
                }
            }
        }
        return false;
    }

    private void storeRest(@NonNull EditableProperties editableProps, @NonNull EditableProperties privProps) {
        // create extended manifest attribute properties if not existing
        if(!editableProps.containsKey(MANIFEST_CUSTOM_CODEBASE) && !privProps.containsKey(MANIFEST_CUSTOM_CODEBASE)) {
            editableProps.setProperty(MANIFEST_CUSTOM_CODEBASE, "*"); // NOI18N
            editableProps.setComment(MANIFEST_CUSTOM_CODEBASE, new String[]{"# " + NbBundle.getMessage(JFXProjectUtils.class, "COMMENT_manifest_custom_codebase")}, false); // NOI18N
        }
        if(!editableProps.containsKey(MANIFEST_CUSTOM_PERMISSIONS) && !privProps.containsKey(MANIFEST_CUSTOM_PERMISSIONS)) {
            editableProps.setProperty(MANIFEST_CUSTOM_PERMISSIONS, ""); // NOI18N
            editableProps.setComment(MANIFEST_CUSTOM_PERMISSIONS, new String[]{"# " + NbBundle.getMessage(JFXProjectUtils.class, "COMMENT_manifest_custom_permissions")}, false); // NOI18N
        }
        // store implementation version
        setOrRemove(editableProps, IMPLEMENTATION_VERSION, implVersion);
        // store signing info
        editableProps.setProperty(JAVAFX_SIGNING_ENABLED, signingEnabled ? "true" : "false"); //NOI18N
        editableProps.setProperty(JAVAFX_SIGNING_BLOB, signingBlob ? "true" : "false"); //NOI18N
        editableProps.setProperty(JAVAFX_SIGNING_TYPE, signingType.getString());
        setOrRemove(editableProps, JAVAFX_SIGNING_KEY, signingKeyAlias);
        setOrRemove(editableProps, JAVAFX_SIGNING_KEYSTORE, signingKeyStore);
        editableProps.setProperty(PERMISSIONS_ELEVATED, permissionsElevated ? "true" : "false"); //NOI18N
        setOrRemove(privProps, JAVAFX_SIGNING_KEYSTORE_PASSWORD, signingKeyStorePassword);
        setOrRemove(privProps, JAVAFX_SIGNING_KEY_PASSWORD, signingKeyPassword);        
        // store native bundling info
        editableProps.setProperty(NATIVE_BUNDLING_ENABLED, nativeBundlingEnabled ? "true" : "false"); //NOI18N
        // store icons
        setOrRemove(editableProps, ICON_FILE, wsIconPath);
        setOrRemove(editableProps, SPLASH_IMAGE_FILE, splashImagePath);
        setOrRemove(editableProps, NATIVE_ICON_FILE, nativeIconPath);
        // store requested RT
        setOrRemove(editableProps, REQUEST_RT, requestedRT);
        // store resources
        storeResources(editableProps);
        // store JavaScript callbacks
        storeJSCallbacks(editableProps);
    }

    private void setOrRemove(EditableProperties props, String name, char [] value) {
        setOrRemove(props, name, value != null ? new String(value) : null);
    }

    private void setOrRemove(@NonNull EditableProperties props, @NonNull String name, String value) {
        if (value != null) {
            props.setProperty(name, value);
        } else {
            props.remove(name);
        }
    }
        
    public void store() throws IOException {
        String fxEnabled = evaluator.getProperty(JFXProjectProperties.JAVAFX_ENABLED);
        if(isTrue(fxEnabled)) {
            storeFX();
        } else {
            storeSE();
        }
    }
    
    private void storeFX() throws IOException {
        updatePreloaderDependencies(CONFIGS);
        CONFIGS.storeActive();
        final EditableProperties ep = new EditableProperties(true);
        final FileObject projPropsFO = project.getProjectDirectory().getFileObject(AntProjectHelper.PROJECT_PROPERTIES_PATH);
        final EditableProperties pep = new EditableProperties(true);
        final FileObject privPropsFO = project.getProjectDirectory().getFileObject(AntProjectHelper.PRIVATE_PROPERTIES_PATH);        
        try {
            ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction() {
                @Override
                public Void run() throws Exception {
                    final InputStream is = projPropsFO.getInputStream();
                    final InputStream pis = privPropsFO.getInputStream();
                    try {
                        ep.load(is);
                    } finally {
                        if (is != null) {
                            is.close();
                        }
                    }
                    try {
                        pep.load(pis);
                    } finally {
                        if (pis != null) {
                            pis.close();
                        }
                    }
                    
                    fxPropGroup.store(ep);
                    storeRest(ep, pep);
                    CONFIGS.store(ep, pep);
                    updatePreloaderComment(ep);
                    //JFXProjectUtils.updateClassPathExtensionProperties(ep);
                    logProps(ep);

                    OutputStream os = null;
                    FileLock lock = null;
                    try {
                        lock = projPropsFO.lock();
                        os = projPropsFO.getOutputStream(lock);
                        ep.store(os);
                    } finally {
                        if (lock != null) {
                            lock.releaseLock();
                        }
                        if (os != null) {
                            os.close();
                        }
                    }
                    try {
                        lock = privPropsFO.lock();
                        os = privPropsFO.getOutputStream(lock);
                        pep.store(os);
                    } finally {
                        if (lock != null) {
                            lock.releaseLock();
                        }
                        if (os != null) {
                            os.close();
                        }
                    }
                    return null;
                }
            });
        } catch (MutexException mux) {
            throw (IOException) mux.getException();
        }
    }

    private void storeSE() throws IOException {
        final EditableProperties ep = new EditableProperties(true);
        final FileObject projPropsFO = project.getProjectDirectory().getFileObject(AntProjectHelper.PROJECT_PROPERTIES_PATH);
        try {
            final InputStream is = projPropsFO.getInputStream();
            ProjectManager.mutex().readAccess(new Mutex.ExceptionAction() {
                @Override
                public Void run() throws Exception {
                    try {
                        ep.load(is);
                    } finally {
                        if (is != null) {
                            is.close();
                        }
                    }
                    return null;
                }
            });
        } catch (MutexException mux) {
            throw (IOException) mux.getException();
        }
        setOrRemove(ep, JAVASE_KEEP_JFXRT_ON_CLASSPATH, keepJFXRTonCP ? "true" : null); //NOI18N
        //Copylibs excludes for J2SE Project with JFX extension
        String copyLibsExcludes = ep.getProperty(COPYLIBS_EXCLUDES);
        if (keepJFXRTonCP) {
            if (copyLibsExcludes == null || copyLibsExcludes.isEmpty()) {
                copyLibsExcludes = JFX_EXTENSION_CPREF;
            } else if (copyLibsExcludes.indexOf(JFX_EXTENSION_CPREF)<0){
                copyLibsExcludes = copyLibsExcludes + ':' + JFX_EXTENSION_CPREF;
            }
            setOrRemove(ep, COPYLIBS_EXCLUDES, copyLibsExcludes);
        } else {
            if (copyLibsExcludes != null) {
                copyLibsExcludes = JFXProjectUtils.removeFromPath(copyLibsExcludes,JFX_EXTENSION_CPREF);
                if (copyLibsExcludes.isEmpty()) {
                    copyLibsExcludes = null;
                }
            }
            setOrRemove(ep, COPYLIBS_EXCLUDES, copyLibsExcludes);
        }
        //JFXProjectUtils.updateClassPathExtensionProperties(ep);
        try {
            ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction() {
                @Override
                public Void run() throws Exception {
                    OutputStream os = null;
                    FileLock lock = null;
                    try {
                        lock = projPropsFO.lock();
                        os = projPropsFO.getOutputStream(lock);
                        ep.store(os);
                    } finally {
                        if (lock != null) {
                            lock.releaseLock();
                        }
                        if (os != null) {
                            os.close();
                        }
                    }
                    return null;
                }
            });
        } catch (MutexException mux) {
            throw (IOException) mux.getException();
        }
    }
    
    private void updatePreloaderComment(EditableProperties ep) {
        if(isTrue(ep.get(JFXProjectProperties.PRELOADER_ENABLED))) {
            ep.setComment(JFXProjectProperties.PRELOADER_ENABLED, new String[]{"# " + NbBundle.getMessage(JFXProjectProperties.class, "COMMENT_use_preloader")}, false); // NOI18N    
        } else {
            ep.setComment(JFXProjectProperties.PRELOADER_ENABLED, new String[]{"# " + NbBundle.getMessage(JFXProjectProperties.class, "COMMENT_dontuse_preloader")}, false); // NOI18N    
        }
    }

    private void initVersion(PropertyEvaluator eval) {
        implVersion = eval.getProperty(IMPLEMENTATION_VERSION);
        if(implVersion == null) {
            implVersion = IMPLEMENTATION_VERSION_DEFAULT;
        }
    }
    
    private void initIcons(PropertyEvaluator eval) {
        wsIconPath = eval.getProperty(ICON_FILE);
        splashImagePath = eval.getProperty(SPLASH_IMAGE_FILE);
        nativeIconPath = eval.getProperty(NATIVE_ICON_FILE);
    }
    
    private void initSigning(PropertyEvaluator eval) {
        String enabled = eval.getProperty(JAVAFX_SIGNING_ENABLED);
        String blob = eval.getProperty(JAVAFX_SIGNING_BLOB);
        String signedProp = eval.getProperty(JAVAFX_SIGNING_TYPE);
        signingEnabled = isTrue(enabled);
        signingBlob = isTrue(blob);
        if(signedProp == null) {
            signingType = SigningType.NOSIGN;
        } else {
            if(signedProp.equalsIgnoreCase(SigningType.SELF.getString())) {
                signingType = SigningType.SELF;
            } else {
                if(signedProp.equalsIgnoreCase(SigningType.KEY.getString())) {
                    signingType = SigningType.KEY;
                } else {
                    signingType = SigningType.NOSIGN;
                }
            }
        }
        signingKeyStore = eval.getProperty(JAVAFX_SIGNING_KEYSTORE);
        //if (signingKeyStore == null) signingKeyStore = "";
        signingKeyAlias = eval.getProperty(JAVAFX_SIGNING_KEY);
        //if (signingKeyAlias == null) signingKeyAlias = "";
        if (eval.getProperty(JAVAFX_SIGNING_KEYSTORE_PASSWORD) != null) {
            signingKeyStorePassword = eval.getProperty(JAVAFX_SIGNING_KEYSTORE_PASSWORD).toCharArray();
        }
        if (eval.getProperty(JAVAFX_SIGNING_KEY_PASSWORD) != null) {
            signingKeyPassword = eval.getProperty(JAVAFX_SIGNING_KEY_PASSWORD).toCharArray();
        }
        permissionsElevated = isTrue(eval.getProperty(PERMISSIONS_ELEVATED));
    }
    
    private void initNativeBundling(PropertyEvaluator eval) {
        String fxEnabled = evaluator.getProperty(JFXProjectProperties.JAVAFX_ENABLED);
        if(isTrue(fxEnabled)) {
            String enabled = eval.getProperty(NATIVE_BUNDLING_ENABLED);
            nativeBundlingEnabled = isTrue(enabled);
        }
    }
    
    private void initRest(PropertyEvaluator eval) {
        requestedRT = eval.getProperty(REQUEST_RT);
        keepJFXRTonCP = isTrue(eval.getProperty(JAVASE_KEEP_JFXRT_ON_CLASSPATH));
    }
    
    private boolean isParentOf(File parent, File child) {
        if(parent == null || child == null) {
            return false;
        }
        if(!parent.exists() || !child.exists()) {
            return false;
        }
        FileObject parentFO = FileUtil.toFileObject(parent);
        FileObject childFO = FileUtil.toFileObject(child);
        return FileUtil.isParentOf(parentFO, childFO);
    }

    private void initResources (final PropertyEvaluator eval, final Project prj, final JFXConfigs configs) {
        final String lz = eval.getProperty(DOWNLOAD_MODE_LAZY_JARS); //old way, when changed rewritten to new
        final String rcp = eval.getProperty(RUN_CP);        
        final String bc = eval.getProperty(BUILD_CLASSES);
        final String plat = eval.getProperty(PLATFORM_ACTIVE);
        JavaPlatform platform = JavaFXPlatformUtils.findJavaPlatform(plat);
        final File prjDir = FileUtil.toFile(prj.getProjectDirectory());
        final File bcDir = bc == null ? null : PropertyUtils.resolveFile(prjDir, bc);
        final List lazyFileList = new ArrayList();
        String[] paths;
        if (lz != null) {
            paths = PropertyUtils.tokenizePath(lz);            
            for (String p : paths) {
                lazyFileList.add(PropertyUtils.resolveFile(prjDir, p));
            }
        }
        paths = rcp != null ? PropertyUtils.tokenizePath(rcp) : new String[0];
        String mainJar = eval.getProperty(DIST_JAR);
        final File mainFile = mainJar != null ? PropertyUtils.resolveFile(prjDir, mainJar) : null;
        List preloaders = new ArrayList();
        try {
            for(PreloaderArtifact pa : getPreloaderArtifactsFromConfigs(configs)) {
                preloaders.addAll(Arrays.asList(pa.getFileObjects()));
            }
        } catch (IOException ex) {
            // no need to react
        }

        Collection platfF = platform != null ? platform.getInstallFolders() : null;
        final List resFileList = new ArrayList(paths.length);
        for (String p : paths) {
            if (p.startsWith("${") && p.endsWith("}")) {    //NOI18N
                continue;
            }
            final File f = PropertyUtils.resolveFile(prjDir, p);
            if (!f.exists()) {
                continue;
            }
            if (mainFile != null && f.equals(mainFile)) {
                continue;
            }
            if(platfF != null) {
                boolean cont = false;
                for(FileObject fo : platfF) {
                    if(isParentOf(FileUtil.toFile(fo), f)) {
                        cont = true;
                    }
                }
                if(cont) {
                    continue;
                }
            }
            boolean isPrel = false;
            for(FileObject prelfo : preloaders) {
                File prelf = FileUtil.toFile(prelfo);
                if(prelf != null && prelf.equals(f)) {
                    isPrel = true;
                    continue;
                }
            }
            if (!isPrel && (bc == null || !bcDir.equals(f)) ) {
                resFileList.add(f);
                if (isTrue(eval.getProperty(String.format(DOWNLOAD_MODE_LAZY_FORMAT, f.getName())))) {
                    lazyFileList.add(f);
                }
            }
        }
        lazyJars = lazyFileList;
        runtimeCP = resFileList;
        lazyJarsChanged = false;
    }
    
    private void storeResources(final EditableProperties props) {
        if (lazyJarsChanged) {
            //Remove old way if exists
            props.remove(DOWNLOAD_MODE_LAZY_JARS);
            final Iterator> it = props.entrySet().iterator();
            while (it.hasNext()) {
                if (it.next().getKey().startsWith(DOWNLOAD_MODE_LAZY_JAR)) {
                    it.remove();
                }
            }
            for (File lazyJar : lazyJars) {
                props.setProperty(String.format(DOWNLOAD_MODE_LAZY_FORMAT, lazyJar.getName()), "true");  //NOI18N
            }
        }
    }

    private void initJSCallbacks (final PropertyEvaluator eval) {
        String platformName = eval.getProperty(PLATFORM_ACTIVE);
        Map/*|null*/> callbacks = JFXProjectUtils.getJSCallbacks(platformName);
        Map result = new LinkedHashMap();
        for(Map.Entry/*|null*/> entry : callbacks.entrySet()) {
            String v = eval.getProperty(JFXProjectProperties.JAVASCRIPT_CALLBACK_PREFIX + entry.getKey());
            if(v != null && !v.isEmpty()) {
                result.put(entry.getKey(), v);
            }
        }
        jsCallbacks = result;
        jsCallbacksChanged = false;
    }
    
    private void storeJSCallbacks(final EditableProperties props) {
        if (jsCallbacksChanged && jsCallbacks != null) {
            for (Map.Entry entry : jsCallbacks.entrySet()) {
                if(entry.getValue() != null && !entry.getValue().isEmpty()) {
                    props.setProperty(JAVASCRIPT_CALLBACK_PREFIX + entry.getKey(), entry.getValue());  //NOI18N
                } else {
                    props.remove(JAVASCRIPT_CALLBACK_PREFIX + entry.getKey());
                }
            }
        }
    }

    public class PreloaderClassComboBoxModel extends DefaultComboBoxModel {
        
        private volatile boolean filling = false;
        private ChangeListener changeListener = null;
              
        public PreloaderClassComboBoxModel() {
            fillNoPreloaderAvailable();
        }
        
        public void addChangeListener (ChangeListener l) {
            changeListener = l;
        }

        public void removeChangeListener (ChangeListener l) {
            changeListener = null;
        }

        public final void fillNoPreloaderAvailable() {
            removeAllElements();
            addElement(NbBundle.getMessage(JFXProjectProperties.class, "MSG_ComboNoPreloaderClassAvailable"));  // NOI18N
        }
        
        public void fillFromProject(final Project project, final String select, final JFXConfigs configs, final String activeConfig) {
            final Collection roots = JFXProjectUtils.getClassPathMap(project).keySet();
            RequestProcessor.getDefault().post(new Runnable() {
                @Override
                public void run() {
                    if(!filling) {
                        filling = true;
                        removeAllElements();
                        if(project == null) {
                            addElement(NbBundle.getMessage(JFXProjectProperties.class, "MSG_ComboNoPreloaderClassAvailable"));  // NOI18N
                            return;
                        }
                        final Set appClassNames = JFXProjectUtils.getAppClassNames(roots, "javafx.application.Preloader"); //NOI18N
                        if(appClassNames.isEmpty()) {
                            addElement(NbBundle.getMessage(JFXProjectProperties.class, "MSG_ComboNoPreloaderClassAvailable"));  // NOI18N
                        } else {
                            addElements(appClassNames);
                            if(select != null) {
                                setSelectedItem(select);
                            }
                            String verify = (String)getSelectedItem();
                            if(!isEqual(configs.getPropertyTransparent(activeConfig, JFXProjectProperties.PRELOADER_CLASS), verify)) {
                                configs.setPropertyTransparent(activeConfig, JFXProjectProperties.PRELOADER_CLASS, verify);
                            }
                        }
                        if (changeListener != null) {
                            changeListener.stateChanged (appClassNames.isEmpty() ? null : new ChangeEvent (this));
                        }
                        filling = false;
                    }
                }
            });            
        }

        public void fillFromJAR(final FileObject jarFile, final JFXProjectProperties fxProps, final String select, final JFXConfigs configs, final String activeConfig) {
            RequestProcessor.getDefault().post(new Runnable() {
                @Override
                public void run() {
                    if(!filling) {
                        filling = true;
                        removeAllElements();
                        if(jarFile == null) {
                            addElement(NbBundle.getMessage(JFXProjectProperties.class, "MSG_ComboNoPreloaderClassAvailable"));  // NOI18N
                            return;
                        }
                        final Set appClassNames = JFXProjectUtils.getAppClassNamesInJar(jarFile, "javafx.application.Preloader", fxProps.getFXRunTimeJar()); //NOI18N    
                        appClassNames.remove("com.javafx.main.Main"); // NOI18N
                        appClassNames.remove("com.javafx.main.NoJavaFXFallback"); // NOI18N
                        if(appClassNames.isEmpty()) {
                            addElement(NbBundle.getMessage(JFXProjectProperties.class, "MSG_ComboNoPreloaderClassAvailable"));  // NOI18N
                        } else {
                            addElements(appClassNames);
                            if(select != null) {
                                setSelectedItem(select);
                            }
                            String verify = (String)getSelectedItem();
                            if(!isEqual(configs.getPropertyTransparent(activeConfig, JFXProjectProperties.PRELOADER_CLASS), verify)) {
                                configs.setPropertyTransparent(activeConfig, JFXProjectProperties.PRELOADER_CLASS, verify);
                            }
                        }
                        if (changeListener != null) {
                            changeListener.stateChanged (appClassNames.isEmpty() ? null : new ChangeEvent (this));
                        }
                        filling = false;
                    }
                }
            });            
        }

        private void addElements(Set elems) {
            for (String elem : elems) {
                addElement(elem);
            }
        }
        
    }
    
    /**
     * Each preloader specified in project configurations needs
     * to be added/removed to/from project dependencies whenever
     * configurations change (see Run category in Project Properties
     * dialog). 
     * List of preoader artifacts is thus needed to keep track which
     * project dependencies are preloader related.
     */
    abstract class PreloaderArtifact {
        
        /**
         * Dependency validity tag
         */
        private boolean valid;
        
        /**
         * Add {@code this} to dependencies of project if it is not there yet
         * @return true if preloader artifact has been added, false if it was already there
         */
        abstract boolean addDependency() throws IOException, UnsupportedOperationException;
        
        /**
         * Remove {@code this} from dependencies of project if it is there
         * @return true if preloader artifact has been removed, false if it was not among project dependencies
         */
        abstract boolean removeDependency() throws IOException, UnsupportedOperationException;
        
        /**
         * Returns array of files represented by this PreloaderArtifact
         * @return array of FileObjects of files represented by this object
         */
        abstract FileObject[] getFileObjects();
        
        /**
         * Set the validity tag for {@code this} artifact
         * @param valid true for dependencies to be kept, false for dependencies to be removed
         */
        void setValid(boolean valid) {
            this.valid = valid;
        }
        
        /**
         * Get the validity tag for {@code this} artifact
         * @return valid true for dependencies to be kept, false for dependencies to be removed
         */
        boolean isValid() {
            return valid;
        }
    }
    
    class PreloaderProjectArtifact extends PreloaderArtifact {

        private final String ID;
        private final AntArtifact[] artifacts;
        private final URI[] artifactElements;
        private final FileObject projectArtifact;
        private final String classPathType;
                
        PreloaderProjectArtifact(final @NonNull AntArtifact[] artifacts, final @NonNull URI[] artifactElements,
            final @NonNull FileObject projectArtifact, final @NonNull String classPathType, final @NonNull String ID) {
            this.artifacts = artifacts;
            this.artifactElements = artifactElements;
            this.projectArtifact = projectArtifact;
            this.classPathType = classPathType;
            this.ID = ID;
        }
        
        @Override
        public boolean addDependency() throws IOException, UnsupportedOperationException {
            return ProjectClassPathModifier.addAntArtifacts(artifacts, artifactElements, projectArtifact, classPathType);
        }

        @Override
        public boolean removeDependency()  throws IOException, UnsupportedOperationException {
            return ProjectClassPathModifier.removeAntArtifacts(artifacts, artifactElements, projectArtifact, classPathType);
        }

        @Override
        public boolean equals(Object that){
            if ( this == that ) return true;
            if ( !(that instanceof PreloaderProjectArtifact) ) return false;
            PreloaderProjectArtifact concrete = (PreloaderProjectArtifact)that;
            return ID.equals(concrete.ID);
        }

        @Override
        final FileObject[] getFileObjects() {
            List l = new ArrayList();
            for(AntArtifact a : artifacts) {
                l.addAll(Arrays.asList(a.getArtifactFiles()));
            }
            return l.toArray(new FileObject[l.size()]);
        }
    }

    class PreloaderJarArtifact extends PreloaderArtifact {

        private final String ID;
        private final URL[] classPathRoots;
        private final FileObject[] fileObjects;
        private final FileObject projectArtifact;
        private final String classPathType;
                
        PreloaderJarArtifact(final @NonNull URL[] classPathRoots, final @NonNull FileObject[] fileObjects, final @NonNull FileObject projectArtifact, 
                final @NonNull String classPathType, final @NonNull String ID) {
            this.classPathRoots = classPathRoots;
            this.fileObjects = fileObjects;
            this.projectArtifact = projectArtifact;
            this.classPathType = classPathType;
            this.ID = ID;
        }
        
        @Override
        public boolean addDependency() throws IOException, UnsupportedOperationException {
            return ProjectClassPathModifier.addRoots(classPathRoots, projectArtifact, classPathType);
        }

        @Override
        public boolean removeDependency()  throws IOException, UnsupportedOperationException {
            return ProjectClassPathModifier.removeRoots(classPathRoots, projectArtifact, classPathType);
        }
        
        @Override
        public boolean equals(Object that){
            if ( this == that ) return true;
            if ( !(that instanceof PreloaderJarArtifact) ) return false;
            PreloaderJarArtifact concrete = (PreloaderJarArtifact)that;
            return ID.equals(concrete.ID);
        }

        @Override
        final FileObject[] getFileObjects() {
            return fileObjects;
        }
    }

    /**
     * Project configurations maintenance class
     * 
     * Getter/Setter naming conventions:
     * "Property" in method name -> method deals with single properties in configuration given by parameter config
     * "Default" in method name -> method deals with properties in default configuration
     * "Active" in method name -> method deals with properties in currently chosen configuration
     * "Transparent" in method name -> method deals with property in configuration fiven by parameter config if
     *     exists, or with property in default configuration otherwise. This is to provide simple access to
     *     union of default and non-default properties that are to be presented to users in non-default configurations
     * "Param" in method name -> metod deals with properties representing sets of application parameters
     */
    public class JFXConfigs extends JFXProjectConfigurations {

        // property groups
        private String PRELOADER_GROUP_NAME = "preloader"; // NOI18N
        private List PRELOADER_PROPERTIES = Arrays.asList(new String[] {
            JFXProjectProperties.PRELOADER_ENABLED, JFXProjectProperties.PRELOADER_TYPE, JFXProjectProperties.PRELOADER_PROJECT, 
            JFXProjectProperties.PRELOADER_JAR_PATH, JFXProjectProperties.PRELOADER_JAR_FILENAME, JFXProjectProperties.PRELOADER_CLASS});

        private String BROWSER_GROUP_NAME = "browser"; // NOI18N
        private List BROWSER_PROPERTIES = Arrays.asList(new String[] {
            JFXProjectProperties.RUN_IN_BROWSER, JFXProjectProperties.RUN_IN_BROWSER_PATH, JFXProjectProperties.RUN_IN_BROWSER_ARGUMENTS});
        
        public final List getPreloaderProperties() {
            return Collections.unmodifiableList(PRELOADER_PROPERTIES);
        }
        
        public final List getBrowserProperties() {
            return Collections.unmodifiableList(BROWSER_PROPERTIES);
        }

        JFXConfigs() {
            super(project.getProjectDirectory());
            registerProjectProperties(new String[] {
                ProjectProperties.MAIN_CLASS, MAIN_CLASS, /*APPLICATION_ARGS,*/ RUN_JVM_ARGS, 
                PRELOADER_ENABLED, PRELOADER_TYPE, PRELOADER_PROJECT, PRELOADER_JAR_PATH, PRELOADER_JAR_FILENAME, PRELOADER_CLASS, 
                RUN_WORK_DIR, RUN_APP_WIDTH, RUN_APP_HEIGHT, RUN_IN_HTMLTEMPLATE, RUN_IN_BROWSER, RUN_IN_BROWSER_PATH, RUN_AS});
            registerPrivateProperties(new String[] {
                RUN_WORK_DIR, RUN_IN_HTMLTEMPLATE, RUN_IN_BROWSER, RUN_IN_BROWSER_PATH, RUN_IN_BROWSER_ARGUMENTS, RUN_AS});
            registerStaticProperties(new String[] {
                RUN_AS});
            
            Map substituteMissing = new HashMap();
            substituteMissing.put(RUN_APP_WIDTH, DEFAULT_APP_WIDTH);
            substituteMissing.put(RUN_APP_HEIGHT, DEFAULT_APP_HEIGHT);
            registerDefaultsIfMissing(substituteMissing);
            
            registerCleanEmptyProjectProperties(new String[] {
                MAIN_CLASS, RUN_JVM_ARGS, 
                PRELOADER_ENABLED, PRELOADER_TYPE, PRELOADER_PROJECT, PRELOADER_JAR_PATH, PRELOADER_JAR_FILENAME, PRELOADER_CLASS, 
                RUN_APP_WIDTH, RUN_APP_HEIGHT});
            registerCleanEmptyPrivateProperties(new String[] {
                RUN_WORK_DIR, RUN_IN_HTMLTEMPLATE, RUN_IN_BROWSER, RUN_IN_BROWSER_PATH});
            
            defineGroup(PRELOADER_GROUP_NAME, getPreloaderProperties());
            defineGroup(BROWSER_GROUP_NAME, getBrowserProperties());
        }
        
    }
    
    static void logProps(EditableProperties ep) {
        LOG.log(Level.INFO, PRELOADER_ENABLED + " = " + (ep.get(PRELOADER_ENABLED)==null ? "null" : ep.get(PRELOADER_ENABLED)));
        LOG.log(Level.INFO, PRELOADER_TYPE + " = " + (ep.get(PRELOADER_TYPE)==null ? "null" : ep.get(PRELOADER_TYPE)));
        LOG.log(Level.INFO, PRELOADER_PROJECT + " = " + (ep.get(PRELOADER_PROJECT)==null ? "null" : ep.get(PRELOADER_PROJECT)));
        LOG.log(Level.INFO, PRELOADER_CLASS + " = " + (ep.get(PRELOADER_CLASS)==null ? "null" : ep.get(PRELOADER_CLASS)));
        LOG.log(Level.INFO, PRELOADER_JAR_FILENAME + " = " + (ep.get(PRELOADER_JAR_FILENAME)==null ? "null" : ep.get(PRELOADER_JAR_FILENAME)));
        LOG.log(Level.INFO, PRELOADER_JAR_PATH + " = " + (ep.get(PRELOADER_JAR_PATH)==null ? "null" : ep.get(PRELOADER_JAR_PATH)));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy