package org.geogebra.desktop.javax.swing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import org.geogebra.common.gui.util.RelationMore;
import org.geogebra.common.javax.swing.RelationPane;
import org.geogebra.common.main.App;
import org.geogebra.common.util.debug.Log;
import org.geogebra.common.util.lang.Unicode;
/**
* Desktop implementation of the Relation Tool information window.
*
* @author Zoltan "of Swing" Kovacs <zoltan@geogebra.org>
*
*/
public class RelationPaneD implements RelationPane, ActionListener {
/**
* The Relation window.
*/
JFrame frame;
private String[] columnNames;
private Object[][] data;
private DefaultTableModel model;
/**
* The contents of the Relation window.
*/
JTable table;
/**
* This stores the array of the actions to be fired when click on "More...".
*/
RelationMore[] callbacks;
private boolean areCallbacks = false;
private int morewidth = 0;
private final static int ORIG_INFOWIDTH = 300;
private int INFOWIDTH;
/**
* Current row height computed by the window size (y), by default it uses
* ORIG_ROWHEIGHT.
*/
double ROWHEIGHT;
private final static int ORIG_ROWHEIGHT = 30;
private final static int MARGIN = 10;
private final static int ROWMARGIN = 1;
private final static int ORIG_MOREWIDTH = 140;
private int MOREWIDTH;
private final static int ORIG_OKHEIGHT = 30;
private int OKHEIGHT;
private final static int ORIG_OKWIDTH = 140;
private int OKWIDTH;
@Override
public void showDialog(String title, final RelationRow[] relations,
App app) {
frame = new JFrame(title);
JPanel panel = new JPanel(new BorderLayout(MARGIN, MARGIN));
ROWHEIGHT = ((double) ORIG_ROWHEIGHT) * app.getFontSize() / 12;
INFOWIDTH = (ORIG_INFOWIDTH * app.getFontSize() / 12);
MOREWIDTH = (ORIG_MOREWIDTH * app.getFontSize() / 12);
OKHEIGHT = (ORIG_OKHEIGHT * app.getFontSize() / 12);
OKWIDTH = (ORIG_OKWIDTH * app.getFontSize() / 12);
final int rels = relations.length;
for (int i = 0; i < rels; ++i) {
if (relations[i].getCallback() != null) {
areCallbacks = true;
morewidth = MOREWIDTH;
}
}
if (areCallbacks) {
columnNames = new String[] { "String", "" };
data = new Object[rels][2];
} else {
columnNames = new String[] { "String" };
data = new Object[rels][1];
}
callbacks = new RelationMore[rels];
int height = 0;
for (int i = 0; i < rels; ++i) {
data[i][0] = relations[i].getInfo();
callbacks[i] = relations[i].getCallback();
if (areCallbacks) {
if (relations[i].getCallback() != null) {
data[i][1] = app.getLocalization().getMenu("More")
+ Unicode.ellipsis;
} else {
data[i][1] = "";
}
}
}
model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
@Override
public boolean isCellEditable(int row, int column) {
return (column == 1) && (callbacks[row] != null);
}
};
table = new JTable(model);
table.setTableHeader(null);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
if (areCallbacks) {
table.getColumnModel().getColumn(1)
.setCellRenderer(new ClientsTableButtonRenderer());
table.getColumnModel().getColumn(1).setCellEditor(
new ClientsTableRenderer(this, new JCheckBox()));
}
table.getColumnModel().getColumn(0)
.setCellRenderer(new ClientsTableTextRenderer());
table.setBackground(UIManager.getColor("Label.background"));
for (int i = 0; i < rels; ++i) {
int thisHeight = (int) (ROWHEIGHT
* (countLines(relations[i].getInfo())));
table.setRowHeight(i, thisHeight - 2 * (ROWMARGIN + 1)); // button
// border
height += thisHeight;
}
table.setShowHorizontalLines(false);
table.setShowVerticalLines(false);
table.setDragEnabled(false);
table.setSize(INFOWIDTH + morewidth, height);
table.setRowMargin(ROWMARGIN);
panel.add(table);
// Adding OK button:
JPanel buttonrow = new JPanel(new FlowLayout());
JButton ok = new JButton(app.getLocalization().getMenu("OK"));
buttonrow.add(ok);
ok.setSize(OKWIDTH, OKHEIGHT);
panel.add(buttonrow, BorderLayout.SOUTH);
ok.addActionListener(this);
panel.setSize(INFOWIDTH + morewidth + 2 * MARGIN,
height + 3 * MARGIN + OKHEIGHT);
panel.setBorder(BorderFactory.createEmptyBorder(MARGIN, MARGIN, MARGIN,
MARGIN));
panel.setBackground(UIManager.getColor("Label.background"));
frame.add(panel);
frame.setSize(INFOWIDTH + morewidth + 2 * MARGIN,
height + 3 * MARGIN + OKHEIGHT);
table.getColumnModel().getColumn(0).setPreferredWidth(INFOWIDTH);
if (areCallbacks) {
table.getColumnModel().getColumn(1).setPreferredWidth(MOREWIDTH);
}
frame.addComponentListener(new ComponentListener() {
@Override
public void componentResized(ComponentEvent evt) {
// Extremely ugly way to learn if this event comes from resizing
// or refresh.
// TODO: Find a better way.
String event = Thread.currentThread().getStackTrace()[3]
.getMethodName();
if ("processEvent".equals(event)) {
return;
}
// Log.debug(event);
int ysize = frame.getContentPane().getHeight() - 3 * MARGIN
- OKHEIGHT;
int r = relations.length;
int currentHeight = 0;
for (int i = 0; i < r; ++i) {
int thisHeight = (ORIG_ROWHEIGHT
* (countLines(table.getValueAt(i, 0).toString())));
currentHeight += thisHeight;
}
ROWHEIGHT = ((double) ysize) / currentHeight * ORIG_ROWHEIGHT;
// Log.debug("resized to rh " + ROWHEIGHT);
for (int i = 0; i < r; ++i) {
int newHeight = (int) (ROWHEIGHT
* (countLines(table.getValueAt(i, 0).toString())));
table.setRowHeight(i, newHeight - 2 * (ROWMARGIN + 1));
}
}
@Override
public void componentHidden(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void componentMoved(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void componentShown(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
});
frame.pack();
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static int countLines(String html) {
int ret = 1;
String[] words = { "<br>", "<li", "<ul>" };
for (String word : words) {
int index = html.indexOf(word);
if (index != -1) {
ret++;
}
while (index >= 0) {
index = html.indexOf(word, index + word.length() - 1);
if (index != -1) {
ret++;
}
}
}
// Log.debug("# " + ret + html);
return ret;
}
@Override
public synchronized void updateRow(int row, RelationRow relation) {
table.setValueAt(relation.getInfo(), row, 0);
callbacks[row] = relation.getCallback();
table.setRowHeight(row, (int) (ROWHEIGHT * (countLines(relation.getInfo()))
- 2 * (ROWMARGIN + 1)));
int height = 0;
areCallbacks = false;
for (int i = 0; i < callbacks.length; ++i) {
height += table.getRowHeight(i);
if (callbacks[i] != null) {
areCallbacks = true;
}
}
if (!areCallbacks) {
morewidth = 0;
if (table.getColumnModel().getColumnCount() > 1) {
table.removeColumn(table.getColumnModel().getColumn(1));
}
}
table.setSize(INFOWIDTH + morewidth, height);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
frame.setSize(INFOWIDTH + morewidth + 2 * MARGIN,
height + 3 * MARGIN + OKHEIGHT);
frame.pack();
frame.paint(frame.getGraphics());
}
/**
* This code is mostly copied from http://stackoverflow.com/a/10348919
* shared by "Bitmap". Button column settings.
*/
private class ClientsTableButtonRenderer extends JButton
implements TableCellRenderer {
private static final long serialVersionUID = 5188521324132632032L;
public ClientsTableButtonRenderer() {
setOpaque(true);
}
@Override
public Component getTableCellRendererComponent(JTable t, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
setForeground(Color.black);
setBackground(UIManager.getColor("Label.background"));
setOpaque(true);
setText((value == null) ? "" : value.toString());
if (callbacks[row] == null) {
return null;
}
return this;
}
}
/* Text column settings. */
private static class ClientsTableTextRenderer extends JLabel
implements TableCellRenderer {
private static final long serialVersionUID = 5188521324132632032L;
public ClientsTableTextRenderer() {
setOpaque(true);
}
@Override
public Component getTableCellRendererComponent(JTable t, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
setForeground(Color.black);
setBackground(UIManager.getColor("Label.background"));
setHorizontalAlignment(CENTER);
setOpaque(true);
setText((value == null) ? "" : value.toString());
return this;
}
}
private class ClientsTableRenderer extends DefaultCellEditor {
private static final long serialVersionUID = -4426618730428867967L;
private JButton button;
private String label;
private boolean clicked;
private int row, col;
private RelationPane pane;
public ClientsTableRenderer(RelationPane p, JCheckBox checkBox) {
super(checkBox);
pane = p;
button = new JButton();
button.setOpaque(true);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
@Override
public Component getTableCellEditorComponent(JTable t, Object value,
boolean isSelected, int r, int column) {
this.row = r;
this.col = column;
button.setForeground(Color.black);
button.setBackground(UIManager.getColor("Button.background"));
label = (value == null) ? "" : value.toString();
button.setText(label);
clicked = true;
return button;
}
@Override
public Object getCellEditorValue() {
if (clicked) {
callbacks[row].action(pane, this.row);
}
if ((col == 1) && callbacks[row] == null) {
label = "";
}
clicked = false;
return label;
}
@Override
public boolean stopCellEditing() {
clicked = false;
return super.stopCellEditing();
}
@Override
protected void fireEditingStopped() {
/*
* FIXME: In some cases this throws an exception. No idea how to fix
* it.
*/
try {
super.fireEditingStopped();
} catch (Exception e) {
Log.error("Swing error in RelationPaneD");
}
}
}
@Override
public void actionPerformed(ActionEvent arg0) {
frame.dispose();
}
}