1 19 20 package org.netbeans.core.windows.view.ui.tabcontrol; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.util.Iterator ; 25 import java.util.List ; 26 import java.util.logging.Logger ; 27 import org.netbeans.core.windows.Constants; 28 import org.netbeans.core.windows.Debug; 29 import org.netbeans.core.windows.WindowManagerImpl; 30 import org.netbeans.core.windows.view.ui.Tabbed; 31 import org.netbeans.swing.tabcontrol.ComponentConverter; 32 import org.netbeans.swing.tabcontrol.TabData; 33 import org.netbeans.swing.tabcontrol.TabbedContainer; 34 import org.netbeans.swing.tabcontrol.plaf.EqualPolygon; 35 import org.openide.util.WeakListeners; 36 import org.openide.windows.TopComponent; 37 import java.awt.Image ; 38 import org.netbeans.core.windows.view.ui.slides.SlideController; 39 import javax.swing.*; 40 import javax.swing.event.ChangeEvent ; 41 import javax.swing.event.ChangeListener ; 42 import java.awt.*; 43 import java.util.ArrayList ; 44 import java.util.Arrays ; 45 import org.netbeans.core.windows.ModeImpl; 46 import org.netbeans.core.windows.actions.ActionUtils; 47 import org.netbeans.swing.tabcontrol.LocationInformer; 48 import org.netbeans.swing.tabcontrol.TabDisplayer; 49 import org.netbeans.swing.tabcontrol.WinsysInfoForTabbed; 50 import org.netbeans.swing.tabcontrol.event.TabActionEvent; 51 52 58 public class TabbedAdapter extends TabbedContainer implements Tabbed, Tabbed.Accessor, SlideController { 59 60 public static final int DOCUMENT = 1; 61 62 63 private transient java.util.ArrayList <ChangeListener > changeListenerList; 64 65 66 private static final boolean DEBUG = Debug.isLoggable(TabbedAdapter.class); 67 private ChangeEvent changeEvent = new ChangeEvent (this); 68 69 private PropertyChangeListener tooltipListener, weakTooltipListener; 70 71 72 public TabbedAdapter (int type) { 73 super (null, type, new WinsysInfo()); 74 getSelectionModel().addChangeListener(new ChangeListener () { 75 public void stateChanged (ChangeEvent ce) { 76 int idx = getSelectionModel().getSelectedIndex(); 77 if (idx != -1) { 78 fireStateChanged(); 79 } 80 } 81 }); 82 } 85 86 public void addTopComponent(String name, javax.swing.Icon icon, TopComponent tc, String toolTip) { 87 insertComponent (name, icon, tc, toolTip, getTabCount()); 88 } 89 90 public TopComponent getTopComponentAt(int index) { 91 if (index == -1) { 92 return null; 93 } 94 return (TopComponent)getModel().getTab(index).getComponent(); 95 } 96 97 public TopComponent getSelectedTopComponent() { 98 int i = getSelectionModel().getSelectedIndex(); 99 return i == -1 ? null : getTopComponentAt(i); 100 } 101 102 public void requestAttention (TopComponent tc) { 103 int idx = indexOf(tc); 104 if (idx >= 0) { 105 requestAttention(idx); 106 } else { 107 Logger.getAnonymousLogger().fine( 108 "RequestAttention on component unknown to container: " + tc); } 110 } 111 112 public void cancelRequestAttention (TopComponent tc) { 113 int idx = indexOf(tc); 114 if (idx >= 0) { 115 cancelRequestAttention(idx); 116 } else { 117 throw new IllegalArgumentException ("TopComponent " + tc 118 + " is not a child of this container"); } 120 } 121 122 public void insertComponent(String name, javax.swing.Icon icon, Component comp, String toolTip, int position) { 123 TabData td = new TabData (comp, icon, name, toolTip); 124 125 if(DEBUG) { 126 debugLog("InsertTab: " + name + " hash:" + System.identityHashCode(comp)); } 128 129 getModel().addTab(position, td); 130 comp.addPropertyChangeListener(JComponent.TOOL_TIP_TEXT_KEY, getTooltipListener(comp)); 131 } 132 133 public void setSelectedComponent(Component comp) { 134 int i = indexOf (comp); 135 if (i == -1) { 136 throw new IllegalArgumentException ( 137 "Component not a child of this control: " + comp); } else { 139 getSelectionModel().setSelectedIndex(i); 140 } 141 } 142 143 public TopComponent[] getTopComponents() { 144 ComponentConverter cc = getComponentConverter(); 145 TabData[] td = (TabData[]) getModel().getTabs().toArray(new TabData[0]); 146 TopComponent[] result = new TopComponent[getModel().size()]; 147 for (int i=0; i < td.length; i++) { 148 result[i] = (TopComponent) cc.getComponent(td[i]); 149 } 150 return result; 151 } 152 153 public void removeComponent(Component comp) { 154 int i=indexOf(comp); 155 getModel().removeTab(i); 156 comp.removePropertyChangeListener(JComponent.TOOL_TIP_TEXT_KEY, getTooltipListener(comp)); 157 if (getModel().size() == 0) { 158 revalidate(); 159 repaint(); 160 } 161 } 162 163 public void addComponents(Component[] comps, String [] names, javax.swing.Icon [] icons, String [] tips) { 164 ArrayList al = new ArrayList (comps.length); 165 TabData[] data = new TabData[comps.length]; 166 for (int i=0; i < comps.length; i++) { 167 TabData td = new TabData (comps[i], icons[i], names[i], tips[i]); 168 data[i] = td; 169 comps[i].addPropertyChangeListener(JComponent.TOOL_TIP_TEXT_KEY, getTooltipListener(comps[i])); 170 } 171 getModel().addTabs (0, data); 172 } 173 174 public void setTopComponents(TopComponent[] tcs, TopComponent selected) { 175 assert selected != null : "Null passed as component to select"; 176 int sizeBefore = getModel().size(); 177 178 detachTooltipListeners(getModel().getTabs()); 179 180 TabData[] data = new TabData[tcs.length]; 181 int toSelect=-1; 182 for(int i = 0; i < tcs.length; i++) { 183 TopComponent tc = tcs[i]; 184 Image icon = tc.getIcon(); 185 String displayName = WindowManagerImpl.getInstance().getTopComponentDisplayName(tc); 186 data[i] = new TabData( 187 tc, 188 icon == null ? null : new ImageIcon(icon), 189 displayName == null ? "" : displayName, tc.getToolTipText()); 191 if (selected == tcs[i]) { 192 toSelect = i; 193 } 194 tc.addPropertyChangeListener(JComponent.TOOL_TIP_TEXT_KEY, getTooltipListener(tc)); 195 } 196 197 assert toSelect != -1 : "Tried to set a selected component that was " + 203 " not in the array of open components. ToSelect: " + selected + " ToSelectName=" + selected.getDisplayName() + 204 " ToSelectClass=" + selected.getClass() + 205 " open components: " + Arrays.asList(tcs); 206 207 getModel().setTabs(data); 208 209 210 211 if (toSelect != -1) { 212 getSelectionModel().setSelectedIndex(toSelect); 213 } else { 214 Logger.getAnonymousLogger().warning("Tried to" + 216 "set a selected component that was not in the array of open " + 217 "components. ToSelect: " + selected + " components: " + 218 Arrays.asList(tcs)); 219 } 220 int sizeNow = getModel().size(); 221 if (sizeBefore != 0 && sizeNow == 0) { 222 revalidate(); 224 repaint(); 225 } 226 } 227 228 229 private void detachTooltipListeners(List tabs) { 230 JComponent curComp; 231 for (Iterator iter = tabs.iterator(); iter.hasNext(); ) { 232 curComp = (JComponent)((TabData)iter.next()).getComponent(); 233 curComp.removePropertyChangeListener(JComponent.TOOL_TIP_TEXT_KEY, 234 getTooltipListener(curComp)); 235 } 236 } 237 238 244 public Object getConstraintForLocation(Point location, boolean attachingPossible) { 245 int tab = tabForCoordinate(location); 248 if (tab != -1) { 249 int index = dropIndexOfPoint(location); 250 return index < 0 ? null : Integer.valueOf(index); 251 } 252 if(attachingPossible) { 254 String s = getSideForLocation(location); 255 if(s != null) { 256 return s; 257 } 258 } 259 int index = dropIndexOfPoint(location); 260 return index < 0 ? null : Integer.valueOf(index); 261 } 262 263 268 public Shape getIndicationForLocation(Point location, 269 TopComponent startingTransfer, Point startingPoint, boolean attachingPossible) { 270 271 Rectangle rect = getBounds(); 272 rect.setLocation(0, 0); 273 274 int tab = tabForCoordinate(location); 276 if (tab != -1) { 279 Shape s = getDropIndication(startingTransfer, location); 280 if(s != null) { 281 return s; 282 } 283 } 284 285 String side; 286 if(attachingPossible) { 287 side = getSideForLocation(location); 288 } else { 289 side = null; 290 } 291 292 double ratio = Constants.DROP_TO_SIDE_RATIO; 293 if(side == Constants.TOP) { 294 return new Rectangle(0, 0, rect.width, (int)(rect.height * ratio)); 295 } else if(side == Constants.LEFT) { 296 return new Rectangle(0, 0, (int)(rect.width * ratio), rect.height); 297 } else if(side == Constants.RIGHT) { 298 return new Rectangle(rect.width - (int)(rect.width * ratio), 0, (int)(rect.width * ratio), rect.height); 299 } else if(side == Constants.BOTTOM) { 300 return new Rectangle(0, rect.height - (int)(rect.height * ratio), rect.width, (int)(rect.height * ratio)); 301 } 302 303 Shape s = getDropIndication(startingTransfer, location); 305 if(s != null) { 306 return s; 307 } 308 309 if(startingPoint != null 310 && indexOf(startingTransfer) != -1) { 311 return getStartingIndication(startingPoint, location); 312 } 313 314 return rect; 315 } 316 317 private String getSideForLocation(Point location) { 318 Rectangle bounds = getBounds(); 319 bounds.setLocation(0, 0); 320 321 final int TOP_HEIGHT = 10; 322 final int BOTTOM_HEIGHT = (int)(0.25 * bounds.height); 323 324 final int LEFT_WIDTH = Math.max (getWidth() / 8, 40); 325 final int RIGHT_WIDTH = LEFT_WIDTH; 326 327 if(DEBUG) { 328 debugLog(""); debugLog("TOP_HEIGHT =" + TOP_HEIGHT); debugLog("BOTTOM_HEIGHT =" + BOTTOM_HEIGHT); debugLog("LEFT_WIDTH =" + LEFT_WIDTH); debugLog("RIGHT_WIDTH =" + RIGHT_WIDTH); } 334 335 Rectangle top = new Rectangle(0, 0, bounds.width, BOTTOM_HEIGHT); 338 if(top.contains(location)) { 339 return Constants.TOP; 340 } 341 342 Polygon left = new EqualPolygon( 343 new int[] {0, LEFT_WIDTH, LEFT_WIDTH, 0}, 344 new int[] {TOP_HEIGHT, TOP_HEIGHT, bounds.height - BOTTOM_HEIGHT, bounds.height}, 345 4 346 ); 347 if(left.contains(location)) { 348 return Constants.LEFT; 349 } 350 351 Polygon right = new EqualPolygon( 352 new int[] {bounds.width - RIGHT_WIDTH, bounds.width, bounds.width, bounds.width - RIGHT_WIDTH}, 353 new int[] {TOP_HEIGHT, TOP_HEIGHT, bounds.height, bounds.height - BOTTOM_HEIGHT}, 354 4 355 ); 356 if(right.contains(location)) { 357 return Constants.RIGHT; 358 } 359 360 Polygon bottom = new EqualPolygon( 361 new int[] {LEFT_WIDTH, bounds.width - RIGHT_WIDTH, bounds.width, 0}, 362 new int[] {bounds.height - BOTTOM_HEIGHT, bounds.height - BOTTOM_HEIGHT, bounds.height, bounds.height}, 363 4 364 ); 365 if(bottom.contains(location)) { 366 return Constants.BOTTOM; 367 } 368 369 return null; 370 } 371 372 private Shape getStartingIndication(Point startingPoint, Point location) { 373 Rectangle rect = getBounds(); 374 rect.setLocation(location.x - startingPoint.x, location.y - startingPoint.y); 375 return rect; 376 } 377 379 380 384 public synchronized void addChangeListener(javax.swing.event.ChangeListener listener) { 385 if (changeListenerList == null ) { 386 changeListenerList = new java.util.ArrayList <ChangeListener >(); 387 } 388 changeListenerList.add(listener); 389 } 390 391 395 public synchronized void removeChangeListener(javax.swing.event.ChangeListener listener) { 396 if (changeListenerList != null ) { 397 changeListenerList.remove(listener); 398 } 399 } 400 401 402 private void fireStateChanged() { 403 java.util.ArrayList <ChangeListener > list; 404 synchronized (this) { 405 if (changeListenerList == null) return; 406 list = new ArrayList <ChangeListener >( changeListenerList ); 407 } 408 417 if (!SwingUtilities.isEventDispatchThread()) { 418 Logger.getAnonymousLogger().warning( 419 "All state changes to the tab component must happen on the event thread!"); Exception e = new Exception (); 421 e.fillInStackTrace(); 422 Logger.getAnonymousLogger().warning(e.getStackTrace()[1].toString()); 423 } 424 425 synchronized (getTreeLock()) { 426 for (int i = 0; i < list.size(); i++) { 427 ((javax.swing.event.ChangeListener )list.get(i)).stateChanged(changeEvent); 428 } 429 } 430 } 431 432 private static void debugLog(String message) { 433 Debug.log(TabbedAdapter.class, message); 434 } 435 436 public Component getComponent() { 437 return this; 438 } 439 440 441 public Action[] getPopupActions(Action[] defaultActions, int tabIndex) { 442 boolean isDocked = WindowManagerImpl.getInstance().isDocked(getTopComponentAt(tabIndex)); 443 if (TabbedContainer.TYPE_EDITOR == getType() || !isDocked) { 445 return defaultActions; 446 } 447 int actionCount = defaultActions.length; 448 Action[] result = new Action[actionCount + 1]; 449 System.arraycopy(defaultActions, 0, result, 0, actionCount); 450 if (actionCount > 0) { 452 result[actionCount] = result[actionCount - 1]; 453 result[actionCount - 1] = new ActionUtils.AutoHideWindowAction(this, tabIndex, false); 454 } 455 return result; 456 } 457 458 463 public static boolean isInMaximizedMode (Component comp) { 464 ModeImpl maxMode = WindowManagerImpl.getInstance().getCurrentMaximizedMode(); 465 if (maxMode == null) { 466 return false; 467 } 468 return maxMode.containsTopComponent((TopComponent)comp); 469 } 470 471 472 473 public void userToggledAutoHide(int tabIndex, boolean enabled) { 474 postActionEvent(new TabActionEvent(this, TabbedContainer.COMMAND_ENABLE_AUTO_HIDE, tabIndex)); 475 } 476 477 478 479 public Tabbed getTabbed() { 480 return this; 481 } 482 483 public Rectangle getTabBounds(int tabIndex) { 484 return getTabRect(tabIndex, new Rectangle()); 485 } 486 487 488 489 static class WinsysInfo implements WinsysInfoForTabbed { 490 491 public Object getOrientation (Component comp) { 492 WindowManagerImpl wmi = WindowManagerImpl.getInstance(); 493 if (!wmi.isDocked((TopComponent)comp)) { 495 return TabDisplayer.ORIENTATION_INVISIBLE; 496 } 497 498 String side = wmi.guessSlideSide((TopComponent)comp); 499 Object result = null; 500 if (side.equals(Constants.LEFT)) { 501 result = TabDisplayer.ORIENTATION_WEST; 502 } else if (side.equals(Constants.RIGHT)) { 503 result = TabDisplayer.ORIENTATION_EAST; 504 } else if (side.equals(Constants.BOTTOM)) { 505 result = TabDisplayer.ORIENTATION_SOUTH; 506 } else { 507 result = TabDisplayer.ORIENTATION_CENTER; 508 } 509 return result; 510 } 511 512 public boolean inMaximizedMode (Component comp) { 513 return isInMaximizedMode(comp); 514 } 515 516 } 518 522 private PropertyChangeListener getTooltipListener(Component comp) { 523 if (tooltipListener == null) { 524 tooltipListener = new ToolTipListener(); 525 weakTooltipListener = WeakListeners.propertyChange(tooltipListener, comp); 526 } 527 return weakTooltipListener; 528 } 529 530 531 private class ToolTipListener implements PropertyChangeListener { 532 533 public void propertyChange(PropertyChangeEvent evt) { 534 if (JComponent.TOOL_TIP_TEXT_KEY.equals(evt.getPropertyName())) { 535 List tabs = getModel().getTabs(); 536 JComponent curComp; 537 int index = 0; 538 for (Iterator iter = tabs.iterator(); iter.hasNext(); index++) { 539 curComp = (JComponent)((TabData)iter.next()).getComponent(); 540 if (curComp == evt.getSource()) { 541 setToolTipTextAt(index, (String )evt.getNewValue()); 542 break; 543 } 544 } 545 } 546 } 547 548 } 549 550 551 } 552 | Popular Tags |