/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.java.sip.communicator.plugin.desktoputil.plaf; /* * The content of this file was based on code borrowed from David Bismut, * davidou@mageos.com Intern, SETLabs, Infosys Technologies Ltd. May 2004 - Jul * 2004 Ecole des Mines de Nantes, France */ import java.awt.*; import java.awt.image.*; import java.util.*; import javax.swing.*; import javax.swing.plaf.*; import javax.swing.plaf.basic.*; import javax.swing.text.*; import net.java.sip.communicator.plugin.desktoputil.*; import net.java.sip.communicator.util.skin.*; /** * This UI displays a different interface, which is independent from the look * and feel. * * @author David Bismut, davidou@mageos.com * @author Yana Stamcheva * @author Adam Netocny */ public class SIPCommTabbedPaneEnhancedUI extends SIPCommTabbedPaneUI implements Skinnable { private static Color TAB_HIGHLIGHT_FOREGROUND_COLOR = new Color(DesktopUtilActivator.getResources() .getColor("service.gui.TAB_TITLE_HIGHLIGHT")); private static Color TAB_SELECTED_FOREGROUND_COLOR = new Color(DesktopUtilActivator.getResources() .getColor("service.gui.TAB_TITLE_SELECTED")); private static final int TAB_OVERLAP = Integer.parseInt(DesktopUtilActivator.getResources(). getSettingsString("impl.gui.TAB_OVERLAP")); private static final int PREFERRED_WIDTH = 150; /** * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background * of a selected tab. */ private static final String SELECTED_TAB_LEFT_BG = "service.gui.lookandfeel.SELECTED_TAB_LEFT_BG"; /** * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background * of a selected tab. */ private static final String SELECTED_TAB_MIDDLE_BG = "service.gui.lookandfeel.SELECTED_TAB_MIDDLE_BG"; /** * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background * of a selected tab. */ private static final String SELECTED_TAB_RIGHT_BG = "service.gui.lookandfeel.SELECTED_TAB_RIGHT_BG"; /** * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background * of a tab. */ private static final String TAB_LEFT_BG = "service.gui.lookandfeel.TAB_LEFT_BG"; /** * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background * of a tab. */ private static final String TAB_MIDDLE_BG = "service.gui.lookandfeel.TAB_MIDDLE_BG"; /** * The image used in the <tt>SIPCommLookAndFeel</tt> to paint the background * of a tab. */ private static final String TAB_RIGHT_BG = "service.gui.lookandfeel.TAB_RIGHT_BG"; protected final java.util.List<Integer> highlightedTabs = new Vector<Integer>(); public static ComponentUI createUI(JComponent c) { return new SIPCommTabbedPaneEnhancedUI(); } @Override protected void paintFocusIndicator(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect, boolean isSelected) {} /** * Overriden to paint nothing. */ @Override protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) {} @Override protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { if (tabPane.getTabCount() < 1) return; g.setColor(shadow); g.drawLine(x, y, x + w - 2, y); } @Override protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { if (tabPane.getTabCount() < 1) return; g.setColor(shadow); g.drawLine(x, y, x, y + h - 3); } @Override protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { if (tabPane.getTabCount() < 1) return; g.setColor(shadow); g.drawLine(x + 1, y + h - 3, x + w - 2, y + h - 3); g.drawLine(x + 1, y + h - 2, x + w - 2, y + h - 2); g.setColor(shadow.brighter()); g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1); } @Override protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { if (tabPane.getTabCount() < 1) return; g.setColor(shadow); g.drawLine(x + w - 3, y + 1, x + w - 3, y + h - 3); g.drawLine(x + w - 2, y + 1, x + w - 2, y + h - 3); g.setColor(shadow.brighter()); g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 2); } @Override protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { g = g.create(); try { internalPaintTabBackground(g, tabPlacement, tabIndex, x, y, w, h, isSelected); } finally { g.dispose(); } } private void internalPaintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { BufferedImage leftImg = null; BufferedImage middleImg = null; BufferedImage rightImg = null; Graphics2D g2 = (Graphics2D) g; AntialiasingManager.activateAntialiasing(g2); int tabOverlap = 0; if (isSelected) { if (tabPane.isEnabledAt(tabIndex)) { leftImg = DesktopUtilActivator.getImage(SELECTED_TAB_LEFT_BG); middleImg = DesktopUtilActivator.getImage(SELECTED_TAB_MIDDLE_BG); rightImg = DesktopUtilActivator.getImage(SELECTED_TAB_RIGHT_BG); tabOverlap = TAB_OVERLAP; } else { leftImg = DesktopUtilActivator.getImage(TAB_LEFT_BG); middleImg = DesktopUtilActivator.getImage(TAB_MIDDLE_BG); rightImg = DesktopUtilActivator.getImage(TAB_RIGHT_BG); } } else { leftImg = DesktopUtilActivator.getImage(TAB_LEFT_BG); middleImg = DesktopUtilActivator.getImage(TAB_MIDDLE_BG); rightImg = DesktopUtilActivator.getImage(TAB_RIGHT_BG); } // Remove the existing gap between the tabs and the panel, which is due // to the removal of the tabbed pane border. y++; // If the current tab is not the selected tab we paint it 2 more pixels // to the bottom in order to create the disabled look. if (!isSelected) y+=2; g2.drawImage(leftImg, x, y, null); g2.drawImage(middleImg, x + leftImg.getWidth(), y, w - leftImg.getWidth() - rightImg.getWidth() + tabOverlap, leftImg.getHeight(), null); g2.drawImage(rightImg, x + w - rightImg.getWidth() + tabOverlap, y, null); } @Override protected void paintText(Graphics g, int tabPlacement, Font font, FontMetrics metrics, int tabIndex, String title, Rectangle textRect, boolean isSelected) { g.setFont(font); int titleWidth = SwingUtilities.computeStringWidth(metrics, title); int preferredWidth = 0; if (isOneActionButtonEnabled()) { preferredWidth = calculateTabWidth(tabPlacement, tabIndex, metrics) - WIDTHDELTA - 15; if (isCloseEnabled()) preferredWidth -= BUTTONSIZE; if (isMaxEnabled()) preferredWidth -= BUTTONSIZE; } else { preferredWidth = titleWidth; } while (titleWidth > preferredWidth) { if (title.endsWith("...")) title = title.substring(0, title.indexOf("...") - 1) .concat("..."); else title = title.substring(0, title.length() - 4) .concat("..."); titleWidth = SwingUtilities.computeStringWidth(metrics, title); } textRect.width = titleWidth; View v = getTextViewForTab(tabIndex); if (v != null) { // html v.paint(g, textRect); } else { // plain text int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex); if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex)) { if (isSelected) g.setColor(TAB_SELECTED_FOREGROUND_COLOR); else { if (this.isTabHighlighted(tabIndex)) { g.setColor(TAB_HIGHLIGHT_FOREGROUND_COLOR); } else g.setColor(tabPane.getForegroundAt(tabIndex)); } BasicGraphicsUtils .drawString(g, title, mnemIndex, textRect.x, textRect.y + metrics.getAscent()); } else { // tab disabled g.setColor(tabPane.getBackgroundAt(tabIndex).brighter()); BasicGraphicsUtils .drawStringUnderlineCharAt(g, title, mnemIndex, textRect.x, textRect.y + metrics.getAscent()); g.setColor(tabPane.getBackgroundAt(tabIndex).darker()); BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex, textRect.x - 1, textRect.y + metrics.getAscent() - 1); } } } protected class ScrollableTabButton extends SIPCommTabbedPaneUI.ScrollableTabButton { /** * Serial version UID. */ private static final long serialVersionUID = 0L; public ScrollableTabButton(int direction) { super(direction); setRolloverEnabled(true); } @Override public Dimension getPreferredSize() { return new Dimension(16, calculateMaxTabHeight(0)); } @Override public void paint(Graphics g) { Color origColor; boolean isPressed, isRollOver, isEnabled; int w, h, size; w = getWidth(); h = getHeight(); origColor = g.getColor(); isPressed = getModel().isPressed(); isRollOver = getModel().isRollover(); isEnabled = isEnabled(); g.setColor(getBackground()); g.fillRect(0, 0, w, h); g.setColor(shadow); // Using the background color set above if (direction == WEST) { g.drawLine(0, 0, 0, h - 1); // left g.drawLine(w - 1, 0, w - 1, 0); // right } else g.drawLine(w - 2, h - 1, w - 2, 0); // right g.drawLine(0, 0, w - 2, 0); // top if (isRollOver) { // do highlights or shadows Color color1; Color color2; if (isPressed) { color2 = Color.WHITE; color1 = shadow; } else { color1 = Color.WHITE; color2 = shadow; } g.setColor(color1); if (direction == WEST) { g.drawLine(1, 1, 1, h - 1); // left g.drawLine(1, 1, w - 2, 1); // top g.setColor(color2); g.drawLine(w - 1, h - 1, w - 1, 1); // right } else { g.drawLine(0, 1, 0, h - 1); g.drawLine(0, 1, w - 3, 1); // top g.setColor(color2); g.drawLine(w - 3, h - 1, w - 3, 1); // right } } // g.drawLine(0, h - 1, w - 1, h - 1); //bottom // If there's no room to draw arrow, bail if (h < 5 || w < 5) { g.setColor(origColor); return; } if (isPressed) { g.translate(1, 1); } // Draw the arrow size = Math.min((h - 4) / 3, (w - 4) / 3); size = Math.max(size, 2); boolean highlight = false; if(!highlightedTabs.isEmpty() && ((direction == WEST && tabScroller.scrollBackwardButton.isEnabled()) || (direction == EAST && tabScroller.scrollForwardButton.isEnabled()))) { Rectangle viewRect = tabScroller.viewport.getViewRect(); if(direction == WEST) { int leadingTabIndex = getClosestTab(viewRect.x, viewRect.y); for(int i = 0; i < leadingTabIndex; i++) { if(highlightedTabs.contains(i) && !isScrollTabVisible(i)) { highlight = true; break; } } } else { int leadingTabIndex = getClosestTab(viewRect.x + viewRect.y, viewRect.y); for(int i = leadingTabIndex; i < tabPane.getTabCount(); i++) { if(highlightedTabs.contains(i) && !isScrollTabVisible(i)) { highlight = true; break; } } } if(highlight) { Image img = DesktopUtilActivator.getImage( direction == WEST ? "service.gui.icons.TAB_UNREAD_BACKWARD_ICON" : "service.gui.icons.TAB_UNREAD_FORWARD_ICON"); int wi = img.getWidth(null); g.drawImage(img, (w - wi)/2, (h - size) / 2 - 2/* 2 borders 1px width*/, null); } } if(!highlight) paintTriangle(g, (w - size) / 2, (h - size) / 2, size, direction, isEnabled); // Reset the Graphics back to it's original settings if (isPressed) { g.translate(-1, -1); } g.setColor(origColor); } } /** * Checks whether the <tt>tabIndex</tt> is visible in the scrollable * tabs list. * * @param tabIndex the tab index to check. * @return whether <tt>tabIndex</tt> is visible in the list of scrollable * tabs. */ private boolean isScrollTabVisible(int tabIndex) { Rectangle tabRect = rects[tabIndex]; Rectangle viewRect = tabScroller.viewport.getViewRect(); if ((tabRect.x + tabRect.width - BUTTONSIZE < viewRect.x) || (tabRect.x + BUTTONSIZE > viewRect.x + viewRect.width)) { return false; } else { return true; } } @Override protected SIPCommTabbedPaneUI.ScrollableTabButton createScrollableTabButton( int direction) { return new ScrollableTabButton(direction); } @Override protected int calculateTabWidth(int tabPlacement, int tabIndex, FontMetrics metrics) { int width = super.calculateTabWidth(tabPlacement, tabIndex, metrics); if (isOneActionButtonEnabled()) { if(width > PREFERRED_WIDTH) width = PREFERRED_WIDTH; } return width + WIDTHDELTA; } public void tabAddHightlight(int tabIndex) { this.highlightedTabs.add(tabIndex); } public void tabRemoveHighlight(int tabIndex) { Iterator<Integer> highlightedIter = highlightedTabs.iterator(); while (highlightedIter.hasNext()) { if (highlightedIter.next().intValue() == tabIndex) { highlightedIter.remove(); break; } } } public boolean isTabHighlighted(int tabIndex) { return highlightedTabs.contains(tabIndex); } /** * Reloads color info. */ @Override public void loadSkin() { super.loadSkin(); TAB_HIGHLIGHT_FOREGROUND_COLOR = new Color(DesktopUtilActivator.getResources() .getColor("service.gui.TAB_TITLE_HIGHLIGHT")); TAB_SELECTED_FOREGROUND_COLOR = new Color(DesktopUtilActivator.getResources() .getColor("service.gui.TAB_TITLE_SELECTED")); } }