| /******************************************************************************* |
| * 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); |
| } |
| } |
| } |
| } |