package tk.amberide.ide.swing;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DragSource;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import javax.activation.ActivationDataFlavor;
import javax.activation.DataHandler;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileSystemView;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
/**
* @author Tudor
*/
public class UIUtil {
public final static int POPUP = 0;
public final static int UTILITY = 1;
public final static int NORMAL = 2;
/**
* Attempts to set the current L&F to native, and perform appearance tweaks
* to mimic the current OS's L&F. Has a large positive effect on Mac
* systems.
*/
public static void makeNative() {
// Mac tweaks
System.setProperty("apple.laf.useScreenMenuBar", "true");
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Amber IDE");
System.setProperty("apple.awt.showGrowBox", "true");
System.setProperty("apple.awt.brushMetalLook", "true");
System.setProperty("sun.java2d.noddraw", "true");
System.setProperty("swing.aatext", "true");
JFrame.setDefaultLookAndFeelDecorated(false);
JDialog.setDefaultLookAndFeelDecorated(false);
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false);
ToolTipManager.sharedInstance().setReshowDelay(0);
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
}
public static boolean setComponentLF(JComponent comp, String ui) {
LookAndFeel previousLF = UIManager.getLookAndFeel();
try {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if (ui.equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
comp.updateUI();
UIManager.setLookAndFeel(previousLF);
} catch (Exception e) {
return false;
}
return true;
}
public static FileFilter makeFileFilter(final String desc, final String... types) {
return new FileFilter() {
public boolean accept(File file) {
if (file.isDirectory()) {
return true;
}
for (String extension : types) {
if (file.getName().toLowerCase().endsWith(extension)) {
return true;
}
}
return false;
}
@Override
public String getDescription() {
return desc;
}
};
}
/**
* Creates an invisible cursor
*
* @return the specified cursor
*/
public static Cursor invisibleCursor() {
return Toolkit.getDefaultToolkit().createCustomCursor(new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB), new Point(0, 0), "invisible_cursor");
}
/**
* Toggles the enabled set of all children of the specified Container,
* recursively
*
* @param comp the root node
* @param flag toggle for enabled state
*/
public static void setTreeEnabled(Container comp, boolean flag) {
comp.setEnabled(flag);
for (Component child : comp.getComponents()) {
if (child instanceof Container) {
setTreeEnabled((Container) child, flag);
} else {
child.setEnabled(flag);
}
}
}
/**
* Sets the default Font for the current UIManager
*
* @param fon the new Font
*/
public static void setUIFont(Font fon) {
FontUIResource f = new FontUIResource(fon);
Enumeration keys = UIManager.getDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
Object value = UIManager.get(key);
if (value != null && value instanceof javax.swing.plaf.FontUIResource) {
UIManager.put(key, f);
}
}
for (Window w : Window.getWindows()) {
SwingUtilities.updateComponentTreeUI(w);
}
}
/**
* Sets the look of the given dialog. Works only on Java 7+, but does not
* crash on Java 6-.
*
* @param dialog
* @param type one of UIUtil.(POPUP, UTILITY, NORMAL)
*/
public static void decorate(JDialog dialog, int type) {
try {
Class windowType = Class.forName("java.awt.Window$Type");
Method setType = Window.class.getDeclaredMethod("setType", windowType);
switch (type) {
case POPUP:
setType.invoke(dialog, Enum.valueOf((Class<Enum>) windowType.getDeclaredField("POPUP").getType(), "POPUP"));
break;
case UTILITY:
setType.invoke(dialog, Enum.valueOf((Class<Enum>) windowType.getDeclaredField("UTILITY").getType(), "UTILITY"));
break;
case NORMAL:
setType.invoke(dialog, Enum.valueOf((Class<Enum>) windowType.getDeclaredField("NORMAL").getType(), "NORMAL"));
break;
}
} catch (Exception e) {
// This ClassNotFound occurs if the user doesn't have Java 7 installed.
// We can still create a utility-looking window, though.
// Just doesn't look as nice.
dialog.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
}
}
public static void adjustColumnPreferredWidths(JTable table) {
// strategy - get max width for cells in column and
// make that the preferred width
TableColumnModel columnModel = table.getColumnModel();
for (int col = 0; col < table.getColumnCount(); col++) {
int maxwidth = 0;
for (int row = 0; row < table.getRowCount(); row++) {
TableCellRenderer rend =
table.getCellRenderer(row, col);
Object value = table.getValueAt(row, col);
Component comp =
rend.getTableCellRendererComponent(table,
value,
false,
false,
row,
col);
maxwidth = Math.max(comp.getPreferredSize().width, maxwidth);
}
TableColumn column = columnModel.getColumn(col);
TableCellRenderer headerRenderer = column.getHeaderRenderer();
if (headerRenderer == null) {
headerRenderer = table.getTableHeader().getDefaultRenderer();
}
Object headerValue = column.getHeaderValue();
Component headerComp =
headerRenderer.getTableCellRendererComponent(table,
headerValue,
false,
false,
0,
col);
maxwidth = Math.max(maxwidth, headerComp.getPreferredSize().width);
column.setPreferredWidth(maxwidth);
}
}
public static int getComponentTreeCount(Container c) {
int cn = 1;
for (Component node : c.getComponents()) {
if (node instanceof Container) {
cn += getComponentTreeCount((Container) node);
} else {
cn++;
}
}
return cn;
}
public static void makeFluidSplitPane(final JSplitPane pane) {
}
public static void throwUnimplemented() {
Dialogs.confirmDialog()
.setTitle("Easy there...")
.setMessage("This feature is not yet implemented. Sorry; check back later.")
.setOptionType(JOptionPane.OK_CANCEL_OPTION)
.setMessageType(JOptionPane.INFORMATION_MESSAGE)
.show();
}
public static Icon getFileSystemIcon(String extension) {
File file = new File(System.getProperty("java.io.tmpdir") + File.pathSeparator + System.currentTimeMillis() + "." + extension);
try {
file.createNewFile();
} catch (IOException ex) {
Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), ex);
}
file.deleteOnExit();
return FileSystemView.getFileSystemView().getSystemIcon(file);
}
public static void makeDnD(final JTable table) {
table.setTransferHandler(new TransferHandler() {
private final DataFlavor localObjectFlavor = new ActivationDataFlavor(Integer.class, DataFlavor.javaJVMLocalObjectMimeType, "DnD_table");
@Override
protected Transferable createTransferable(JComponent c) {
return new DataHandler(new Integer(table.getSelectedRow()), localObjectFlavor.getMimeType());
}
@Override
public boolean canImport(TransferHandler.TransferSupport info) {
boolean b = info.getComponent() == table && info.isDrop() && info.isDataFlavorSupported(localObjectFlavor);
table.setCursor(b ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop);
return b;
}
@Override
public int getSourceActions(JComponent c) {
return TransferHandler.COPY_OR_MOVE;
}
@Override
public boolean importData(TransferHandler.TransferSupport info) {
JTable target = (JTable) info.getComponent();
JTable.DropLocation dl = (JTable.DropLocation) info.getDropLocation();
int index = dl.getRow();
int max = table.getModel().getRowCount();
if (index < 0 || index > max) {
index = max;
}
target.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
try {
Integer rowFrom = (Integer) info.getTransferable().getTransferData(localObjectFlavor);
if (rowFrom != -1 && rowFrom != index) {
DefaultTableModel model = (DefaultTableModel) table.getModel();
Object o = model.getDataVector().get(rowFrom);
model.removeRow(rowFrom);
if (index > rowFrom) {
index--;
}
model.getDataVector().add(index, o);
target.getSelectionModel().addSelectionInterval(index, index);
return true;
}
} catch (Exception e) {
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
}
return false;
}
@Override
protected void exportDone(JComponent c, Transferable t, int act) {
if (act == TransferHandler.MOVE) {
table.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
});
}
public static void setHeaderIcon(JTable table, final int column, final ImageIcon icon) {
final TableCellRenderer orig = table.getTableHeader().getDefaultRenderer();
table.getTableHeader().getColumnModel().getColumn(column).setHeaderRenderer(new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
JLabel com = (JLabel) orig.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
com.setHorizontalAlignment(JLabel.LEADING); // On Fedora its TRAILING; looks odd with the icon itself trailing
com.setIcon(icon);
return com;
}
});
}
public static void mapInput(JComponent component, int scope, final int keycode, final int modifiers, final AbstractAction action) {
if (component instanceof JComponent) {
JComponent jc = (JComponent) component;
String hash = String.valueOf(System.identityHashCode(action));
jc.getInputMap(scope).put(KeyStroke.getKeyStroke(keycode, modifiers), hash);
jc.getActionMap().put(hash, action);
}
}
public static ButtonGroup groupButtons(AbstractButton... buttons) {
ButtonGroup group = new ButtonGroup();
for (AbstractButton button : buttons) {
group.add(button);
}
return group;
}
public static Window getFocusedWindow() {
for (Window w : Window.getWindows()) {
if (w.isFocused()) {
return w;
}
}
return null;
}
}