/**
* Copyright (C) 2015 drrb
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.drrb.rust.netbeans.project;
import com.github.drrb.rust.netbeans.project.logicalview.RustProjectNode;
import com.github.drrb.rust.netbeans.cargo.CargoConfig;
import com.github.drrb.rust.netbeans.project.action.RustProjectActionProvider;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.nio.file.Path;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import org.netbeans.api.annotations.common.StaticResource;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectInformation;
import org.netbeans.spi.project.ProjectState;
import org.netbeans.spi.project.support.LookupProviderSupport;
import org.netbeans.spi.project.ui.LogicalViewProvider;
import org.netbeans.spi.project.ui.support.UILookupMergerSupport;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataFolder;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.Exceptions;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.lookup.Lookups;
/**
*
*/
public class RustProject implements Project {
private static final Logger LOGGER = Logger.getLogger(RustProject.class.getName());
public static final String TYPE = "com-github-drrb-rust-netbeans-project";
// Has things in it that are registered as @ProjectServiceProviders (e.g. Sources implementations)
private static final String PROJECT_LOOKUP_NAME = String.format("Projects/%s/Lookup", TYPE);
@StaticResource
public static final String RUST_PROJECT_ICON = "com/github/drrb/rust/netbeans/rust-icon_16x16.png";
private final FileObject projectDirectory;
private final ProjectState state;
public RustProject(FileObject projectDirectory, ProjectState state) {
this.projectDirectory = projectDirectory;
this.state = state;
}
@Override
public FileObject getProjectDirectory() {
return projectDirectory;
}
public File dir() {
return new File(projectDirectory.getPath());
}
@Override
public Lookup getLookup() {
Lookup baseLookup = Lookups.fixed(
this, // So people can cast it without casting it, you know?
new Info(),
new LogicalView(),
new RustProjectActionProvider(this),
LookupProviderSupport.createSourcesMerger(), // Gets implementations of Sources from named lookup below
//TODO: saw this in Maven project. What does it do?
//ProjectClassPathModifier.extenderForModifier(this), // Gets implementations of ProjectClassPathModifierImplementation from the named lookup below
UILookupMergerSupport.createProjectOpenHookMerger(null) // Gets implementations of ProjectOpenedHook from named lookup below
);
// Provides Mergers in the base lookup with implementations from the Projects/TYPE/Lookup lookup (e.g. Sources implementations)
return LookupProviderSupport.createCompositeLookup(baseLookup, PROJECT_LOOKUP_NAME);
}
public CargoConfig getCargoConfig() {
return new CargoConfig(projectDirectory);
}
private class Info implements ProjectInformation {
@Override
public String getName() {
return projectDirectory.getName();
}
@Override
public String getDisplayName() {
String packageName = getCargoConfig().getPackageName();
if (packageName == null) {
LOGGER.log(Level.WARNING, "Failed to load project name from Cargo config");
packageName = getName();
}
return packageName;
}
@Override
public Icon getIcon() {
return ImageUtilities.loadImageIcon(RUST_PROJECT_ICON, false);
}
@Override
public Project getProject() {
return RustProject.this;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
}
}
private class LogicalView implements LogicalViewProvider {
@Override
public Node createLogicalView() {
//TODO: test this!
//TODO: remove these comments if necessary
try {
//Obtain the project directory's node:
FileObject projectDirectory = getProjectDirectory();
DataFolder projectFolder = DataFolder.findFolder(projectDirectory);
Node nodeOfProjectFolder = projectFolder.getNodeDelegate();
//Decorate the project directory's node:
return new RustProjectNode(nodeOfProjectFolder, RustProject.this);
} catch (DataObjectNotFoundException e) {
Exceptions.printStackTrace(e);
//Fallback-the directory couldn't be created -
//read-only filesystem or something evil happened
return new AbstractNode(Children.LEAF);
}
}
@Override
public Node findPath(Node root, Object target) {
return null;
}
}
}