/src/mpv5/ui/misc/CloseableTabbedPane.java

http://mp-rechnungs-und-kundenverwaltung.googlecode.com/ · Java · 718 lines · 368 code · 76 blank · 274 comment · 66 complexity · e6febc48cacf3fa685d547af1a626d09 MD5 · raw file

  1. /*
  2. * This file is part of YaBS.
  3. *
  4. * YaBS is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * YaBS is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with YaBS. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. package mpv5.ui.misc;
  18. import java.awt.BorderLayout;
  19. import java.util.EventListener;
  20. import javax.swing.Icon;
  21. import javax.swing.JComponent;
  22. import javax.swing.JTabbedPane;
  23. import javax.swing.JViewport;
  24. import javax.swing.SwingUtilities;
  25. import java.awt.Color;
  26. import java.awt.Component;
  27. import java.awt.FontMetrics;
  28. import java.awt.Graphics;
  29. import java.awt.Point;
  30. import java.awt.Rectangle;
  31. import java.awt.event.MouseEvent;
  32. import java.awt.event.MouseListener;
  33. import java.awt.event.MouseMotionListener;
  34. import javax.swing.ImageIcon;
  35. import javax.swing.border.EmptyBorder;
  36. import javax.swing.event.EventListenerList;
  37. import javax.swing.plaf.basic.BasicTabbedPaneUI;
  38. import javax.swing.plaf.metal.MetalTabbedPaneUI;
  39. import mpv5.YabsView;
  40. import mpv5.logging.Log;
  41. import mpv5.ui.frames.MPView;
  42. /**
  43. * A JTabbedPane which has a close ('X') icon on each tab.
  44. *
  45. * To add a tab, use the method addTab(String, Component)
  46. *
  47. * To have an extra icon on each tab (e.g. like in JBuilder, showing the file
  48. * type) use the method addTab(String, Component, Icon). Only clicking the 'X'
  49. * closes the tab.
  50. *
  51. * @author http://forums.sun.com/profile.jspa?userID=484725
  52. */
  53. public final class CloseableTabbedPane extends JTabbedPane implements MouseListener,
  54. MouseMotionListener {
  55. /**
  56. * The <code>EventListenerList</code>.
  57. */
  58. private EventListenerList listenerList = null;
  59. /**
  60. * The viewport of the scrolled tabs.
  61. */
  62. private JViewport headerViewport = null;
  63. /**
  64. * The normal closeicon.
  65. */
  66. private Icon normalCloseIcon = null;
  67. /**
  68. * The closeicon when the mouse is over.
  69. */
  70. private Icon hooverCloseIcon = null;
  71. /**
  72. * The closeicon when the mouse is pressed.
  73. */
  74. private Icon pressedCloseIcon = null;
  75. private YabsView parentv;
  76. private volatile int oldSelection;
  77. /**
  78. * Creates a new instance of <code>CloseableTabbedPane</code>
  79. * @param view
  80. */
  81. public CloseableTabbedPane(YabsView view) {
  82. super();
  83. init(SwingUtilities.LEFT);
  84. setCloseIcons(new ImageIcon(CloseableTabbedPane.class.getResource("/mpv5/resources/images/close.png")),
  85. new ImageIcon(CloseableTabbedPane.class.getResource("/mpv5/resources/images/closehoover.png")),
  86. new ImageIcon(CloseableTabbedPane.class.getResource("/mpv5/resources/images/closeclick.png")));
  87. setBorder(new EmptyBorder(0, 0,0, 0));
  88. this.parentv = view;
  89. setLayout(new BorderLayout());
  90. }
  91. /**
  92. * Creates a new instance of <code>CloseableTabbedPane</code>
  93. * @param horizontalTextPosition the horizontal position of the text (e.g.
  94. * SwingUtilities.TRAILING or SwingUtilities.LEFT)
  95. */
  96. public CloseableTabbedPane(int horizontalTextPosition) {
  97. super();
  98. init(horizontalTextPosition);
  99. }
  100. /**
  101. * Initializes the <code>CloseableTabbedPane</code>
  102. * @param horizontalTextPosition the horizontal position of the text (e.g.
  103. * SwingUtilities.TRAILING or SwingUtilities.LEFT)
  104. */
  105. private void init(int horizontalTextPosition) {
  106. listenerList = new EventListenerList();
  107. addMouseListener(this);
  108. addMouseMotionListener(this);
  109. setUI(new CloseableTabbedPaneUI(horizontalTextPosition));
  110. }
  111. /**
  112. * Allows setting own closeicons.
  113. * @param normal the normal closeicon
  114. * @param hoover the closeicon when the mouse is over
  115. * @param pressed the closeicon when the mouse is pressed
  116. */
  117. public void setCloseIcons(Icon normal, Icon hoover, Icon pressed) {
  118. normalCloseIcon = normal;
  119. hooverCloseIcon = hoover;
  120. pressedCloseIcon = pressed;
  121. }
  122. @Override
  123. public void setSelectedComponent(Component component) {
  124. int index = indexOfComponent(component);
  125. if (index != -1) {
  126. setSelectedIndex(index);
  127. } else {
  128. throw new IllegalArgumentException("Component not found in this tabbed pane");
  129. }
  130. }
  131. @Override
  132. public void setSelectedIndex(int index) {
  133. try {
  134. super.setSelectedIndex(index);
  135. } catch (Exception e) {
  136. Log.Debug(this, e.getMessage());
  137. }
  138. // boolean enable = false;
  139. // Class[] faces = getSelectedComponent().getClass().getInterfaces();
  140. // for (int i = 0; i < faces.length; i++) {
  141. // if (faces[i].getName().equals("mpv5.ui.panels.DataPanel")) {
  142. // enable = true;
  143. // }
  144. // }
  145. // parentv.enableToolBar(enable);
  146. }
  147. /**
  148. * Adds a <code>Component</code> represented by a title and no icon.
  149. * @param title the title to be displayed in this tab
  150. * @param component the component to be displayed when this tab is clicked
  151. */
  152. @Override
  153. public void addTab(String title, Component component) {
  154. addTab(title, component, null);
  155. }
  156. /**
  157. * Adds a <code>Component</code> represented by a title and an icon.
  158. * @param title the title to be displayed in this tab
  159. * @param component the component to be displayed when this tab is clicked
  160. * @param extraIcon the icon to be displayed in this tab
  161. */
  162. public void addTab(String title, Component component, Icon extraIcon) {
  163. boolean doPaintCloseIcon = true;
  164. try {
  165. Object prop = null;
  166. if ((prop = ((JComponent) component).getClientProperty("isClosable")) != null) {
  167. doPaintCloseIcon = (Boolean) prop;
  168. }
  169. } catch (Exception ignored) {/*Could probably be a ClassCastException*/
  170. }
  171. super.addTab(title,
  172. doPaintCloseIcon ? new CloseTabIcon(extraIcon) : null,
  173. component);
  174. if (headerViewport == null) {
  175. for (Component c : getComponents()) {
  176. if ("TabbedPane.scrollableViewport".equals(c.getName())) {
  177. headerViewport = (JViewport) c;
  178. }
  179. }
  180. }
  181. }
  182. /**
  183. * Invoked when the mouse button has been clicked (pressed and released) on
  184. * a component.
  185. * @param e the <code>MouseEvent</code>
  186. */
  187. public void mouseClicked(MouseEvent e) {
  188. processMouseEvents(e);
  189. }
  190. /**
  191. * Invoked when the mouse enters a component.
  192. * @param e the <code>MouseEvent</code>
  193. */
  194. public void mouseEntered(MouseEvent e) {
  195. oldSelection = getSelectedIndex();
  196. }
  197. /**
  198. * Invoked when the mouse exits a component.
  199. * @param e the <code>MouseEvent</code>
  200. */
  201. public void mouseExited(MouseEvent e) {
  202. for (int i = 0; i < getTabCount(); i++) {
  203. CloseTabIcon icon = (CloseTabIcon) getIconAt(i);
  204. if (icon != null) {
  205. icon.mouseover = false;
  206. }
  207. }
  208. repaint();
  209. }
  210. /**
  211. * Invoked when a mouse button has been pressed on a component.
  212. * @param e the <code>MouseEvent</code>
  213. */
  214. public void mousePressed(MouseEvent e) {
  215. processMouseEvents(e);
  216. }
  217. /**
  218. * Invoked when a mouse button has been released on a component.
  219. * @param e the <code>MouseEvent</code>
  220. */
  221. public void mouseReleased(MouseEvent e) {
  222. }
  223. /**
  224. * Invoked when a mouse button is pressed on a component and then dragged.
  225. * <code>MOUSE_DRAGGED</code> events will continue to be delivered to the
  226. * component where the drag originated until the mouse button is released
  227. * (regardless of whether the mouse position is within the bounds of the
  228. * component).<br/>
  229. * <br/>
  230. * Due to platform-dependent Drag&Drop implementations,
  231. * <code>MOUSE_DRAGGED</code> events may not be delivered during a native
  232. * Drag&amp;Drop operation.
  233. * @param e the <code>MouseEvent</code>
  234. */
  235. public void mouseDragged(MouseEvent e) {
  236. processMouseEvents(e);
  237. }
  238. /**
  239. * Invoked when the mouse cursor has been moved onto a component but no
  240. * buttons have been pushed.
  241. * @param e the <code>MouseEvent</code>
  242. */
  243. public void mouseMoved(MouseEvent e) {
  244. processMouseEvents(e);
  245. }
  246. /**
  247. * Processes all caught <code>MouseEvent</code>s.
  248. * @param e the <code>MouseEvent</code>
  249. */
  250. private void processMouseEvents(MouseEvent e) {
  251. int tabNumber = getUI().tabForCoordinate(this, e.getX(), e.getY());
  252. if (tabNumber < 0) {
  253. return;
  254. }
  255. CloseTabIcon icon = (CloseTabIcon) getIconAt(tabNumber);
  256. if (icon != null) {
  257. Rectangle rect = icon.getBounds();
  258. Point pos = headerViewport == null ? new Point() : headerViewport.getViewPosition();
  259. Rectangle drawRect = new Rectangle(
  260. rect.x - pos.x, rect.y - pos.y, rect.width, rect.height);
  261. if (e.getID() == e.MOUSE_PRESSED) {
  262. icon.mousepressed = e.getModifiers() == e.BUTTON1_MASK;
  263. repaint(drawRect);
  264. } else if (e.getID() == e.MOUSE_MOVED || e.getID() == e.MOUSE_DRAGGED ||
  265. e.getID() == e.MOUSE_CLICKED) {
  266. pos.x += e.getX();
  267. pos.y += e.getY();
  268. if (rect.contains(pos)) {
  269. if (e.getID() == e.MOUSE_CLICKED) {
  270. int selIndex = getSelectedIndex();
  271. if (fireCloseTab(selIndex)) {
  272. if (selIndex > 0) {
  273. // to prevent uncatchable null-pointers
  274. Rectangle rec = getUI().getTabBounds(this, selIndex - 1);
  275. MouseEvent event = new MouseEvent((Component) e.getSource(),
  276. e.getID() + 1,
  277. System.currentTimeMillis(),
  278. e.getModifiers(),
  279. rec.x,
  280. rec.y,
  281. e.getClickCount(),
  282. e.isPopupTrigger(),
  283. e.getButton());
  284. dispatchEvent(event);
  285. }
  286. //the tab is being closed
  287. //removeTabAt(tabNumber);
  288. remove(selIndex);
  289. try {
  290. if (selIndex < oldSelection) {
  291. setSelectedIndex(oldSelection-1);
  292. } else if (selIndex > oldSelection){
  293. setSelectedIndex(oldSelection);
  294. }
  295. } catch (Exception selex) {
  296. Log.Debug(selex);
  297. }
  298. } else {
  299. icon.mouseover = false;
  300. icon.mousepressed = false;
  301. repaint(drawRect);
  302. }
  303. } else {
  304. icon.mouseover = true;
  305. icon.mousepressed = e.getModifiers() == e.BUTTON1_MASK;
  306. }
  307. } else {
  308. icon.mouseover = false;
  309. }
  310. repaint(drawRect);
  311. }
  312. }
  313. e.consume();
  314. }
  315. /**
  316. * Adds an <code>CloseableTabbedPaneListener</code> to the tabbedpane.
  317. * @param l the <code>CloseableTabbedPaneListener</code> to be added
  318. */
  319. public void addCloseableTabbedPaneListener(CloseableTabbedPaneListener l) {
  320. listenerList.add(CloseableTabbedPaneListener.class, l);
  321. }
  322. /**
  323. * Removes an <code>CloseableTabbedPaneListener</code> from the tabbedpane.
  324. * @param l the listener to be removed
  325. */
  326. public void removeCloseableTabbedPaneListener(CloseableTabbedPaneListener l) {
  327. listenerList.remove(CloseableTabbedPaneListener.class, l);
  328. }
  329. /**
  330. * Returns an array of all the <code>SearchListener</code>s added to this
  331. * <code>SearchPane</code> with addSearchListener().
  332. * @return all of the <code>SearchListener</code>s added or an empty array if
  333. * no listeners have been added
  334. */
  335. public CloseableTabbedPaneListener[] getCloseableTabbedPaneListener() {
  336. return listenerList.getListeners(CloseableTabbedPaneListener.class);
  337. }
  338. /**
  339. * Notifies all listeners that have registered interest for notification on
  340. * this event type.
  341. * @param tabIndexToClose the index of the tab which should be closed
  342. * @return true if the tab can be closed, false otherwise
  343. */
  344. protected boolean fireCloseTab(int tabIndexToClose) {
  345. boolean closeit = true;
  346. // Guaranteed to return a non-null array
  347. Object[] listeners = listenerList.getListenerList();
  348. for (Object i : listeners) {
  349. if (i instanceof CloseableTabbedPaneListener) {
  350. if (!((CloseableTabbedPaneListener) i).closeTab(tabIndexToClose)) {
  351. closeit = false;
  352. break;
  353. }
  354. }
  355. }
  356. return closeit;
  357. }
  358. /**
  359. * Removes all tabs but the selected one
  360. */
  361. public void removeAllButSelected() {
  362. // int index = getSelectedIndex();
  363. // for (int i = 0; i < getTabCount(); i++) {
  364. // if(i!=index)remove(i);
  365. //
  366. // }
  367. // validate();
  368. try {
  369. Component selected = getSelectedComponent();
  370. String title = getTitleAt(getSelectedIndex());
  371. removeAll();
  372. add(title, selected);
  373. } catch (Exception e) {
  374. Log.Debug(e);
  375. }
  376. }
  377. /**
  378. * The class which generates the 'X' icon for the tabs. The constructor
  379. * accepts an icon which is extra to the 'X' icon, so you can have tabs
  380. * like in JBuilder. This value is null if no extra icon is required.
  381. */
  382. class CloseTabIcon implements Icon {
  383. /**
  384. * the x position of the icon
  385. */
  386. private int x_pos;
  387. /**
  388. * the y position of the icon
  389. */
  390. private int y_pos;
  391. /**
  392. * the width the icon
  393. */
  394. private int width;
  395. /**
  396. * the height the icon
  397. */
  398. private int height;
  399. /**
  400. * the additional fileicon
  401. */
  402. private Icon fileIcon;
  403. /**
  404. * true whether the mouse is over this icon, false otherwise
  405. */
  406. private boolean mouseover = false;
  407. /**
  408. * true whether the mouse is pressed on this icon, false otherwise
  409. */
  410. private boolean mousepressed = false;
  411. /**
  412. * Creates a new instance of <code>CloseTabIcon</code>
  413. * @param fileIcon the additional fileicon, if there is one set
  414. */
  415. public CloseTabIcon(Icon fileIcon) {
  416. this.fileIcon = fileIcon;
  417. width = 16;
  418. height = 16;
  419. }
  420. /**
  421. * Draw the icon at the specified location. Icon implementations may use the
  422. * Component argument to get properties useful for painting, e.g. the
  423. * foreground or background color.
  424. * @param c the component which the icon belongs to
  425. * @param g the graphic object to draw on
  426. * @param x the upper left point of the icon in the x direction
  427. * @param y the upper left point of the icon in the y direction
  428. */
  429. public void paintIcon(Component c, Graphics g, int x, int y) {
  430. boolean doPaintCloseIcon = true;
  431. try {
  432. // JComponent.putClientProperty("isClosable", new Boolean(false));
  433. JTabbedPane tabbedpane = (JTabbedPane) c;
  434. int tabNumber = tabbedpane.getUI().tabForCoordinate(tabbedpane, x, y);
  435. JComponent curPanel = (JComponent) tabbedpane.getComponentAt(tabNumber);
  436. Object prop = null;
  437. if ((prop = curPanel.getClientProperty("isClosable")) != null) {
  438. doPaintCloseIcon = (Boolean) prop;
  439. }
  440. } catch (Exception ignored) {/*Could probably be a ClassCastException*/
  441. }
  442. if (doPaintCloseIcon) {
  443. x_pos = x;
  444. y_pos = y;
  445. int y_p = y + 1;
  446. if (normalCloseIcon != null && !mouseover) {
  447. normalCloseIcon.paintIcon(c, g, x, y_p);
  448. } else if (hooverCloseIcon != null && mouseover && !mousepressed) {
  449. hooverCloseIcon.paintIcon(c, g, x, y_p);
  450. } else if (pressedCloseIcon != null && mousepressed) {
  451. pressedCloseIcon.paintIcon(c, g, x, y_p);
  452. } else {
  453. y_p++;
  454. Color col = g.getColor();
  455. if (mousepressed && mouseover) {
  456. g.setColor(Color.WHITE);
  457. g.fillRect(x + 1, y_p, 12, 13);
  458. }
  459. g.setColor(Color.black);
  460. g.drawLine(x + 1, y_p, x + 12, y_p);
  461. g.drawLine(x + 1, y_p + 13, x + 12, y_p + 13);
  462. g.drawLine(x, y_p + 1, x, y_p + 12);
  463. g.drawLine(x + 13, y_p + 1, x + 13, y_p + 12);
  464. g.drawLine(x + 3, y_p + 3, x + 10, y_p + 10);
  465. if (mouseover) {
  466. g.setColor(Color.GRAY);
  467. }
  468. g.drawLine(x + 3, y_p + 4, x + 9, y_p + 10);
  469. g.drawLine(x + 4, y_p + 3, x + 10, y_p + 9);
  470. g.drawLine(x + 10, y_p + 3, x + 3, y_p + 10);
  471. g.drawLine(x + 10, y_p + 4, x + 4, y_p + 10);
  472. g.drawLine(x + 9, y_p + 3, x + 3, y_p + 9);
  473. g.setColor(col);
  474. if (fileIcon != null) {
  475. fileIcon.paintIcon(c, g, x + width, y_p);
  476. }
  477. }
  478. }
  479. }
  480. /**
  481. * Returns the icon's width.
  482. * @return an int specifying the fixed width of the icon.
  483. */
  484. public int getIconWidth() {
  485. return width + (fileIcon != null ? fileIcon.getIconWidth() : 0);
  486. }
  487. /**
  488. * Returns the icon's height.
  489. * @return an int specifying the fixed height of the icon.
  490. */
  491. public int getIconHeight() {
  492. return height;
  493. }
  494. /**
  495. * Gets the bounds of this icon in the form of a <code>Rectangle<code>
  496. * object. The bounds specify this icon's width, height, and location
  497. * relative to its parent.
  498. * @return a rectangle indicating this icon's bounds
  499. */
  500. public Rectangle getBounds() {
  501. return new Rectangle(x_pos, y_pos, width, height);
  502. }
  503. }
  504. /**
  505. * A specific <code>BasicTabbedPaneUI</code>.
  506. */
  507. class CloseableTabbedPaneUI extends BasicTabbedPaneUI {
  508. /**
  509. * the horizontal position of the text
  510. */
  511. private int horizontalTextPosition = SwingUtilities.LEFT;
  512. /**
  513. * Creates a new instance of <code>CloseableTabbedPaneUI</code>
  514. */
  515. public CloseableTabbedPaneUI() {
  516. }
  517. /**
  518. * Creates a new instance of <code>CloseableTabbedPaneUI</code>
  519. * @param horizontalTextPosition the horizontal position of the text (e.g.
  520. * SwingUtilities.TRAILING or SwingUtilities.LEFT)
  521. */
  522. public CloseableTabbedPaneUI(int horizontalTextPosition) {
  523. this.horizontalTextPosition = horizontalTextPosition;
  524. }
  525. /**
  526. * Layouts the label
  527. * @param tabPlacement the placement of the tabs
  528. * @param metrics the font metrics
  529. * @param tabIndex the index of the tab
  530. * @param title the title of the tab
  531. * @param icon the icon of the tab
  532. * @param tabRect the tab boundaries
  533. * @param iconRect the icon boundaries
  534. * @param textRect the text boundaries
  535. * @param isSelected true whether the tab is selected, false otherwise
  536. */
  537. @Override
  538. protected void layoutLabel(int tabPlacement, FontMetrics metrics,
  539. int tabIndex, String title, Icon icon,
  540. Rectangle tabRect, Rectangle iconRect,
  541. Rectangle textRect, boolean isSelected) {
  542. textRect.x = textRect.y = iconRect.x = iconRect.y = 0;
  543. javax.swing.text.View v = getTextViewForTab(tabIndex);
  544. if (v != null) {
  545. tabPane.putClientProperty("html", v);
  546. }
  547. SwingUtilities.layoutCompoundLabel((JComponent) tabPane,
  548. metrics, title, icon,
  549. SwingUtilities.CENTER,
  550. SwingUtilities.CENTER,
  551. SwingUtilities.CENTER,
  552. //SwingUtilities.TRAILING,
  553. horizontalTextPosition,
  554. tabRect,
  555. iconRect,
  556. textRect,
  557. textIconGap + 0);
  558. tabPane.putClientProperty("html", null);
  559. int xNudge = getTabLabelShiftX(tabPlacement, tabIndex, isSelected);
  560. int yNudge = getTabLabelShiftY(tabPlacement, tabIndex, isSelected);
  561. iconRect.x += xNudge;
  562. iconRect.y += yNudge;
  563. textRect.x += xNudge;
  564. textRect.y += yNudge;
  565. }
  566. }
  567. /**
  568. * A specific <code>MetalTabbedPaneUI</code>.
  569. */
  570. class CloseableMetalTabbedPaneUI extends MetalTabbedPaneUI {
  571. /**
  572. * the horizontal position of the text
  573. */
  574. private int horizontalTextPosition = SwingUtilities.LEFT;
  575. /**
  576. * Creates a new instance of <code>CloseableMetalTabbedPaneUI</code>
  577. */
  578. public CloseableMetalTabbedPaneUI() {
  579. }
  580. /**
  581. * Creates a new instance of <code>CloseableMetalTabbedPaneUI</code>
  582. * @param horizontalTextPosition the horizontal position of the text (e.g.
  583. * SwingUtilities.TRAILING or SwingUtilities.LEFT)
  584. */
  585. public CloseableMetalTabbedPaneUI(int horizontalTextPosition) {
  586. this.horizontalTextPosition = horizontalTextPosition;
  587. }
  588. /**
  589. * Layouts the label
  590. * @param tabPlacement the placement of the tabs
  591. * @param metrics the font metrics
  592. * @param tabIndex the index of the tab
  593. * @param title the title of the tab
  594. * @param icon the icon of the tab
  595. * @param tabRect the tab boundaries
  596. * @param iconRect the icon boundaries
  597. * @param textRect the text boundaries
  598. * @param isSelected true whether the tab is selected, false otherwise
  599. */
  600. protected void layoutLabel(int tabPlacement, FontMetrics metrics,
  601. int tabIndex, String title, Icon icon,
  602. Rectangle tabRect, Rectangle iconRect,
  603. Rectangle textRect, boolean isSelected) {
  604. textRect.x = textRect.y = iconRect.x = iconRect.y = 0;
  605. javax.swing.text.View v = getTextViewForTab(tabIndex);
  606. if (v != null) {
  607. tabPane.putClientProperty("html", v);
  608. }
  609. SwingUtilities.layoutCompoundLabel((JComponent) tabPane,
  610. metrics, title, icon,
  611. SwingUtilities.CENTER,
  612. SwingUtilities.CENTER,
  613. SwingUtilities.CENTER,
  614. //SwingUtilities.TRAILING,
  615. horizontalTextPosition,
  616. tabRect,
  617. iconRect,
  618. textRect,
  619. textIconGap + 2);
  620. tabPane.putClientProperty("html", null);
  621. int xNudge = getTabLabelShiftX(tabPlacement, tabIndex, isSelected);
  622. int yNudge = getTabLabelShiftY(tabPlacement, tabIndex, isSelected);
  623. iconRect.x += xNudge;
  624. iconRect.y += yNudge;
  625. textRect.x += xNudge;
  626. textRect.y += yNudge;
  627. }
  628. }
  629. }
  630. /**
  631. * The listener that's notified when an tab should be closed in the
  632. * <code>CloseableTabbedPane</code>.
  633. */
  634. interface CloseableTabbedPaneListener extends EventListener {
  635. /**
  636. * Informs all <code>CloseableTabbedPaneListener</code>s when a tab should be
  637. * closed
  638. * @param tabIndexToClose the index of the tab which should be closed
  639. * @return true if the tab can be closed, false otherwise
  640. */
  641. boolean closeTab(int tabIndexToClose);
  642. }