/*******************************************************************************
* Copyright (c) 2012, 2016, 2017 PDT Extension Group and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* PDT Extension Group - initial API and implementation
* Kaloyan Raev - [501269] externalize strings
* Kaloyan Raev - [501591] No scroll in the package area when creating a project
* Kaloyan Raev - [513981] Sync issue with filtering packages
*******************************************************************************/
package org.eclipse.php.composer.ui.wizard.project.template;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.eclipse.equinox.internal.p2.ui.discovery.util.ControlListItem;
import org.eclipse.equinox.internal.p2.ui.discovery.util.ControlListViewer;
import org.eclipse.equinox.internal.p2.ui.discovery.util.FilteredViewer;
import org.eclipse.equinox.internal.p2.ui.discovery.wizards.DiscoveryResources;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.osgi.util.NLS;
import org.eclipse.php.composer.api.MinimalPackage;
import org.eclipse.php.composer.api.packages.AsyncPackagistSearch;
import org.eclipse.php.composer.api.packages.PackageSearchListenerInterface;
import org.eclipse.php.composer.api.packages.SearchResult;
import org.eclipse.php.composer.core.log.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
/**
*
* @author Robert Gruendler <r.gruendler@gmail.com>
*
*/
public class PackageFilterViewer extends FilteredViewer implements PackageFilterChangedListener {
protected final static Object[] EMTPY = new Object[0];
private DiscoveryResources resources;
private Button showProjectsCheckbox;
private PackagistContentProvider contentProvider;
private PackageFilterItem currentSelection = null;
private List<PackageFilterChangedListener> listeners = new ArrayList<PackageFilterChangedListener>();
private Label searchResultCount;
private String lastQuery;
@Override
public void createControl(Composite parent) {
super.createControl(parent);
doFind(""); //$NON-NLS-1$
}
public void addChangeListener(PackageFilterChangedListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
@Override
protected StructuredViewer doCreateViewer(Composite container) {
resources = new DiscoveryResources(getControl().getDisplay());
StructuredViewer viewer = new ControlListViewer(container, SWT.BORDER) {
@Override
protected ControlListItem<?> doCreateItem(Composite parent, Object element) {
return doCreateViewerItem(parent, element);
}
};
viewer.setContentProvider(contentProvider = new PackagistContentProvider());
searchResultCount = new Label(container, SWT.NONE);
GridDataFactory.fillDefaults().grab(true, false).span(3, 1).align(SWT.BEGINNING, SWT.CENTER)
.hint(400, SWT.DEFAULT).applyTo(searchResultCount);
return viewer;
}
@Override
protected void doCreateHeaderControls(Composite parent) {
showProjectsCheckbox = new Button(parent, SWT.CHECK);
showProjectsCheckbox.setSelection(true);
showProjectsCheckbox.setText(Messages.PackageFilterViewer_ProjectsOnlyLabel);
showProjectsCheckbox.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
public void widgetSelected(SelectionEvent e) {
doFind(getFilterText());
}
});
}
protected ControlListItem<?> doCreateViewerItem(Composite parent, Object element) {
if (element instanceof PackageFilterItem) {
PackagistItem packagistItem = new PackagistItem(parent, SWT.NONE, resources, (PackageFilterItem) element);
packagistItem.addFilterChangedListener(this);
return packagistItem;
}
return null;
}
@Override
protected void doFind(String text) {
try {
lastQuery = text;
contentProvider.clear();
viewer.setInput(contentProvider.packages);
viewer.refresh();
AsyncPackagistSearch search = new AsyncPackagistSearch();
search.addPackageSearchListener(new PackageSearchListenerInterface() {
@Override
public void errorOccured(Exception e) {
}
@Override
public void aborted(String url) {
}
@Override
public void packagesFound(List<MinimalPackage> packages, final String query, final SearchResult result) {
if (packages != null) {
final List<PackageFilterItem> items = new ArrayList<PackageFilterItem>();
for (MinimalPackage pkg : packages) {
items.add(new PackageFilterItem(pkg));
}
getControl().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
if (viewer.getControl().isDisposed()) {
return;
}
if (!Objects.equals(query, lastQuery)) {
// this data is already obsolete
return;
}
contentProvider.add(items);
viewer.refresh();
viewer.getControl().requestLayout();
searchResultCount
.setText(NLS.bind(Messages.PackageFilterViewer_PackagesFound, result.total));
}
});
}
}
});
if (showProjectsCheckbox.getSelection()) {
search.setFilter("project"); //$NON-NLS-1$
}
if (!text.trim().isEmpty()) {
search.search(text);
}
} catch (Exception e) {
Logger.logException(e);
}
}
protected static class PackagistContentProvider implements ITreeContentProvider {
private List<PackageFilterItem> packages;
public void dispose() {
packages = null;
}
public Object[] getChildren(Object parentElement) {
return null;
}
public Object[] getElements(Object inputElement) {
if (packages != null) {
List<Object> elements = new ArrayList<Object>();
elements.addAll(packages);
return elements.toArray(new Object[elements.size()]);
}
return EMTPY;
}
public Object getParent(Object element) {
if (element instanceof PackageFilterItem) {
return packages;
}
return null;
}
public boolean hasChildren(Object element) {
if (element instanceof PackageFilterItem) {
return false;
}
if (packages != null) {
return packages.size() > 0;
}
return false;
}
public void add(List<PackageFilterItem> items) {
if (packages != null && items != null) {
packages.addAll(items);
}
}
public void clear() {
packages = new ArrayList<PackageFilterItem>();
}
@SuppressWarnings("unchecked")
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
packages = (List<PackageFilterItem>) newInput;
}
}
public PackageFilterItem getSelectedPackage() {
for (PackageFilterItem item : contentProvider.packages) {
if (item.isChecked()) {
return item;
}
}
return null;
}
@Override
public void filterChanged(PackageFilterItem item) {
if (currentSelection != null) {
if (item == currentSelection) {
fireEvent(item);
return;
}
}
List<PackageFilterItem> input = (List<PackageFilterItem>) viewer.getInput();
if (!item.isChecked()) {
return;
}
for (PackageFilterItem filterItem : input) {
if (filterItem == item) {
continue;
}
filterItem.setChecked(false);
}
ScrolledComposite control = (ScrolledComposite) viewer.getControl();
Point origin = control.getOrigin();
viewer.refresh();
control.setOrigin(origin);
fireEvent(item);
}
protected void fireEvent(PackageFilterItem item) {
for (PackageFilterChangedListener listener : listeners) {
listener.filterChanged(item);
}
currentSelection = item;
}
}