blob: ec0ffce4b7ff8569a542f461bdd8cfdc75b25e48 [file] [log] [blame]
/*
* 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.Cursor;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.swing.SwingUtilities;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.ant.AntBuildExtender;
import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator;
import org.netbeans.spi.project.ProjectConfigurationProvider;
import org.netbeans.spi.project.ProjectServiceProvider;
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
import org.netbeans.spi.project.ui.ProjectOpenedHook;
import org.openide.awt.Notification;
import org.openide.awt.NotificationDisplayer;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.Parameters;
import org.openide.windows.WindowManager;
/**
*
* @author Tomas Zezula
* @author Petr Somol
* @author Anton Chechel
*/
@ProjectServiceProvider(service=ProjectOpenedHook.class, projectType={"org-netbeans-modules-java-j2seproject"}) // NOI18N
public final class JFXProjectOpenedHook extends ProjectOpenedHook {
private static final Logger LOGGER = Logger.getLogger("javafx"); // NOI18N
private final Project prj;
private final J2SEPropertyEvaluator eval;
private ConfigChangeListener chl = null;
private static final Map<String, List<Notification>> projectNotifications = new HashMap<String, List<Notification>>();
public JFXProjectOpenedHook(final Lookup lkp) {
Parameters.notNull("lkp", lkp); //NOI18N
this.prj = lkp.lookup(Project.class);
Parameters.notNull("prj", prj); //NOI18N
this.eval = lkp.lookup(J2SEPropertyEvaluator.class);
Parameters.notNull("eval", eval); //NOI18N
}
@Override
protected synchronized void projectOpened() {
if(!isFXProject(eval)) {
final JFXPlatformUpdater updater = prj.getLookup().lookup(JFXPlatformUpdater.class);
// replace Default_JavaFX_Platform by default Java Platform (since NB7.4)
final Runnable runUpdateJFXPlatform = updater != null ? new Runnable() {
@Override
public void run() {
updater.updateFXPlatform();
}
} : null;
if(runUpdateJFXPlatform != null) {
switchBusy();
runUpdateJFXPlatform.run();
switchDefault();
}
} else {
JFXProjectGenerator.logUsage(JFXProjectGenerator.Action.OPEN);
//hotfix for Bug 214819 - Completion list is corrupted after IDE upgrade
//http://netbeans.org/bugzilla/show_bug.cgi?id=214819
Preferences prefs = ProjectUtils.getPreferences(prj, Project.class, false);
prefs.put("issue214819_fx_enabled", "true"); //NOI18N
ProjectConfigurationProvider<?> pcp = prj.getLookup().lookup(ProjectConfigurationProvider.class);
assert pcp != null;
LOGGER.log(Level.INFO, "FX PCP: " + pcp.toString());
chl = new ConfigChangeListener(prj);
pcp.addPropertyChangeListener(chl);
final JFXPlatformUpdater updater = prj.getLookup().lookup(JFXPlatformUpdater.class);
// replace Default_JavaFX_Platform by default Java Platform (since NB7.4)
final Runnable runUpdateJFXPlatform = updater != null ? new Runnable() {
@Override
public void run() {
updater.updateFXPlatform();
}
} : null;
// and update FX build script file jfx-impl.xml if it is not in expected state
// #204765
// and create Default RunAs Configurations
// #204760
final Runnable runUpdateJFXImpl;
runUpdateJFXImpl = isEnabledJFXUpdate() ? new Runnable() {
@Override
public void run() {
updateDefaultConfigs();
FileObject readmeFO = updateJfxImpl();
if(readmeFO != null && isEnabledJFXUpdateNotification()) {
final String headerTemplate = NbBundle.getMessage(JFXProjectUtils.class, "TXT_UPDATED_README_FILE_CONTENT_HEADER"); //NOI18N
final String header = MessageFormat.format(headerTemplate, new Object[] {ProjectUtils.getInformation(prj).getDisplayName()});
final String content = NbBundle.getMessage(JFXProjectUtils.class, "TXT_UPDATED_NOTIFICATION_CONTENT"); //NOI18N
Notification noteUpdate = NotificationDisplayer.getDefault().notify(
header,
ImageUtilities.loadImageIcon("org/netbeans/modules/javafx2/project/ui/resources/jfx_project.png", true), //NOI18N
content,
null,
NotificationDisplayer.Priority.LOW,
NotificationDisplayer.Category.INFO);
addNotification(prj, noteUpdate);
}
}
} : null;
if(runUpdateJFXPlatform != null || runUpdateJFXImpl != null) {
switchBusy();
if(runUpdateJFXPlatform != null) {
runUpdateJFXPlatform.run();
}
if(runUpdateJFXImpl != null) {
runUpdateJFXImpl.run();
}
switchDefault();
}
}
}
public static void addNotification(@NonNull final Project project, @NonNull final Notification notification) {
synchronized(projectNotifications) {
final String path = project.getProjectDirectory().getPath();
List<Notification> notifications = projectNotifications.get(path);
if(notifications == null) {
notifications = new ArrayList<Notification>();
projectNotifications.put(path, notifications);
}
notifications.add(notification);
}
}
@Override
protected void projectClosed() {
if(isFXProject(eval)) {
JFXProjectGenerator.logUsage(JFXProjectGenerator.Action.CLOSE);
if(chl != null) {
ProjectConfigurationProvider<?> pcp = prj.getLookup().lookup(ProjectConfigurationProvider.class);
assert pcp != null;
pcp.removePropertyChangeListener(chl);
chl = null;
}
}
final String path = prj.getProjectDirectory().getPath();
List<Notification> notifications;
synchronized(projectNotifications) {
notifications = projectNotifications.get(path);
projectNotifications.remove(path);
}
if(notifications != null) {
for(Notification n : notifications) {
n.clear();
}
}
final JFXPlatformUpdater updater = prj.getLookup().lookup(JFXPlatformUpdater.class);
if(updater != null) {
updater.resetUpdated();
}
}
private boolean isEnabledJFXUpdate() {
final PropertyEvaluator evaluator = eval.evaluator();
if(evaluator != null) {
return !JFXProjectProperties.isTrue(evaluator.getProperty(JFXProjectProperties.JAVAFX_DISABLE_AUTOUPDATE));
} else {
LOGGER.log(Level.WARNING, "PropertyEvaluator instantiation failed, disabling jfx-impl.xml auto-update."); // NOI18N
}
return false;
}
private boolean isEnabledJFXUpdateNotification() {
final PropertyEvaluator evaluator = eval.evaluator();
if(evaluator != null) {
return !JFXProjectProperties.isTrue(evaluator.getProperty(JFXProjectProperties.JAVAFX_DISABLE_AUTOUPDATE_NOTIFICATION));
} else {
LOGGER.log(Level.WARNING, "PropertyEvaluator instantiation failed, disabling jfx-impl.xml auto-update notification."); // NOI18N
}
return false;
}
private FileObject updateJfxImpl() {
// this operation must be finished before any user
// action on this project involving Run, Build, Debug, etc.
FileObject readmeFO = null;
try {
final AntBuildExtender extender = prj.getLookup().lookup(AntBuildExtender.class);
if (extender == null) {
LOGGER.log(
Level.WARNING,
"The project {0} ({1}) does not support AntBuildExtender.", //NOI18N
new Object[] {
ProjectUtils.getInformation(prj).getDisplayName(),
FileUtil.getFileDisplayName(prj.getProjectDirectory())
});
} else {
// update jfx-impl.xml on project open only if build-impl extension version is compatible
if (extender.getExtension(JFXProjectUtils.getCurrentExtensionName()) != null) {
readmeFO = JFXProjectUtils.updateJfxImpl(prj);
}
}
} catch (Exception ex) {
LOGGER.log(Level.WARNING, "Can't update JavaFX specific build script jfx-impl.xml: {0}", ex); // NOI18N
}
return readmeFO;
}
private boolean updateDefaultConfigs() {
// this operation must be finished before any user
// action on this project involving Run, Build, Debug, etc.
boolean updated = false;
final PropertyEvaluator evaluator = eval.evaluator();
if(evaluator != null) {
try {
updated |= JFXProjectUtils.updateDefaultRunAsConfigFile(prj.getProjectDirectory(), JFXProjectProperties.RunAsType.ASWEBSTART, false);
updated |= JFXProjectUtils.updateDefaultRunAsConfigFile(prj.getProjectDirectory(), JFXProjectProperties.RunAsType.INBROWSER,
!JFXProjectProperties.isNonEmpty(evaluator.getProperty(JFXProjectProperties.RUN_IN_BROWSER)) ||
!JFXProjectProperties.isNonEmpty(evaluator.getProperty(JFXProjectProperties.RUN_IN_BROWSER_PATH)));
} catch (Exception ex) {
LOGGER.log(Level.WARNING, "Can't update JavaFX specific RunAs configuration files: {0}", ex); // NOI18N
}
} else {
LOGGER.log(Level.WARNING, "PropertyEvaluator instantiation failed, disabling jfx-impl.xml auto-update."); // NOI18N
}
return updated;
}
private void switchBusy() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
});
}
private void switchDefault() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
});
}
private static final class ConfigChangeListener implements PropertyChangeListener {
private final Project prj;
public ConfigChangeListener(Project p) {
this.prj = p;
}
@Override public void propertyChange(PropertyChangeEvent evt) {
if(evt.getPropertyName().equals(ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE)) {
LOGGER.log(Level.FINE, "FX config change: " + evt.toString()); // NOI18N
final Lookup look = prj.getLookup();
JFXProjectProperties props = JFXProjectProperties.getInstanceIfExists(look);
if(props == null || props.hasPreloaderInAnyConfig()) {
boolean propsDidNotExist = props == null;
JFXProjectProperties.cleanup(look);
props = JFXProjectProperties.getInstance(look);
props.updatePreloaderDependencies();
if(propsDidNotExist) {
JFXProjectProperties.cleanup(look);
}
}
}
}
}
private static boolean isFXProject(@NonNull final J2SEPropertyEvaluator eval) {
if (eval == null) {
return false;
}
//Don't use JFXProjectProperties.isTrue to prevent JFXProjectProperties from being loaded
//JFXProjectProperties.JAVAFX_ENABLED is inlined by compliler
return isTrue(eval.evaluator().getProperty(JFXProjectProperties.JAVAFX_ENABLED));
}
private static boolean isTrue(@NullAllowed final String value) {
return value != null && (
"true".equalsIgnoreCase(value) || //NOI18N
"yes".equalsIgnoreCase(value) || //NOI18N
"on".equalsIgnoreCase(value)); //NOI18N
}
}