Java tutorial
/* * uDig - User Friendly Desktop Internet GIS client * http://udig.refractions.net * (C) 2012, Refractions Research Inc. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). */ package org.locationtech.udig.catalog.ui.search; import java.io.IOException; import java.net.URL; import java.text.MessageFormat; import java.util.Arrays; import java.util.List; import org.locationtech.udig.aoi.IAOIService; import org.locationtech.udig.catalog.CatalogPlugin; import org.locationtech.udig.catalog.ICatalog; import org.locationtech.udig.catalog.ICatalogInfo; import org.locationtech.udig.catalog.IGeoResource; import org.locationtech.udig.catalog.IGeoResourceInfo; import org.locationtech.udig.catalog.IResolve; import org.locationtech.udig.catalog.IResolveChangeEvent; import org.locationtech.udig.catalog.IResolveChangeEvent.Type; import org.locationtech.udig.catalog.IResolveChangeListener; import org.locationtech.udig.catalog.ISearch; import org.locationtech.udig.catalog.IService; import org.locationtech.udig.catalog.IServiceInfo; import org.locationtech.udig.catalog.internal.ui.ImageConstants; import org.locationtech.udig.catalog.ui.CatalogTreeViewer; import org.locationtech.udig.catalog.ui.CatalogUIPlugin; import org.locationtech.udig.catalog.ui.ResolveContentProvider; import org.locationtech.udig.catalog.ui.ResolveLabelProviderSimple; import org.locationtech.udig.catalog.ui.ResolveTitlesDecorator; import org.locationtech.udig.catalog.ui.StatusLineMessageBoardAdapter; import org.locationtech.udig.catalog.ui.internal.Messages; import org.locationtech.udig.internal.ui.UiPlugin; import org.locationtech.udig.ui.PlatformGIS; import org.locationtech.udig.ui.SearchPart; import org.locationtech.udig.ui.UDIGDragDropUtilities; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.DecoratingLabelProvider; import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.part.PageBook; import com.vividsolutions.jts.geom.Envelope; /** * Search view is a distinct, simple implementation focused on Catalog searches. * <p> * We are unable to make use of the usual eclipse search facilities (ie * org.eclipse.search.searchPages) as this would cause our application to be dependent on * org.eclipse.core.resources - aka IResource. This would represent a signigicant jump in download * size etc... * </p> * <p> * Of Note: * <ul> * <li>At this time Search only works against the Local Catalog * <li>As more Catalogs are implemented they will be made available in a manner similar to existing * Filter specification. * </ul> * </p> */ public class SearchView extends SearchPart { /** ID for this view */ public static final String VIEW_ID = "org.locationtech.udig.catalog.ui.search.searchView"; //$NON-NLS-1$ public Text text; private Button bbox; private Label label; /** Cache for info used by details */ private Info cache; private Text summary; private PageBook book; private Action refreshAction; /** * @param dialogSettings */ public SearchView() { super(CatalogUIPlugin.getDefault().getDialogSettings()); } static class Query { String text; // match against everything we can Envelope bbox; // latlong bbox List<ISearch> scope; // list of catalogs to search } @Override protected void setOrientation(Orientation orientation) { super.setOrientation(orientation); if (splitter.getOrientation() == SWT.HORIZONTAL) { label.setText(Messages.SearchView_prompt); //bbox.setText(Messages.SearchView_bbox); } else { label.setText(""); //$NON-NLS-1$ //bbox.setText(""); //$NON-NLS-1$ } parent.layout(); } @Override public void createPartControl(Composite aParent) { label = new Label(aParent, SWT.NONE); label.setText(Messages.SearchView_prompt); text = new Text(aParent, SWT.BORDER); text.setText(Messages.SearchView_default); text.setEditable(true); text.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { search(createQuery()); // search according to filter } public void widgetSelected(SelectionEvent e) { quick(text.getText()); } }); // Create bbox button // bbox = new Button(aParent, SWT.CHECK); // bbox.setText(Messages.SearchView_bbox); // bbox.setToolTipText(Messages.SearchView_bboxTooltip); // bbox.setSelection(true); super.createPartControl(aParent); // Layout using Form Layout (+ indicates FormAttachment) // + // +label+text+bbox+ // + // contents // + FormLayout layout = new FormLayout(); layout.marginHeight = 0; layout.marginWidth = 0; layout.spacing = 0; aParent.setLayout(layout); FormData dLabel = new FormData(); // bind to left & text dLabel.left = new FormAttachment(0); dLabel.top = new FormAttachment(text, 5, SWT.CENTER); label.setLayoutData(dLabel); FormData dText = new FormData(); // bind to top, label, bbox dText.top = new FormAttachment(1); dText.left = new FormAttachment(label, 5); dText.right = new FormAttachment(100); text.setLayoutData(dText); FormData dBbox = new FormData(); // text & right dBbox.right = new FormAttachment(100); dBbox.top = new FormAttachment(text, 0, SWT.CENTER); //bbox.setLayoutData(dBbox); FormData dsashForm = new FormData(100, 100); // text & bottom dsashForm.right = new FormAttachment(100); // bind to right of form dsashForm.left = new FormAttachment(0); // bind to left of form dsashForm.top = new FormAttachment(text, 2); // attach with 5 pixel offset dsashForm.bottom = new FormAttachment(100); // bind to bottom of form splitter.setWeights(new int[] { 60, 40 }); splitter.setLayoutData(dsashForm); createContextMenu(); } @Override protected void initDragAndDrop() { UDIGDragDropUtilities.addDragSupport(this.viewer.getControl(), viewer); } @Override protected Composite createDetails(SashForm parent) { book = new PageBook(parent, SWT.NONE); summary = new Text(book, SWT.V_SCROLL | SWT.READ_ONLY | SWT.WRAP | SWT.BORDER); summary.setText(""); //$NON-NLS-1$ Color white = new Color(parent.getDisplay(), 255, 255, 255); summary.setBackground(white); white.dispose(); CatalogPlugin.addListener(sync); book.showPage(summary); return book; } IResolveChangeListener sync = new IResolveChangeListener() { public void changed(IResolveChangeEvent event) { // changes made to the search results reported in the event final IResolve res = event.getResolve(); Type type = event.getType(); // we only care about changes to it if (type != IResolveChangeEvent.Type.POST_CHANGE) { return; } if (res == null) { return; } if (Display.getCurrent() == null) { Display.getDefault().asyncExec(new Runnable() { public void run() { refresh(res); } }); } else { refresh(res); } } /** * Attempts to resolve the URL from the IResolve parameter If cached data shares same URL * with changed data found, and the Info can be resolved,then we update the cached data and * redraw the infoDisplay text field. * * @param res */ private void refresh(IResolve res) { URL resolveURL = res.getIdentifier(); URL cachedURL = null; if (cache != null) { cachedURL = cache.getId(); } if (resolveURL != null && resolveURL.equals(cachedURL)) { if (res.canResolve(ICatalogInfo.class)) { try { showInfo(new Info(cache.getId(), res.resolve(ICatalogInfo.class, searchMonitor))); } catch (IOException e) { CatalogUIPlugin.log(null, e); } } if (res.canResolve(IServiceInfo.class)) { try { showInfo(new Info(cache.getId(), res.resolve(IServiceInfo.class, searchMonitor))); } catch (IOException e) { CatalogUIPlugin.log(null, e); } } if (res.canResolve(IGeoResourceInfo.class)) { try { showInfo(new Info(cache.getId(), res.resolve(IGeoResourceInfo.class, searchMonitor))); } catch (IOException e) { CatalogUIPlugin.log(null, e); } } } }// end refresh }; private boolean aoiFilter; private void createContextMenu() { final MenuManager contextMenu = new MenuManager(); refreshAction = new Action() { public void run() { IStructuredSelection sel = (IStructuredSelection) viewer.getSelection(); sel.getFirstElement(); viewer.refresh(); } }; Messages.initAction(refreshAction, "action_refresh"); //$NON-NLS-1$ contextMenu.setRemoveAllWhenShown(true); contextMenu.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager mgr) { contextMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); contextMenu.add(new Separator()); refreshAction.setImageDescriptor( CatalogUIPlugin.getDefault().getImageDescriptor(ImageConstants.REFRESH_CO)); // contextMenu.add(refreshAction); IWorkbenchWindow window = getSite().getWorkbenchWindow(); IAction action = ActionFactory.IMPORT.create(window); contextMenu.add(action); contextMenu.add(new Separator()); contextMenu .add(UiPlugin.getDefault().getOperationMenuFactory().getContextMenu(viewer.getSelection())); } }); // Create menu. Menu menu = contextMenu.createContextMenu(viewer.getControl()); viewer.getControl().setMenu(menu); // Register menu for extension. getSite().registerContextMenu(contextMenu, viewer); } @Override protected StructuredViewer createViewer(Composite parent) { CatalogTreeViewer catalogTreeViewer = new CatalogTreeViewer(parent, true); catalogTreeViewer.setMessageBoard( new StatusLineMessageBoardAdapter(getViewSite().getActionBars().getStatusLineManager())); return catalogTreeViewer; } /** * Construct a query based on the state of the user interface controls, and possibly workbecnh. * * @return A catalog query */ Query createQuery() { Query filter = new Query(); filter.text = text.getText(); filter.bbox = new Envelope(); //if (bbox.getSelection()) { boolean aoiFilter2 = isAOIFilter(); if (aoiFilter2) { IAOIService aOIService = PlatformGIS.getAOIService(); try { filter.bbox = aOIService.getExtent(); } catch (Throwable t) { CatalogUIPlugin.log("Unable to create search:" + t, t); //$NON-NLS-1$ } } return filter; } @Override protected IBaseLabelProvider createLabelProvider() { ResolveLabelProviderSimple base = new ResolveLabelProviderSimple(); return new DecoratingLabelProvider(base, new ResolveTitlesDecorator(base)); } protected void showInfo(Info info) { book.showPage(summary); if (cache != null) { if (info.getId().equals(cache.getId())) { return; } } cache = info; summary.setText(""); //$NON-NLS-1$ URL url = cache.getId(); String serverName = ""; //$NON-NLS-1$ if (url != null) { serverName = url.getHost(); // summary.append("Server: " + serverName + "\n\n"); } if (cache.title != null && !(cache.title.equals(""))) { //$NON-NLS-1$ summary.append(MessageFormat.format(Messages.SearchView_title, new Object[] { cache.title }) + "\n\n"); //$NON-NLS-1$ } if (cache.name != null && !(cache.name.equals(""))) { //$NON-NLS-1$ summary.append(MessageFormat.format(Messages.SearchView_name, new Object[] { cache.name, serverName }) + ")\n\n"); //$NON-NLS-1$ } else { if (serverName != null && !serverName.equals("")) { //$NON-NLS-1$ summary.append( MessageFormat.format(Messages.SearchView_server, new Object[] { serverName }) + "\n\n"); //$NON-NLS-1$ } } if (cache.keys != null && cache.keys.length > 0) { summary.append(Messages.SearchView_keywords); for (int i = 0; i < cache.keys.length; i++) { String keyword = cache.keys[i]; keyword = keyword == null ? null : keyword.trim(); if (keyword != null && !(keyword).equalsIgnoreCase("")) { //$NON-NLS-1$ if (i == cache.keys.length - 1) { summary.append(keyword + "\n\n"); //$NON-NLS-1$ } else { summary.append(keyword + ", "); //$NON-NLS-1$ } } } } if (cache.description != null && !(cache.description.equals(""))) { //$NON-NLS-1$ summary.append( MessageFormat.format(Messages.SearchView_description, new Object[] { cache.description })); } } @Override protected void showDetail(Object selection) { if (!(selection instanceof IResolve)) { return; } IResolve record = (IResolve) selection; if (record instanceof ICatalog) { ICatalog catalog = (ICatalog) record; try { ICatalogInfo info = catalog.getInfo(searchMonitor); showInfo(new Info(catalog.getIdentifier(), info)); } catch (IOException e) { CatalogUIPlugin.log("No information for catalog", e); //$NON-NLS-1$ } } else if (record instanceof IService) { IService service = (IService) record; IServiceInfo info; try { info = service.getInfo(searchMonitor); showInfo(new Info(service.getIdentifier(), info)); } catch (IOException e) { CatalogUIPlugin.log("No information for service", e); //$NON-NLS-1$ } } else if (record instanceof IGeoResource) { IGeoResource layer = (IGeoResource) record; try { IGeoResourceInfo info = layer.getInfo(searchMonitor); showInfo(new Info(layer.getIdentifier(), info)); } catch (IOException e) { CatalogUIPlugin.log("No information for layer", e); //$NON-NLS-1$ } } } protected IStructuredContentProvider createContentProvider() { return new ResolveContentProvider(); } /** Status message ... */ public void setStatus(String message) { // change book to status and show message } /** * Search the catalog for text and update view contents * * @param pattern */ @Override protected void searchImplementation(Object filter, IProgressMonitor monitor, ResultSet results) { Query query = (Query) filter; if (query == null) return; if ((query.bbox == null || query.bbox.isNull()) && (query.text == null || query.text.trim().length() == 0)) { return; // no actual query } if (query.bbox == null) { query.bbox = new Envelope(); } if (query.scope == null) { query.scope = Arrays.asList(CatalogPlugin.getDefault().getCatalogs()); } monitor.beginTask(Messages.SearchView_searching, query.scope.size() * 3); int work = 0; for (ISearch catalog : query.scope) { String name = null; try { name = catalog.getInfo(null).getTitle(); if (name == null && catalog.getIdentifier() != null) name = "url: " + catalog.getIdentifier(); //$NON-NLS-1$ if (name == null) name = catalog.getClass().getSimpleName(); } catch (Exception unknown) { name = catalog.getClass().getSimpleName(); } List<IResolve> records = null; try { monitor.subTask( MessageFormat.format(Messages.SearchView_searching_for, new Object[] { query.text, name })); monitor.worked(++work); records = catalog.search(query.text, query.bbox, monitor); if (records != null && !records.isEmpty()) { results.addAll(records); } } catch (Throwable t) { CatalogUIPlugin.log("Search for " + name + " failed", t); //$NON-NLS-1$ //$NON-NLS-2$ } } } public void setAOIFilter(boolean filter) { aoiFilter = filter; search(createQuery()); } public boolean isAOIFilter() { return aoiFilter; } } class Info { public String title; public String name; public String description; public String[] keys; private URL id; public URL getId() { return id; } public Info(URL id, IServiceInfo info) { title = info.getTitle(); name = null; description = info.getDescription(); keys = info.getKeywords().toArray(new String[0]); this.id = id; } public Info(URL id, ICatalogInfo info) { title = info.getTitle(); name = null; description = info.getDescription(); keys = info.getKeywords(); this.id = id; } public Info(URL id, IGeoResourceInfo info) { title = info.getTitle(); name = info.getName(); description = info.getDescription(); keys = info.getKeywords().toArray(new String[0]); this.id = id; } }