Lines 19-30
Link Here
|
19 |
|
19 |
|
20 |
import java.lang.ref.WeakReference; |
20 |
import java.lang.ref.WeakReference; |
21 |
import java.lang.ref.Reference; |
21 |
import java.lang.ref.Reference; |
|
|
22 |
import java.lang.reflect.InvocationHandler; |
23 |
import java.lang.reflect.InvocationTargetException; |
24 |
import java.lang.reflect.Proxy; |
22 |
|
25 |
|
23 |
import java.util.LinkedList; |
26 |
import java.util.LinkedList; |
|
|
27 |
import java.awt.*; |
24 |
|
28 |
|
25 |
import javax.swing.ComboBoxModel; |
29 |
import javax.swing.*; |
26 |
import javax.swing.JComboBox; |
|
|
27 |
import javax.swing.JEditorPane; |
28 |
import javax.swing.event.ListDataEvent; |
30 |
import javax.swing.event.ListDataEvent; |
29 |
|
31 |
|
30 |
import org.openide.cookies.SourceCookie; |
32 |
import org.openide.cookies.SourceCookie; |
Lines 147-152
Link Here
|
147 |
return rootChangeListener = new RootL(); |
149 |
return rootChangeListener = new RootL(); |
148 |
} |
150 |
} |
149 |
|
151 |
|
|
|
152 |
private JCBRender cellRender = null; |
150 |
/** |
153 |
/** |
151 |
* Finds the context where the view is actually used. |
154 |
* Finds the context where the view is actually used. |
152 |
*/ |
155 |
*/ |
Lines 171-176
Link Here
|
171 |
topComponent.addPropertyChangeListener(rootChangeListener); |
174 |
topComponent.addPropertyChangeListener(rootChangeListener); |
172 |
} |
175 |
} |
173 |
getExplorerManager().addPropertyChangeListener(rootChangeListener); |
176 |
getExplorerManager().addPropertyChangeListener(rootChangeListener); |
|
|
177 |
|
178 |
if (cellRender == null && topComponent != null) { |
179 |
//System.out.println("##create renderer for: " + (topComponent==null?"warmup":topComponent.getDisplayName())); |
180 |
cellRender = new JCBRender(); |
181 |
cellRender.addNotify(); |
182 |
} |
174 |
} |
183 |
} |
175 |
|
184 |
|
176 |
public void removeNotify() { |
185 |
public void removeNotify() { |
Lines 494-498
Link Here
|
494 |
Node n = (Node)k; |
503 |
Node n = (Node)k; |
495 |
return new Node[] { new FNode(n, new FChildren(n)) }; |
504 |
return new Node[] { new FNode(n, new FChildren(n)) }; |
496 |
} |
505 |
} |
|
|
506 |
} |
507 |
|
508 |
private class JCBRender implements InvocationHandler { |
509 |
|
510 |
private final ListCellRenderer orig; |
511 |
private boolean isHackable = true; |
512 |
private boolean isThin = false; |
513 |
private JPopupMenu popup; |
514 |
private JList list; |
515 |
private int height = 0; |
516 |
private int width; |
517 |
private Component comp; |
518 |
private final JComboBox comboToHack; |
519 |
private boolean debug = false; |
520 |
|
521 |
public JCBRender() { |
522 |
this.comboToHack = NavigationView.this; |
523 |
this.orig = comboToHack.getRenderer(); |
524 |
this.width = comboToHack.getWidth(); |
525 |
} |
526 |
|
527 |
public void addNotify() { |
528 |
if (comboToHack.getRenderer() == orig) { |
529 |
comboToHack.setRenderer(getProxy()); |
530 |
this.width = comboToHack.getWidth(); |
531 |
} |
532 |
} |
533 |
|
534 |
public void removeNotify() { |
535 |
comboToHack.setRenderer(orig); |
536 |
} |
537 |
|
538 |
private int lastMaxWidth; |
539 |
private boolean isReshaped = false; |
540 |
private boolean isFirstRun = true; |
541 |
public void processListCellRendererComponent(JList list, Object value, int index, Component comp) { |
542 |
if (index < 0) return; |
543 |
if (index == 0) { |
544 |
popup = findPopupMenu(list); |
545 |
this.list = list; |
546 |
if (popup == null) { |
547 |
//System.out.println("## is not hackable: " + this); |
548 |
isHackable = false; |
549 |
return; |
550 |
} |
551 |
height = 0; |
552 |
if (isReshaped) { |
553 |
this.lastMaxWidth = this.width; |
554 |
isReshaped = false; |
555 |
} |
556 |
this.width = comboToHack.getWidth(); |
557 |
if (lastMaxWidth < width) lastMaxWidth = width; |
558 |
} |
559 |
Dimension size = comp.getPreferredSize(); |
560 |
height += size.height; |
561 |
if (width < size.width) { |
562 |
width = size.width; |
563 |
this.comp = comp; |
564 |
isThin = true; |
565 |
} |
566 |
//System.out.println("##process: idx:"+index+",last:" + lastMaxWidth + ",curr:" + width + ",size:"+size.width + ",isThin:" + isThin + ",model:"+(list.getModel().getSize() - 1)+", @" + System.identityHashCode(this)); |
567 |
if (isThin && index == list.getModel().getSize() - 1 && width != lastMaxWidth || |
568 |
isFirstRun && index == list.getModel().getSize() - 1) { |
569 |
isReshaped = true; |
570 |
isThin = false; |
571 |
isFirstRun = false; |
572 |
reshapePopup(); |
573 |
height = 0; |
574 |
} |
575 |
} |
576 |
|
577 |
public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable { |
578 |
Object res = null; |
579 |
try { |
580 |
res = method.invoke(orig, args); |
581 |
if (isHackable && "getListCellRendererComponent".equals(method.getName())) { |
582 |
Component c = (Component) res; |
583 |
JList l = (JList) args[0]; |
584 |
Object value = args[1]; |
585 |
int index = ((Integer) args[2]).intValue(); |
586 |
processListCellRendererComponent(l, value, index, c); |
587 |
} |
588 |
} catch (IllegalArgumentException ex) { |
589 |
ex.printStackTrace(); |
590 |
} catch (InvocationTargetException ex) { |
591 |
Throwable t = ex.getCause(); |
592 |
if (t != null) throw t; |
593 |
else ex.printStackTrace(); |
594 |
} |
595 |
return res; |
596 |
} |
597 |
|
598 |
|
599 |
|
600 |
void reshapePopup() { |
601 |
int preferredWidth = Math.min(width + 20, getMaxWidth()); |
602 |
int prefferedHeight = Math.min(height, getMaxHeight()); |
603 |
|
604 |
//System.out.println("revalidate: w: " + preferredWidth + ", h: " +prefferedHeight + ", @" + System.identityHashCode(this) + ", AWT: " +EventQueue.isDispatchThread()); |
605 |
this.comp = null; |
606 |
popup.removeAll(); |
607 |
scroller.remove(list); |
608 |
popup.setPopupSize(preferredWidth, prefferedHeight); |
609 |
popup.add(createScroller()); |
610 |
popup.revalidate(); |
611 |
popup.repaint(); |
612 |
} |
613 |
|
614 |
private JScrollPane scroller; |
615 |
|
616 |
private JPopupMenu findPopupMenu(Component c) { |
617 |
Component parent = c; |
618 |
Component previous = c; |
619 |
while (parent != null && !(parent instanceof JPopupMenu)) { |
620 |
previous = parent; |
621 |
parent = parent.getParent(); |
622 |
} |
623 |
|
624 |
if (previous instanceof JScrollPane) { |
625 |
scroller = (JScrollPane) previous; |
626 |
} else { |
627 |
parent = null; // unsupported component hierarchy |
628 |
} |
629 |
return (JPopupMenu) parent; |
630 |
} |
631 |
/** |
632 |
* Creates the scroll pane which houses the scrollable list. |
633 |
*/ |
634 |
private JScrollPane createScroller() { |
635 |
JScrollPane scroller = new JScrollPane(list, |
636 |
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, |
637 |
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); |
638 |
scroller.setFocusable(false); |
639 |
scroller.getVerticalScrollBar().setFocusable(false); |
640 |
scroller.setBorder(null); |
641 |
return scroller; |
642 |
} |
643 |
|
644 |
private int maxWidth = -1; |
645 |
private int maxHeight = -1; |
646 |
|
647 |
private int getMaxWidth() { |
648 |
TopComponent tc = NavigationView.this.findParentTopComponent(); |
649 |
if (tc != null) { |
650 |
maxWidth = tc.getX() + tc.getWidth() - comboToHack.getX(); |
651 |
} else { |
652 |
maxWidth = Toolkit.getDefaultToolkit().getScreenSize().width >> 1; |
653 |
} |
654 |
return maxWidth; |
655 |
} |
656 |
|
657 |
private int getMaxHeight() { |
658 |
TopComponent tc = NavigationView.this.findParentTopComponent(); |
659 |
if (tc != null) { |
660 |
maxHeight = tc.getY() + tc.getHeight() - comboToHack.getY() - comboToHack.getHeight(); |
661 |
} else { |
662 |
maxHeight = Toolkit.getDefaultToolkit().getScreenSize().height >> 1; |
663 |
} |
664 |
return maxHeight; |
665 |
} |
666 |
|
667 |
public ListCellRenderer getProxy() { |
668 |
return (ListCellRenderer) Proxy.newProxyInstance( |
669 |
this.getClass().getClassLoader(), new Class[] {ListCellRenderer.class}, this); |
670 |
} |
671 |
|
497 |
} |
672 |
} |
498 |
} |
673 |
} |