blob: 5c84f8d66c89c1ab51e6416254b702d2c19564a9 [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.maven.nodes;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFileChooser;
import org.apache.maven.project.MavenProject;
import org.netbeans.api.annotations.common.StaticResource;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.api.project.ui.OpenProjects;
import org.netbeans.modules.maven.NbMavenProjectImpl;
import org.netbeans.modules.maven.actions.OpenPOMAction;
import org.netbeans.modules.maven.api.FileUtilities;
import org.netbeans.modules.maven.api.NbMavenProject;
import org.netbeans.modules.maven.model.ModelOperation;
import org.netbeans.modules.maven.model.pom.POMModel;
import static org.netbeans.modules.maven.nodes.Bundle.*;
import org.netbeans.modules.maven.spi.nodes.NodeUtils;
import org.netbeans.modules.project.ui.api.ProjectActionUtils;
import org.netbeans.spi.project.ui.LogicalViewProvider;
import org.netbeans.spi.project.ui.support.CommonProjectActions;
import org.netbeans.spi.project.ui.support.ProjectChooser;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.FilterNode;
import org.openide.nodes.Node;
import org.openide.util.ContextAwareAction;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.openide.util.RequestProcessor;
import org.openide.util.WeakListeners;
/**
* display the modules for pom packaged project
* @author Milos Kleint
*/
public class ModulesNode extends AbstractNode {
private static final @StaticResource String MODULES_BADGE = "org/netbeans/modules/maven/modules-badge.png";
private final NbMavenProjectImpl proj;
@Messages("LBL_Modules=Modules")
public ModulesNode(NbMavenProjectImpl proj) {
super(Children.create(new ModulesChildFactory(proj), true));
this.proj = proj;
setName("Modules"); //NOI18N
setDisplayName(LBL_Modules());
}
@Override
public Action[] getActions(boolean bool) {
return new Action[] {
new AddModuleAction(),
new CreateModuleAction()
};
}
private Image getIcon(boolean opened) {
Image badge = ImageUtilities.loadImage(MODULES_BADGE, true); //NOI18N
return ImageUtilities.mergeImages(NodeUtils.getTreeFolderIcon(opened), badge, 8, 8);
}
@Override
public Image getIcon(int type) {
return getIcon(false);
}
@Override
public Image getOpenedIcon(int type) {
return getIcon(true);
}
private static class Wrapper {
boolean isAggregator;
LogicalViewProvider provider;
NbMavenProjectImpl proj;
}
private static class ModulesChildFactory extends ChildFactory<Wrapper>{
private final NbMavenProjectImpl project;
private final PropertyChangeListener listener;
ModulesChildFactory(NbMavenProjectImpl proj) {
project = proj;
NbMavenProject watcher = project.getProjectWatcher();
listener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (NbMavenProject.PROP_PROJECT.equals(evt.getPropertyName())) {
refresh(false);
}
}
};
watcher.addPropertyChangeListener(WeakListeners.propertyChange(listener, watcher));
}
@Override
protected boolean createKeys(final List<Wrapper> modules) {
for (String module : project.getOriginalMavenProject().getModules()) {
File base = project.getOriginalMavenProject().getBasedir();
File projDir = FileUtil.normalizeFile(new File(base, module));
FileObject fo = FileUtil.toFileObject(projDir);
if (fo != null) {
try {
Project prj = ProjectManager.getDefault().findProject(fo);
if(prj == null) {
// issue #242542
// the projects pom might be already cached by ProjectManager as NO_SUCH_PROJECT,
// we have to get rid of that cached value.
// Would prefer a better place to call .clearNonProjectCache after a project was created,
// unfortunatelly .createKeys is invoked by a chain of events triggered by the poms save document
// - not sure how to hook before that, so that we can ensure that it isn't cached anymore.
// - on the other hand lets not clear the ProjectManager cache on each Node refresh.
ProjectManager.getDefault().clearNonProjectCache();
prj = ProjectManager.getDefault().findProject(fo);
}
if (prj != null && prj.getLookup().lookup(NbMavenProjectImpl.class) != null) {
Wrapper wr = new Wrapper();
wr.proj = (NbMavenProjectImpl) prj;
MavenProject mp = wr.proj.getOriginalMavenProject();
wr.isAggregator = NbMavenProject.TYPE_POM.equals(mp.getPackaging()) && !mp.getModules().isEmpty();
wr.provider = prj.getLookup().lookup(LogicalViewProvider.class);
assert wr.provider != null;
modules.add(wr);
}
} catch (IllegalArgumentException ex) {
ex.printStackTrace();//TODO log ?
} catch (IOException ex) {
ex.printStackTrace();//TODO log ?
}
} else {
//TODO broken module reference.. show as such..
}
}
return true;
}
@Override
protected Node createNodeForKey(Wrapper wr) {
return new ProjectFilterNode(project, wr.proj, wr.provider.createLogicalView(), wr.isAggregator);
}
}
private static class ProjectFilterNode extends FilterNode {
private final NbMavenProjectImpl project;
private final NbMavenProjectImpl parent;
ProjectFilterNode(NbMavenProjectImpl parent, NbMavenProjectImpl proj, Node original, boolean isAggregator) {
super(original, isAggregator ? Children.create(new ModulesChildFactory(proj), true) : Children.LEAF);
// disableDelegation(DELEGATE_GET_ACTIONS);
project = proj;
this.parent = parent;
}
@Override
public Action[] getActions(boolean b) {
ArrayList<Action> lst = new ArrayList<Action>();
lst.add(OpenProjectAction.SINGLETON);
lst.add(OpenPOMAction.instance());
lst.add(new RemoveModuleAction(parent, project));
// lst.addAll(Arrays.asList(super.getActions(b)));
return lst.toArray(new Action[lst.size()]);
}
@Override
public Action getPreferredAction() {
return OpenProjectAction.SINGLETON;
}
}
private static class RemoveModuleAction extends AbstractAction {
private final NbMavenProjectImpl project;
private final NbMavenProjectImpl parent;
@Messages("BTN_Remove_Module=Remove Module")
RemoveModuleAction(NbMavenProjectImpl parent, NbMavenProjectImpl proj) {
putValue(Action.NAME, BTN_Remove_Module());
project = proj;
this.parent = parent;
}
@Messages("MSG_Remove_Module=Do you want to remove the module from the parent POM?")
@Override public void actionPerformed(ActionEvent e) {
NotifyDescriptor nd = new NotifyDescriptor.Confirmation(MSG_Remove_Module(), NotifyDescriptor.YES_NO_OPTION);
Object ret = DialogDisplayer.getDefault().notify(nd);
if (ret == NotifyDescriptor.YES_OPTION) {
FileObject fo = FileUtil.toFileObject(parent.getPOMFile());
ModelOperation<POMModel> operation = new ModelOperation<POMModel>() {
@Override
public void performOperation(POMModel model) {
List<String> modules = model.getProject().getModules();
if (modules != null) {
for (String path : modules) {
File rel = new File(parent.getPOMFile().getParent(), path);
File norm = FileUtil.normalizeFile(rel);
FileObject folder = FileUtil.toFileObject(norm);
if (folder != null && folder.equals(project.getProjectDirectory())) {
model.getProject().removeModule(path);
break;
}
}
}
}
};
org.netbeans.modules.maven.model.Utilities.performPOMModelOperations(fo, Collections.singletonList(operation));
//TODO is the manual reload necessary if pom.xml file is being saved?
NbMavenProject.fireMavenProjectReload(project);
}
}
}
private static class OpenProjectAction extends AbstractAction implements ContextAwareAction {
static final OpenProjectAction SINGLETON = new OpenProjectAction();
private OpenProjectAction() {}
public @Override void actionPerformed(ActionEvent e) {
assert false;
}
@Messages("BTN_Open_Project=Open Project")
public @Override Action createContextAwareInstance(final Lookup context) {
return new AbstractAction(BTN_Open_Project()) {
public @Override void actionPerformed(ActionEvent e) {
Collection<? extends NbMavenProjectImpl> projects = context.lookupAll(NbMavenProjectImpl.class);
final NbMavenProjectImpl[] projectsArray = projects.toArray(new NbMavenProjectImpl[0]);
if(projectsArray.length > 0) {
RequestProcessor.getDefault().post(new Runnable() {
public @Override void run() {
OpenProjects.getDefault().open(projectsArray, false, true);
RequestProcessor.getDefault().post(new Runnable() {
public @Override void run() {
ProjectActionUtils.selectAndExpandProject(projectsArray[0]);
}
}, 500);
}
});
}
}
};
}
}
private class AddModuleAction extends AbstractAction {
@Messages("BTN_add_module=Add Existing Module...")
AddModuleAction() {
super(BTN_add_module());
}
@Override public void actionPerformed(ActionEvent e) {
JFileChooser c = ProjectChooser.projectChooser();
File basedir = FileUtil.toFile(proj.getProjectDirectory());
c.setCurrentDirectory(basedir);
if (c.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
return;
}
final List<String> mods = new ArrayList<String>();
for (File d : c.getSelectedFiles()) {
String mod = FileUtilities.relativizeFile(basedir, d);
if (mod != null && !mod.equals(".")) {
mods.add(mod);
}
}
if (mods.isEmpty()) {
return;
}
org.netbeans.modules.maven.model.Utilities.performPOMModelOperations(proj.getProjectDirectory().getFileObject("pom.xml"), Collections.singletonList(new ModelOperation<POMModel>() {
@Override public void performOperation(POMModel model) {
for (String mod : mods) {
model.getProject().addModule(mod);
}
}
}));
}
}
private class CreateModuleAction extends AbstractAction {
@Messages("BTN_create_module=Create New Module...")
CreateModuleAction() {
super(BTN_create_module());
}
@Override public void actionPerformed(ActionEvent e) {
Action act = CommonProjectActions.newProjectAction();
act.putValue("PRESELECT_CATEGORY" /*ProjectTemplates.PRESELECT_CATEGORY */, "Maven2");
act.putValue(CommonProjectActions.PROJECT_PARENT_FOLDER, proj.getPOMFile().getParentFile());
act.putValue("initialValueProperties", new String[] {"groupId", "version"});
act.putValue("groupId", proj.getOriginalMavenProject().getGroupId());
act.putValue("version", proj.getOriginalMavenProject().getVersion());
act.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "actionPerformed"));
}
}
}