1 package com.sun.java.swing.plaf.windows; 2 3 import com.sun.java.swing.plaf.windows.WindowsFileChooserUI.WindowsFileListUI; 4 import java.awt.Color; 5 import java.awt.Component; 6 import java.awt.Dimension; 7 import java.awt.Graphics; 8 import java.awt.Insets; 9 import java.awt.Rectangle; 10 import static java.awt.Toolkit.getDefaultToolkit; 11 import java.awt.event.MouseAdapter; 12 import java.awt.event.MouseEvent; 13 import java.beans.PropertyChangeEvent; 14 import java.beans.PropertyChangeListener; 15 import java.io.File; 16 import java.io.FileNotFoundException; 17 import java.io.UncheckedIOException; 18 import java.util.Arrays; 19 import java.util.Collections; 20 import static java.util.Collections.emptyList; 21 import java.util.Enumeration; 22 import java.util.HashMap; 23 import java.util.List; 24 import java.util.Map; 25 import static java.util.stream.Collectors.toList; 26 import javax.swing.JComponent; 27 import javax.swing.JFileChooser; 28 import javax.swing.JTree; 29 import javax.swing.filechooser.FileSystemView; 30 import javax.swing.tree.DefaultTreeCellRenderer; 31 import javax.swing.tree.DefaultTreeModel; 32 import javax.swing.tree.TreeNode; 33 import javax.swing.tree.TreePath; 34 import sun.awt.shell.ShellFolder; 35 import static sun.awt.shell.ShellFolder.getShellFolder; 36 import static com.sun.java.swing.plaf.windows.WindowsFileChooserUI.WindowsFileListUI.ITEM_SELECTED_COLOR; 37 import static com.sun.java.swing.plaf.windows.WindowsFileChooserUI.WindowsFileListUI.ITEM_HOVERED_COLOR; 38 import java.awt.AlphaComposite; 39 import java.awt.Composite; 40 import java.awt.Cursor; 41 import java.awt.Graphics2D; 42 import java.awt.Image; 43 import java.awt.Point; 44 import java.awt.image.BufferedImage; 45 import static java.lang.Boolean.TRUE; 46 import static java.time.Duration.between; 47 import java.time.Instant; 48 import static java.time.Instant.now; 49 import java.util.ArrayList; 50 import java.util.function.Supplier; 51 import javax.swing.Icon; 52 import javax.swing.ImageIcon; 53 import static javax.swing.JFileChooser.FILE_SYSTEM_VIEW_CHANGED_PROPERTY; 54 import javax.swing.JScrollPane; 55 import javax.swing.JSeparator; 56 import javax.swing.JViewport; 57 import javax.swing.Timer; 58 import javax.swing.UIManager; 59 import javax.swing.filechooser.FileSystemView.EssentialFolderSection; 60 import javax.swing.tree.TreeSelectionModel; 61 import static javax.swing.tree.TreeSelectionModel.SINGLE_TREE_SELECTION; 62 63 public class WindowsNavigationTree extends JTree implements PropertyChangeListener { 64 65 private int hover = -1; 66 private Point mousePoint; 67 68 private final JFileChooser fileChooser; 69 private final FileSystemView view; 70 71 private static final Icon EXPAND_ICON = new ImageIcon(initRightArrowNormalImage()); 72 private static final Icon COLLAPSE_ICON = new ImageIcon(initDownArrowNormalImage()); 73 74 private static final Icon EXPAND_ICON_HOVER = new ImageIcon(initRightArrowHoverImage()); 75 private static final Icon COLLAPSE_ICON_HOVER = new ImageIcon(initDownArrowHoverImage()); 76 77 public WindowsNavigationTree(WindowsFileChooserUI fileChooserUI) { 78 this.fileChooser = fileChooserUI.getFileChooser(); 79 this.view = fileChooser.getFileSystemView(); 80 81 super.setRootVisible(false); 82 super.setUI(new NavTreeUI()); 83 super.addMouseListener(new MouseAdapter() { 84 85 @Override 86 public void mouseExited(MouseEvent e) { 87 hover = -1; 88 setCursor(Cursor.getDefaultCursor()); 89 repaint(); 90 } 91 92 }); 93 super.addMouseMotionListener(new MouseAdapter() { 94 @Override 95 public void mouseMoved(MouseEvent e) { 96 mousePoint = e.getPoint(); 97 98 int row = getRowForLocation(e.getX(), e.getY()); 99 TreePath path = getPathForRow(row); 100 if (row == -1 || path.getLastPathComponent() instanceof EmptyNode) { 101 hover = -1; 102 setCursor(Cursor.getDefaultCursor()); 103 } else { 104 hover = row; 105 Rectangle rowBounds = ((NavTreeUI) getUI()).getStrictBounds(path); 106 if (rowBounds.contains(mousePoint)) { 107 setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 108 } else { 109 setCursor(Cursor.getDefaultCursor()); 110 } 111 } 112 repaint(); 113 } 114 }); 115 super.setCellRenderer(new DefaultTreeCellRenderer() { 116 117 private boolean isSeparatorNode; 118 119 @Override 120 public Color getBackgroundNonSelectionColor() { 121 return null; 122 } 123 124 @Override 125 public Color getBackground() { 126 return null; 127 } 128 129 @Override 130 public Component getTreeCellRendererComponent(JTree tree, Object value, 131 boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { 132 isSeparatorNode = false; 133 134 if (value instanceof RootNode) { 135 return this; 136 } 137 if (value instanceof EmptyNode) { 138 if (value instanceof SeparatorNode) { 139 isSeparatorNode = true; 140 } 141 setText(""); 142 setIcon(null); 143 return this; 144 } 145 146 File folder = ((FolderTreeNode) value).folder; 147 148 setIcon(view.getSystemIcon(folder)); 149 setText(view.getSystemDisplayName(folder)); 150 return this; 151 } 152 153 @Override 154 public Dimension getPreferredSize() { 155 if (getText().isEmpty() && getIcon() == null) { 156 return new Dimension(0, isSeparatorNode ? 18 : 12); 157 } else { 158 Dimension result = super.getPreferredSize();; 159 result.height = 24; 160 return result; 161 } 162 } 163 164 }); 165 166 RootNode rootNode = new RootNode(); 167 super.setModel(new DefaultTreeModel(rootNode)); 168 169 int childCount = rootNode.getChildCount(); 170 for (int i = childCount - 1; i >= 0; i--) { 171 if (i != childCount - 2) { 172 super.expandRow(i); 173 } 174 } 175 176 super.setRowHeight(0); 177 178 getSelectionModel().addTreeSelectionListener(evt -> { 179 TreePath path = evt.getNewLeadSelectionPath(); 180 if (path == null) { 181 return; 182 } 183 184 if (path.getLastPathComponent() instanceof EmptyNode) { 185 // disable selecting an EmptyNode 186 187 if (evt.getOldLeadSelectionPath() == null 188 || !(evt.getOldLeadSelectionPath(). 189 getLastPathComponent() instanceof EmptyNode)) { 190 setSelectionPath(evt.getOldLeadSelectionPath()); 191 } 192 return; 193 } 194 195 FolderTreeNode node = (FolderTreeNode) path.getLastPathComponent(); 196 fileChooser.setCurrentDirectory(node.folder); 197 }); 198 199 getSelectionModel().setSelectionMode(SINGLE_TREE_SELECTION); 200 201 setTransferHandler(fileChooser.getTransferHandler()); 202 putClientProperty("Tree.enableDoubleClickOnExpandControl", TRUE); 203 204 // these 2 values are used in BasicFileChooserUI's FileTransferHandler 205 putClientProperty("FileChooser.instance", fileChooser); 206 putClientProperty("FileChooser.supportsFileDrop", TRUE); 207 } 208 209 @Override 210 public void propertyChange(PropertyChangeEvent evt) { 211 if (evt.getPropertyName().equals("transferHandler")) { 212 setTransferHandler(fileChooser.getTransferHandler()); 213 } 214 if (evt.getPropertyName().equals((FILE_SYSTEM_VIEW_CHANGED_PROPERTY))) { 215 repaint(); 216 } 217 } 218 219 public TreePath getPathForLocation(int x, int y) { 220 return getClosestPathForLocation(x, y); 221 } 222 223 @Override 224 public Dimension getPreferredSize() { 225 Dimension result = super.getPreferredSize(); 226 result.width = 230; 227 return result; 228 } 229 230 private class RootNode implements TreeNode { 231 232 private final List<TreeNode> children = new ArrayList<>(); 233 private FileSystemView.EssentialFolderSection[] prevCategories; 234 235 private FileSystemView.EssentialFolderSection[] getCategories() { 236 return fileChooser.getFileSystemView().getEssentialFolders(); 237 } 238 239 private boolean isModified() { 240 FileSystemView.EssentialFolderSection[] categories = getCategories(); 241 if (Arrays.equals(prevCategories, categories)) { 242 return false; 243 } 244 245 prevCategories = categories; 246 return true; 247 } 248 249 private void validateChildrenCache() { 250 if (isModified()) { 251 EssentialFolderSection[] categories = getCategories(); 252 253 children.clear(); 254 children.add(new EmptyNode(this)); 255 for (EssentialFolderSection category : categories) { 256 children.add(new SeparatorNode(this)); 257 258 int firstEmptyNodeLocation = children.size(); 259 for (File folder : category.getFolders()) { 260 children.add(new EmptyNode(this)); 261 children.add(FOLDER_NODE_CACHE.computeIfAbsent(folder, 262 f -> new FolderTreeNode(this, f, true))); 263 } 264 265 children.remove(firstEmptyNodeLocation); 266 } 267 children.add(new EmptyNode(this)); 268 children.remove(1); // remove the first separator 269 } 270 } 271 272 @Override 273 public TreeNode getChildAt(int childIndex) { 274 validateChildrenCache(); 275 return children.get(childIndex); 276 } 277 278 @Override 279 public int getChildCount() { 280 validateChildrenCache(); 281 return children.size(); 282 } 283 284 @Override 285 public TreeNode getParent() { 286 return null; 287 } 288 289 @Override 290 public int getIndex(TreeNode node) { 291 return -1; 292 } 293 294 @Override 295 public boolean getAllowsChildren() { 296 return true; 297 } 298 299 @Override 300 public boolean isLeaf() { 301 return false; 302 } 303 304 @Override 305 public Enumeration children() { 306 validateChildrenCache(); 307 return Collections.enumeration(children); 308 } 309 310 } 311 private static final Map<File, FolderTreeNode> FOLDER_NODE_CACHE = new HashMap<>(); 312 313 public class FolderTreeNode implements TreeNode { 314 315 public final File folder; 316 private final TreeNode parent; 317 private final boolean recursiveChildren; 318 319 private FolderTreeNode(TreeNode parent, File folder, boolean recursiveChildren) { 320 assert folder != null; 321 322 try { 323 while (fileChooser.getFileSystemView().isLink(folder)) { 324 folder = fileChooser.getFileSystemView().getLinkLocation(folder); 325 } 326 } catch (FileNotFoundException ex) { 327 throw new UncheckedIOException(ex); 328 } 329 330 this.parent = parent; 331 this.folder = folder; 332 this.recursiveChildren = recursiveChildren; 333 } 334 335 private List<File> childrenCache; 336 337 @SuppressWarnings("ReturnOfCollectionOrArrayField") 338 private List<File> getChildren() { 339 if (childrenCache != null) { 340 return childrenCache; 341 } 342 343 if (!recursiveChildren && !(parent instanceof RootNode)) { 344 return childrenCache = emptyList(); 345 } 346 347 Object hidingValue = getDefaultToolkit().getDesktopProperty("awt.file.showHiddenFiles"); 348 File[] files = view.getFiles(folder, (boolean) hidingValue); 349 return childrenCache = Arrays.stream(files). 350 filter(view::isTraversable). 351 collect(toList()); 352 } 353 354 @Override 355 public int getChildCount() { 356 return getChildren().size(); 357 } 358 359 @Override 360 public TreeNode getChildAt(int childIndex) { 361 File file = getChildren().get(childIndex); 362 return FOLDER_NODE_CACHE.computeIfAbsent(file, 363 f -> new FolderTreeNode(this, f, recursiveChildren)); 364 } 365 366 @Override 367 public TreeNode getParent() { 368 return parent; 369 } 370 371 @Override 372 public int getIndex(TreeNode node) { 373 return ((FolderTreeNode) node).getChildren().indexOf(folder); 374 } 375 376 @Override 377 public boolean getAllowsChildren() { 378 return true; 379 } 380 381 @Override 382 public boolean isLeaf() { 383 if (!recursiveChildren && !(parent instanceof RootNode)) { 384 return true; 385 } 386 387 if (childrenCache == null) { 388 return false; 389 } 390 return childrenCache.isEmpty(); 391 } 392 393 @Override 394 public Enumeration children() { 395 return Collections.enumeration(getChildren()); 396 } 397 398 } 399 400 private class EmptyNode implements TreeNode { 401 402 private final TreeNode parent; 403 404 private EmptyNode(TreeNode parent) { 405 this.parent = parent; 406 } 407 408 @Override 409 public TreeNode getChildAt(int childIndex) { 410 throw new UnsupportedOperationException("an EmptyNode doesn't have children"); 411 } 412 413 @Override 414 public int getChildCount() { 415 return 0; 416 } 417 418 @Override 419 public TreeNode getParent() { 420 return parent; 421 } 422 423 @Override 424 public int getIndex(TreeNode node) { 425 throw new UnsupportedOperationException("an EmptyNode doesn't have children"); 426 } 427 428 @Override 429 public boolean getAllowsChildren() { 430 return false; 431 } 432 433 @Override 434 public boolean isLeaf() { 435 return true; 436 } 437 438 @Override 439 public Enumeration children() { 440 return Collections.emptyEnumeration(); 441 } 442 } 443 444 public class SeparatorNode extends EmptyNode { 445 446 public SeparatorNode(TreeNode parent) { 447 super(parent); 448 } 449 450 } 451 452 private class NavTreeUI extends WindowsTreeUI { 453 454 private boolean expandControlHover; 455 456 @Override 457 protected void installDefaults() { 458 super.installDefaults(); 459 setLeftChildIndent(0); 460 461 setExpandedIcon(new AnimatableIcon(COLLAPSE_ICON)); 462 setCollapsedIcon(new AnimatableIcon(EXPAND_ICON)); 463 } 464 465 @Override 466 protected void installListeners() { 467 super.installListeners(); 468 tree.addMouseListener(new MouseAdapter() { 469 470 private final Timer animationTimer = new Timer(30, evt -> onAnimFrame()); 471 472 @Override 473 public void mouseEntered(MouseEvent e) { 474 Instant start = now(); 475 iconAlphaSupplier = () -> ((float) between(start, now()).toMillis()) / 300; 476 animationTimer.start(); 477 } 478 479 @Override 480 public void mouseExited(MouseEvent e) { 481 Instant start = now(); 482 iconAlphaSupplier = () -> 1 - ((float) between(start, now()).toMillis()) / 1000; 483 animationTimer.start(); 484 } 485 486 private void onAnimFrame() { 487 if (iconAlphaSupplier.get() < 0) { 488 animationTimer.stop(); 489 iconAlphaSupplier = () -> 0f; 490 } else if (iconAlphaSupplier.get() > 1) { 491 animationTimer.stop(); 492 iconAlphaSupplier = () -> 1f; 493 } else { 494 tree.repaint(); 495 } 496 } 497 }); 498 } 499 500 @Override 501 protected void updateDepthOffset() { 502 depthOffset = 1; 503 } 504 505 @Override 506 protected boolean shouldPaintExpandControl(TreePath path, int row, 507 boolean isExpanded, 508 boolean hasBeenExpanded, 509 boolean isLeaf) { 510 return !isLeaf; 511 } 512 513 public Rectangle getStrictBounds(TreePath path) { 514 return super.getPathBounds(WindowsNavigationTree.this, path); 515 } 516 517 @Override 518 public Rectangle getPathBounds(JTree tree, TreePath path) { 519 Rectangle result = super.getPathBounds(tree, path); 520 if (result == null) { 521 return null; 522 } 523 524 result.x = 0; 525 result.width = getWidth(); 526 return result; 527 } 528 529 @Override 530 protected void paintExpandControl(Graphics g, Rectangle clipBounds, 531 Insets insets, Rectangle bounds, TreePath path, 532 int row, boolean isExpanded, 533 boolean hasBeenExpanded, boolean isLeaf) { 534 paintBackground(g, row, bounds); 535 expandControlHover = row == hover && isLocationInExpandControl(path, 536 mousePoint.x, mousePoint.y); 537 try { 538 super.paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf); 539 } finally { 540 expandControlHover = false; 541 } 542 } 543 544 @Override 545 public Icon getCollapsedIcon() { 546 if (expandControlHover) { 547 return EXPAND_ICON_HOVER; 548 } 549 return super.getCollapsedIcon(); 550 } 551 552 @Override 553 public Icon getExpandedIcon() { 554 if (expandControlHover) { 555 return COLLAPSE_ICON_HOVER; 556 } 557 return super.getExpandedIcon(); 558 } 559 560 @Override 561 protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds, TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf) { 562 if (!shouldPaintExpandControl(path, row, isExpanded, hasBeenExpanded, isLeaf)) { 563 paintBackground(g, row, bounds); 564 } 565 566 if (path.getLastPathComponent() instanceof SeparatorNode) { 567 bounds.y += bounds.height / 2 - 1; 568 569 g.setColor(UIManager.getColor("Separator.foreground")); 570 g.drawLine(0, bounds.y, tree.getWidth(), bounds.y); 571 572 g.setColor(UIManager.getColor("Separator.background")); 573 g.drawLine(0, bounds.y + 1, tree.getWidth(), bounds.y + 1); 574 return; 575 } 576 577 super.paintRow(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf); 578 } 579 580 private void paintBackground(Graphics g, int row, Rectangle bounds) { 581 if (hover == row) { 582 g.setColor(ITEM_HOVERED_COLOR); 583 g.fillRect(0, bounds.y, tree.getWidth(), bounds.height); 584 } 585 if (tree.isRowSelected(row)) { 586 g.setColor(ITEM_SELECTED_COLOR); 587 g.fillRect(0, bounds.y, tree.getWidth(), bounds.height); 588 if (hover == row) { 589 g.setColor(WindowsFileListUI.ITEM_SELECTED_BORDER_COLOR); 590 g.drawRect(0, bounds.y, tree.getWidth() - 1, tree.getRowHeight()); 591 } 592 } 593 } 594 595 @Override 596 protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left, int right) { 597 } 598 599 @Override 600 protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, int bottom) { 601 } 602 } 603 604 private Supplier<Float> iconAlphaSupplier = () -> 0f; 605 606 private class AnimatableIcon implements Icon { 607 608 private final Icon icon; 609 610 public AnimatableIcon(Icon icon) { 611 this.icon = icon; 612 } 613 614 @Override 615 public void paintIcon(Component c, Graphics g, int x, int y) { 616 if (g instanceof Graphics2D) { 617 Graphics2D g2d = (Graphics2D) g; 618 Composite prevComposite = g2d.getComposite(); 619 620 float alpha = Math.min(1, Math.max(0, iconAlphaSupplier.get())); 621 g2d.setComposite(AlphaComposite.SrcOver.derive(alpha)); 622 icon.paintIcon(c, g, x, y); 623 g2d.setComposite(prevComposite); 624 } else { 625 icon.paintIcon(c, g, x, y); 626 } 627 } 628 629 @Override 630 public int getIconWidth() { 631 return icon.getIconWidth(); 632 } 633 634 @Override 635 public int getIconHeight() { 636 return icon.getIconHeight(); 637 } 638 639 } 640 641 private static Image initDownArrowNormalImage() { 642 BufferedImage img = new BufferedImage(9, 6, 6); 643 img.setRGB(0, 0, 1610612736); 644 img.setRGB(0, 1, -2013265920); 645 img.setRGB(0, 2, 83886080); 646 img.setRGB(0, 3, 14277081); 647 img.setRGB(0, 4, 14277081); 648 img.setRGB(0, 5, 14277081); 649 img.setRGB(1, 0, -2013265920); 650 img.setRGB(1, 1, -1073741824); 651 img.setRGB(1, 2, -2013265920); 652 img.setRGB(1, 3, 67108864); 653 img.setRGB(1, 4, 14277081); 654 img.setRGB(1, 5, 14277081); 655 img.setRGB(2, 0, 67108864); 656 img.setRGB(2, 1, -2013265920); 657 img.setRGB(2, 2, -1073741824); 658 img.setRGB(2, 3, -2013265920); 659 img.setRGB(2, 4, 67108864); 660 img.setRGB(2, 5, 14277081); 661 img.setRGB(3, 0, 14277081); 662 img.setRGB(3, 1, 67108864); 663 img.setRGB(3, 2, -2013265920); 664 img.setRGB(3, 3, -1073741824); 665 img.setRGB(3, 4, -2013265920); 666 img.setRGB(3, 5, 67108864); 667 img.setRGB(4, 0, 14277081); 668 img.setRGB(4, 1, 14277081); 669 img.setRGB(4, 2, 150994944); 670 img.setRGB(4, 3, -1291845632); 671 img.setRGB(4, 4, -1073741824); 672 img.setRGB(4, 5, 1577058304); 673 img.setRGB(5, 0, 14277081); 674 img.setRGB(5, 1, 67108864); 675 img.setRGB(5, 2, -2013265920); 676 img.setRGB(5, 3, -1073741824); 677 img.setRGB(5, 4, -2013265920); 678 img.setRGB(5, 5, 83886080); 679 img.setRGB(6, 0, 67108864); 680 img.setRGB(6, 1, -2013265920); 681 img.setRGB(6, 2, -1073741824); 682 img.setRGB(6, 3, -2013265920); 683 img.setRGB(6, 4, 67108864); 684 img.setRGB(6, 5, 14277081); 685 img.setRGB(7, 0, -2013265920); 686 img.setRGB(7, 1, -1073741824); 687 img.setRGB(7, 2, -2013265920); 688 img.setRGB(7, 3, 67108864); 689 img.setRGB(7, 4, 14277081); 690 img.setRGB(7, 5, 14277081); 691 img.setRGB(8, 0, 1593835520); 692 img.setRGB(8, 1, -2013265920); 693 img.setRGB(8, 2, 67108864); 694 img.setRGB(8, 3, 14277081); 695 img.setRGB(8, 4, 14277081); 696 img.setRGB(8, 5, 14277081); 697 return img; 698 } 699 700 private static Image initRightArrowNormalImage() { 701 BufferedImage img = new BufferedImage(6, 9, 6); 702 img.setRGB(0, 0, 754974720); 703 img.setRGB(0, 1, 1073741824); 704 img.setRGB(0, 2, 33554432); 705 img.setRGB(0, 6, 33554432); 706 img.setRGB(0, 7, 1073741824); 707 img.setRGB(0, 8, 754974720); 708 img.setRGB(1, 0, 1073741824); 709 img.setRGB(1, 1, 1493172224); 710 img.setRGB(1, 2, 1073741824); 711 img.setRGB(1, 3, 33554432); 712 img.setRGB(1, 5, 33554432); 713 img.setRGB(1, 6, 1073741824); 714 img.setRGB(1, 7, 1493172224); 715 img.setRGB(1, 8, 1073741824); 716 img.setRGB(2, 0, 33554432); 717 img.setRGB(2, 1, 1073741824); 718 img.setRGB(2, 2, 1493172224); 719 img.setRGB(2, 3, 1073741824); 720 img.setRGB(2, 4, 83886080); 721 img.setRGB(2, 5, 1073741824); 722 img.setRGB(2, 6, 1493172224); 723 img.setRGB(2, 7, 1073741824); 724 img.setRGB(2, 8, 33554432); 725 img.setRGB(3, 1, 33554432); 726 img.setRGB(3, 2, 1073741824); 727 img.setRGB(3, 3, 1493172224); 728 img.setRGB(3, 4, 1392508928); 729 img.setRGB(3, 5, 1493172224); 730 img.setRGB(3, 6, 1073741824); 731 img.setRGB(3, 7, 33554432); 732 img.setRGB(4, 2, 33554432); 733 img.setRGB(4, 3, 1073741824); 734 img.setRGB(4, 4, 1493172224); 735 img.setRGB(4, 5, 1073741824); 736 img.setRGB(4, 6, 33554432); 737 img.setRGB(5, 3, 33554432); 738 img.setRGB(5, 4, 721420288); 739 img.setRGB(5, 5, 33554432); 740 return img; 741 } 742 743 private static Image initDownArrowHoverImage() { 744 BufferedImage img = new BufferedImage(9, 6, 6); 745 img.setRGB(0, 0, 1879096822); 746 img.setRGB(0, 1, -1627341067); 747 img.setRGB(0, 2, 100702207); 748 img.setRGB(0, 3, 15070207); 749 img.setRGB(0, 4, 15070207); 750 img.setRGB(0, 5, 15070207); 751 img.setRGB(1, 0, -1627341067); 752 img.setRGB(1, 1, -536822282); 753 img.setRGB(1, 2, -1627341067); 754 img.setRGB(1, 3, 67156735); 755 img.setRGB(1, 4, 15070207); 756 img.setRGB(1, 5, 15070207); 757 img.setRGB(2, 0, 67156735); 758 img.setRGB(2, 1, -1627341067); 759 img.setRGB(2, 2, -536822282); 760 img.setRGB(2, 3, -1627341067); 761 img.setRGB(2, 4, 67156735); 762 img.setRGB(2, 5, 15070207); 763 img.setRGB(3, 0, 15070207); 764 img.setRGB(3, 1, 67156735); 765 img.setRGB(3, 2, -1627341067); 766 img.setRGB(3, 3, -536822282); 767 img.setRGB(3, 4, -1627341067); 768 img.setRGB(3, 5, 67156735); 769 img.setRGB(4, 0, 15070207); 770 img.setRGB(4, 1, 15070207); 771 img.setRGB(4, 2, 184600063); 772 img.setRGB(4, 3, -771703049); 773 img.setRGB(4, 4, -536822282); 774 img.setRGB(4, 5, 1828765174); 775 img.setRGB(5, 0, 15070207); 776 img.setRGB(5, 1, 67156735); 777 img.setRGB(5, 2, -1627341067); 778 img.setRGB(5, 3, -536822282); 779 img.setRGB(5, 4, -1627341067); 780 img.setRGB(5, 5, 100702207); 781 img.setRGB(6, 0, 67156735); 782 img.setRGB(6, 1, -1627341067); 783 img.setRGB(6, 2, -536822282); 784 img.setRGB(6, 3, -1627341067); 785 img.setRGB(6, 4, 67156735); 786 img.setRGB(6, 5, 15070207); 787 img.setRGB(7, 0, -1627341067); 788 img.setRGB(7, 1, -536822282); 789 img.setRGB(7, 2, -1627341067); 790 img.setRGB(7, 3, 67156735); 791 img.setRGB(7, 4, 15070207); 792 img.setRGB(7, 5, 15070207); 793 img.setRGB(8, 0, 1862319862); 794 img.setRGB(8, 1, -1627341067); 795 img.setRGB(8, 2, 67156735); 796 img.setRGB(8, 3, 15070207); 797 img.setRGB(8, 4, 15070207); 798 img.setRGB(8, 5, 15070207); 799 return img; 800 } 801 802 private static Image initRightArrowHoverImage() { 803 BufferedImage img = new BufferedImage(6, 9, 6); 804 img.setRGB(0, 0, 1409335286); 805 img.setRGB(0, 1, 1996537334); 806 img.setRGB(0, 2, 50374655); 807 img.setRGB(0, 3, 15070207); 808 img.setRGB(0, 4, 15070207); 809 img.setRGB(0, 5, 15070207); 810 img.setRGB(0, 6, 67156735); 811 img.setRGB(0, 7, 1996537334); 812 img.setRGB(0, 8, 1409335286); 813 img.setRGB(1, 0, 1996537334); 814 img.setRGB(1, 1, -1476346122); 815 img.setRGB(1, 2, 1996537334); 816 img.setRGB(1, 3, 50374655); 817 img.setRGB(1, 4, 15070207); 818 img.setRGB(1, 5, 67156735); 819 img.setRGB(1, 6, 1996537334); 820 img.setRGB(1, 7, -1476346122); 821 img.setRGB(1, 8, 1996537334); 822 img.setRGB(2, 0, 67156735); 823 img.setRGB(2, 1, 1996537334); 824 img.setRGB(2, 2, -1476346122); 825 img.setRGB(2, 3, 1996537334); 826 img.setRGB(2, 4, 151042815); 827 img.setRGB(2, 5, 1996537334); 828 img.setRGB(2, 6, -1476346122); 829 img.setRGB(2, 7, 1996537334); 830 img.setRGB(2, 8, 67156735); 831 img.setRGB(3, 0, 15070207); 832 img.setRGB(3, 1, 67156735); 833 img.setRGB(3, 2, 1996537334); 834 img.setRGB(3, 3, -1476346122); 835 img.setRGB(3, 4, -1660895755); 836 img.setRGB(3, 5, -1476346122); 837 img.setRGB(3, 6, 1996537334); 838 img.setRGB(3, 7, 67156735); 839 img.setRGB(3, 8, 15070207); 840 img.setRGB(4, 0, 15070207); 841 img.setRGB(4, 1, 15070207); 842 img.setRGB(4, 2, 67156735); 843 img.setRGB(4, 3, 1996537334); 844 img.setRGB(4, 4, -1476346122); 845 img.setRGB(4, 5, 1996537334); 846 img.setRGB(4, 6, 67156735); 847 img.setRGB(4, 7, 15070207); 848 img.setRGB(4, 8, 15070207); 849 img.setRGB(5, 0, 15070207); 850 img.setRGB(5, 1, 15070207); 851 img.setRGB(5, 2, 15070207); 852 img.setRGB(5, 3, 67156735); 853 img.setRGB(5, 4, 1375779830); 854 img.setRGB(5, 5, 67156735); 855 img.setRGB(5, 6, 15070207); 856 img.setRGB(5, 7, 15070207); 857 img.setRGB(5, 8, 15070207); 858 return img; 859 } 860 }