1 19 20 21 package org.netbeans.modules.editor.completion; 22 23 import java.awt.*; 24 import java.awt.event.ActionEvent ; 25 import java.awt.event.InputEvent ; 26 import java.awt.event.KeyEvent ; 27 import java.awt.event.MouseAdapter ; 28 import java.awt.event.MouseEvent ; 29 import java.io.IOException ; 30 import java.net.MalformedURLException ; 31 import java.net.URL ; 32 import java.util.ArrayList ; 33 import java.util.List ; 34 import javax.swing.*; 35 import javax.swing.event.HyperlinkEvent ; 36 import javax.swing.event.HyperlinkListener ; 37 import javax.swing.plaf.TextUI ; 38 import javax.swing.text.EditorKit ; 39 import javax.swing.text.JTextComponent ; 40 import javax.swing.text.Keymap ; 41 import javax.swing.text.html.HTMLDocument ; 42 43 import org.netbeans.editor.*; 44 import org.netbeans.editor.ext.ExtKit; 45 import org.netbeans.spi.editor.completion.CompletionDocumentation; 46 47 import org.openide.awt.HtmlBrowser; 48 import org.openide.awt.StatusDisplayer; 49 import org.openide.util.NbBundle; 50 51 55 public class DocumentationScrollPane extends JScrollPane { 56 57 private static final String BACK = "org/netbeans/modules/editor/completion/resources/back.png"; private static final String FORWARD = "org/netbeans/modules/editor/completion/resources/forward.png"; private static final String GOTO_SOURCE = "org/netbeans/modules/editor/completion/resources/open_source_in_editor.png"; private static final String SHOW_WEB = "org/netbeans/modules/editor/completion/resources/open_in_external_browser.png"; 62 private static final String JAVADOC_ESCAPE = "javadoc-escape"; private static final String JAVADOC_BACK = "javadoc-back"; private static final String JAVADOC_FORWARD = "javadoc-forward"; private static final String JAVADOC_OPEN_IN_BROWSER = "javadoc-open-in-browser"; private static final String JAVADOC_OPEN_SOURCE = "javadoc-open-source"; 68 private static final int ACTION_JAVADOC_ESCAPE = 0; 69 private static final int ACTION_JAVADOC_BACK = 1; 70 private static final int ACTION_JAVADOC_FORWARD = 2; 71 private static final int ACTION_JAVADOC_OPEN_IN_BROWSER = 3; 72 private static final int ACTION_JAVADOC_OPEN_SOURCE = 4; 73 74 private JButton bBack, bForward, bGoToSource, bShowWeb; 75 private HTMLDocView view; 76 77 private List <CompletionDocumentation> history = new ArrayList <CompletionDocumentation>(5); 79 private int currentHistoryIndex = -1; 80 protected CompletionDocumentation currentDocumentation = null; 81 82 private Dimension documentationPreferredSize; 83 84 85 public DocumentationScrollPane(JTextComponent editorComponent) { 86 super(); 87 88 documentationPreferredSize = CompletionSettings.INSTANCE.documentationPopupPreferredSize(); 90 setPreferredSize(null); 92 Color bgColor = CompletionSettings.INSTANCE.documentationBackgroundColor(); 93 94 view = new HTMLDocView(bgColor); 96 view.addHyperlinkListener(new HyperlinkAction()); 97 setViewportView(view); 98 99 installTitleComponent(); 100 installKeybindings(editorComponent); 101 setFocusable(false); 102 } 103 104 public void setPreferredSize(Dimension preferredSize) { 105 if (preferredSize == null) { 106 preferredSize = documentationPreferredSize; 107 } 108 super.setPreferredSize(preferredSize); 109 } 110 111 112 public void setData(CompletionDocumentation doc) { 113 setDocumentation(doc); 114 addToHistory(doc); 115 } 116 117 private ImageIcon resolveIcon(String res){ 118 return new ImageIcon(org.openide.util.Utilities.loadImage (res)); 119 } 120 121 private void installTitleComponent() { 122 JToolBar toolbar = new JToolBar(); 123 toolbar.setFloatable(false); 124 toolbar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIManager.getColor("controlDkShadow"))); toolbar.setLayout(new GridBagLayout()); 126 127 GridBagConstraints gdc = new GridBagConstraints(); 128 gdc.gridx = 0; 129 gdc.gridy = 0; 130 gdc.anchor = GridBagConstraints.WEST; 131 ImageIcon icon = resolveIcon(BACK); 132 if (icon != null) { 133 bBack = new BrowserButton(icon); 134 bBack.addMouseListener(new MouseEventListener(bBack)); 135 bBack.setEnabled(false); 136 bBack.setFocusable(false); 137 bBack.setContentAreaFilled(false); 138 bBack.setMargin(new Insets(0, 0, 0, 0)); 139 bBack.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_back_button")); toolbar.add(bBack, gdc); 141 } 142 143 gdc.gridx = 1; 144 gdc.gridy = 0; 145 gdc.anchor = GridBagConstraints.WEST; 146 icon = resolveIcon(FORWARD); 147 if (icon != null) { 148 bForward = new BrowserButton(icon); 149 bForward.addMouseListener(new MouseEventListener(bForward)); 150 bForward.setEnabled(false); 151 bForward.setFocusable(false); 152 bForward.setContentAreaFilled(false); 153 bForward.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_forward_button")); bForward.setMargin(new Insets(0, 0, 0, 0)); 155 toolbar.add(bForward, gdc); 156 } 157 158 gdc.gridx = 2; 159 gdc.gridy = 0; 160 gdc.anchor = GridBagConstraints.WEST; 161 icon = resolveIcon(SHOW_WEB); 162 if (icon != null) { 163 bShowWeb = new BrowserButton(icon); 164 bShowWeb.addMouseListener(new MouseEventListener(bShowWeb)); 165 bShowWeb.setEnabled(false); 166 bShowWeb.setFocusable(false); 167 bShowWeb.setContentAreaFilled(false); 168 bShowWeb.setMargin(new Insets(0, 0, 0, 0)); 169 bShowWeb.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_show_web_button")); toolbar.add(bShowWeb, gdc); 171 } 172 173 gdc.gridx = 3; 174 gdc.gridy = 0; 175 gdc.weightx = 1.0; 176 gdc.anchor = GridBagConstraints.WEST; 177 icon = resolveIcon(GOTO_SOURCE); 178 if (icon != null) { 179 bGoToSource = new BrowserButton(icon); 180 bGoToSource.addMouseListener(new MouseEventListener(bGoToSource)); 181 bGoToSource.setEnabled(false); 182 bGoToSource.setFocusable(false); 183 bGoToSource.setContentAreaFilled(false); 184 bGoToSource.setMargin(new Insets(0, 0, 0, 0)); 185 bGoToSource.setToolTipText(NbBundle.getMessage(DocumentationScrollPane.class, "HINT_doc_browser_goto_source_button")); toolbar.add(bGoToSource, gdc); 187 } 188 setColumnHeaderView(toolbar); 189 } 190 191 private synchronized void setDocumentation(CompletionDocumentation doc) { 192 currentDocumentation = doc; 193 String text = currentDocumentation.getText(); 194 URL url = currentDocumentation.getURL(); 195 if (text != null){ 196 if (url!=null){ 197 javax.swing.text.Document document = view.getDocument(); 199 if (document instanceof HTMLDocument ){ 200 ((HTMLDocument )document).setBase(url); 201 } 202 } 203 if (currentDocumentation instanceof DefaultDoc) { 204 String ref = ((DefaultDoc)currentDocumentation).desc; 205 view.setContent(text, ref.startsWith("#") ? ref.substring(1) : null); } else { 207 view.setContent(text, null); 208 } 209 } else if (url != null){ 210 try{ 211 view.setPage(url); 212 }catch(IOException ioe){ 213 StatusDisplayer.getDefault().setStatusText(ioe.toString()); 214 } 215 } 216 bShowWeb.setEnabled(url != null); 217 bGoToSource.setEnabled(currentDocumentation.getGotoSourceAction() != null); 218 } 219 220 private synchronized void addToHistory(CompletionDocumentation doc) { 221 int histSize = history.size(); 222 for (int i = currentHistoryIndex + 1; i < histSize; i++){ 223 history.remove(history.size() - 1); 224 } 225 history.add(doc); 226 currentHistoryIndex = history.size() - 1; 227 if (currentHistoryIndex > 0) 228 bBack.setEnabled(true); 229 bForward.setEnabled(false); 230 } 231 232 private synchronized void backHistory() { 233 if (currentHistoryIndex > 0) { 234 currentHistoryIndex--; 235 setDocumentation(history.get(currentHistoryIndex)); 236 if (currentHistoryIndex == 0) 237 bBack.setEnabled(false); 238 bForward.setEnabled(true); 239 } 240 } 241 242 private synchronized void forwardHistory(){ 243 if (currentHistoryIndex <history.size()-1){ 244 currentHistoryIndex++; 245 setDocumentation(history.get(currentHistoryIndex)); 246 if (currentHistoryIndex == history.size() - 1) 247 bForward.setEnabled(false); 248 bBack.setEnabled(true); 249 } 250 } 251 252 synchronized void clearHistory(){ 253 currentHistoryIndex = -1; 254 history.clear(); 255 bBack.setEnabled(false); 256 bForward.setEnabled(false); 257 } 258 259 private void openInExternalBrowser(){ 260 URL url = currentDocumentation.getURL(); 261 if (url != null) 262 HtmlBrowser.URLDisplayer.getDefault().showURL(url); 263 } 264 265 private void goToSource() { 266 Action action = currentDocumentation.getGotoSourceAction(); 267 if (action != null) 268 action.actionPerformed(new ActionEvent (currentDocumentation, 0, null)); 269 } 270 271 272 private KeyStroke[] findEditorKeys(String editorActionName, KeyStroke defaultKey, JTextComponent component) { 273 KeyStroke[] ret = new KeyStroke[] { defaultKey }; 276 if (component != null) { 277 TextUI ui = component.getUI(); 278 Keymap km = component.getKeymap(); 279 if (ui != null && km != null) { 280 EditorKit kit = ui.getEditorKit(component); 281 if (kit instanceof BaseKit) { 282 Action a = ((BaseKit)kit).getActionByName(editorActionName); 283 if (a != null) { 284 KeyStroke[] keys = km.getKeyStrokesForAction(a); 285 if (keys != null && keys.length > 0) { 286 ret = keys; 287 } 288 } 289 } 290 } 291 } 292 return ret; 293 } 294 295 private void registerKeybinding(int action, String actionName, KeyStroke stroke, String editorActionName, JTextComponent component){ 296 KeyStroke[] keys = findEditorKeys(editorActionName, stroke, component); 297 for (int i = 0; i < keys.length; i++) { 298 getInputMap().put(keys[i], actionName); 299 } 300 getActionMap().put(actionName, new DocPaneAction(action)); 301 } 302 303 private void installKeybindings(JTextComponent component) { 304 registerKeybinding(ACTION_JAVADOC_ESCAPE, JAVADOC_ESCAPE, 306 KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), 307 ExtKit.escapeAction, component); 308 309 registerKeybinding(ACTION_JAVADOC_BACK, JAVADOC_BACK, 311 KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.ALT_MASK), 312 null, component); 313 314 registerKeybinding(ACTION_JAVADOC_FORWARD, JAVADOC_FORWARD, 316 KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.ALT_MASK), 317 null, component); 318 319 registerKeybinding(ACTION_JAVADOC_OPEN_IN_BROWSER, JAVADOC_OPEN_IN_BROWSER, 321 KeyStroke.getKeyStroke(KeyEvent.VK_F1, KeyEvent.ALT_MASK | KeyEvent.SHIFT_MASK), 322 null, component); 323 324 registerKeybinding(ACTION_JAVADOC_OPEN_SOURCE, JAVADOC_OPEN_SOURCE, 326 KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.ALT_MASK | KeyEvent.CTRL_MASK), 327 null, component); 328 329 mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)); 331 mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)); 332 mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0)); 333 mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0)); 334 mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, KeyEvent.CTRL_MASK)); 335 mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_END, KeyEvent.CTRL_MASK)); 336 mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0)); 337 mapWithShift(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)); 338 } 339 340 private void mapWithShift(KeyStroke key) { 341 InputMap inputMap = getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 342 Object actionKey = inputMap.get(key); 343 if (actionKey != null) { 344 key = KeyStroke.getKeyStroke(key.getKeyCode(), key.getModifiers() | InputEvent.SHIFT_MASK); 345 getInputMap().put(key, actionKey); 346 } 347 } 348 349 private class BrowserButton extends JButton { 350 public BrowserButton() { 351 setBorderPainted(false); 352 setFocusPainted(false); 353 } 354 355 public BrowserButton(String text){ 356 super(text); 357 setBorderPainted(false); 358 setFocusPainted(false); 359 } 360 361 public BrowserButton(Icon icon){ 362 super(icon); 363 setBorderPainted(false); 364 setFocusPainted(false); 365 } 366 367 public void setEnabled(boolean b) { 368 super.setEnabled(b); 369 } 370 371 372 } 373 374 private class MouseEventListener extends MouseAdapter { 375 private JButton button; 376 377 MouseEventListener(JButton button) { 378 this.button = button; 379 } 380 381 public void mouseEntered(MouseEvent ev) { 382 if (button.isEnabled()){ 383 button.setContentAreaFilled(true); 384 button.setBorderPainted(true); 385 } 386 } 387 public void mouseExited(MouseEvent ev) { 388 button.setContentAreaFilled(false); 389 button.setBorderPainted(false); 390 } 391 392 public void mouseClicked(MouseEvent evt) { 393 if (button.equals(bBack)){ 394 backHistory(); 395 }else if(button.equals(bForward)){ 396 forwardHistory(); 397 }else if(button.equals(bGoToSource)){ 398 goToSource(); 399 }else if (button.equals(bShowWeb)){ 400 openInExternalBrowser(); 401 } 402 } 403 } 404 405 private class HyperlinkAction implements HyperlinkListener { 406 407 public void hyperlinkUpdate(HyperlinkEvent e) { 408 if (e != null && HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) { 409 final String desc = e.getDescription(); 410 if (desc != null) { 411 CompletionDocumentation doc = currentDocumentation.resolveLink(desc); 412 if (doc == null) 413 doc = new DefaultDoc(currentDocumentation, desc); 414 setData(doc); 415 } 416 } 417 } 418 } 419 420 private class DefaultDoc implements CompletionDocumentation { 421 422 private CompletionDocumentation baseDoc = null; 423 private URL url = null; 424 private String desc = null; 425 426 private DefaultDoc(CompletionDocumentation baseDoc, String desc) { 427 try { 428 url = new URL (baseDoc.getURL(), desc); 429 } catch (MalformedURLException ex) { 430 this.baseDoc = baseDoc; 431 this.desc = desc; 432 } 433 } 434 435 public String getText() { 436 return baseDoc != null ? baseDoc.getText() : null; 437 } 438 439 public URL getURL() { 440 return url; 441 } 442 443 public CompletionDocumentation resolveLink(String link) { 444 return baseDoc != null ? baseDoc.resolveLink(link) : null; 445 } 446 447 public Action getGotoSourceAction() { 448 return null; 449 } 450 } 451 452 private class DocPaneAction extends AbstractAction { 453 private int action; 454 455 private DocPaneAction(int action) { 456 this.action = action; 457 } 458 459 public void actionPerformed(java.awt.event.ActionEvent actionEvent) { 460 switch (action) { 461 case ACTION_JAVADOC_ESCAPE: 462 CompletionImpl.get().hideDocumentation(false); 463 break; 464 case ACTION_JAVADOC_BACK: 465 backHistory(); 466 break; 467 case ACTION_JAVADOC_FORWARD: 468 forwardHistory(); 469 break; 470 case ACTION_JAVADOC_OPEN_IN_BROWSER: 471 openInExternalBrowser(); 472 break; 473 case ACTION_JAVADOC_OPEN_SOURCE: 474 goToSource(); 475 break; 476 } 477 478 } 479 } 480 } 481 | Popular Tags |