blob: 4ff8a2dc684a3e0fbd2ce27c6b921e56095c8170 [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.php.project;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.io.InputStream;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.modules.php.project.connections.ConfigManager;
import org.netbeans.modules.php.project.util.PhpProjectUtils;
import org.netbeans.spi.project.ActionProvider;
import org.netbeans.spi.project.ProjectConfiguration;
import org.netbeans.spi.project.ProjectConfigurationProvider;
import org.netbeans.spi.project.support.ant.EditableProperties;
import org.openide.filesystems.FileChangeAdapter;
import org.openide.filesystems.FileChangeListener;
import org.openide.filesystems.FileEvent;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileRenameEvent;
import org.openide.filesystems.FileUtil;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
/**
* Manages configurations for a PHP project (copy/pasted from Java SE project).
* @author Jesse Glick, Radek Matous
*/
public final class PhpConfigurationProvider implements ProjectConfigurationProvider<PhpConfigurationProvider.Config> {
private static final Logger LOGGER = Logger.getLogger(PhpConfigurationProvider.class.getName());
/**
* Ant property name for active config.
*/
public static final String PROP_CONFIG = "config"; // NOI18N
/**
* Ant property file which specified active config.
*/
public static final String CONFIG_PROPS_PATH = "nbproject/private/config.properties"; // NOI18N
public static final class Config implements ProjectConfiguration {
/** The file basename, or <code>null</code> for default config. */
public final String name;
private final String displayName;
public Config(String name, String displayName) {
this.name = name;
this.displayName = displayName;
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
@Override
public boolean equals(Object o) {
return (o instanceof Config) && Utilities.compareObjects(name, ((Config) o).name);
}
@Override
public String toString() {
return "PhpConfigurationProvider.Config[" + name + "," + displayName + "]"; // NOI18N
}
}
private static final Config DEFAULT = new Config(null,
NbBundle.getMessage(PhpConfigurationProvider.class, "LBL_DefaultConfiguration"));
private final PhpProject project;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private final FileChangeListener fcl = new FileChangeAdapter() {
@Override
public void fileFolderCreated(FileEvent fe) {
update(fe);
}
@Override
public void fileDataCreated(FileEvent fe) {
update(fe);
}
@Override
public void fileDeleted(FileEvent fe) {
update(fe);
}
@Override
public void fileRenamed(FileRenameEvent fe) {
update(fe);
}
private void update(FileEvent ev) {
LOGGER.log(Level.FINEST, "Received {0}", ev);
Set<String> oldConfigs = configs != null ? configs.keySet() : Collections.<String>emptySet();
configDir = project.getProjectDirectory().getFileObject("nbproject/configs"); // NOI18N
if (configDir != null) {
configDir.removeFileChangeListener(fclWeak);
configDir.addFileChangeListener(fclWeak);
LOGGER.log(Level.FINEST, "(Re-)added listener to {0}", configDir);
} else {
LOGGER.log(Level.FINEST, "No nbproject/configs exists");
}
calculateConfigs();
Set<String> newConfigs = configs.keySet();
if (!oldConfigs.equals(newConfigs)) {
LOGGER.log(Level.FINER, "Firing " + ProjectConfigurationProvider.PROP_CONFIGURATIONS + ": {0} -> {1}", new Object[]{oldConfigs, newConfigs});
pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATIONS, null, null);
// XXX also fire PROP_ACTIVE_CONFIGURATION?
}
}
};
private final FileChangeListener fclWeak;
private FileObject configDir;
private Map<String, Config> configs;
private final FileObject nbp;
public PhpConfigurationProvider(PhpProject project) {
this.project = project;
fclWeak = FileUtil.weakFileChangeListener(fcl, null);
nbp = project.getProjectDirectory().getFileObject("nbproject"); // NOI18N
if (nbp != null) {
nbp.addFileChangeListener(fclWeak);
LOGGER.log(Level.FINEST, "Added listener to {0}", nbp);
configDir = nbp.getFileObject("configs"); // NOI18N
if (configDir != null) {
configDir.addFileChangeListener(fclWeak);
LOGGER.log(Level.FINEST, "Added listener to {0}", configDir);
}
}
project.getEvaluator().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (PROP_CONFIG.equals(evt.getPropertyName())) {
LOGGER.log(Level.FINER, "Refiring " + PROP_CONFIG + " -> " + ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE);
pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE, null, null);
}
}
});
}
private void calculateConfigs() {
configs = new HashMap<>();
if (configDir != null) {
for (FileObject kid : configDir.getChildren()) {
if (!kid.hasExt("properties")) {
continue;
}
try {
try (InputStream is = kid.getInputStream()) {
Properties p = new Properties();
p.load(is);
String name = kid.getName();
String label = p.getProperty(ConfigManager.PROP_DISPLAY_NAME);
configs.put(name, new Config(name, label != null ? label : name));
}
} catch (IOException x) {
LOGGER.log(Level.INFO, null, x);
}
}
}
LOGGER.log(Level.FINEST, "Calculated configurations: {0}", configs);
}
@Override
public Collection<Config> getConfigurations() {
calculateConfigs();
List<Config> l = new ArrayList<>();
l.addAll(configs.values());
Collections.sort(l, new Comparator<Config>() {
Collator c = Collator.getInstance();
@Override
public int compare(Config c1, Config c2) {
return c.compare(c1.getDisplayName(), c2.getDisplayName());
}
});
l.add(0, DEFAULT);
return l;
}
@Override
public Config getActiveConfiguration() {
calculateConfigs();
String config = project.getEvaluator().getProperty(PROP_CONFIG);
if (config != null && configs.containsKey(config)) {
return configs.get(config);
} else {
return DEFAULT;
}
}
@Override
public void setActiveConfiguration(Config c) throws IOException {
if (c != DEFAULT && !configs.values().contains(c)) {
throw new IllegalArgumentException();
}
final String n = c.name;
EditableProperties ep = project.getHelper().getProperties(CONFIG_PROPS_PATH);
if (Utilities.compareObjects(n, ep.getProperty(PROP_CONFIG))) {
return;
}
if (n != null) {
ep.setProperty(PROP_CONFIG, n);
} else {
ep.remove(PROP_CONFIG);
}
project.getHelper().putProperties(CONFIG_PROPS_PATH, ep);
pcs.firePropertyChange(ProjectConfigurationProvider.PROP_CONFIGURATION_ACTIVE, null, null);
ProjectManager.getDefault().saveProject(project);
assert project.getProjectDirectory().getFileObject(CONFIG_PROPS_PATH) != null;
}
@Override
public boolean hasCustomizer() {
return true;
}
@Override
public void customize() {
PhpProjectUtils.openCustomizerRun(project);
}
@Override
public boolean configurationsAffectAction(String command) {
return command.equals(ActionProvider.COMMAND_RUN)
|| command.equals(ActionProvider.COMMAND_DEBUG);
}
@Override
public void addPropertyChangeListener(PropertyChangeListener lst) {
pcs.addPropertyChangeListener(lst);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener lst) {
pcs.removePropertyChangeListener(lst);
}
}