1 11 package org.eclipse.help.ui.internal.views; 12 13 import java.net.URL ; 14 import java.util.ArrayList ; 15 16 import org.eclipse.core.runtime.IStatus; 17 import org.eclipse.core.runtime.Platform; 18 import org.eclipse.help.IHelpResource; 19 import org.eclipse.help.internal.base.BaseHelpSystem; 20 import org.eclipse.help.internal.base.HelpBasePlugin; 21 import org.eclipse.help.internal.search.SearchHit; 22 import org.eclipse.help.search.ISearchEngineResult; 23 import org.eclipse.help.search.ISearchEngineResult2; 24 import org.eclipse.help.ui.internal.HelpUIPlugin; 25 import org.eclipse.help.ui.internal.HelpUIResources; 26 import org.eclipse.help.ui.internal.IHelpUIConstants; 27 import org.eclipse.help.ui.internal.Messages; 28 import org.eclipse.osgi.util.NLS; 29 import org.eclipse.swt.SWT; 30 import org.eclipse.swt.custom.BusyIndicator; 31 import org.eclipse.swt.graphics.Image; 32 import org.eclipse.swt.graphics.ImageData; 33 import org.eclipse.swt.layout.GridData; 34 import org.eclipse.swt.layout.GridLayout; 35 import org.eclipse.swt.widgets.Composite; 36 import org.eclipse.swt.widgets.Control; 37 import org.eclipse.swt.widgets.Label; 38 import org.eclipse.swt.widgets.Menu; 39 import org.eclipse.ui.ISharedImages; 40 import org.eclipse.ui.IWorkbenchPage; 41 import org.eclipse.ui.IWorkbenchWindow; 42 import org.eclipse.ui.PartInitException; 43 import org.eclipse.ui.PlatformUI; 44 import org.eclipse.ui.forms.IFormColors; 45 import org.eclipse.ui.forms.events.ExpansionEvent; 46 import org.eclipse.ui.forms.events.HyperlinkAdapter; 47 import org.eclipse.ui.forms.events.HyperlinkEvent; 48 import org.eclipse.ui.forms.events.IExpansionListener; 49 import org.eclipse.ui.forms.events.IHyperlinkListener; 50 import org.eclipse.ui.forms.widgets.FormText; 51 import org.eclipse.ui.forms.widgets.FormToolkit; 52 import org.eclipse.ui.forms.widgets.ImageHyperlink; 53 import org.eclipse.ui.forms.widgets.Section; 54 import org.eclipse.ui.forms.widgets.TableWrapData; 55 import org.eclipse.ui.forms.widgets.TableWrapLayout; 56 import org.osgi.framework.Bundle; 57 58 public class EngineResultSection { 59 60 private static final String KEY_PREFIX_GRAYED = "grayed:"; 62 private static final String CAT_HEADING_PREFIX = "catheading:"; 64 private SearchResultsPart part; 65 66 private EngineDescriptor desc; 67 68 private IStatus errorStatus; 69 70 private ArrayList hits; 71 72 private Section section; 73 74 private Composite container; 75 76 private FormText searchResults; 77 78 private ImageHyperlink prevLink; 79 80 private ImageHyperlink nextLink; 81 82 private boolean needsUpdating; 83 84 private FederatedSearchSorter sorter; 85 86 private int HITS_PER_PAGE = 10; 87 88 private static final String HREF_PROGRESS = "__progress__"; 90 private static final String PROGRESS_VIEW = "org.eclipse.ui.views.ProgressView"; 92 private int resultOffset = 0; 93 94 public EngineResultSection(SearchResultsPart part, EngineDescriptor desc) { 95 this.part = part; 96 this.desc = desc; 97 hits = new ArrayList (); 98 sorter = new FederatedSearchSorter(); 99 } 100 101 public boolean hasControl(Control control) { 102 return searchResults.equals(control); 103 } 104 105 public boolean matches(EngineDescriptor desc) { 106 return this.desc == desc; 107 } 108 109 public Control createControl(Composite parent, final FormToolkit toolkit) { 110 section = toolkit.createSection(parent, Section.SHORT_TITLE_BAR | Section.COMPACT | Section.TWISTIE 111 | Section.EXPANDED | Section.LEFT_TEXT_CLIENT_ALIGNMENT); 112 container = toolkit.createComposite(section); 114 TableWrapLayout layout = new TableWrapLayout(); 115 layout.topMargin = 0; 116 layout.bottomMargin = 0; 117 layout.leftMargin = 0; 118 layout.rightMargin = 0; 119 layout.verticalSpacing = 0; 120 container.setLayout(layout); 121 createFormText(container, toolkit); 122 searchResults.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB)); 123 searchResults.setColor("summary", parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW)); section.setClient(container); 125 updateSectionTitle(0); 126 section.addExpansionListener(new IExpansionListener() { 127 128 public void expansionStateChanging(ExpansionEvent e) { 129 if (needsUpdating) 130 asyncUpdateResults(true, false); 131 } 132 133 public void expansionStateChanged(ExpansionEvent e) { 134 } 135 }); 136 return section; 137 } 138 139 private void createFormText(Composite parent, FormToolkit toolkit) { 140 searchResults = toolkit.createFormText(parent, false); 141 searchResults.setColor(IFormColors.TITLE, toolkit.getColors().getColor(IFormColors.TITLE)); 142 searchResults.marginHeight = 5; 143 String topicKey = IHelpUIConstants.IMAGE_FILE_F1TOPIC; 144 String searchKey = IHelpUIConstants.IMAGE_HELP_SEARCH; 145 searchResults.setImage(topicKey, HelpUIResources.getImage(topicKey)); 146 searchResults.setImage(searchKey, HelpUIResources.getImage(searchKey)); 147 searchResults.setColor("summary", parent.getDisplay().getSystemColor( SWT.COLOR_WIDGET_DARK_SHADOW)); 149 searchResults.setImage(ISharedImages.IMG_TOOL_FORWARD, PlatformUI.getWorkbench().getSharedImages() 150 .getImage(ISharedImages.IMG_TOOL_FORWARD)); 151 searchResults.setImage(ISharedImages.IMG_TOOL_BACK, PlatformUI.getWorkbench().getSharedImages() 152 .getImage(ISharedImages.IMG_TOOL_BACK)); 153 searchResults.setImage(ISharedImages.IMG_OBJS_ERROR_TSK, PlatformUI.getWorkbench().getSharedImages() 154 .getImage(ISharedImages.IMG_OBJS_ERROR_TSK)); 155 searchResults.setImage(desc.getId(), desc.getIconImage()); 156 searchResults.setImage(KEY_PREFIX_GRAYED + desc.getId(), getGrayedImage(desc.getIconImage())); 157 searchResults.addHyperlinkListener(new IHyperlinkListener() { 158 159 public void linkActivated(HyperlinkEvent e) { 160 Object href = e.getHref(); 161 String shref = (String ) href; 162 if (HREF_PROGRESS.equals(href)) { 163 showProgressView(); 164 } else if (shref.startsWith("bmk:")) { doBookmark(e.getLabel(), shref); 166 } else if (shref.startsWith(CAT_HEADING_PREFIX)) { 167 part.doCategoryLink(shref.substring(CAT_HEADING_PREFIX.length())); 168 } else 169 part.doOpenLink(e.getHref()); 170 } 171 172 public void linkEntered(HyperlinkEvent e) { 173 part.parent.handleLinkEntered(e); 174 } 175 176 public void linkExited(HyperlinkEvent e) { 177 part.parent.handleLinkExited(e); 178 } 179 }); 180 initializeText(); 181 part.parent.hookFormText(searchResults); 182 needsUpdating = true; 183 } 184 185 private void initializeText() { 186 Bundle bundle = Platform.getBundle("org.eclipse.ui.views"); if (bundle != null) { 188 StringBuffer buff = new StringBuffer (); 189 buff.append("<form>"); buff.append("<p><a HREF=\""); buff.append(HREF_PROGRESS); 192 buff.append("\""); if (!Platform.getWS().equals(Platform.WS_GTK)) { 194 buff.append(" alt=\""); buff.append(Messages.EngineResultSection_progressTooltip); 196 buff.append("\""); } 198 buff.append(">"); buff.append(Messages.EngineResultSection_searchInProgress); 200 buff.append("</a></p></form>"); searchResults.setText(buff.toString(), true, false); 202 } else { 203 searchResults.setText(Messages.EngineResultSection_progress2, false, false); 204 } 205 } 206 207 private void showProgressView() { 208 IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); 209 if (window != null) { 210 IWorkbenchPage page = window.getActivePage(); 211 if (page != null) { 212 try { 213 page.showView(PROGRESS_VIEW); 214 } catch (PartInitException e) { 215 HelpUIPlugin.logError(Messages.EngineResultSection_progressError, e); 216 } 217 } 218 } 219 } 220 221 public synchronized void add(ISearchEngineResult match) { 222 hits.add(match); 223 asyncUpdateResults(false, false); 224 } 225 226 231 public synchronized void add(ISearchEngineResult[] matches) { 232 for (int i = 0; i < matches.length; i++) 233 hits.add(matches[i]); 234 asyncUpdateResults(false, false); 235 } 236 237 public synchronized void error(IStatus status) { 238 errorStatus = status; 239 asyncUpdateResults(false, false); 240 } 241 242 public synchronized void completed() { 243 if (hits.size() == 0 && !searchResults.isDisposed()) 244 asyncUpdateResults(false, false); 245 } 246 247 public synchronized void canceling() { 248 if (hits.size() == 0 && !searchResults.isDisposed()) { 249 StringBuffer buff = new StringBuffer (); 250 buff.append("<form>"); buff.append("<p><span color=\"summary\">"); buff.append(Messages.EngineResultSection_canceling); 253 buff.append("</span></p>"); buff.append("</form>"); searchResults.setText(buff.toString(), true, false); 256 } 257 } 258 259 private void asyncUpdateResults(boolean now, final boolean scrollToBeginning) { 260 Runnable runnable = new Runnable () { 261 262 public void run() { 263 BusyIndicator.showWhile(section.getDisplay(), new Runnable () { 264 265 public void run() { 266 updateResults(true); 267 if (scrollToBeginning) { 268 searchResults.setFocus(); 269 FormToolkit.setControlVisible(section, true); 270 part.updateSeparatorVisibility(); 271 } 272 } 273 }); 274 } 275 }; 276 if (section.isDisposed()) 277 return; 278 if (now) 279 section.getDisplay().syncExec(runnable); 280 else 281 section.getDisplay().asyncExec(runnable); 282 } 283 284 private ISearchEngineResult[] getResults() { 285 ArrayList list = hits; 286 if (desc.getEngineTypeId().equals(IHelpUIConstants.INTERNAL_HELP_ID)) { 287 if (part.parent.isFilteredByRoles()) { 288 list = new ArrayList (); 289 for (int i = 0; i < hits.size(); i++) { 290 ISearchEngineResult hit = (ISearchEngineResult) hits.get(i); 291 if (HelpBasePlugin.getActivitySupport().isEnabled(hit.getHref())) 292 list.add(hit); 293 } 294 } 295 } 296 ISearchEngineResult[] results = (ISearchEngineResult[]) list.toArray(new ISearchEngineResult[list 297 .size()]); 298 if (part.getShowCategories()) 299 sorter.sort(null, results); 300 return results; 301 } 302 303 310 private Image getGrayedImage(Image image) { 311 Image temp = new Image(image.getDevice(), image, SWT.IMAGE_GRAY); 313 ImageData data = temp.getImageData(); 315 ImageData maskData = data.getTransparencyMask(); 316 if (maskData != null) { 317 for (int y=0;y<maskData.height;++y) { 318 for (int x=0;x<maskData.width;++x) { 319 if (maskData.getPixel(x, y) == 0) { 320 data.setAlpha(x, y, 0); 322 } 323 else { 324 data.setAlpha(x, y, 128); 326 } 327 } 328 } 329 data.maskData = null; 330 } 331 Image grayed = new Image(image.getDevice(), data); 332 temp.dispose(); 333 return grayed; 334 } 335 336 void updateResults(boolean reflow) { 337 ISearchEngineResult[] results = getResults(); 338 updateSectionTitle(results.length); 339 StringBuffer buff = new StringBuffer (); 340 buff.append("<form>"); IHelpResource oldCat = null; 342 343 for (int i = resultOffset; i < results.length; i++) { 344 if (i - resultOffset == HITS_PER_PAGE) { 345 break; 346 } 347 ISearchEngineResult hit = results[i]; 348 IHelpResource cat = hit.getCategory(); 349 if (part.getShowCategories() && cat != null 350 && (oldCat == null || !oldCat.getLabel().equals(cat.getLabel()))) { 351 buff.append("<p>"); if (cat.getHref() != null) { 353 buff.append("<a bold=\"true\" HREF=\""); String absoluteHref = ""; if (cat.getHref().endsWith(".xml")) { absoluteHref = absoluteHref + CAT_HEADING_PREFIX; 357 } 358 absoluteHref = absoluteHref + hit.toAbsoluteHref(cat.getHref(), true); 359 buff.append(part.parent.escapeSpecialChars(absoluteHref)); 360 buff.append("\">"); buff.append(cat.getLabel()); 362 buff.append("</a>"); } else { 364 buff.append("<b>"); buff.append(cat.getLabel()); 366 buff.append("</b>"); } 368 buff.append("</p>"); oldCat = cat; 370 } 371 int indent = part.getShowCategories() && cat != null ? 26 : 21; 372 int bindent = part.getShowCategories() && cat != null ? 5 : 0; 373 buff.append("<li indent=\"" + indent + "\" bindent=\"" + bindent + "\" style=\"image\" value=\""); String imageId = desc.getId(); 375 boolean isPotentialHit = (hit instanceof SearchHit && ((SearchHit)hit).isPotentialHit()); 376 if (hit instanceof ISearchEngineResult2) { 377 URL iconURL = ((ISearchEngineResult2) hit).getIconURL(); 378 if (iconURL != null) { 379 String id = null; 380 if (isPotentialHit) { 381 id = registerGrayedHitIcon(iconURL); 382 } 383 else { 384 id = registerHitIcon(iconURL); 385 } 386 if (id != null) 387 imageId = id; 388 } 389 } 390 391 if (isPotentialHit) { 392 imageId = KEY_PREFIX_GRAYED + imageId; 393 } 394 395 buff.append(imageId); 396 buff.append("\">"); buff.append("<a HREF=\""); String HREF=null; 399 if (hit instanceof ISearchEngineResult2) { 400 ISearchEngineResult2 hit2 = (ISearchEngineResult2)hit; 401 if (((ISearchEngineResult2)hit).canOpen()) { 402 href = "open:"+desc.getId()+"?id="+hit2.getId(); } 404 } 405 if (href==null) { 406 if (hit.getForceExternalWindow()) 407 href = "nw:"; href = part.parent.escapeSpecialChars(hit.toAbsoluteHref(hit.getHref(), false)); 409 } 410 buff.append(href); 411 buff.append("\""); if (hit.getCategory() != null && Platform.getWS() != Platform.WS_GTK) { 413 buff.append(" alt=\""); buff.append(hit.getCategory().getLabel()); 415 buff.append("\""); } 417 buff.append(">"); String elabel = null; 419 if (isPotentialHit) { 420 elabel = Messages.bind(Messages.SearchPart_potential_hit, hit.getLabel()); 422 } 423 else { 424 elabel = hit.getLabel(); 425 } 426 427 elabel = part.parent.escapeSpecialChars(elabel); 428 buff.append(elabel); 429 buff.append("</a>"); if (part.getShowDescription()) { 431 String edesc = hit.getDescription(); 432 if (edesc != null) { 433 edesc = part.parent.escapeSpecialChars(edesc); 434 buff.append("<br/>"); buff.append(edesc); 436 } 437 } 438 buff.append("</li>"); } 440 if (errorStatus != null) 441 updateErrorStatus(buff); 442 updateNavigation(results.length); 443 buff.append("</form>"); searchResults.setText(buff.toString(), true, false); 445 section.layout(); 446 if (reflow) 447 part.reflow(); 448 } 449 450 458 private String registerHitIcon(URL iconURL) { 459 Image image = HelpUIResources.getImage(iconURL); 460 if (image != null) { 461 searchResults.setImage(iconURL.toString(), image); 462 return iconURL.toString(); 463 } 464 return null; 465 } 466 467 475 private String registerGrayedHitIcon(URL iconURL) { 476 Image image = HelpUIResources.getImage(iconURL); 477 if (image != null) { 478 searchResults.setImage(iconURL.toString(), image); 479 return KEY_PREFIX_GRAYED + iconURL.toString(); 480 } 481 return null; 482 } 483 484 private void updateErrorStatus(StringBuffer buff) { 485 int indent = 21; 486 buff.append("<li indent=\"" + indent + "\" style=\"image\" value=\""); buff.append(ISharedImages.IMG_OBJS_ERROR_TSK); 488 buff.append("\">"); buff.append("<b>"); buff.append(part.parent.escapeSpecialChars(errorStatus.getMessage())); 491 buff.append("</b>"); buff.append("<br/>"); Throwable t = errorStatus.getException(); 494 if (t != null) 495 buff.append(part.parent.escapeSpecialChars(t.getMessage())); 496 buff.append("</li>"); } 498 499 private void updateNavigation(int size) { 500 if (size > HITS_PER_PAGE) { 501 if (prevLink == null) { 502 FormToolkit toolkit = part.getToolkit(); 503 Composite navContainer = toolkit.createComposite(container); 504 TableWrapData td = new TableWrapData(TableWrapData.FILL_GRAB); 505 navContainer.setLayoutData(td); 506 GridLayout glayout = new GridLayout(); 507 glayout.numColumns = 2; 508 navContainer.setLayout(glayout); 509 GridData gd; 510 515 prevLink = toolkit.createImageHyperlink(navContainer, SWT.NULL); 516 517 prevLink.setText(NLS.bind(Messages.EngineResultSection_previous, "" + HITS_PER_PAGE)); prevLink.setImage(PlatformUI.getWorkbench().getSharedImages().getImage( 519 ISharedImages.IMG_TOOL_BACK)); 520 prevLink.addHyperlinkListener(new HyperlinkAdapter() { 521 522 public void linkActivated(HyperlinkEvent e) { 523 resultOffset -= HITS_PER_PAGE; 524 asyncUpdateResults(false, true); 525 } 526 }); 527 nextLink = toolkit.createImageHyperlink(navContainer, SWT.RIGHT); 528 529 nextLink.setImage(PlatformUI.getWorkbench().getSharedImages().getImage( 530 ISharedImages.IMG_TOOL_FORWARD)); 531 gd = new GridData(GridData.HORIZONTAL_ALIGN_END); 532 gd.grabExcessHorizontalSpace = true; 533 nextLink.setLayoutData(gd); 534 nextLink.addHyperlinkListener(new HyperlinkAdapter() { 535 536 public void linkActivated(HyperlinkEvent e) { 537 resultOffset += HITS_PER_PAGE; 538 asyncUpdateResults(false, true); 539 } 540 }); 541 } 542 prevLink.setVisible(resultOffset > 0); 543 544 int nextOffset = resultOffset + HITS_PER_PAGE; 545 int remainder = hits.size() - nextOffset; 546 remainder = Math.min(remainder, HITS_PER_PAGE); 547 548 nextLink.setText(NLS.bind(Messages.EngineResultSection_next, "" + remainder)); nextLink.setVisible(hits.size() > resultOffset + HITS_PER_PAGE); 550 } else { 551 if (prevLink != null) { 552 prevLink.getParent().setMenu(null); 553 prevLink.getParent().dispose(); 554 prevLink = null; 555 nextLink = null; 556 } 557 } 558 } 559 560 private void updateSectionTitle(int size) { 561 if (errorStatus != null) { 562 Label label = part.getToolkit().createLabel(section, null); 563 label.setImage(PlatformUI.getWorkbench().getSharedImages().getImage( 564 ISharedImages.IMG_OBJS_ERROR_TSK)); 565 section.setTextClient(label); 566 section.setText(Messages.EngineResultSection_sectionTitle_error); 567 } else { 568 section.setTextClient(null); 569 } 570 if (size == 1) 571 section.setText(NLS.bind(Messages.EngineResultSection_sectionTitle_hit, desc.getLabel(), "" + hits.size())); 573 else if (size <= HITS_PER_PAGE) 574 section.setText(NLS.bind(Messages.EngineResultSection_sectionTitle_hits, desc.getLabel(), 575 "" + hits.size())); else { 577 int from = (resultOffset + 1); 578 int to = (resultOffset + HITS_PER_PAGE); 579 to = Math.min(to, size); 580 section.setText(NLS.bind(Messages.EngineResultSection_sectionTitle_hitsRange, new String [] { 581 desc.getLabel(), "" + from, "" + to, "" + size })); } 583 } 584 585 private void doBookmark(final String label, String href) { 586 final String fhref = href.substring(4); 587 BusyIndicator.showWhile(container.getDisplay(), new Runnable () { 588 589 public void run() { 590 BaseHelpSystem.getBookmarkManager().addBookmark(fhref, label); 591 } 592 }); 593 } 594 595 public void dispose() { 596 part.parent.unhookFormText(searchResults); 597 if (!section.isDisposed()) { 598 recursiveSetMenu(section, null); 599 section.dispose(); 600 } 601 } 602 603 private void recursiveSetMenu(Control control, Menu menu) { 604 control.setMenu(menu); 605 if (control instanceof Composite) { 606 Composite parent = (Composite) control; 607 Control[] children = parent.getChildren(); 608 for (int i = 0; i < children.length; i++) { 609 recursiveSetMenu(children[i], menu); 610 } 611 } 612 } 613 } 614 | Popular Tags |