1 19 20 package org.netbeans.editor; 21 22 import java.awt.Dimension ; 23 import java.awt.Point ; 24 import java.awt.Rectangle ; 25 import java.awt.event.KeyEvent ; 26 import java.awt.event.KeyListener ; 27 28 import javax.swing.Action ; 29 import javax.swing.ActionMap ; 30 import javax.swing.InputMap ; 31 import javax.swing.JComponent ; 32 import javax.swing.JLayeredPane ; 33 import javax.swing.JRootPane ; 34 import javax.swing.KeyStroke ; 35 import javax.swing.text.JTextComponent ; 36 37 import org.netbeans.editor.EditorUI; 38 import org.netbeans.editor.Utilities; 39 import java.awt.event.ComponentAdapter ; 40 import java.awt.event.ComponentEvent ; 41 import javax.swing.SwingUtilities ; 42 import java.awt.Component ; 43 import javax.swing.JViewport ; 44 import javax.swing.text.BadLocationException ; 45 46 47 54 public class PopupManager { 55 56 private JComponent popup = null; 57 private JTextComponent textComponent; 58 59 60 public static final Placement Above = new Placement("Above"); 62 63 public static final Placement Below = new Placement("Below"); 65 67 public static final Placement Largest = new Placement("Largest"); 69 71 public static final Placement AbovePreferred = new Placement("AbovePreferred"); 73 75 public static final Placement BelowPreferred = new Placement("BelowPreferred"); 77 78 public static final HorizontalBounds ViewPortBounds = new HorizontalBounds("ViewPort"); 80 81 public static final HorizontalBounds ScrollBarBounds = new HorizontalBounds("ScrollBar"); 83 private KeyListener keyListener; 84 85 private TextComponentListener componentListener; 86 87 88 public PopupManager(JTextComponent textComponent) { 89 this.textComponent = textComponent; 90 keyListener = new PopupKeyListener(); 91 textComponent.addKeyListener(keyListener); 92 componentListener = new TextComponentListener(); 93 textComponent.addComponentListener(componentListener); 94 } 95 96 103 public void install(JComponent popup) { 104 if (textComponent == null) return; 105 int caretPos = textComponent.getCaret().getDot(); 106 try { 107 Rectangle caretBounds = textComponent.modelToView(caretPos); 108 install(popup, caretBounds, Largest); 109 } catch (BadLocationException e) { 110 } 112 } 113 114 118 public void uninstall(JComponent popup){ 119 if (this.popup != null){ 120 if (this.popup.isVisible()) this.popup.setVisible(false); 121 removeFromRootPane(this.popup); 122 } 123 124 if (popup!=this.popup && popup!= null){ 125 if (popup.isVisible()) popup.setVisible(false); 126 removeFromRootPane(popup); 127 } 128 } 129 130 public void install(JComponent popup, Rectangle cursorBounds, 131 Placement placement, HorizontalBounds horizontalBounds, int horizontalAdjustment, int verticalAdjustment){ 132 137 if (this.popup != null) { 138 if (this.popup.isVisible() && this.popup!=popup) this.popup.setVisible(false); 141 removeFromRootPane(this.popup); 142 } 143 144 this.popup = popup; 145 146 if (this.popup != null) { 147 installToRootPane(this.popup); 148 } 149 150 Rectangle bounds = computeBounds(this.popup, textComponent, 152 cursorBounds, placement, horizontalBounds); 153 154 if (bounds != null){ 155 157 if (horizontalBounds == ScrollBarBounds){ 158 bounds.x = 0; 159 } 160 161 JRootPane rp = textComponent.getRootPane(); 162 if (rp!=null){ 163 bounds = SwingUtilities.convertRectangle(textComponent, bounds, 164 rp.getLayeredPane()); 165 } 166 167 if (horizontalBounds == ScrollBarBounds){ 168 if (textComponent.getParent() instanceof JViewport ){ 169 int shift = textComponent.getParent().getX(); 170 Rectangle viewBounds = ((JViewport )textComponent.getParent()).getViewRect(); 171 bounds.x += viewBounds.x; 172 bounds.x -= shift; 173 bounds.width += shift; 174 } 175 } 176 177 bounds.x = bounds.x + horizontalAdjustment; 178 bounds.y = bounds.y + verticalAdjustment; 179 bounds.width = bounds.width - horizontalAdjustment; 180 bounds.height = bounds.height - verticalAdjustment; 181 this.popup.setBounds(bounds); 182 183 } else { this.popup.setVisible(false); 185 } 186 } 187 188 public void install(JComponent popup, Rectangle cursorBounds, 189 Placement placement, HorizontalBounds horizontalBounds){ 190 install(popup, cursorBounds, placement, ViewPortBounds, 0, 0); 191 } 192 193 194 public void install(JComponent popup, Rectangle cursorBounds, 195 Placement placement){ 196 install(popup, cursorBounds, placement, ViewPortBounds); 197 } 198 199 200 public JComponent get(){ 201 return popup; 202 } 203 204 205 206 private void installToRootPane(JComponent c) { 207 JRootPane rp = textComponent.getRootPane(); 208 if (rp != null) { 209 rp.getLayeredPane().add(c, JLayeredPane.POPUP_LAYER, 0); 210 } 211 } 212 213 214 private void removeFromRootPane(JComponent c) { 215 JRootPane rp = c.getRootPane(); 216 if (rp != null) { 217 rp.getLayeredPane().remove(c); 218 } 219 } 220 221 236 protected static Rectangle computeBounds(JComponent popup, 237 JComponent view, Rectangle cursorBounds, Placement placement, HorizontalBounds horizontalBounds) { 238 239 if (horizontalBounds == null) horizontalBounds = ViewPortBounds; 240 241 Rectangle ret; 242 Component viewParent = view.getParent(); 243 244 if (viewParent instanceof JViewport ) { 245 Rectangle viewBounds = ((JViewport )viewParent).getViewRect(); 246 247 Rectangle translatedCursorBounds = (Rectangle )cursorBounds.clone(); 248 translatedCursorBounds.translate(-viewBounds.x, -viewBounds.y); 249 250 ret = computeBounds(popup, viewBounds.width, viewBounds.height, 251 translatedCursorBounds, placement, horizontalBounds); 252 253 if (ret != null) { ret.translate(viewBounds.x, viewBounds.y); 255 } 256 257 } else { ret = computeBounds(popup, view.getWidth(), view.getHeight(), 259 cursorBounds, placement); 260 } 261 262 return ret; 263 } 264 265 protected static Rectangle computeBounds(JComponent popup, 266 JComponent view, Rectangle cursorBounds, Placement placement) { 267 return computeBounds(popup, view, cursorBounds, placement, ViewPortBounds); 268 } 269 270 321 protected static Rectangle computeBounds(JComponent popup, 322 int viewWidth, int viewHeight, Rectangle cursorBounds, Placement placement, HorizontalBounds horizontalBounds) { 323 324 if (placement == null) { 325 throw new NullPointerException ("placement cannot be null"); } 327 328 int aboveCursorHeight = cursorBounds.y; 330 int belowCursorY = cursorBounds.y + cursorBounds.height; 331 int belowCursorHeight = viewHeight - belowCursorY; 332 333 if (placement == AbovePreferred || placement == BelowPreferred) { 335 int prefHeight = popup.getPreferredSize().height; 336 if (placement == AbovePreferred) { 337 placement = (prefHeight <= aboveCursorHeight) ? Above : Largest; 338 } else { placement = (prefHeight <= belowCursorHeight) ? Below : Largest; 340 } 341 } 342 343 if (placement == Largest) { 345 placement = (aboveCursorHeight < belowCursorHeight) 346 ? Below 347 : Above; 348 } 349 350 Rectangle popupBounds = null; 351 352 while (true) { popup.putClientProperty(Placement.class, placement); 354 355 int height = (placement == Above || placement == AbovePreferred) 356 ? aboveCursorHeight 357 : belowCursorHeight; 358 359 popup.setSize(viewWidth, height); 360 popupBounds = popup.getBounds(); 361 362 Placement updatedPlacement = (Placement)popup.getClientProperty(Placement.class); 363 364 if (updatedPlacement != placement) { if (placement == AbovePreferred && updatedPlacement == null) { 366 placement = Below; 367 continue; 368 369 } else if (placement == BelowPreferred && updatedPlacement == null) { 370 placement = Above; 371 continue; 372 } 373 } 374 375 if (updatedPlacement == null) { 376 popupBounds = null; 377 } 378 379 break; 380 } 381 382 if (popupBounds != null) { 383 popupBounds.x = Math.min(cursorBounds.x, viewWidth - popupBounds.width); 385 386 popupBounds.y = (placement == Above || placement == AbovePreferred) 387 ? (aboveCursorHeight - popupBounds.height) 388 : belowCursorY; 389 } 390 391 return popupBounds; 392 } 393 394 protected static Rectangle computeBounds(JComponent popup, 395 int viewWidth, int viewHeight, Rectangle cursorBounds, Placement placement) { 396 return computeBounds(popup, viewWidth, viewHeight, cursorBounds, placement, ViewPortBounds); 397 } 398 399 400 private class PopupKeyListener implements KeyListener { 401 402 public void keyTyped(KeyEvent e){} 403 public void keyReleased(KeyEvent e){} 404 405 public void keyPressed(KeyEvent e){ 406 if (e == null) return; 407 if (popup != null && popup.isShowing()){ 408 409 ActionMap am = popup.getActionMap(); 411 InputMap im = popup.getInputMap(); 412 413 Object obj = im.get(KeyStroke.getKeyStrokeForEvent(e)); 415 if (obj!=null){ 416 Action action = am.get(obj); 419 if (action != null) { 420 action.actionPerformed(null); 421 e.consume(); 422 } 423 } 424 } 425 } 426 427 } 428 429 private final class TextComponentListener extends ComponentAdapter { 430 431 public void componentHidden(ComponentEvent evt) { 432 install(null); } 434 435 } 436 437 438 public static final class Placement { 439 440 private final String representation; 441 442 private Placement(String representation) { 443 this.representation = representation; 444 } 445 446 public String toString() { 447 return representation; 448 } 449 450 } 451 452 453 public static final class HorizontalBounds { 454 455 private final String representation; 456 457 private HorizontalBounds(String representation) { 458 this.representation = representation; 459 } 460 461 public String toString() { 462 return representation; 463 } 464 465 } 466 467 } 468 469 | Popular Tags |