/******************************************************************************* * Copyright (c) 2006, 2009 Steffen Pingel 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: * Steffen Pingel - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.trac.core.model; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.internal.trac.core.TracCorePlugin; import org.eclipse.mylyn.internal.trac.core.client.ITracClient; import org.eclipse.mylyn.internal.trac.core.model.TracSearchFilter.CompareOperator; import org.eclipse.osgi.util.NLS; /** * Represents a Trac search. A search can have multiple {@link TracSearchFilter}s that all need to match. * * @author Steffen Pingel */ public class TracSearch { /** Stores search criteria in the order entered by the user. */ private final Map filterByFieldName = new LinkedHashMap(); /** The field the result is ordered by. */ private String orderBy; private boolean ascending = true; private int max = -1; public TracSearch(String queryParameter) { fromUrl(queryParameter); } public TracSearch() { } public void addFilter(String key, String value) { TracSearchFilter filter = filterByFieldName.get(key); if (filter == null) { filter = new TracSearchFilter(key); CompareOperator operator = CompareOperator.fromUrl(value); filter.setOperator(operator); filterByFieldName.put(key, filter); } filter.addValue(value.substring(filter.getOperator().getQueryValue().length())); } public void addFilter(TracSearchFilter filter) { filterByFieldName.put(filter.getFieldName(), filter); } public List getFilters() { return new ArrayList(filterByFieldName.values()); } public void setAscending(boolean ascending) { this.ascending = ascending; } public boolean isAscending() { return ascending; } public void setOrderBy(String orderBy) { this.orderBy = orderBy; } public String getOrderBy() { return orderBy; } /** * @see #toQuery(boolean) */ public String toQuery() { return toQuery(false); } /** * Returns a Trac query string that conforms to the format defined at {@link http * ://projects.edgewall.com/trac/wiki/TracQuery#QueryLanguage}. * * @return the empty string, if no search order and criteria are defined; a string that starts with &, otherwise */ public String toQuery(boolean supportsMax) { StringBuilder sb = new StringBuilder(); if (orderBy != null) { sb.append("&order="); //$NON-NLS-1$ sb.append(orderBy); if (!ascending) { sb.append("&desc=1"); //$NON-NLS-1$ } } if (supportsMax && max != -1) { sb.append("&max="); //$NON-NLS-1$ sb.append(max); } for (TracSearchFilter filter : filterByFieldName.values()) { sb.append("&"); //$NON-NLS-1$ sb.append(filter.getFieldName()); sb.append(filter.getOperator().getQueryValue()); sb.append("="); //$NON-NLS-1$ List values = filter.getValues(); for (Iterator it = values.iterator(); it.hasNext();) { sb.append(it.next()); if (it.hasNext()) { sb.append("|"); //$NON-NLS-1$ } } } return sb.toString(); } /** * Returns a URL encoded string that can be passed as an argument to the Trac query script. * * @return the empty string, if no search order and criteria are defined; a string that starts with &, otherwise */ public String toUrl() { StringBuilder sb = new StringBuilder(); if (orderBy != null) { sb.append("&order="); //$NON-NLS-1$ sb.append(orderBy); if (!ascending) { sb.append("&desc=1"); //$NON-NLS-1$ } } else if (filterByFieldName.isEmpty()) { // TODO figure out why search must be ordered when logged in (otherwise // no results will be returned) sb.append("&order=id"); //$NON-NLS-1$ } if (max != -1) { sb.append("&max="); //$NON-NLS-1$ sb.append(max); } for (TracSearchFilter filter : filterByFieldName.values()) { for (String value : filter.getValues()) { sb.append("&"); //$NON-NLS-1$ sb.append(filter.getFieldName()); sb.append("="); //$NON-NLS-1$ try { sb.append(URLEncoder.encode(filter.getOperator().getQueryValue(), ITracClient.CHARSET)); sb.append(URLEncoder.encode(value, ITracClient.CHARSET)); } catch (UnsupportedEncodingException e) { StatusHandler.log(new Status(IStatus.WARNING, TracCorePlugin.ID_PLUGIN, "Unexpected exception while decoding URL", e)); //$NON-NLS-1$ } } } return sb.toString(); } public void fromUrl(String url) { StringTokenizer t = new StringTokenizer(url, "&"); //$NON-NLS-1$ while (t.hasMoreTokens()) { String token = t.nextToken(); int i = token.indexOf("="); //$NON-NLS-1$ if (i != -1) { try { String key = URLDecoder.decode(token.substring(0, i), ITracClient.CHARSET); String value = URLDecoder.decode(token.substring(i + 1), ITracClient.CHARSET); if ("order".equals(key)) { //$NON-NLS-1$ setOrderBy(value); } else if ("desc".equals(key)) { //$NON-NLS-1$ setAscending(!"1".equals(value)); //$NON-NLS-1$ } else if ("group".equals(key) || "groupdesc".equals(key) || "verbose".equals(key)) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ // ignore these parameters } else if ("max".equals(key)) { //$NON-NLS-1$ try { setMax(Integer.parseInt(value)); } catch (NumberFormatException e) { StatusHandler.log(new Status(IStatus.WARNING, TracCorePlugin.ID_PLUGIN, NLS.bind( "Illegal format in URL, expected a number ''{0}''", value), e)); //$NON-NLS-1$ } } else { addFilter(key, value); } } catch (UnsupportedEncodingException e) { StatusHandler.log(new Status(IStatus.WARNING, TracCorePlugin.ID_PLUGIN, "Unexpected exception while decoding URL", e)); //$NON-NLS-1$ } } } } public int getMax() { return max; } public void setMax(int max) { this.max = max; } }