/* * Copyright 2003-2012 Yusuke Yamamoto * * 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 samurai.swing; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.ArrayList; import java.util.List; /*package*/class TilePanel extends JPanel implements AncestorListener { GridBagLayout gridBagLayout = new GridBagLayout(); private List<ComponentInfo> components; /** * */ private boolean supportsFocusable; /** * flag for tiling orientation */ private boolean horizontal = true; private int selectedIndex = 0; private List<Tile> tiles = new ArrayList<Tile>(3); private List<JPanel> dividers = new ArrayList<JPanel>(2); public TilePanel(boolean supportsFocusable) { this.supportsFocusable = supportsFocusable; this.components = new ArrayList<ComponentInfo>(3); this.setLayout(gridBagLayout); ensureOrientation(); } public final static int HORIZONTAL = 0; public final static int VERTICAL = 1; public void setOrientation(int orientation) { if (orientation != HORIZONTAL && orientation != VERTICAL) { throw new IllegalArgumentException("Unsupported orientation"); } if ((horizontal && HORIZONTAL == orientation) || (!horizontal && VERTICAL == orientation)) { return; } horizontal = HORIZONTAL == orientation; ensureOrientation(); } private void ensureOrientation() { for (int i = 0; i < constraints.size(); i++) { GridBagConstraints constraint = constraints.get(i); if (horizontal) { constraint.gridx = constraint.gridy; constraint.gridy = 0; constraint.weightx = constraint.weighty; constraint.weighty = 1; } else { constraint.gridy = constraint.gridx; constraint.gridx = 0; constraint.weighty = constraint.weightx; constraint.weightx = 1; } add(tiles.get(i), constraint); } for (int i = 0; i < dividers.size(); i++) { JPanel divider = dividers.get(i); if (horizontal) { divider.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); } else { divider.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); } add(divider, getDividerConstraints(i*2+1)); } validate(); } private List<MouseListener> titleMouseListeners = new ArrayList<MouseListener>(1); private List<MouseMotionListener> titleMouseMotionListeners = new ArrayList<MouseMotionListener>(1); public int getSelectedIndex() { return this.selectedIndex; } public int getTileCount() { return components.size(); } public Component getSelectedComponent() { return tiles.get(selectedIndex).getInnerComponent(); } public void setSelectedIndex(int index) { this.selectedIndex = index; if (supportsFocusable) { if (tiles.size() == 1) { tiles.get(0).enableTitleWithoutFocus(); } else { for (int i = 0; i < tiles.size(); i++) { if (i == index) { tiles.get(i).setFocused(true); } else { tiles.get(i).setFocused(false); } } } } } public void addMouseListnerToTitles(MouseListener listener) { titleMouseListeners.add(listener); setMouseListners(); } public void addMouseMotionListnerToTitles(MouseMotionListener listener) { titleMouseMotionListeners.add(listener); setMouseListners(); } private void setMouseListners() { for (Tile sp : tiles) { for (MouseListener theListener : titleMouseListeners) { sp.addMouseListenerToTitle(theListener); } for (MouseMotionListener theListener : titleMouseMotionListeners) { sp.addMouseMotionListenerToTitle(theListener); } if (supportsFocusable) { sp.addMouseListenerToComponent(mouseAdapter); } } } MouseAdapter mouseAdapter = new MouseAdapter() { public void mousePressed(MouseEvent mouseEvent) { this_mousePressed(mouseEvent); } }; public void this_mousePressed(MouseEvent mouseEvent) { for (int i = 0; i < tiles.size(); i++) { if (tiles.get(i).isAncestorOf(mouseEvent.getComponent())) { setSelectedIndex(i); break; } } } public void addComponent(String title, JComponent component) { addComponent(title, null, component); } public int indexAtLocation(MouseEvent event) { for (int i = 0; i < tiles.size(); i++) { if (tiles.get(i).isOnTitle(event)) { return i; } } return -1; } private Dimension dividerSize = new Dimension(3, 3); public void setDeviderSize(int size) { this.dividerSize = new Dimension(size, size); for (JPanel divider : dividers) { divider.setMinimumSize(dividerSize); divider.setMaximumSize(dividerSize); divider.setPreferredSize(dividerSize); } } private List<GridBagConstraints> constraints = new ArrayList<GridBagConstraints>(3); private GridBagConstraints getDividerConstraints(int grid){ GridBagConstraints dividerConstraint = new GridBagConstraints(); dividerConstraint.weightx = 0; dividerConstraint.weighty = 0; if(horizontal){ dividerConstraint.gridx = grid; dividerConstraint.fill = GridBagConstraints.VERTICAL; }else{ dividerConstraint.gridy = grid; dividerConstraint.fill = GridBagConstraints.HORIZONTAL; } return dividerConstraint; } public void addComponent(String title, ImageIcon icon, JComponent component) { GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.BOTH; gbc.gridx = 0; gbc.gridy = 0; gbc.weightx = 100; gbc.weighty = 1; if (tiles.size() > 0) { JPanel divider = new JPanel(); dividers.add(divider); divider.addMouseListener(dividerMouseListener); divider.addMouseMotionListener(dividerMouseListener); divider.setMinimumSize(dividerSize); divider.setMaximumSize(dividerSize); divider.setPreferredSize(dividerSize); if (horizontal) { gbc.gridx = tiles.size() * 2; divider.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); gbc.gridy = 0; double sum = 0; for (GridBagConstraints constraint : constraints) { sum += constraint.weightx; } gbc.weightx = sum / constraints.size(); } else { gbc.gridx = 0; gbc.gridy = tiles.size() * 2; divider.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); double sum = 0; for (GridBagConstraints constraint : constraints) { sum += constraint.weighty; } gbc.weighty = sum / constraints.size(); } add(divider, getDividerConstraints(tiles.size() * 2 - 1)); } Tile splittedPanel = new Tile(component, title, icon); splittedPanel.setPreferredSize(new Dimension(0, 0)); add(splittedPanel, gbc); constraints.add(gbc); ComponentInfo<JComponent> cf = new ComponentInfo<JComponent>(component, title, icon); components.add(cf); tiles.add(splittedPanel); setMouseListners(); setSelectedIndex(this.getTileCount() - 1); validate(); } DividerMouseListener dividerMouseListener = new DividerMouseListener(); class DividerMouseListener extends MouseAdapter implements MouseMotionListener { private int originalWidths[]; private int draggingDividerIndex; private int dragRangeMin; private int dragRangeMax; private int dragStartCoordinate; DividerMouseListener() { } public void mouseDragged(MouseEvent event) { JComponent divider = (JComponent) event.getSource(); int dragDistance = (horizontal ? event.getX() + divider.getX() : event.getY() + divider.getY()) - dragStartCoordinate; if (dragDistance < dragRangeMin || dragDistance > dragRangeMax) { dragDistance = 0; } double rightRatio = 0; for (int i = 0; i < originalWidths.length; i++) { double newWeight; GridBagConstraints gbc = constraints.get(i); if (i < draggingDividerIndex) { newWeight = originalWidths[i]; } else { if (i == draggingDividerIndex) { newWeight = originalWidths[i] + dragDistance; for (int j = i + 1; j < originalWidths.length; j++) { rightRatio += originalWidths[j]; } rightRatio = (rightRatio - dragDistance) / rightRatio; } else { newWeight = originalWidths[i] * rightRatio; } } if (horizontal) { gbc.weightx = newWeight; } else { gbc.weighty = newWeight; } add(tiles.get(i), gbc); } validate(); } public void mouseMoved(MouseEvent event) { } public void mousePressed(MouseEvent event) { JComponent divider = (JComponent) event.getSource(); dragStartCoordinate = horizontal ? divider.getX() : divider.getY(); for (int i = 0; i < dividers.size(); i++) { if (dividers.get(i).equals(divider)) { draggingDividerIndex = i; break; } } originalWidths = new int[tiles.size()]; dragRangeMin = 0; dragRangeMax = 0; for (int i = 0; i < originalWidths.length; i++) { if (horizontal) { originalWidths[i] = tiles.get(i).getWidth(); } else { originalWidths[i] = tiles.get(i).getHeight(); } if (i == draggingDividerIndex) { dragRangeMin = -originalWidths[i]; } if (i > draggingDividerIndex) { dragRangeMax += originalWidths[i]; } } } public void mouseReleased(MouseEvent event) { } } public void setForegroundAt(int index, Color color) { tiles.get(index).title.setForeground(color); // tiles.get(index).rightLabel.seBackground(color); } public Color getForegroundAt(int index) { return tiles.get(index).title.getForeground(); } public void removeTileAt(int index) { //remove the divider next to the specified component if (components.size() > 1) { if(index == 0){ remove(dividers.remove(0)); }else{ remove(dividers.remove(index -1)); } } remove(tiles.remove(index)); constraints.remove(index); components.remove(index); for(int i=index;i<components.size();i++){ GridBagConstraints gbc = constraints.get(i); if(horizontal){ gbc.gridx = i * 2; }else{ gbc.gridy = i * 2; } add(tiles.get(i), gbc); if (i > 0) { add(dividers.get(i-1), getDividerConstraints(i * 2 - 1)); } } if (this.selectedIndex >= this.getTileCount()) { selectedIndex = this.getTileCount() - 1; } this.setSelectedIndex(selectedIndex); } public void removeComponent(Component component) { for (int i = 0; i < components.size(); i++) { if (components.get(i).getComponent() == component) { removeTileAt(i); break; } } } /*package*/ void setLeftIconAt(int index, ImageIcon icon) { tiles.get(index).setLeftIcon(icon); } /*package*/ ImageIcon getLeftIconAt(int index) { return components.get(index).getIcon(); } /*package*/ void setRightIconAt(int index, ImageIcon icon) { tiles.get(index).setRightIcon(icon); } /*package*/ ImageIcon getRightIconAt(int index) { return tiles.get(index).getRightIcon(); } /*package*/ void setComponentAt(int index, JComponent component) { tiles.get(index).setComponent(component); } /*package*/ Component getComponentAt(int index) { return components.get(index).getComponent(); } /*package*/ void setTitleAt(int index, String text) { tiles.get(index).setTitle(text); } /*package*/ String getTitleAt(int index) { return components.get(index).getName(); } /*package*/ boolean isOnButton(int index, MouseEvent event) { return tiles.get(index).isOnRightLabel(event); } public void ancestorAdded(AncestorEvent event) { } public void ancestorRemoved(AncestorEvent event) { for (Tile tile : tiles) { if (tile.getInnerComponent() == event.getComponent()) { removeComponent(event.getComponent()); break; } } } public void ancestorMoved(AncestorEvent event) { } public void removeAll() { super.removeAll(); while (components.size() > 0) { removeComponent(components.get(0).getComponent()); } } }