blob: 1b9ef0c9573aee5b768ac4c2b2221378a8f12776 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.help.ui.internal.views;
import java.util.ArrayList;
import org.eclipse.core.runtime.*;
import org.eclipse.help.IHelpResource;
import org.eclipse.help.internal.base.*;
import org.eclipse.help.search.ISearchEngineResult;
import org.eclipse.help.ui.internal.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.*;
import org.eclipse.ui.forms.FormColors;
import org.eclipse.ui.forms.events.*;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.*;
import org.osgi.framework.Bundle;
public class EngineResultSection {
private SearchResultsPart part;
private EngineDescriptor desc;
private IStatus errorStatus;
private ArrayList hits;
private Section section;
private Composite container;
private FormText searchResults;
private ImageHyperlink prevLink;
private ImageHyperlink nextLink;
private boolean needsUpdating;
private FederatedSearchSorter sorter;
private int HITS_PER_PAGE = 10;
private static final String HREF_PROGRESS = "__progress__"; //$NON-NLS-1$
private static final String PROGRESS_VIEW = "org.eclipse.ui.views.ProgressView"; //$NON-NLS-1$
private int resultOffset = 0;
public EngineResultSection(SearchResultsPart part, EngineDescriptor desc) {
this.part = part;
this.desc = desc;
hits = new ArrayList();
sorter = new FederatedSearchSorter();
}
public boolean hasControl(Control control) {
return searchResults.equals(control);
}
public boolean matches(EngineDescriptor desc) {
return this.desc == desc;
}
public Control createControl(Composite parent, final FormToolkit toolkit) {
section = toolkit.createSection(parent, Section.COMPACT
| Section.TWISTIE | Section.EXPANDED
| Section.LEFT_TEXT_CLIENT_ALIGNMENT);
// section.marginHeight = 10;
container = toolkit.createComposite(section);
TableWrapLayout layout = new TableWrapLayout();
layout.topMargin = 0;
layout.bottomMargin = 0;
layout.leftMargin = 0;
layout.rightMargin = 0;
layout.verticalSpacing = 0;
container.setLayout(layout);
createFormText(container, toolkit);
searchResults.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB));
searchResults
.setColor(
"summary", parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW)); //$NON-NLS-1$
section.setClient(container);
updateSectionTitle(0);
section.addExpansionListener(new IExpansionListener() {
public void expansionStateChanging(ExpansionEvent e) {
if (needsUpdating)
asyncUpdateResults(true, false);
}
public void expansionStateChanged(ExpansionEvent e) {
}
});
return section;
}
private void createFormText(Composite parent, FormToolkit toolkit) {
searchResults = toolkit.createFormText(parent, false);
searchResults.setColor(FormColors.TITLE, toolkit.getColors().getColor(
FormColors.TITLE));
searchResults.marginHeight = 5;
String topicKey = IHelpUIConstants.IMAGE_FILE_F1TOPIC;
String nwKey = IHelpUIConstants.IMAGE_NW;
String searchKey = IHelpUIConstants.IMAGE_HELP_SEARCH;
searchResults.setImage(topicKey, HelpUIResources.getImage(topicKey));
searchResults.setImage(nwKey, HelpUIResources.getImage(nwKey));
searchResults.setImage(searchKey, HelpUIResources.getImage(searchKey));
searchResults.setColor("summary", parent.getDisplay().getSystemColor( //$NON-NLS-1$
SWT.COLOR_WIDGET_DARK_SHADOW));
searchResults.setImage(ISharedImages.IMG_TOOL_FORWARD, PlatformUI
.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_TOOL_FORWARD));
searchResults.setImage(ISharedImages.IMG_TOOL_BACK, PlatformUI
.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_TOOL_BACK));
searchResults.setImage(ISharedImages.IMG_OBJS_ERROR_TSK, PlatformUI
.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_OBJS_ERROR_TSK));
searchResults.setImage(IHelpUIConstants.IMAGE_ADD_BOOKMARK,
HelpUIResources.getImage(IHelpUIConstants.IMAGE_ADD_BOOKMARK));
searchResults.setImage(desc.getId(), desc.getIconImage());
searchResults.addHyperlinkListener(new IHyperlinkListener() {
public void linkActivated(HyperlinkEvent e) {
Object href = e.getHref();
if ("nw:".equals(href)) { //$NON-NLS-1$
part.doOpenLink(e.getHref());
} else if (HREF_PROGRESS.equals(href)) {
showProgressView();
} else if (((String) href).startsWith("bmk:")) { //$NON-NLS-1$
doBookmark(e.getLabel(), (String) href);
} else
part.doOpenLink(e.getHref());
}
public void linkEntered(HyperlinkEvent e) {
part.parent.handleLinkEntered(e);
}
public void linkExited(HyperlinkEvent e) {
part.parent.handleLinkExited(e);
}
});
initializeText();
needsUpdating = true;
}
private void initializeText() {
Bundle bundle = Platform.getBundle("org.eclipse.ui.views"); //$NON-NLS-1$
if (bundle != null) {
StringBuffer buff = new StringBuffer();
buff.append("<form>"); //$NON-NLS-1$
buff.append("<p><a href=\""); //$NON-NLS-1$
buff.append(HREF_PROGRESS);
buff.append("\" alt=\""); //$NON-NLS-1$
buff.append(Messages.EngineResultSection_progressTooltip); //$NON-NLS-1$
buff.append("\">"); //$NON-NLS-1$
buff.append(Messages.EngineResultSection_searchInProgress); //$NON-NLS-1$
buff.append("</a></p></form>"); //$NON-NLS-1$
searchResults.setText(buff.toString(), true, false);
} else {
searchResults.setText(Messages.EngineResultSection_progress2, false, false); //$NON-NLS-1$
}
}
private void showProgressView() {
IWorkbenchWindow window = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
if (window != null) {
IWorkbenchPage page = window.getActivePage();
if (page != null) {
try {
page.showView(PROGRESS_VIEW);
} catch (PartInitException e) {
HelpUIPlugin.logError(Messages.EngineResultSection_progressError, e); //$NON-NLS-1$
}
}
}
}
public synchronized void add(ISearchEngineResult match) {
hits.add(match);
asyncUpdateResults(false, false);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.help.internal.search.federated.ISearchEngineResultCollector#add(org.eclipse.help.internal.search.federated.ISearchEngineResult[])
*/
public synchronized void add(ISearchEngineResult[] matches) {
for (int i = 0; i < matches.length; i++)
hits.add(matches[i]);
asyncUpdateResults(false, false);
}
public synchronized void error(IStatus status) {
errorStatus = status;
asyncUpdateResults(false, false);
}
public synchronized void completed() {
if (hits.size() == 0 && !searchResults.isDisposed())
asyncUpdateResults(false, false);
}
public synchronized void canceling() {
if (hits.size() == 0 && !searchResults.isDisposed()) {
StringBuffer buff = new StringBuffer();
buff.append("<form>"); //$NON-NLS-1$
buff.append("<p><span color=\"summary\">");//$NON-NLS-1$
buff.append(Messages.EngineResultSection_canceling); //$NON-NLS-1$
buff.append("</span></p>"); //$NON-NLS-1$
buff.append("</form>"); //$NON-NLS-1$
searchResults.setText(buff.toString(), true, false);
}
}
private void asyncUpdateResults(boolean now, final boolean scrollToBeginning) {
Runnable runnable = new Runnable() {
public void run() {
BusyIndicator.showWhile(section.getDisplay(), new Runnable() {
public void run() {
updateResults(true);
if (scrollToBeginning) {
searchResults.setFocus();
FormToolkit.setControlVisible(section, true);
}
}
});
}
};
if (section.isDisposed())
return;
if (now)
section.getDisplay().syncExec(runnable);
else
section.getDisplay().asyncExec(runnable);
}
private ISearchEngineResult[] getResults() {
ArrayList list = hits;
if (desc.getEngineTypeId().equals(IHelpUIConstants.INTERNAL_HELP_ID)) {
if (part.parent.isFilteredByRoles()) {
list = new ArrayList();
for (int i = 0; i < hits.size(); i++) {
ISearchEngineResult hit = (ISearchEngineResult) hits.get(i);
if (HelpBasePlugin.getActivitySupport().isEnabled(
hit.getHref()))
list.add(hit);
}
}
}
ISearchEngineResult[] results = (ISearchEngineResult[]) list
.toArray(new ISearchEngineResult[list.size()]);
if (part.getShowCategories())
sorter.sort(null, results);
return results;
}
void updateResults(boolean reflow) {
ISearchEngineResult[] results = getResults();
updateSectionTitle(results.length);
StringBuffer buff = new StringBuffer();
buff.append("<form>"); //$NON-NLS-1$
IHelpResource oldCat = null;
boolean earlyExit = false;
for (int i = resultOffset; i < results.length; i++) {
if (i - resultOffset == HITS_PER_PAGE) {
break;
}
ISearchEngineResult hit = results[i];
IHelpResource cat = hit.getCategory();
if (part.getShowCategories()
&& cat != null
&& (oldCat == null || !oldCat.getLabel().equals(
cat.getLabel()))) {
buff.append("<p>"); //$NON-NLS-1$
if (cat.getHref() != null) {
buff.append("<a bold=\"true\" href=\""); //$NON-NLS-1$
String absoluteHref = hit.toAbsoluteHref(cat.getHref(),
true);
buff.append(part.parent.escapeSpecialChars(absoluteHref));
buff.append("\">"); //$NON-NLS-1$
buff.append(cat.getLabel());
buff.append("</a>"); //$NON-NLS-1$
} else {
buff.append("<b>"); //$NON-NLS-1$
buff.append(cat.getLabel());
buff.append("</b>"); //$NON-NLS-1$
}
buff.append("</p>"); //$NON-NLS-1$
oldCat = cat;
}
int indent = part.getShowCategories() && cat != null ? 26 : 21;
int bindent = part.getShowCategories() && cat != null ? 5 : 0;
buff
.append("<li indent=\"" + indent + "\" bindent=\"" + bindent + "\" style=\"image\" value=\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
buff.append(desc.getId());
buff.append("\">"); //$NON-NLS-1$
buff.append("<a href=\""); //$NON-NLS-1$
if (hit.getForceExternalWindow())
buff.append("nw:"); //$NON-NLS-1$
buff.append(part.parent.escapeSpecialChars(hit.toAbsoluteHref(hit
.getHref(), false)));
buff.append("\""); //$NON-NLS-1$
if (hit.getCategory() != null) {
buff.append(" alt=\""); //$NON-NLS-1$
buff.append(hit.getCategory().getLabel());
buff.append("\""); //$NON-NLS-1$
}
buff.append(">"); //$NON-NLS-1$
String elabel = part.parent.escapeSpecialChars(hit.getLabel());
buff.append(elabel);
buff.append("</a>"); //$NON-NLS-1$
if (!hit.getForceExternalWindow()) {
buff.append(" <a href=\""); //$NON-NLS-1$
buff.append("nw:");//$NON-NLS-1$
String ahref = part.parent.escapeSpecialChars(hit
.toAbsoluteHref(hit.getHref(), true));
buff.append(ahref);
buff.append("\"><img href=\""); //$NON-NLS-1$
buff.append(IHelpUIConstants.IMAGE_NW);
buff.append("\" alt=\""); //$NON-NLS-1$
buff.append(Messages.SearchResultsPart_nwtooltip);//$NON-NLS-1$
buff.append("\""); //$NON-NLS-1$
buff.append("/>"); //$NON-NLS-1$
buff.append("</a>"); //$NON-NLS-1$
}
addBookmarkLink(buff, hit);
if (part.getShowDescription()) {
String edesc = hit.getDescription();
if (edesc != null)
edesc = part.parent.escapeSpecialChars(edesc);
String summary = getSummary(elabel, edesc);
if (summary != null) {
buff.append("<br/>"); //$NON-NLS-1$
// buff.append("<span color=\"summary\">"); //$NON-NLS-1$
// System.out.println(summary);
buff.append(summary);
// buff.append("</span>"); //$NON-NLS-1$
}
}
buff.append("</li>"); //$NON-NLS-1$
}
if (errorStatus != null)
updateErrorStatus(buff);
updateNavigation(results.length);
buff.append("</form>"); //$NON-NLS-1$
searchResults.setText(buff.toString(), true, false);
section.layout();
if (reflow)
part.reflow();
}
private void addBookmarkLink(StringBuffer buff, ISearchEngineResult hit) {
buff.append(" <a href=\""); //$NON-NLS-1$
buff.append("bmk:");//$NON-NLS-1$
String ahref = part.parent.escapeSpecialChars(hit.toAbsoluteHref(hit
.getHref(), true));
buff.append(ahref);
buff.append("\"><img href=\""); //$NON-NLS-1$
buff.append(IHelpUIConstants.IMAGE_ADD_BOOKMARK);
buff.append("\" alt=\""); //$NON-NLS-1$
buff.append(Messages.SearchResultsPart_bmktooltip);
buff.append("\" text=\""); //$NON-NLS-1$
buff.append(hit.getLabel());
buff.append("\""); //$NON-NLS-1$
buff.append("/>"); //$NON-NLS-1$
buff.append("</a>"); //$NON-NLS-1$
}
private void updateErrorStatus(StringBuffer buff) {
int indent = 21;
buff.append("<li indent=\"" + indent + "\" style=\"image\" value=\""); //$NON-NLS-1$ //$NON-NLS-2$
buff.append(ISharedImages.IMG_OBJS_ERROR_TSK);
buff.append("\">"); //$NON-NLS-1$
buff.append("<b>"); //$NON-NLS-1$
buff.append(part.parent.escapeSpecialChars(errorStatus.getMessage()));
buff.append("</b>"); //$NON-NLS-1$
buff.append("<br/>"); //$NON-NLS-1$
Throwable t = errorStatus.getException();
if (t != null)
buff.append(part.parent.escapeSpecialChars(t.getMessage()));
buff.append("</li>"); //$NON-NLS-1$
}
private void updateNavigation(int size) {
if (size > HITS_PER_PAGE) {
if (prevLink == null) {
FormToolkit toolkit = part.getToolkit();
Composite navContainer = toolkit.createComposite(container);
TableWrapData td = new TableWrapData(TableWrapData.FILL_GRAB);
navContainer.setLayoutData(td);
GridLayout glayout = new GridLayout();
glayout.numColumns = 2;
navContainer.setLayout(glayout);
Label sep = toolkit.createLabel(navContainer, null,
SWT.SEPARATOR | SWT.HORIZONTAL);
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gd.horizontalSpan = 2;
gd.widthHint = 2;
sep.setLayoutData(gd);
prevLink = toolkit.createImageHyperlink(navContainer, SWT.NULL);
prevLink.setText(NLS.bind("EngineResultSection.previous", "" + HITS_PER_PAGE)); //$NON-NLS-1$ //$NON-NLS-2$
prevLink.setImage(PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_TOOL_BACK));
prevLink.addHyperlinkListener(new HyperlinkAdapter() {
public void linkActivated(HyperlinkEvent e) {
resultOffset -= HITS_PER_PAGE;
asyncUpdateResults(false, true);
}
});
nextLink = toolkit
.createImageHyperlink(navContainer, SWT.RIGHT);
nextLink.setImage(PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_TOOL_FORWARD));
gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
gd.grabExcessHorizontalSpace = true;
nextLink.setLayoutData(gd);
nextLink.addHyperlinkListener(new HyperlinkAdapter() {
public void linkActivated(HyperlinkEvent e) {
resultOffset += HITS_PER_PAGE;
asyncUpdateResults(false, true);
}
});
}
prevLink.setVisible(resultOffset > 0);
int nextOffset = resultOffset + HITS_PER_PAGE;
int remainder = hits.size() - nextOffset;
remainder = Math.min(remainder, HITS_PER_PAGE);
nextLink.setText(NLS.bind("EngineResultSection.next", "" + remainder)); //$NON-NLS-1$ //$NON-NLS-2$
nextLink.setVisible(hits.size() >= resultOffset + HITS_PER_PAGE);
} else {
if (prevLink != null) {
prevLink.getParent().setMenu(null);
prevLink.getParent().dispose();
prevLink = null;
nextLink = null;
}
}
}
private String getSummary(String elabel, String edesc) {
if (edesc != null) {
if (!edesc.equals(elabel)) {
if (edesc.length() > elabel.length()) {
String ldesc = edesc.substring(0, elabel.length());
if (ldesc.equalsIgnoreCase(elabel))
edesc = edesc.substring(elabel.length() + 1);
}
return edesc;
}
}
return null;
}
private void updateSectionTitle(int size) {
if (errorStatus != null) {
Label label = part.getToolkit().createLabel(section, null);
label.setImage(PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_OBJS_ERROR_TSK));
section.setTextClient(label);
section.setText(Messages.EngineResultSection_sectionTitle_error);//$NON-NLS-1$
} else {
section.setTextClient(null);
}
if (size == 1)
section.setText(NLS.bind("EngineResultSection.sectionTitle.hit", desc.getLabel(), "" //$NON-NLS-1$ //$NON-NLS-2$
+ hits.size()));
else if (size <= HITS_PER_PAGE)
section.setText(NLS.bind("EngineResultSection.sectionTitle.hits", desc.getLabel(), "" + hits.size())); //$NON-NLS-1$
else {
int from = (resultOffset + 1);
int to = (resultOffset + HITS_PER_PAGE);
to = Math.min(to, size);
section.setText(NLS.bind("EngineResultSection.sectionTitle.hitsRange", new String [] {desc //$NON-NLS-1$
.getLabel(), "" + from, "" + to, "" + size})); //$NON-NLS-1$
}
}
private void doBookmark(final String label, String href) {
final String fhref = href.substring(4);
BusyIndicator.showWhile(container.getDisplay(), new Runnable() {
public void run() {
BaseHelpSystem.getBookmarkManager().addBookmark(fhref, label);
}
});
}
public void dispose() {
if (!section.isDisposed()) {
recursiveSetMenu(section, null);
section.dispose();
}
}
private void recursiveSetMenu(Control control, Menu menu) {
control.setMenu(menu);
if (control instanceof Composite) {
Composite parent = (Composite) control;
Control[] children = parent.getChildren();
for (int i = 0; i < children.length; i++) {
recursiveSetMenu(children[i], menu);
}
}
}
}