1 22 23 package org.gjt.sp.jedit.gui; 24 25 import java.awt.Color ; 27 import java.awt.Component ; 28 import java.awt.Graphics ; 29 import java.awt.Rectangle ; 30 import java.awt.event.ActionEvent ; 31 import java.awt.event.ActionListener ; 32 import java.awt.event.KeyAdapter ; 33 import java.awt.event.KeyEvent ; 34 import java.awt.event.KeyListener ; 35 import java.util.*; 36 37 import javax.swing.AbstractButton ; 38 import javax.swing.JComponent ; 39 import javax.swing.JMenuItem ; 40 import javax.swing.JPanel ; 41 import javax.swing.JPopupMenu ; 42 import javax.swing.SwingUtilities ; 43 44 import org.gjt.sp.jedit.EBComponent; 45 import org.gjt.sp.jedit.EBMessage; 46 import org.gjt.sp.jedit.EditBus; 47 import org.gjt.sp.jedit.PluginJAR; 48 import org.gjt.sp.jedit.View; 49 import org.gjt.sp.jedit.jEdit; 50 import org.gjt.sp.jedit.gui.KeyEventTranslator.Key; 51 import org.gjt.sp.jedit.msg.DockableWindowUpdate; 52 import org.gjt.sp.jedit.msg.PluginUpdate; 53 import org.gjt.sp.jedit.msg.PropertiesChanged; 54 import org.gjt.sp.util.Log; 55 57 130 public class DockableWindowManager extends JPanel implements EBComponent 131 { 132 137 public static final String FLOATING = "floating"; 138 139 143 public static final String TOP = "top"; 144 145 149 public static final String LEFT = "left"; 150 151 155 public static final String BOTTOM = "bottom"; 156 157 161 public static final String RIGHT = "right"; 162 164 private View view; 166 private DockableWindowFactory factory; 167 168 169 private Map<String , Entry> windows; 170 private PanelWindowContainer left; 171 private PanelWindowContainer right; 172 private PanelWindowContainer top; 173 private PanelWindowContainer bottom; 174 private List<Entry> clones; 175 176 private Entry lastEntry; 177 public Stack showStack = new Stack(); 178 180 184 public static String [] getRegisteredDockableWindows() 185 { 186 return DockableWindowFactory.getInstance() 187 .getRegisteredDockableWindows(); 188 } 190 199 public DockableWindowManager(View view, DockableWindowFactory factory, 200 View.ViewConfig config) 201 { 202 setLayout(new DockableLayout()); 203 this.view = view; 204 this.factory = factory; 205 206 windows = new HashMap<String , Entry>(); 207 clones = new ArrayList<Entry>(); 208 209 top = new PanelWindowContainer(this,TOP,config.topPos); 210 left = new PanelWindowContainer(this,LEFT,config.leftPos); 211 bottom = new PanelWindowContainer(this,BOTTOM,config.bottomPos); 212 right = new PanelWindowContainer(this,RIGHT,config.rightPos); 213 214 add(DockableLayout.TOP_BUTTONS,top.buttonPanel); 215 add(DockableLayout.LEFT_BUTTONS,left.buttonPanel); 216 add(DockableLayout.BOTTOM_BUTTONS,bottom.buttonPanel); 217 add(DockableLayout.RIGHT_BUTTONS,right.buttonPanel); 218 219 add(TOP,top.dockablePanel); 220 add(LEFT,left.dockablePanel); 221 add(BOTTOM,bottom.dockablePanel); 222 add(RIGHT,right.dockablePanel); 223 } 225 229 public void init() 230 { 231 EditBus.addToBus(this); 232 233 Iterator<DockableWindowFactory.Window> entries = factory.getDockableWindowIterator(); 234 235 while(entries.hasNext()) 236 addEntry(entries.next()); 237 238 propertiesChanged(); 239 } 241 256 public KeyListener closeListener(String dockableName) { 257 return new KeyHandler(dockableName); 258 } 259 261 266 public View getView() 267 { 268 return view; 269 } 271 279 public JComponent floatDockableWindow(String name) 280 { 281 Entry entry = windows.get(name); 282 if(entry == null) 283 { 284 Log.log(Log.ERROR,this,"Unknown dockable window: " + name); 285 return null; 286 } 287 288 Entry newEntry = new Entry(entry.factory,FLOATING); 290 newEntry.win = newEntry.factory.createDockableWindow(view,FLOATING); 291 292 if(newEntry.win != null) 293 { 294 FloatingWindowContainer fwc = new FloatingWindowContainer(this,true); 295 newEntry.container = fwc; 296 newEntry.container.register(newEntry); 297 newEntry.container.show(newEntry); 298 299 300 } 301 clones.add(newEntry); 302 return newEntry.win; 303 } 305 311 public void showDockableWindow(String name) 312 { 313 lastEntry = windows.get(name); 314 if(lastEntry == null) 315 { 316 Log.log(Log.ERROR,this,"Unknown dockable window: " + name); 317 return; 318 } 319 320 if(lastEntry.win == null) 321 { 322 lastEntry.win = lastEntry.factory.createDockableWindow( 323 view,lastEntry.position); 324 } 325 326 if(lastEntry.win != null) 327 { 328 if(lastEntry.position.equals(FLOATING) 329 && lastEntry.container == null) 330 { 331 FloatingWindowContainer fwc = new FloatingWindowContainer( 332 this,view.isPlainView()); 333 lastEntry.container = fwc; 334 lastEntry.container.register(lastEntry); 335 } 336 showStack.push(name); 337 lastEntry.container.show(lastEntry); 338 Object reason = DockableWindowUpdate.ACTIVATED; 339 EditBus.send(new DockableWindowUpdate(this, reason, name)); 340 } 341 else 342 ; 343 } 345 352 public void addDockableWindow(String name) 353 { 354 showDockableWindow(name); 355 } 357 363 public void hideDockableWindow(String name) 364 { 365 366 Entry entry = windows.get(name); 367 if(entry == null) 368 { 369 Log.log(Log.ERROR,this,"Unknown dockable window: " + name); 370 return; 371 } 372 373 374 375 if(entry.win == null) 376 return; 377 Object reason = DockableWindowUpdate.DEACTIVATED; 378 EditBus.send(new DockableWindowUpdate(this, reason, name)); 379 380 entry.container.show(null); 381 } 383 390 public void removeDockableWindow(String name) 391 { 392 hideDockableWindow(name); 393 } 395 400 public void toggleDockableWindow(String name) 401 { 402 if(isDockableWindowVisible(name)) 403 removeDockableWindow(name); 404 else 405 addDockableWindow(name); 406 } 408 419 public JComponent getDockableWindow(String name) 420 { 421 return getDockable(name); 422 } 424 438 public JComponent getDockable(String name) 439 { 440 441 Entry entry = windows.get(name); 442 if(entry == null || entry.win == null) 443 return null; 444 else 445 return entry.win; 446 } 448 454 public String getDockableTitle(String name) 455 { 456 Entry e = windows.get(name); 457 return e.longTitle(); 458 } 460 471 public void setDockableTitle(String dockableName, String newTitle) { 472 Entry entry = windows.get(dockableName); 473 String propName = entry.factory.name + ".longtitle"; 474 String oldTitle = jEdit.getProperty(propName); 475 jEdit.setProperty(propName, newTitle); 476 firePropertyChange(propName, oldTitle, newTitle); 477 } 478 480 485 public boolean isDockableWindowVisible(String name) 486 { 487 Entry entry = windows.get(name); 488 if(entry == null || entry.win == null) 489 return false; 490 else 491 return entry.container.isVisible(entry); 492 } 494 501 public boolean isDockableWindowDocked(String name) 502 { 503 Entry entry = windows.get(name); 504 if(entry == null) 505 return false; 506 else 507 return !entry.position.equals(FLOATING); 508 } 510 515 public void closeCurrentArea() 516 { 517 SwingUtilities.invokeLater(new Runnable () 521 { 522 public void run() 523 { 524 525 try { 526 String dockableName = showStack.pop().toString(); 527 hideDockableWindow(dockableName); 528 return; 529 } 530 catch (Exception e) {} 531 532 Component comp = view.getFocusOwner(); 533 while(comp != null) 534 { 535 if(comp instanceof DockablePanel) 537 { 538 DockablePanel panel = (DockablePanel) comp; 539 540 PanelWindowContainer container = panel.getWindowContainer(); 541 542 container.show(null); 543 return; 544 } 545 546 comp = comp.getParent(); 547 } 548 549 getToolkit().beep(); 550 } 551 }); 552 } 554 559 public void close() 560 { 561 EditBus.removeFromBus(this); 562 563 for (Entry entry : windows.values()) 564 { 565 if (entry.win != null) 566 entry.container.unregister(entry); 567 } 568 569 for (Entry clone : clones) 570 { 571 if (clone.win != null) 572 clone.container.unregister(clone); 573 } 574 } 576 public PanelWindowContainer getTopDockingArea() 578 { 579 return top; 580 } 582 public PanelWindowContainer getLeftDockingArea() 584 { 585 return left; 586 } 588 public PanelWindowContainer getBottomDockingArea() 590 { 591 return bottom; 592 } 594 public PanelWindowContainer getRightDockingArea() 596 { 597 return right; 598 } 600 public JPopupMenu createPopupMenu( 602 final DockableWindowContainer container, 603 final String dockable, 604 final boolean clone) 605 { 606 JPopupMenu popup = new JPopupMenu (); 607 if(dockable == null && container instanceof PanelWindowContainer) 608 { 609 ActionListener listener = new ActionListener () 610 { 611 public void actionPerformed(ActionEvent evt) 612 { 613 showDockableWindow(evt.getActionCommand()); 614 } 615 }; 616 617 String [] dockables = ((PanelWindowContainer) 618 container).getDockables(); 619 Map<String ,String > dockableMap = new TreeMap<String , String >(); 620 for (int i = 0; i < dockables.length; i++) 621 { 622 String action = dockables[i]; 623 dockableMap.put(getDockableTitle(action), action); 624 } 625 for (Map.Entry<String , String > entry : dockableMap.entrySet()) 626 { 627 JMenuItem item = new JMenuItem (entry.getKey()); 628 item.setActionCommand(entry.getValue()); 629 item.addActionListener(listener); 630 popup.add(item); 631 } 632 } 633 else 634 { 635 JMenuItem caption = new JMenuItem (getDockableTitle(dockable)); 636 caption.setEnabled(false); 637 popup.add(caption); 638 popup.addSeparator(); 639 String currentPos = jEdit.getProperty(dockable + ".dock-position",FLOATING); 640 if(!clone) 641 { 642 String [] positions = { FLOATING, TOP, LEFT, BOTTOM, RIGHT }; 643 for(int i = 0; i < positions.length; i++) 644 { 645 final String pos = positions[i]; 646 if(pos.equals(currentPos)) 647 continue; 648 649 JMenuItem moveMenuItem = new JMenuItem (jEdit.getProperty("view.docking.menu-" 650 + pos)); 651 652 moveMenuItem.addActionListener(new ActionListener () 653 { 654 public void actionPerformed(ActionEvent evt) 655 { 656 jEdit.setProperty(dockable + ".dock-position",pos); 657 EditBus.send(new DockableWindowUpdate( 658 DockableWindowManager.this, 659 DockableWindowUpdate.PROPERTIES_CHANGED, 660 null 661 )); 662 showDockableWindow(dockable); 663 } 664 }); 665 popup.add(moveMenuItem); 666 } 667 668 popup.addSeparator(); 669 } 670 671 JMenuItem cloneMenuItem = new JMenuItem (jEdit.getProperty("view.docking.menu-clone")); 672 673 cloneMenuItem.addActionListener(new ActionListener () 674 { 675 public void actionPerformed(ActionEvent evt) 676 { 677 floatDockableWindow(dockable); 678 } 679 }); 680 popup.add(cloneMenuItem); 681 682 popup.addSeparator(); 683 684 JMenuItem closeMenuItem = new JMenuItem (jEdit.getProperty("view.docking.menu-close")); 685 686 closeMenuItem.addActionListener(new ActionListener () 687 { 688 public void actionPerformed(ActionEvent evt) 689 { 690 if(clone) 691 ((FloatingWindowContainer)container).dispose(); 692 else 693 removeDockableWindow(dockable); 694 } 695 }); 696 popup.add(closeMenuItem); 697 698 if(!(clone || currentPos.equals(FLOATING))) 699 { 700 JMenuItem undockMenuItem = new JMenuItem (jEdit.getProperty("view.docking.menu-undock")); 701 702 undockMenuItem.addActionListener(new ActionListener () 703 { 704 public void actionPerformed(ActionEvent evt) 705 { 706 jEdit.setProperty(dockable + ".dock-position",FLOATING); 707 EditBus.send(new DockableWindowUpdate( 708 DockableWindowManager.this, 709 DockableWindowUpdate.PROPERTIES_CHANGED, 710 null 711 )); 712 } 713 }); 714 popup.add(undockMenuItem); 715 } 716 } 717 718 return popup; 719 } 721 public void paintChildren(Graphics g) 723 { 724 super.paintChildren(g); 725 726 if(resizeRect != null) 727 { 728 g.setColor(Color.darkGray); 729 g.fillRect(resizeRect.x,resizeRect.y, 730 resizeRect.width,resizeRect.height); 731 } 732 } 734 public void handleMessage(EBMessage msg) 736 { 737 if(msg instanceof DockableWindowUpdate) 738 { 739 if(((DockableWindowUpdate)msg).getWhat() 740 == DockableWindowUpdate.PROPERTIES_CHANGED) 741 propertiesChanged(); 742 } 743 else if(msg instanceof PropertiesChanged) 744 propertiesChanged(); 745 else if(msg instanceof PluginUpdate) 746 { 747 PluginUpdate pmsg = (PluginUpdate)msg; 748 if(pmsg.getWhat() == PluginUpdate.LOADED) 749 { 750 Iterator<DockableWindowFactory.Window> iter = factory.getDockableWindowIterator(); 751 752 while(iter.hasNext()) 753 { 754 DockableWindowFactory.Window w = iter.next(); 755 if(w.plugin == pmsg.getPluginJAR()) 756 addEntry(w); 757 } 758 759 propertiesChanged(); 760 } 761 else if(pmsg.isExiting()) 762 { 763 } 765 else if(pmsg.getWhat() == PluginUpdate.DEACTIVATED) 766 { 767 Iterator<Entry> iter = getAllPluginEntries( 768 pmsg.getPluginJAR(),false); 769 while(iter.hasNext()) 770 { 771 Entry entry = iter.next(); 772 if(entry.container != null) 773 entry.container.remove(entry); 774 } 775 } 776 else if(pmsg.getWhat() == PluginUpdate.UNLOADED) 777 { 778 Iterator<Entry> iter = getAllPluginEntries( 779 pmsg.getPluginJAR(),true); 780 while(iter.hasNext()) 781 { 782 Entry entry = iter.next(); 783 if(entry.container != null) 784 { 785 entry.container.unregister(entry); 786 entry.win = null; 787 entry.container = null; 788 } 789 } 790 } 791 } 792 } 794 int resizePos; 796 800 Rectangle resizeRect; 801 802 void setResizePos(int resizePos, PanelWindowContainer resizing) 804 { 805 this.resizePos = resizePos; 806 807 if(resizePos < 0) 808 resizePos = 0; 809 810 Rectangle newResizeRect = new Rectangle (0,0, 811 PanelWindowContainer.SPLITTER_WIDTH - 2, 812 PanelWindowContainer.SPLITTER_WIDTH - 2); 813 if(resizing == top) 814 { 815 resizePos = Math.min(resizePos,getHeight() 816 - top.buttonPanel.getHeight() 817 - bottom.dockablePanel.getHeight() 818 - bottom.buttonPanel.getHeight() 819 - PanelWindowContainer.SPLITTER_WIDTH); 820 newResizeRect.x = top.dockablePanel.getX() + 1; 821 newResizeRect.y = resizePos + top.buttonPanel.getHeight() + 1; 822 newResizeRect.width = top.dockablePanel.getWidth() - 2; 823 } 824 else if(resizing == left) 825 { 826 resizePos = Math.min(resizePos,getWidth() 827 - left.buttonPanel.getWidth() 828 - right.dockablePanel.getWidth() 829 - right.buttonPanel.getWidth() 830 - PanelWindowContainer.SPLITTER_WIDTH); 831 newResizeRect.x = resizePos + left.buttonPanel.getWidth() + 1; 832 newResizeRect.y = left.dockablePanel.getY() + 1; 833 newResizeRect.height = left.dockablePanel.getHeight() - 2; 834 } 835 else if(resizing == bottom) 836 { 837 resizePos = Math.min(resizePos,getHeight() 838 - bottom.buttonPanel.getHeight() 839 - top.dockablePanel.getHeight() 840 - top.buttonPanel.getHeight() 841 - PanelWindowContainer.SPLITTER_WIDTH); 842 newResizeRect.x = bottom.dockablePanel.getX() + 1; 843 newResizeRect.y = getHeight() - bottom.buttonPanel.getHeight() - resizePos 844 - PanelWindowContainer.SPLITTER_WIDTH + 2; 845 newResizeRect.width = bottom.dockablePanel.getWidth() - 2; 846 } 847 else if(resizing == right) 848 { 849 resizePos = Math.min(resizePos,getWidth() 850 - right.buttonPanel.getWidth() 851 - left.dockablePanel.getWidth() 852 - left.buttonPanel.getWidth() 853 - PanelWindowContainer.SPLITTER_WIDTH); 854 newResizeRect.x = getWidth() - right.buttonPanel.getWidth() - resizePos 855 - PanelWindowContainer.SPLITTER_WIDTH + 1; 856 newResizeRect.y = right.dockablePanel.getY() + 1; 857 newResizeRect.height = right.dockablePanel.getHeight() - 2; 858 } 859 860 Rectangle toRepaint; 861 if(resizeRect == null) 862 toRepaint = newResizeRect; 863 else 864 toRepaint = resizeRect.union(newResizeRect); 865 resizeRect = newResizeRect; 866 repaint(toRepaint); 867 } 869 void finishResizing() 871 { 872 resizeRect = null; 873 repaint(); 874 } 876 878 private void propertiesChanged() 880 { 881 if(view.isPlainView()) 882 return; 883 884 ((DockableLayout)getLayout()).setAlternateLayout( 885 jEdit.getBooleanProperty("view.docking.alternateLayout")); 886 887 String [] windowList = factory.getRegisteredDockableWindows(); 888 889 for(int i = 0; i < windowList.length; i++) 890 { 891 String dockable = windowList[i]; 892 Entry entry = windows.get(dockable); 893 894 String newPosition = jEdit.getProperty(dockable 895 + ".dock-position",FLOATING); 896 if(newPosition.equals(entry.position)) 897 { 898 continue; 899 } 900 901 entry.position = newPosition; 902 if(entry.container != null) 903 { 904 entry.container.unregister(entry); 905 entry.container = null; 906 entry.win = null; 907 } 908 909 if(newPosition.equals(FLOATING)) 910 { 911 } 912 913 else 914 { 915 if(newPosition.equals(TOP)) 916 entry.container = top; 917 else if(newPosition.equals(LEFT)) 918 entry.container = left; 919 else if(newPosition.equals(BOTTOM)) 920 entry.container = bottom; 921 else if(newPosition.equals(RIGHT)) 922 entry.container = right; 923 else 924 { 925 Log.log(Log.WARNING,this, 926 "Unknown position: " 927 + newPosition); 928 continue; 929 } 930 931 entry.container.register(entry); 932 } 933 } 934 935 top.sortDockables(); 936 left.sortDockables(); 937 bottom.sortDockables(); 938 right.sortDockables(); 939 940 revalidate(); 941 repaint(); 942 } 944 private void addEntry(DockableWindowFactory.Window factory) 946 { 947 Entry e; 948 if(view.isPlainView()) 949 { 950 e = new Entry(factory,FLOATING); 952 } 953 else 954 { 955 e = new Entry(factory); 956 if(e.position.equals(FLOATING)) 957 ; 958 else if(e.position.equals(TOP)) 959 e.container = top; 960 else if(e.position.equals(LEFT)) 961 e.container = left; 962 else if(e.position.equals(BOTTOM)) 963 e.container = bottom; 964 else if(e.position.equals(RIGHT)) 965 e.container = right; 966 else 967 { 968 Log.log(Log.WARNING,this, 969 "Unknown position: " 970 + e.position); 971 } 972 973 if(e.container != null) 974 e.container.register(e); 975 } 976 windows.put(factory.name,e); 977 } 979 984 private Iterator<Entry> getAllPluginEntries(PluginJAR plugin, boolean remove) 985 { 986 List<Entry> returnValue = new LinkedList<Entry>(); 987 Iterator<Entry> iter = windows.values().iterator(); 988 while(iter.hasNext()) 989 { 990 Entry entry = iter.next(); 991 if(entry.factory.plugin == plugin) 992 { 993 returnValue.add(entry); 994 if(remove) 995 iter.remove(); 996 } 997 } 998 999 iter = clones.iterator(); 1000 while(iter.hasNext()) 1001 { 1002 Entry entry = iter.next(); 1003 if(entry.factory.plugin == plugin) 1004 { 1005 returnValue.add(entry); 1006 iter.remove(); 1007 } 1008 } 1009 1010 return returnValue.iterator(); 1011 } 1013 class Entry 1015 { 1016 DockableWindowFactory.Window factory; 1017 1018 String position; 1020 DockableWindowContainer container; 1021 1022 JComponent win; 1024 1025 AbstractButton btn; 1027 1028 Entry(DockableWindowFactory.Window factory) 1030 { 1031 this(factory,jEdit.getProperty(factory.name 1032 + ".dock-position",FLOATING)); 1033 } 1035 1036 1039 public String longTitle() 1040 { 1041 String title = jEdit.getProperty(factory.name + ".longtitle"); 1042 if (title == null) return shortTitle(); 1043 else return title; 1044 1045 } 1046 1047 1050 public String shortTitle() 1051 { 1052 1053 String title = jEdit.getProperty(factory.name + ".title"); 1054 if(title == null) 1055 return "NO TITLE PROPERTY: " + factory.name; 1056 else 1057 return title; 1058 } 1059 1062 public String label() { 1063 String retval = jEdit.getProperty(factory.name + ".label"); 1064 retval = retval.replaceAll("\\$", ""); 1065 return retval; 1066 } 1067 Entry(DockableWindowFactory.Window factory, String position) 1069 { 1070 this.factory = factory; 1071 this.position = position; 1072 1073 1077 } } 1080 1087 class KeyHandler extends KeyAdapter { 1088 static final String action = "close-docking-area"; 1089 Key b1, b2; 1090 String name; 1091 1092 public KeyHandler(String dockableName) { 1093 String shortcut1=jEdit.getProperty(action + ".shortcut"); 1094 String shortcut2=jEdit.getProperty(action + ".shortcut2"); 1095 if (shortcut1 != null) 1096 b1 = KeyEventTranslator.parseKey(shortcut1); 1097 if (shortcut2 != null) 1098 b2 = KeyEventTranslator.parseKey(shortcut2); 1099 name = dockableName; 1100 } 1101 public void keyTyped(KeyEvent e) 1102 { 1103 char cc = e.getKeyChar(); 1104 if ((b1 != null && cc == b1.key) || 1105 (b2 != null && cc == b2.key)) 1106 hideDockableWindow(name); 1107 } 1108 1109 1110 } 1111 1112} 1113 | Popular Tags |