1 19 20 21 package org.netbeans.modules.palette.ui; 22 23 import java.awt.BorderLayout ; 24 import java.awt.Color ; 25 import java.awt.Component ; 26 import java.awt.Container ; 27 import java.awt.FocusTraversalPolicy ; 28 import java.awt.Image ; 29 import java.awt.Insets ; 30 import java.awt.KeyboardFocusManager ; 31 import java.awt.Point ; 32 import java.awt.Rectangle ; 33 import java.awt.dnd.Autoscroll ; 34 import java.awt.event.ActionEvent ; 35 import java.awt.event.KeyEvent ; 36 import java.awt.event.MouseEvent ; 37 import java.beans.BeanInfo ; 38 import java.lang.ref.WeakReference ; 39 import javax.swing.AbstractAction ; 40 import javax.swing.Action ; 41 import javax.swing.ActionMap ; 42 import javax.swing.BorderFactory ; 43 import javax.swing.ImageIcon ; 44 import javax.swing.InputMap ; 45 import javax.swing.JComponent ; 46 import javax.swing.JList ; 47 import javax.swing.JPopupMenu ; 48 import javax.swing.JToggleButton ; 49 import javax.swing.JToolBar ; 50 import javax.swing.KeyStroke ; 51 import javax.swing.ListCellRenderer ; 52 import javax.swing.ListSelectionModel ; 53 import javax.swing.SwingConstants ; 54 import javax.swing.SwingUtilities ; 55 import javax.swing.UIManager ; 56 import javax.swing.border.Border ; 57 import javax.swing.border.EmptyBorder ; 58 import javax.swing.event.MouseInputListener ; 59 import javax.swing.plaf.basic.BasicListUI ; 60 import org.netbeans.modules.palette.Category; 61 import org.netbeans.modules.palette.Item; 62 import org.netbeans.modules.palette.Utils; 63 import org.openide.nodes.Node; 64 import org.openide.util.Utilities; 65 66 73 74 public class CategoryList extends JList implements Autoscroll { 75 76 private int rolloverIndex = -1; 77 private boolean showNames; 78 79 static final int BASIC_ICONSIZE = BeanInfo.ICON_COLOR_16x16; 80 private int iconSize = BASIC_ICONSIZE; 81 82 private Category category; 83 private PalettePanel palettePanel; 84 85 private static WeakReference <ListCellRenderer > rendererRef; 86 87 private Item draggingItem; 88 89 private AutoscrollSupport support; 90 91 94 CategoryList( Category category, PalettePanel palettePanel ) { 95 this.category = category; 96 this.palettePanel = palettePanel; 97 setBackground(UIManager.getColor ("Panel.background")); 98 setBorder (new EmptyBorder (0, 0, 0, 0)); 99 setVisibleRowCount (0); 100 setSelectionMode (ListSelectionModel.SINGLE_SELECTION); 101 setCellRenderer (getItemRenderer ()); 102 setLayoutOrientation( HORIZONTAL_WRAP ); 103 getAccessibleContext().setAccessibleName( category.getDisplayName() ); 104 getAccessibleContext().setAccessibleDescription( category.getShortDescription() ); 105 106 initActions(); 107 } 108 109 private void initActions() { 110 InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED); 111 inputMap.put( KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0, false ), "defaultAction" ); 112 inputMap.put( KeyStroke.getKeyStroke( KeyEvent.VK_F10, KeyEvent.SHIFT_DOWN_MASK, false ), "popup" ); 113 114 ActionMap map = getActionMap(); 115 map.put( "defaultAction", new DefaultAction( this ) ); 116 map.put( "popup", new PopupAction() ); 117 map.put( "selectPreviousRow", new MoveFocusAction( map.get( "selectPreviousRow" ), false ) ); 118 map.put( "selectNextRow", new MoveFocusAction( map.get( "selectNextRow" ), true ) ); 119 map.put( "selectPreviousColumn", new MoveFocusAction( new ChangeColumnAction( map.get( "selectPreviousColumn" ), false ), false ) ); 120 map.put( "selectNextColumn", new MoveFocusAction( new ChangeColumnAction( map.get( "selectNextColumn" ), true ), true ) ); 121 Node categoryNode = (Node)category.getLookup().lookup( Node.class ); 122 if( null != categoryNode ) 123 map.put( "paste", new Utils.PasteItemAction( categoryNode ) ); 124 else 125 map.remove( "paste" ); 126 map.put( "copy", new CutCopyAction( true ) ); 127 map.put( "cut", new CutCopyAction( false ) ); 128 } 129 130 Item getItemAt( int index ) { 131 if( index < 0 || index >= getModel().getSize() ) 132 return null; 133 134 return (Item)getModel().getElementAt( index ); 135 } 136 137 Category getCategory() { 138 return category; 139 } 140 141 public void updateUI () { 142 if( null != rendererRef ) 143 rendererRef.clear(); 144 setUI (new CategoryListUI ()); 145 invalidate (); 146 } 147 148 Integer tempWidth; 155 156 public int getWidth () { 157 return (tempWidth == null) ? super.getWidth () : tempWidth.intValue (); 158 } 159 160 162 boolean getShowNames () { 163 return showNames; 164 } 165 166 void setShowNames (boolean show) { 167 if (show != showNames) { 168 showNames = show; 169 firePropertyChange ("cellRenderer", null, null); } 171 } 172 173 int getIconSize () { 174 return iconSize; 175 } 176 177 void setIconSize (int size) { 178 if (size != iconSize) { 179 iconSize = size; 180 firePropertyChange ("cellRenderer", null, null); } 182 } 183 184 public int getScrollableUnitIncrement (Rectangle visibleRect, int orientation, int direction) { 190 int row; 191 if (orientation == SwingConstants.VERTICAL && 192 direction < 0 && (row = getFirstVisibleIndex ()) != -1) { 193 Rectangle r = getCellBounds (row, row); 194 if ((r.y == visibleRect.y) && (row != 0)) { 195 Point loc = r.getLocation (); 196 loc.y--; 197 int prevIndex = locationToIndex (loc); 198 Rectangle prevR = getCellBounds (prevIndex, prevIndex); 199 200 if (prevR == null || prevR.y >= r.y) { 201 return 0; 202 } 203 return prevR.height; 204 } 205 } 206 return super.getScrollableUnitIncrement (visibleRect, orientation, direction); 207 } 208 209 214 public int getPreferredHeight (int width) { 215 return ((CategoryListUI) getUI ()).getPreferredHeight (width); 216 } 217 218 public void resetRollover() { 219 rolloverIndex = -1; 220 repaint(); 221 } 222 223 int getColumnCount() { 224 if( getModel().getSize() > 0 ) { 225 Insets insets = getInsets (); 226 int listWidth = getWidth () - (insets.left + insets.right); 227 int cellWidth = getCellBounds( 0, 0 ).width; 228 if( listWidth >= cellWidth ) { 229 return listWidth / cellWidth; 230 } 231 } 232 return 1; 233 } 234 235 238 private static ListCellRenderer getItemRenderer () { 239 ListCellRenderer renderer = rendererRef == null ? null : rendererRef.get (); 240 if (renderer == null) { 241 renderer = new ItemRenderer (); 242 rendererRef = new WeakReference <ListCellRenderer >( renderer ); 243 } 244 return renderer; 245 } 246 247 static class ItemRenderer implements ListCellRenderer { 248 249 250 private JToolBar toolbar; 251 252 private JToggleButton button; 253 254 ItemRenderer () { 255 if (button == null) { 256 button = new JToggleButton (); 257 button.setMargin (new Insets (1, 1, 1, 0)); 258 259 if (!CategoryButton.isGTK) { 260 toolbar = new JToolBar (); 261 toolbar.setRollover (true); 262 toolbar.setFloatable (false); 263 toolbar.setLayout (new BorderLayout (0, 0)); 264 toolbar.setBorder (BorderFactory.createEmptyBorder()); 265 toolbar.add (button); 266 } 267 } 268 } 269 270 public Component getListCellRendererComponent (JList list, 271 Object value, 272 int index, 273 boolean isSelected, 274 boolean cellHasFocus) { 275 CategoryList categoryList = (CategoryList) list; 276 boolean showNames = categoryList.getShowNames (); 277 int iconSize = categoryList.getIconSize (); 278 279 JComponent rendererComponent = toolbar != null ? toolbar : button; 280 281 Item item = (Item) value; 282 Image icon = item.getIcon (iconSize); 283 if (icon != null) { 284 button.setIcon (new ImageIcon (icon)); 285 } 286 287 button.setText (showNames ? item.getDisplayName () : null); 288 rendererComponent.setToolTipText( item.getShortDescription() ); 290 button.setSelected (isSelected); 291 button.getModel ().setRollover (index == categoryList.rolloverIndex && !isSelected); 294 297 button.setBorderPainted ((index == categoryList.rolloverIndex) || isSelected); 298 299 button.setHorizontalAlignment (showNames ? SwingConstants.LEFT : SwingConstants.CENTER); 300 button.setHorizontalTextPosition (SwingConstants.RIGHT); 301 button.setVerticalTextPosition (SwingConstants.CENTER); 302 303 return rendererComponent; 304 } 305 } 306 307 308 public void autoscroll( Point cursorLoc ) { 309 if( null != getParent() && null != getParent().getParent() ) { 310 Point p = SwingUtilities.convertPoint( this, cursorLoc, getParent().getParent() ); 311 getSupport().autoscroll( p ); 312 } 313 } 314 315 319 public Insets getAutoscrollInsets() { 320 return getSupport().getAutoscrollInsets(); 321 } 322 323 324 AutoscrollSupport getSupport() { 325 if( null == support ) { 326 support = new AutoscrollSupport( getParent().getParent() ); 327 } 328 329 return support; 330 } 331 332 335 void takeFocusFrom( Component c ) { 336 int indexToSelect = -1; 337 if( c.getParent() != getParent() ) { 338 indexToSelect = getModel().getSize()-1; 340 } else if( getModel().getSize() > 0 ) { 341 indexToSelect = 0; 342 } 343 requestFocus(); 344 setSelectedIndex( indexToSelect ); 345 if( indexToSelect >= 0 ) { 346 ensureIndexIsVisible( indexToSelect ); 347 } 348 } 349 350 351 354 static class CategoryListUI extends BasicListUI { 355 356 protected void updateLayoutState () { 357 super.updateLayoutState (); 358 359 if (list.getLayoutOrientation () == JList.HORIZONTAL_WRAP) { 360 Insets insets = list.getInsets (); 361 int listWidth = list.getWidth () - (insets.left + insets.right); 362 if (listWidth >= cellWidth) { 363 int columnCount = listWidth / cellWidth; 364 cellWidth = (columnCount == 0) ? 1 : listWidth / columnCount; 365 } 366 } 367 } 368 369 public int getPreferredHeight (int width) { 370 ((CategoryList) list).tempWidth = Integer.valueOf (width); 371 int result; 372 try { 373 result = (int) getPreferredSize (list).getHeight (); 374 } finally { 375 ((CategoryList) list).tempWidth = null; 376 } 377 return result; 378 } 379 380 protected MouseInputListener createMouseInputListener () { 381 return new ListMouseInputHandler (); 382 } 383 384 private class ListMouseInputHandler extends MouseInputHandler { 385 386 int selIndex = -1; 387 388 public void mouseClicked(MouseEvent e) { 389 if( !list.isEnabled() ) 390 return; 391 392 if( e.getClickCount() > 1 ) { 393 selIndex = getValidIndex( e.getPoint() ); 394 if( selIndex >= 0 ) { 395 list.setSelectedIndex( selIndex ); 396 Item item = (Item)list.getModel().getElementAt( selIndex ); 397 ActionEvent ae = new ActionEvent ( e.getSource(), e.getID(), "doubleclick", e.getWhen(), e.getModifiers() ); 398 item.invokePreferredAction( ae ); 399 e.consume(); 400 } 401 } 402 } 403 404 public void mousePressed( MouseEvent e ) { 405 if( getValidIndex( e.getPoint() ) >= 0 ) { 406 selIndex = list.getSelectedIndex (); 407 super.mousePressed (e); 408 } 409 } 410 411 public void mouseDragged( MouseEvent e ) { 412 } 413 414 public void mouseMoved( MouseEvent e ) { 415 mouseEntered( e ); 416 } 417 418 public void mouseEntered( MouseEvent e ) { 419 if( list.isEnabled() ) 420 setRolloverIndex( getValidIndex( e.getPoint() ) ); 421 } 422 423 public void mouseExited( MouseEvent e ) { 424 if( list.isEnabled() ) 425 setRolloverIndex( -1 ); 426 } 427 428 public void mouseReleased( MouseEvent e ) { 429 if( getValidIndex( e.getPoint() ) >= 0) { 430 super.mouseReleased (e); 431 if( selIndex > -1 && list.getSelectedIndex () == selIndex ) 432 list.removeSelectionInterval( selIndex, selIndex ); 433 } 434 } 435 436 private void setRolloverIndex (int index) { 437 int oldIndex = ((CategoryList) list).rolloverIndex; 438 if (index != oldIndex) { 439 ((CategoryList) list).rolloverIndex = index; 440 if (oldIndex > -1) { 441 Rectangle r = getCellBounds (list, oldIndex, oldIndex); 442 if (r != null) 443 list.repaint (r.x, r.y, r.width, r.height); 444 } 445 if (index > -1) { 446 Rectangle r = getCellBounds (list, index, index); 447 if (r != null) 448 list.repaint (r.x, r.y, r.width, r.height); 449 } 450 } 451 } 452 } 453 454 private int getValidIndex (Point p) { 455 int index = locationToIndex (list, p); 456 return index >= 0 && getCellBounds (list, index, index).contains (p) ? 457 index : -1; 458 } 459 } 460 461 private static class DefaultAction extends AbstractAction { 462 private CategoryList list; 463 public DefaultAction( CategoryList list ) { 464 this.list = list; 465 } 466 467 public void actionPerformed( ActionEvent e ) { 468 Item item = list.getItemAt( list.getSelectedIndex() ); 469 item.invokePreferredAction( e ); 470 } 471 472 public boolean isEnabled() { 473 return list.isEnabled() && list.getSelectedIndex() >= 0; 474 } 475 } 476 477 private class PopupAction extends AbstractAction { 478 479 public void actionPerformed(ActionEvent e) { 480 int posX = 0; 481 int posY = 0; 482 Item item = getItemAt( getSelectedIndex() ); 483 if( null != item ) { 484 Rectangle rect = getCellBounds( getSelectedIndex(), getSelectedIndex() ); 485 posX = rect.x; 486 posY = rect.y + rect.height; 487 } 488 Action [] actions = null == item ? category.getActions() : item.getActions(); 489 JPopupMenu popup = Utilities.actionsToPopup( actions, CategoryList.this ); 490 Utils.addCustomizationMenuItems( popup, palettePanel.getController(), palettePanel.getSettings() ); 491 popup.show( getParent(), posX, posY ); 492 } 493 494 public boolean isEnabled() { 495 return CategoryList.this.isEnabled(); 496 } 497 } 498 499 private class MoveFocusAction extends AbstractAction { 500 private Action defaultAction; 501 private boolean focusNext; 502 503 public MoveFocusAction( Action defaultAction, boolean focusNext ) { 504 this.defaultAction = defaultAction; 505 this.focusNext = focusNext; 506 } 507 508 public void actionPerformed(ActionEvent e) { 509 int selIndexBefore = getSelectedIndex(); 510 defaultAction.actionPerformed( e ); 511 int selIndexCurrent = getSelectedIndex(); 512 if( selIndexBefore != selIndexCurrent ) 513 return; 514 515 if( focusNext && 0 == selIndexCurrent ) 516 return; 517 518 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); 519 Container container = kfm.getCurrentFocusCycleRoot(); 520 FocusTraversalPolicy policy = container.getFocusTraversalPolicy(); 521 if( null == policy ) 522 policy = kfm.getDefaultFocusTraversalPolicy(); 523 Component next = focusNext ? policy.getComponentAfter( container, CategoryList.this ) 524 : policy.getComponentBefore( container, CategoryList.this ); 525 if( null != next && next instanceof CategoryButton ) { 526 clearSelection(); 527 next.requestFocus(); 528 } 529 } 530 } 531 532 private class ChangeColumnAction extends AbstractAction { 533 private Action defaultAction; 534 private boolean selectNext; 535 536 public ChangeColumnAction( Action defaultAction, boolean selectNext ) { 537 this.defaultAction = defaultAction; 538 this.selectNext = selectNext; 539 } 540 541 public void actionPerformed(ActionEvent e) { 542 int selIndexBefore = getSelectedIndex(); 543 defaultAction.actionPerformed( e ); 544 int selIndexCurrent = getSelectedIndex(); 545 if( (selectNext && selIndexBefore < selIndexCurrent) 546 || 547 (!selectNext && selIndexBefore > selIndexCurrent) ) 548 return; 549 550 if( selectNext ) { 551 if( selIndexCurrent == selIndexBefore+1 ) 552 selIndexCurrent++; 553 if( selIndexCurrent < getModel().getSize()-1 ) { 554 setSelectedIndex( selIndexCurrent+1 ); 555 scrollRectToVisible( getCellBounds( selIndexCurrent+1, selIndexCurrent+1 ) ); 556 } 557 } else { 558 if( selIndexCurrent > 0 ) { 559 setSelectedIndex( selIndexCurrent-1 ); 560 scrollRectToVisible( getCellBounds( selIndexCurrent-1, selIndexCurrent-1 ) ); 561 } 562 } 563 } 564 } 565 566 private class CutCopyAction extends AbstractAction { 567 private boolean doCopy; 568 public CutCopyAction( boolean doCopy ) { 569 this.doCopy = doCopy; 570 } 571 572 public void actionPerformed( ActionEvent e ) { 573 Item item = getItemAt( getSelectedIndex() ); 574 if( null == item ) 575 return; 576 Node itemNode = (Node)item.getLookup().lookup( Node.class ); 577 if( null == itemNode ) 578 return; 579 Action performer; 580 if( doCopy ) 581 performer = new Utils.CopyItemAction( itemNode ); 582 else 583 performer = new Utils.CutItemAction( itemNode ); 584 if( performer.isEnabled() ) 585 performer.actionPerformed( e ); 586 } 587 588 public boolean isEnabled() { 589 return getSelectedIndex() >= 0; 590 } 591 } 592 } 593 | Popular Tags |