package org.gjt.sp.jedit.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.DefaultButtonModel;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
import org.gjt.sp.jedit.Buffer;
import org.gjt.sp.jedit.EditBus;
import org.gjt.sp.jedit.EditPane;
import org.gjt.sp.jedit.GUIUtilities;
import org.gjt.sp.jedit.jEdit;
import org.gjt.sp.jedit.bufferset.BufferSet;
import org.gjt.sp.jedit.msg.PropertiesChanged;
import org.gjt.sp.util.ThreadUtilities;
public class TabbedBufferSwitcher extends JPanel {
private int maxOpenFile;
private int index;
private boolean updating;
private List<Tab> tabs;
private final EditPane editPane;
private JPanel center;
private JPanel middle;
private Tab selected;
private JPanel left;
private JPanel right;
private int width_parent;
private static Color selectedColor = new Color(0xffffff);
private static Color unselectedColor = new Color(0xeeeeee);
private static Color borderColor = new Color(0x7a8a99);
private static Color buttonClose = new Color(0xc0bcfe);
private static Border emptyBorder = BorderFactory.createEmptyBorder();
private static Border colorBorder = new AbstractBorder() {
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Tab t = (Tab)c;
if (!t.isSelected()){
Graphics2D g2 = (Graphics2D)g;
g2.setColor(TabbedBufferSwitcher.borderColor);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawArc(0, 0, 20, 20, 90, 90);
g2.drawArc(width-21, 0,20, 20, 0, 90);
g2.drawLine(10, 0, width-11, 0);
g2.drawLine(0, 10, 0, height-1);
g2.drawLine(width-1, 10, width-1, height-1);
}
}
};
private static Border moveBorders = new AbstractBorder() {
private Color border = new Color(0x7a8a99);
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
g.setColor(border);
g.drawLine(0, 0, 0, height);
g.drawLine(0, 0, width-1, 0);
g.drawLine(width-1, 0, width-1, height);
};
};
public TabbedBufferSwitcher(final EditPane editPane){
//Things for custom tab
this.editPane = editPane;
JPanel up = new JPanel();
center = new JPanel();
middle = new JPanel();
setLayout(new BorderLayout(0,0));
middle.setLayout(new BorderLayout());
up.setBackground(TabbedBufferSwitcher.unselectedColor);
up.setPreferredSize(new Dimension(0,2));
center.setBackground(new Color(0xeeeeee));
center.setLayout(new FlowLayout(FlowLayout.LEFT, 1, 0));
middle.add(center,BorderLayout.CENTER);
add(up,BorderLayout.NORTH);
add(middle,BorderLayout.CENTER);
//add(down,BorderLayout.SOUTH);
tabs = new ArrayList<Tab>();
index = 0;
left = new JPanel(new FlowLayout(FlowLayout.CENTER));
left.add(new JLabel(GUIUtilities.loadIcon("arrow-left.png")));
left.setBorder(TabbedBufferSwitcher.moveBorders);
right = new JPanel();
right.add(new JLabel(GUIUtilities.loadIcon("arrow-right.png")));
right.setBorder(TabbedBufferSwitcher.moveBorders);
width_parent = -1;
//Things for jedit
updating = false;
setMaximumRowCount(jEdit.getIntegerProperty("bufferSwitcher.maxRowCount", 10));
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
setUITabs();
}
});
left.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (index == 0)
return;
index --;
setUITabs();
}
});
right.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (tabs.size()-1 == index)
return;
index ++;
setUITabs();
}
});
EditBus.addToBus(this);
}
public void updateBufferList() {
// if the buffer count becomes 0, then it is guaranteed to
// become 1 very soon, so don't do anything in that case.
final BufferSet bufferSet = editPane.getBufferSet();
if(bufferSet.size() == 0)
return;
Runnable runnable = new Runnable()
{
@Override
public void run()
{
updating = true;
setMaximumRowCount(jEdit.getIntegerProperty("bufferSwitcher.maxRowCount",10));
Buffer[] buffers = bufferSet.getAllBuffers();
/*if (jEdit.getBooleanProperty("bufferswitcher.sortBuffers", true)) {
Arrays.sort(buffers, new Comparator<Buffer>(){
public int compare(Buffer a, Buffer b) {
if (jEdit.getBooleanProperty("bufferswitcher.sortByName", true)) {
return a.getName().toLowerCase().compareTo(b.getName().toLowerCase());
} else {
return a.getPath().toLowerCase().compareTo(b.getPath().toLowerCase());
}
}
});
}*/
setTabs(buffers);
int result;
do{
result = setUITabs();
switch(result){
case 1:
index++;
break;
case 2:
index--;
break;
}
}while(result==1 || result==2);
setSelectedItem(editPane.getBuffer());
//addDnD();
updating = false;
}
};
ThreadUtilities.runInDispatchThread(runnable);
}
private void setTabs(Buffer[] buffers) {
List<Tab> tbuff = new LinkedList<Tab>(tabs);
for(int i = 0; i<buffers.length && i<maxOpenFile; i++){
Tab t = new Tab(buffers[i],this);
if (!tabs.contains(t)){
tabs.add(t);
}
tbuff.remove(t);
}
tabs.removeAll(tbuff);
//setUITabs();
}
private int setUITabs() {
center.removeAll();
middle.remove(left);
middle.remove(right);
int length = 17*2, width = getWidth();
int position = -1;
if (width_parent == -1)
return position;
if (index == -1){
index = 0;
return -1;
}
boolean overflow = false;
Tab t;
int j;
for(j = index ; j < tabs.size() ; j++){
t = tabs.get(j);
if (t.getWidth() + length > width){
overflow = true;
break;
}
if (t.equals(getSelectedItem()))
position = 0;
length += t.getWidth();
center.add(t);
}
if (overflow){
if (tabs.subList(j, tabs.size()).contains(getSelectedItem()))
position = 1;
middle.add(right,BorderLayout.EAST);
middle.add(left,BorderLayout.WEST);
}else{
while(index > 0){
t = tabs.get(index-1);
if ( t.getWidth() + length > width){
middle.add(right,BorderLayout.EAST);
middle.add(left,BorderLayout.WEST);
break;
}
if (t.equals(getSelectedItem()))
position = 0;
index--;
length += t.getWidth();
center.add(t,0);
}
}
middle.revalidate();
middle.repaint();
center.revalidate();
center.repaint();
return position==-1 ? 2 :position;
}
public void setMaximumRowCount(int integerProperty) {
maxOpenFile = integerProperty;
}
public void handlePropertiesChanged(PropertiesChanged msg) {
updateBufferList();
}
public Object getSelectedItem() {
return selected;
}
public EditPane getEditPane(){
return editPane;
}
public void setSelectedItem(Object anObject) {
if (selected != null) selected.unselect();
for (Tab t : tabs){
if (t.getObject() == anObject){
selected = t;
selected.select();
break;
}
}
}
private void setTab(Tab tab) {
setSelectedItem(tab.getObject());
editPane.setBuffer((Buffer)tab.getObject());
}
public boolean specialState() {
return false;
}
@Override
public void paint(Graphics g) {
if (width_parent == -1){
width_parent = 1;
updateBufferList();
}
super.paint(g);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
public void showPopup(){ }
private class Tab extends JPanel{
final TabbedBufferSwitcher tp;
private Buffer buffer;
Tab(Buffer anObject, final TabbedBufferSwitcher switcher){
tp = switcher;
buffer = anObject;
add(new JLabel(buffer.getName()));
setToolTipText(buffer.getPath());
add(new RoundButton("",GUIUtilities.loadIcon(jEdit.getProperty("close-tab.icon")),this));
addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent e) {
Component t = e.getComponent();
if (t instanceof Tab){
Tab tab = (Tab) t;
tp.setTab(tab);
}
}
@Override
public void mouseEntered(MouseEvent e) {
setBorder(TabbedBufferSwitcher.colorBorder);
}
@Override
public void mouseExited(MouseEvent e) {
setBorder(TabbedBufferSwitcher.emptyBorder);
}
});
}
public void select() {
setBackground(TabbedBufferSwitcher.selectedColor);
}
public void unselect() {
setBackground(TabbedBufferSwitcher.unselectedColor);
}
public Object getObject(){
return buffer;
}
public boolean isSelected(){
return getBackground() == TabbedBufferSwitcher.selectedColor;
}
@Override
protected void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
g.setColor(getBackground());
g.fillRect(0, 5, w, h-5);
g.fillRoundRect(0, 0, w, h-5, 10, 10);
}
public TabbedBufferSwitcher getTabbedPane(){
return tp;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Tab){
Tab t = (Tab) obj;
return this.buffer.equals(t.buffer);
}
return false;
}
}
private class RoundButton extends JButton {
private final Tab tab;
private boolean over;
public RoundButton(String text, Icon icon, final Tab tab) {
this.tab = tab;
over = false;
setModel(new DefaultButtonModel());
init(text, icon);
if(icon==null) {
return;
}
setPreferredSize(new Dimension(icon.getIconWidth() + 20, icon.getIconHeight() + 20));
setBorder(BorderFactory.createRaisedBevelBorder());
//setBackground(Color.BLACK);
setContentAreaFilled(false);
setFocusPainted(false);
//setVerticalAlignment(SwingConstants.TOP);
setAlignmentY(Component.TOP_ALIGNMENT);
initShape();
setToolTipText("Close");
setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
tab.dispatchEvent(e);
if (e.getComponent() instanceof RoundButton){
final RoundButton b = (RoundButton)e.getComponent();
b.over = true;
b.setBorder(new AbstractBorder() {
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(TabbedBufferSwitcher.borderColor);
g2.drawOval(0, 0, width - 1, height - 1);
}
public Insets getBorderInsets(Component c, Insets insets) {
insets.set(2, 2, 2, 2);
return insets;
};
});
}
}
@Override
public void mouseExited(MouseEvent e) {
if (e.getComponent() instanceof RoundButton){
RoundButton b = (RoundButton)e.getComponent();
b.over = false;
b.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
}
}
});
addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
close();
}
});
}
protected Shape shape, base;
protected Insets insets;
protected void initShape() {
if(!getBounds().equals(base)) {
Dimension s = getPreferredSize();
base = getBounds();
shape = new Ellipse2D.Float(0, 0, s.width-1, s.height-1);
}
}
@Override
public Dimension getPreferredSize() {
Icon icon = getIcon();
Insets i = getInsets();
int iw = Math.max(icon.getIconWidth(), icon.getIconHeight());
return new Dimension(iw+i.right+i.left, iw+i.top+i.bottom);
}
@Override
public boolean contains(int x, int y) {
initShape();
return shape.contains(x, y);
//or return super.contains(x, y) && ((image.getRGB(x, y) >> 24) & 0xff) > 0;
}
private void close(){
jEdit.closeBuffer( tab.getTabbedPane().getEditPane(), (Buffer)tab.getObject());
}
@Override
protected void paintComponent(Graphics g) {
if (over){
g.setColor(TabbedBufferSwitcher.buttonClose);
g.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
}
super.paintComponent(g);
}
}
}