bndtools.explorer.BndtoolsExplorer Maven / Gradle / Ivy
The newest version!
package bndtools.explorer;
import static org.eclipse.jface.layout.GridLayoutFactory.fillDefaults;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.bndtools.api.BndtoolsConstants;
import org.bndtools.build.api.AbstractBuildListener;
import org.bndtools.build.api.BuildListener;
import org.bndtools.core.ui.icons.Icons;
import org.bndtools.utils.swt.FilterPanelPart;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.FormText;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceRegistration;
import aQute.bnd.build.Workspace;
import aQute.bnd.exceptions.Exceptions;
import aQute.bnd.exceptions.FunctionWithException;
import aQute.lib.io.IO;
import bndtools.Plugin;
import bndtools.central.Central;
import bndtools.central.sync.WorkspaceSynchronizer;
import bndtools.editor.common.HelpButtons;
import bndtools.preferences.BndPreferences;
import bndtools.preferences.ui.BndPreferencePage;
public class BndtoolsExplorer extends PackageExplorerPart {
public static final String VIEW_ID = "bndtools.PackageExplorer";
static final ImageDescriptor warnImage = Icons.desc("warnings");
static final ImageDescriptor errorImage = Icons.desc("errors");
static final ImageDescriptor okImage = Icons.desc("allok");
static final BndPreferences preferences = new BndPreferences();
static final IWorkbench workbench = PlatformUI.getWorkbench();
private Model model = new Model();
private boolean installed;
private final List closeables = new ArrayList<>();
/**
* The GUI:
*
*
*
* parent
* explorer
* header
* toolbar
* status
* reload
* message
* filterControl
* original
*
*/
@Override
public void createPartControl(Composite parent) {
Composite explorer = new Composite(parent, SWT.NONE);
fillDefaults().spacing(2, 2)
.margins(4, 4)
.applyTo(explorer);
Composite header = doHeader(explorer);
FilterPanelPart filterPart = new FilterPanelPart(Plugin.getDefault()
.getScheduler());
Control filterControl = filterPart.createControl(explorer);
filterPart.setHint("Filter for projects (glob)");
model.onUpdate(() -> {
if (Objects.equals(model.filterText, filterPart.getFilter()))
return;
filterPart.getFilterControl()
.setText(model.filterText);
filterPart.setFilter(model.filterText);
});
super.createPartControl(explorer);
Control[] children = explorer.getChildren();
assert children.length > 2 : "Package explorer must have changed and added more than one control :-(";
Control original = children[2];
GridDataFactory.fillDefaults()
.grab(true, false)
.applyTo(filterControl);
GridDataFactory.fillDefaults()
.grab(true, true)
.applyTo(original);
GridDataFactory.fillDefaults()
.grab(true, false)
.applyTo(header);
fixupRefactoringPasteAction(filterPart);
PropertyChangeListener filterListener = e -> {
model.setFilterText((String) e.getNewValue());
};
filterPart.addPropertyChangeListener(filterListener);
model.onUpdate(() -> filterPart.setFilter(model.filterText));
closeables.add(() -> filterPart.removePropertyChangeListener(filterListener));
IWorkbenchWindow activeWorkbenchWindow = workbench.getActiveWorkbenchWindow();
IWorkbenchPage activePage = activeWorkbenchWindow.getActivePage();
IPartListener partListener = getPartListener();
activePage.addPartListener(partListener);
closeables.add(() -> activePage.removePartListener(partListener));
closeables.add(preferences.onPrompt(model::setPrompt));
ISelectionChangedListener evListener = (event) -> {
selected(event.getSelection());
};
getSite().getSelectionProvider()
.addSelectionChangedListener(evListener);
closeables.add(() -> getSite().getSelectionProvider()
.removeSelectionChangedListener(evListener));
model.onUpdate(this::updateTreeViewer);
model.update();
}
private Composite doHeader(Composite parent) {
ToolBarManager toolBarManager = new ToolBarManager(SWT.HORIZONTAL);
Composite header = new Composite(parent, SWT.NONE);
ToolBar toolbar = toolBarManager.createControl(header);
FormText message = new FormText(header, SWT.NONE);
message.setBackground(null);
message.addHyperlinkListener(new IHyperlinkListener() {
@Override
public void linkExited(HyperlinkEvent e) {}
@Override
public void linkEntered(HyperlinkEvent e) {}
@Override
public void linkActivated(HyperlinkEvent e) {
if ("prefs".equals(e.getHref())) {
PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(null, BndPreferencePage.PAGE_ID,
new String[] {}, null);
dialog.open();
} else {
try {
PlatformUI.getWorkbench()
.getBrowserSupport()
.getExternalBrowser()
.openURL(new URL((String) e.getHref()));
} catch (IOException | PartInitException e1) {
// ignore
}
}
}
});
model.onUpdate(() -> {
try {
message.setText(asForm(model.message), true, false);
} catch (Exception e) {
message.setText(asForm(model.message), false, false);
}
});
fillDefaults().numColumns(2)
.equalWidth(false)
.applyTo(header);
GridDataFactory.fillDefaults()
.grab(true, false)
.indent(0, 4)
.applyTo(message);
Action severity = severityAction();
toolBarManager.add(severity);
model.onUpdate(() -> {
ImageDescriptor descriptor = getImageDescriptor(model.severity);
severity.setImageDescriptor(descriptor);
toolBarManager.update(true);
});
buildListener();
Action reloadAction = reloadAction();
toolBarManager.add(reloadAction);
toolBarManager.update(true);
Action pin = pinAction();
toolBarManager.add(pin);
toolBarManager.update(true);
toolBarManager.add(HelpButtons.HELP_BTN_BNDTOOLS_EXPLORER);
toolBarManager.update(true);
return header;
}
@Override
public void dispose() {
model.close();
closeables.forEach(IO::close);
super.dispose();
}
@Override
public int tryToReveal(Object element) {
int result = super.tryToReveal(element);
afterReveal(element);
return result;
}
private void afterReveal(Object element) {
if (element instanceof IResource) {
model.setActualSelection(element);
model.setSelectedProject(getProject((IResource) element));
} else {
model.setActualSelection(null);
model.setSelectedProject(null);
}
}
@Override
public void selectAndReveal(Object element) {
super.selectAndReveal(element);
afterReveal(element);
}
@Override
public void selectReveal(ISelection selection) {
selected(selection);
super.selectReveal(selection);
}
private void selected(ISelection selection) {
if (selection instanceof IStructuredSelection) {
Object firstElement = ((IStructuredSelection) selection).getFirstElement();
if (firstElement instanceof IResource) {
model.setActualSelection(firstElement);
IProject project = getProject((IResource) firstElement);
if (project != null) {
model.setSelectedProject(project);
}
} else if (firstElement instanceof JavaProject) {
model.setActualSelection(((JavaProject) firstElement).getProject());
} else
model.setActualSelection(null);
}
}
private IProject getProject(IEditorInput iEditorInput) {
if (iEditorInput == null) {
return null;
}
if (iEditorInput instanceof IFileEditorInput) {
IResource resource = ((IFileEditorInput) iEditorInput).getFile();
return getProject(resource);
}
return null;
}
private IProject getProject(IResource resource) {
while (resource != null) {
if (resource instanceof IProject)
return (IProject) resource;
resource = resource.getParent();
}
return null;
}
private ImageDescriptor getImageDescriptor(int severity) {
switch (severity) {
case IMarker.SEVERITY_INFO :
return okImage;
case IMarker.SEVERITY_WARNING :
return warnImage;
case IMarker.SEVERITY_ERROR :
return errorImage;
}
return null;
}
private int getMaxSeverity() {
return Arrays.stream(ResourcesPlugin.getWorkspace()
.getRoot()
.getProjects())
.filter(IProject::isOpen)
.filter(p -> !Objects.equals(p.getName(), BndtoolsConstants.BNDTOOLS_JAREDITOR_TEMP_PROJECT_NAME))
.map(FunctionWithException.asFunction(p -> p.findMaxProblemSeverity(null, false, IResource.DEPTH_INFINITE)))
.reduce(IMarker.SEVERITY_INFO, Integer::max);
}
private void updateTreeViewer() {
if (!installed) {
installed = true;
installFilter();
model.filterDirty.set(true);
}
if (model.filterDirty.getAndSet(false))
getTreeViewer().refresh();
}
private void installFilter() {
getTreeViewer().addFilter(new ViewerFilter() {
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (model.glob == null)
return true;
if (element instanceof JavaProject) {
IJavaProject project = (JavaProject) element;
String name = project.getElementName();
return isSelected(project.getProject(), name);
} else if (element instanceof IProject) {
IProject project = (IProject) element;
String name = project.getName();
return isSelected(project, name);
} else
return true;
}
private boolean isSelected(IProject project, String name) {
if (project == model.selectedProject)
return true;
if (model.glob.finds(name) >= 0)
return true;
if (model.isPinned(project))
return true;
try {
int maxSeverity = project.findMaxProblemSeverity(null, false, IResource.DEPTH_INFINITE);
switch (maxSeverity) {
case 0 :
return false;
case IMarker.SEVERITY_ERROR :
return model.glob.finds(":error") >= 0;
case IMarker.SEVERITY_WARNING :
return model.glob.finds(":warning") >= 0;
}
} catch (CoreException e) {
// ignore
}
return false;
}
});
}
private Action reloadAction() {
Action rebuild = new Action("Reload workspace", Icons.desc("refresh")) {
WorkspaceSynchronizer s;
@Override
public void run() {
try {
Workspace workspace = Central.getWorkspace();
if (workspace.isDefaultWorkspace())
return;
setImageDescriptor(Icons.desc("refresh.disabled"));
setEnabled(false);
s = new WorkspaceSynchronizer();
Job syncjob = Job.create("Sync bnd workspace", monitor -> {
s.synchronize(true, monitor, this::done);
});
syncjob.setRule(ResourcesPlugin.getWorkspace()
.getRoot());
syncjob.schedule();
} catch (Exception e) {
throw Exceptions.duck(e);
}
}
private void done() {
Display.getDefault()
.asyncExec(() -> {
setEnabled(true);
setImageDescriptor(Icons.desc("refresh"));
});
}
};
return rebuild;
}
private Action pinAction() {
Action pin = new Action("Pin project", Icons.desc("pin.plus")) {
@Override
public void run() {
model.doPin();
}
};
Runnable runnable = () -> {
if (!(model.selection instanceof IProject)) {
pin.setImageDescriptor(Icons.desc("pin.disabled"));
pin.setEnabled(false);
return;
}
pin.setEnabled(true);
if (model.isPinned((IProject) model.selection)) {
pin.setImageDescriptor(Icons.desc("pin.minus"));
} else {
pin.setImageDescriptor(Icons.desc("pin.plus"));
}
};
runnable.run();
model.onUpdate(runnable);
return pin;
}
private void fixupRefactoringPasteAction(FilterPanelPart filterPart) {
IActionBars actionBars = getViewSite().getActionBars();
IAction originalPaste = actionBars.getGlobalActionHandler(ActionFactory.PASTE.getId());
actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(), new Action() {
@Override
public void runWithEvent(Event event) {
Text filterText = filterPart.getFilterControl();
if (Objects.equals(event.widget, filterText)) {
filterText.paste();
} else {
originalPaste.runWithEvent(event);
}
}
});
}
private void buildListener() {
BundleContext bundleContext = FrameworkUtil.getBundle(BndtoolsExplorer.class)
.getBundleContext();
BuildListener buildListener = new AbstractBuildListener() {
@Override
public void released(IProject project) {
model.setSeverity(getMaxSeverity());
model.updateMessage();
}
};
ServiceRegistration buildListenerRegistration = bundleContext
.registerService(BuildListener.class, buildListener, null);
closeables.add(buildListenerRegistration::unregister);
}
private Action severityAction() {
Action action = new Action("Build status", getImageDescriptor(IMarker.SEVERITY_INFO)) {
@Override
public void runWithEvent(Event event) {
switch (model.severity) {
case IMarker.SEVERITY_ERROR :
model.setFilterText(":error");
break;
case IMarker.SEVERITY_WARNING :
model.setFilterText(":warning");
break;
default :
}
}
};
return action;
}
private String asForm(String s) {
StringBuilder prompt = new StringBuilder();
prompt.append("");
return prompt.toString();
}
private IPartListener getPartListener() {
return new IPartListener() {
@Override
public void partOpened(IWorkbenchPart part) {}
@Override
public void partDeactivated(IWorkbenchPart part) {}
@Override
public void partClosed(IWorkbenchPart part) {
if (part instanceof IEditorPart) {
IProject selectedProject = getProject(((IEditorPart) part).getEditorInput());
model.closeProject(selectedProject);
}
}
@Override
public void partBroughtToTop(IWorkbenchPart part) {}
@Override
public void partActivated(IWorkbenchPart part) {
if (part instanceof IEditorPart) {
IProject selectedProject = getProject(((IEditorPart) part).getEditorInput());
model.setSelectedProject(selectedProject);
}
}
};
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy