package com.applang; import java.awt.AWTEvent; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Dialog; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Frame; import java.awt.Insets; import java.awt.KeyboardFocusManager; import java.awt.LayoutManager; import java.awt.Point; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.AWTEventListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.event.InputEvent; import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Writer; import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.EventListener; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Scanner; import java.util.Set; import java.util.regex.MatchResult; import java.util.regex.Pattern; import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.DefaultCellEditor; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListModel; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JToolBar; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.ProgressMonitor; import javax.swing.ProgressMonitorInputStream; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.WindowConstants; import javax.swing.border.TitledBorder; import javax.swing.event.AncestorListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellEditor; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.text.JTextComponent; import com.applang.Util.Constraint; import com.applang.Util.Job; import com.applang.Util.ValList; import android.app.Activity; import android.app.AlertDialog; import android.util.Log; import android.widget.Toast; import static com.applang.Util.*; import static com.applang.Util2.*; public class SwingUtil { private static final String TAG = SwingUtil.class.getSimpleName(); public interface ComponentFunction<T> { public T apply(Component comp, Object[] parms); } public static Component[] components(Component...params) { return params; } public static <T> Object[] iterateComponents(Container container, ComponentFunction<T> func, Object...params) { params = reduceDepth(params); if (container != null) { Component[] components = params.length > 0 ? container.getComponents() : components(container); for (Component comp : components) { T t = func.apply(comp, params); if (comp instanceof Container) iterateComponents((Container)comp, func, t); } } return params; } /** * @param <C> the type of the return value (derived from <code>Component</code>) * @param container the containing <code>Component</code> * @param regex pattern for the name of the <code>Component</code> searched for in the container including descendants * @return the <code>Component</code> found if unequal <code>null</code> otherwise nothing was found */ public static <C extends Component> C findFirstComponent(Container container, final String regex) { return findFirstComponent(container, new Predicate<Component>() { public boolean apply(Component c) { String name = c.getName(); return name != null && name.matches(regex); } }); } public static <C extends Component> C findFirstComponent(Container container, final String part, final Constraint constraint) { return findFirstComponent(container, new Predicate<Component>() { public boolean apply(Component c) { String name = c.getName(); return name != null && check(name, constraint, part); } }); } @SuppressWarnings("unchecked") public static <C extends Component> C findFirstComponent(Container container, Predicate<Component> predicate) { Component[] comps = findComponents(container, predicate); if (comps.length > 0) try { return (C)comps[0]; } catch (Exception e) {} return null; } public static Component[] findComponents(Container container, final Predicate<Component> predicate) { final ArrayList<Component> al = alist(); iterateComponents(container, new ComponentFunction<Object[]>() { public Object[] apply(Component c, Object[] parms) { if (predicate.apply(c)) al.add(c); return parms; } }, null, null); return al.toArray(new Component[al.size()]); } public static Component findAncestor(Component component, Predicate<Component> predicate) { do { component = component.getParent(); if(component == null) break; } while(!predicate.apply(component)); return component; } public static int getComponentIndex(Component component) { Container container = component.getParent(); if (component != null && container != null) { for (int i = 0; i < container.getComponentCount(); i++) { if (container.getComponent(i) == component) return i; } } return -1; } public static boolean swapComponents(Component component, Component peer) { Container container = component.getParent(); if (component != null && container != null && peer != null && container.equals(peer.getParent())) { printContainer("before swap", container, _null()); int cIndex = getComponentIndex(component); int pIndex = getComponentIndex(peer); if (cIndex > pIndex) { container.remove(cIndex); container.add(component, pIndex); container.remove(pIndex + 1); container.add(peer, cIndex); } else if (pIndex > cIndex) { container.remove(pIndex); container.add(peer, cIndex); container.remove(cIndex + 1); container.add(component, pIndex); } printContainer("after swap", container, _null()); return true; } return false; } public static void addNamePart(Component component, String part) { component.setName(addPart(component.getName(), part)); } public static void removeNamePart(Component component, String part) { component.setName(removePart(component.getName(), part)); } public static boolean containsComponent(Container container, final Component component) { return findComponents(container, new Predicate<Component>() { public boolean apply(Component c) { return component.equals(c); } }).length > 0; } public static void addCenterComponent(Component target, Container container) { if (container.getLayout() instanceof BorderLayout) container.add(target, BorderLayout.CENTER); else container.add(target); } public static boolean replaceCenterComponent(Component target, Container container) { if (container.getLayout() instanceof BorderLayout) { BorderLayout borderLayout = (BorderLayout) container.getLayout(); for (Component c : container.getComponents()) if (BorderLayout.CENTER.equals(borderLayout.getConstraints(c))) { container.remove(c); } container.add(target, BorderLayout.CENTER); return true; } return false; } public static Container getRootContainer(Container container) { if (container == null) return null; Container parent = container.getParent(); while (parent != null) { container = parent; parent = container.getParent(); } return container; } public static class Timing { public Timing(Component comp) { this.comp = comp; if (this.comp != null) { this.curs = this.comp.getCursor(); this.comp.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); this.comp.requestFocus(); } this.millis = System.currentTimeMillis(); } private long millis; public long current() { return System.currentTimeMillis() - millis; } Component comp; Cursor curs; /* (non-Javadoc) * @see java.lang.Object#finalize() */ @Override public void finalize() { try { this.millis -= System.currentTimeMillis(); if (this.comp != null) this.comp.setCursor(curs); } finally { try { super.finalize(); } catch (Throwable e) {} } } } public static long waiting(Component component, ComponentFunction<Void> func, Object... params) { final Timing timing = new Timing(component); try { func.apply(component, arrayextend(params, true, timing)); long current = timing.current(); return current; } finally { timing.finalize(); } } public static class Deadline extends SwingWorker<Void, Void> { public Deadline(Window wnd, Integer[] keyEvents) { mWnd = wnd; mKeyEvents = keyEvents; } Window mWnd; Integer[] mKeyEvents = null; @Override protected Void doInBackground(){ println(String.format("deadline after %d ms", WAIT)); waiting(mWnd, new ComponentFunction<Void>() { public Void apply(Component comp, Object[] parms) { Timing timing = (Timing)parms[0]; while (timing.current() < WAIT && !isCancelled()) Thread.yield(); return null; } }); return null; } @Override protected void done() { if (isCancelled()) return; if (!nullOrEmpty(mKeyEvents)) doKeyEvents(); else if (mWnd != null) pullThePlug(mWnd); timedOut = true; } public void cancel() { if (this.cancel(true)) println("deadline cancelled"); started = false; } void doKeyEvents() { try { Robot robot = new Robot(); for (int i = 0; i < mKeyEvents.length; i++) { if (mKeyEvents[i] != null) { robot.keyPress(mKeyEvents[i]); } } robot.delay(DELAY); for (int i = 0; i < mKeyEvents.length; i++) { if (mKeyEvents[i] != null) { robot.keyRelease(mKeyEvents[i]); } } } catch (Exception e) { e.printStackTrace(); } } public static int DELAY = 1000; public static int WAIT = 1000; public static Deadline start(int millis, Integer... keyEvents) { Deadline.WAIT = millis; return start(null, keyEvents); } public static Deadline start(Window wnd, Integer... keyEvents) { if (wnd == null && notAvailable(0, keyEvents)) return null; timedOut = false; final Deadline deadline = new Deadline(wnd, keyEvents); deadline.execute(); Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { public void eventDispatched(AWTEvent ev) { deadline.cancel(); } }, AWTEvent.MOUSE_MOTION_EVENT_MASK); started = true; return deadline; } public static boolean started = false; public static boolean timedOut = false; public static void finish() { if (started) { try { SwingUtilities.invokeAndWait(doEvents); } catch (Exception e) { e.printStackTrace(); } started = false; println("deadline finished"); } } static Runnable doEvents = new Runnable() { public void run() { Deadline deadline = new Deadline(null, null); deadline.execute(); } }; } /** * closes the <code>Window</code> programmatically * @param wnd */ public static void pullThePlug(Window wnd) { WindowEvent wev = new WindowEvent(wnd, WindowEvent.WINDOW_CLOSING); Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev); } public static class Bounds extends Rectangle { public Bounds() {} public Bounds(Window window, Object... params) { super(window != null ? window.getBounds() : param(new Rectangle(300,300,400,400), 0, params)); } public static Rectangle load(Window window, String category, String title, Object...params) { String key = key(category, title); Bounds rect = new Bounds(null, params); for (MatchResult mr : findAllIn(getSetting(key, ""), Pattern.compile("(\\w+)=(\\d+)"))) { if ("x".equals(mr.group(1))) rect.x = toInt(-1, mr.group(2)); else if ("y".equals(mr.group(1))) rect.y = toInt(-1, mr.group(2)); else if ("width".equals(mr.group(1))) rect.width = toInt(-1, mr.group(2)); else if ("height".equals(mr.group(1))) rect.height = toInt(-1, mr.group(2)); } Rectangle bounds = new Bounds(window, params); if (rect.x > -1) bounds.x = rect.x; if (rect.y > -1) bounds.y = rect.y; if (rect.width > -1) bounds.width = rect.width; if (rect.height > -1) bounds.height = rect.height; if (window != null) window.setBounds(bounds); return bounds; } static String key(String category, String title) { return category + "." + title.replaceAll("\\s+", "") + ".bounds"; } public static void save(Window window, String category, String title, Object...params) { String key = key(category, title); String value = stringValueOf(new Bounds(window, params)); int brac = value.indexOf('['); putSetting(key, value.substring(brac > -1 ? brac : 0)); } } public static class Behavior { public static final int NONE = 4; public static final int MODAL = 8; public static final int TIMEOUT = 16; public static final int ALWAYS_ON_TOP = 32; public static final int EXIT_ON_CLOSE = 64; public static final int HIDDEN = 128; public static int getOptionType(int behavior) { return (behavior + 1) % 4 - 1; } public static int getFlags(int behavior) { return (behavior + 1) / 4 * 4; } public static boolean hasFlags(int behavior, int flags) { return (getFlags(behavior) & flags) > 0; } public static int setFlags(int behavior, int flags) { return flags < 0 ? behavior & ~Math.abs(flags) : behavior | flags; } public static int setTimeout(int behavior, boolean timeout) { return setFlags(behavior, timeout ? TIMEOUT : -TIMEOUT); } public static int setModal(int behavior, boolean modal) { return setFlags(behavior, modal ? MODAL : -MODAL); } } public interface UIFunction extends ComponentFunction<Component[]> { } private static boolean finished = false; public static JFrame showFrame(Object relative, String title, UIFunction assembleUI, UIFunction arrangeUI, final UIFunction completeUI, int behavior, final Object...params) { final JFrame frame = new JFrame(title); try { frame.setName(title); if (assembleUI != null) { Component[] widgets = assembleUI.apply(frame, params); if (widgets != null) if (widgets.length == 1 && widgets[0] instanceof Container) frame.setContentPane((Container)widgets[0]); else for (Component widget : widgets) frame.getContentPane().add(widget); } frame.pack(); if (relative == null || relative instanceof Component) frame.setLocationRelativeTo((Component)relative); else if (relative instanceof Point) frame.setLocation((Point)relative); else if (relative instanceof Rectangle) frame.setBounds((Rectangle)relative); boolean exitOnClose = Behavior.hasFlags(behavior, Behavior.EXIT_ON_CLOSE); frame.setDefaultCloseOperation(exitOnClose ? JFrame.EXIT_ON_CLOSE : JFrame.DISPOSE_ON_CLOSE); frame.setVisible(!Behavior.hasFlags(behavior, Behavior.HIDDEN)); if (arrangeUI != null) arrangeUI.apply(frame, params); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { if (completeUI != null) completeUI.apply(frame, params); finished = true; } }); boolean deadline = Behavior.hasFlags(behavior, Behavior.TIMEOUT); if (deadline) { Deadline.start(frame); finished = false; while (!finished) { Thread.yield(); } } } catch (Exception e) { handleException(e); } return frame; } public static void startFrame(final Action action, Object...params) { showFrame(null, "Start", new UIFunction() { public Component[] apply(final Component comp, Object[] parms) { return components(action != null ? new JButton(action) : new JButton(new AbstractAction("Dispose") { @Override public void actionPerformed(ActionEvent ev) { pullThePlug((JFrame)comp); } })); } }, null, null, Behavior.TIMEOUT, params); } public static int dialogResult = JOptionPane.CLOSED_OPTION; public static JDialog showDialog(Component parent, Component relative, String title, UIFunction assembleUI, UIFunction arrangeUI, final UIFunction completeUI, final int behavior, final Object...params) { dialogResult = JOptionPane.CLOSED_OPTION; boolean modal = Behavior.hasFlags(behavior, Behavior.MODAL); Frame frame = JOptionPane.getFrameForComponent(parent); final JDialog dlg = new JDialog(frame, title, modal); boolean alwaysOnTop = Behavior.hasFlags(behavior, Behavior.ALWAYS_ON_TOP); dlg.setAlwaysOnTop(alwaysOnTop); if (assembleUI != null) { Component[] widgets = assembleUI.apply(dlg, params); if (widgets != null) if (widgets.length == 1 && widgets[0] instanceof Container) dlg.setContentPane((Container) widgets[0]); else for (Component widget : widgets) dlg.getContentPane().add(widget); } boolean deadline = Behavior.hasFlags(behavior, Behavior.TIMEOUT); if (deadline) Deadline.start(dlg); dlg.pack(); dlg.setLocationRelativeTo(relative); dlg.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); if (modal && arrangeUI != null) arrangeUI.apply(dlg, params); if (!deadline) Deadline.start(null); dlg.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { if (completeUI != null) completeUI.apply(dlg, params); if (Behavior.hasFlags(behavior, Behavior.EXIT_ON_CLOSE)) System.exit(0); } }); dlg.setVisible(!Behavior.hasFlags(behavior, Behavior.HIDDEN)); if (!modal && arrangeUI != null) arrangeUI.apply(dlg, null); no_println("dialogResult", dialogResult); return dlg; } public static int showOptionDialog(Component parent, final Object message, String title, final int optionType, final int messageType, Icon icon, final Object[] options, final Object initialOption, Object...params) { if (optionType > JOptionPane.OK_CANCEL_OPTION) { final Function<Boolean> optionHandler = param(null, 0, params); UIFunction assembleUI = new UIFunction() { public Component[] apply(final Component dialog, Object[] parms) { final JOptionPane optionPane = new JOptionPane(message, messageType, Behavior.getOptionType(optionType), null, options, initialOption); optionPane.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { Object source = ev.getSource(); String prop = ev.getPropertyName(); if (dialog.isVisible() && optionPane.equals(source) && JOptionPane.VALUE_PROPERTY.equals(prop)) { Object value = optionPane.getValue(); if (value == JOptionPane.UNINITIALIZED_VALUE) { dialogResult = JOptionPane.CLOSED_OPTION; return; } else { optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE); if (options != null) dialogResult = asList(options).indexOf(value); else dialogResult = (Integer) value; Boolean visibility = false; if (optionHandler != null) visibility = optionHandler.apply(ev, options, message); dialog.setVisible(visibility); if (!visibility && Behavior.hasFlags(optionType, Behavior.EXIT_ON_CLOSE)) System.exit(0); } }; } }); return components(optionPane); } }; showDialog(JOptionPane.getFrameForComponent(parent), parent, title, assembleUI, null, null, optionType, params); return dialogResult; } else { Deadline.start(null); parent = JOptionPane.getFrameForComponent(parent); return dialogResult = JOptionPane.showOptionDialog(parent, message, title, optionType, messageType, icon, options, initialOption); } } public static Icon defaultIcon(int optionType) { switch (optionType) { case JOptionPane.DEFAULT_OPTION: case 3: return UIManager.getIcon("OptionPane.informationIcon"); default: return UIManager.getIcon("OptionPane.questionIcon"); } } public static ValList defaultOptions(int optionType) { Object[] array; ValList list = vlist(); Object yesString = UIManager.get("OptionPane.yesButtonText"); Object noString = UIManager.get("OptionPane.noButtonText"); Object cancelString = UIManager.get("OptionPane.cancelButtonText"); Object okString = UIManager.get("OptionPane.okButtonText"); switch (optionType) { case JOptionPane.YES_NO_OPTION: array = objects( yesString, noString, null ); break; case JOptionPane.YES_NO_CANCEL_OPTION: array = objects( yesString, noString, cancelString, cancelString ); break; case JOptionPane.OK_CANCEL_OPTION: array = objects( okString, cancelString, cancelString ); break; case JOptionPane.DEFAULT_OPTION: case 3: array = objects( "Close", null ); break; case 5: array = objects( "Yes", "Yes all", "No", "No all", "Cancel", null ); break; case 10: array = objects("OK","Add","Remove","Cancel","OK"); break; case 11: array = objects("OK","Add","Remove","Edit","Cancel","OK"); break; case 12: array = objects("OK","Save","Cancel","Save"); break; case 13: array = objects("Accept","Reject","Accept"); break; case 14: array = objects("Sync", null); break; default: return list; } list.addAll(asList(array)); return list; } public static Object showInputDialog(Component parent, Object message, String title, int optionType, int messageType, Icon icon, Object[] selections, Object initialValue, Integer... keyEvents) { dialogResult = JOptionPane.CLOSED_OPTION; Object[] options = selections; Object initialOption = initialValue; if (options == null) { ValList list = defaultOptions(optionType); initialOption = list.remove(-1); options = list.toArray(); } Object[] widgets = null; JTextComponent textComponent = null; String text = notNullOrEmpty(initialValue) ? initialValue.toString() : ""; parent = JOptionPane.getFrameForComponent(parent); Deadline.start(null, keyEvents); switch (optionType) { case JOptionPane.DEFAULT_OPTION: return JOptionPane.showInputDialog(parent, message, title, messageType, icon, selections, initialValue); default: optionType = JOptionPane.DEFAULT_OPTION; textComponent = new JTextArea(text); textComponent.setEditable(false); widgets = objects(new JScrollPane(textComponent)); break; case JOptionPane.YES_NO_OPTION: case JOptionPane.YES_NO_CANCEL_OPTION: case JOptionPane.OK_CANCEL_OPTION: JTextField textField = new JTextField(text); textField.setHorizontalAlignment(JTextField.CENTER); addSelectAllObserver(textField); JLabel label = new JLabel(message.toString()); label.setDisplayedMnemonic(KeyEvent.VK_I); label.setLabelFor(textField); textComponent = textField; textComponent.requestFocusInWindow(); widgets = objects(label, textComponent); break; } dialogResult = JOptionPane.showOptionDialog(parent, widgets, title, optionType, messageType, icon, options, initialOption); return textComponent.getText(); } public static <T> T showResizableDialog(final JComponent component, AncestorListener ancestorListener, Function<T> show, Object...params) { component.addHierarchyListener(new HierarchyListener() { public void hierarchyChanged(HierarchyEvent e) { Window window = SwingUtilities.getWindowAncestor(component); if (window instanceof Dialog) { Dialog dialog = (Dialog) window; if (!dialog.isResizable()) dialog.setResizable(true); } } }); if (ancestorListener != null) component.addAncestorListener(ancestorListener); return show.apply(arrayappend(objects(component), params)); } public static String getWindowTitle(Component component) { Window window = SwingUtilities.windowForComponent(component); if (window instanceof Frame) return ((Frame)window).getTitle(); else if (window instanceof Dialog) return ((Dialog)window).getTitle(); return null; } public static boolean setWindowTitle(Component component, String title) { boolean retval = true; Window window = SwingUtilities.windowForComponent(component); if (window instanceof Frame) ((Frame)window).setTitle(title); else if (window instanceof Dialog) ((Dialog)window).setTitle(title); else retval = false; return retval; } @SuppressWarnings("unchecked") public static File getFileFromStore(int type, final String title, FileNameExtensionFilter filter, Function<File> chooser, Function<String[]> loader, Job<String[]> saver, Object...params) { Function<String[]> lister = new Function<String[]>() { public String[] apply(Object... params) { List<String> list = alist(); String element = param(null, 0, params); String[] array = param(null, 1, params); if (array != null) { arrayexclude(arrayindexof(element, array), array, list); } boolean sort = param_Boolean(false, 2, params); if (sort) { Set<String> set = sortedSet(list); list = alist(); list.addAll(set); } boolean first = param_Boolean(true, 3, params); if (first) list.add(0, element); return toStrings(list); } }; String fileName = param(null, 0, params); File file = notNullOrEmpty(fileName) ? new File(fileName) : null; boolean allowEdit = type > 0; int option = 1; String[] fileNames = null; try { if (loader != null) fileNames = loader.apply(params); } catch (Exception e) { Log.e(TAG, "getFileFromStore", e); } boolean storeEmpty = nullOrEmpty(fileNames); if (!storeEmpty) { if (nullOrEmpty(fileName)) fileName = fileNames[0]; fileNames = lister.apply(fileName, fileNames, true); @SuppressWarnings({ "rawtypes" }) JComboBox combo = new JComboBox(fileNames); JLabel label = new JLabel(title); label.setLabelFor(combo); Object message = objects(label, combo); ValList list = defaultOptions(allowEdit ? 11 : 10); Object initialOption = list.remove(-1); Object[] options = list.toArray(); option = JOptionPane.showOptionDialog(null, message, "Store", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, initialOption); if (option < 0 || option == options.length - 1) return null; if (option == 2) { // Remove if (fileNames != null) { fileNames = lister.apply(combo.getSelectedItem(), fileNames, false, false); try { saver.perform(fileNames, params); } catch (Exception e) { Log.e(TAG, "getFileFromStore", e); } } return getFileFromStore(type, title, filter, chooser, loader, saver, params); } if (option > -1) file = new File(combo.getSelectedItem().toString()); if (option == 3) { // Edit JTextArea textArea = new JTextArea(""); textArea.setEditable(true); textArea.setText(contentsFromFile(file)); list = defaultOptions(12); initialOption = list.remove(-1); options = list.toArray(); option = showResizableDialog(textArea, null, new Function<Integer>() { public Integer apply(Object...parms) { JScrollPane scrollPane = new JScrollPane((Component) parms[0]); scrollPane.setPreferredSize(new Dimension(500,200)); return JOptionPane.showOptionDialog(null, scrollPane, title, JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, (Object[])parms[1], parms[2]); } }, options, initialOption); if (option < 0 || option == options.length - 1) return null; if (option == 0) { // OK file = tempFile("." + filter.getExtensions()[0]); contentsToFile(file, textArea.getText()); return file; } file = chooser == null ? chooseFile(false, null, title, file, filter) : chooser.apply(false, null, title, file, filter); if (file != null) contentsToFile(file, textArea.getText()); } } if (option == 1) { // Add file = chooser == null ? chooseFile(true, null, title, file, filter) : chooser.apply(true, null, title, file, filter); if (fileNames == null) return file; if (file == null) return getFileFromStore(type, title, filter, chooser, loader, saver, params); } if (file != null) { fileName = file.getPath(); if (fileName.indexOf(NEWLINE) < 0) { fileNames = lister.apply(fileName, fileNames); try { saver.perform(fileNames, params); } catch (Exception e) { Log.e(TAG, "getFileFromStore", e); } } if (!storeEmpty && option > 0) { if (isAvailable(0, params)) params[0] = fileName; else params = objects(fileName); return getFileFromStore(type, title, filter, chooser, loader, saver, params); } } return file; } public static String[] chooseFileNames(boolean toOpen, Container parent, String title, String fileName, FileFilter...fileFilters) { File f = new File(stringValueOf(fileName)); f = chooseFile(toOpen, parent, title, f, fileFilters); return strings(f == null ? "" : f.getPath()); } public static String[] chooseDirectoryNames(Container parent, String title, String dirName) { File f = new File(stringValueOf(dirName)); f = chooseDirectory(parent, title, f); return strings(f == null ? "" : f.getPath()); } /** * @param parent * @param title * @param file * @param fileFilter * @return the chosen <code>File</code> */ public static File chooseFile(boolean toOpen, Container parent, String title, File file, FileFilter...fileFilters) { File dir = null; try { dir = file.getParentFile(); } catch (Exception e) {} if (dir == null) dir = new File(relativePath()); JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(dir); chooser.setDialogTitle(title); chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); if (fileFilters != null) for (FileFilter ff : fileFilters) setFileFilter(chooser, ff); if (fileExists(file)) chooser.setSelectedFile(file); parent = JOptionPane.getFrameForComponent(parent); dialogResult = toOpen ? chooser.showOpenDialog(parent) : chooser.showSaveDialog(parent); if (dialogResult == JFileChooser.APPROVE_OPTION) return chooser.getSelectedFile(); else return null; } static void setFileFilter(JFileChooser chooser, FileFilter fileFilter) { if (fileFilter == null) chooser.resetChoosableFileFilters(); else { chooser.addChoosableFileFilter(chooser.getAcceptAllFileFilter()); chooser.addChoosableFileFilter(fileFilter); } chooser.setAcceptAllFileFilterUsed(true); } /** * @param parent * @param title * @param dir * @return the chosen directory <code>File</code> */ public static File chooseDirectory(Container parent, String title, File dir) { JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(dir); chooser.setDialogTitle(title); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setAcceptAllFileFilterUsed(false); parent = JOptionPane.getFrameForComponent(parent); dialogResult = chooser.showOpenDialog(parent); if (dialogResult == JFileChooser.APPROVE_OPTION) return chooser.getSelectedFile(); else return null; } public static void tabKeyForwarding(JComponent jc) { jc.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { no_println("pressed", e.getKeyCode(), "ctrl", e.isControlDown()); if (e.getKeyCode() == KeyEvent.VK_TAB) { e.consume(); if (e.isShiftDown()) KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent(); else KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(); } } @Override public void keyReleased(KeyEvent e) { no_println("released", e.getKeyCode(), "ctrl", e.isControlDown()); } }); } @SuppressWarnings("rawtypes") public static JTextField comboEdit(JComboBox combo) { return (JTextField)combo.getEditor().getEditorComponent(); } public static boolean underTest = false; public static JToolBar northToolBar(Container container, Object...params) { JToolBar bar = new JToolBar(); bar.setFloatable(true); container.add(bar, param(BorderLayout.NORTH, 0, params)); bar.setName(param(BorderLayout.NORTH, 1, params)); return bar; } public static JToolBar southStatusBar(Container container, Object...params) { JToolBar bar = new JToolBar(); bar.setFloatable(false); messageBox(bar); container.add(bar, param(BorderLayout.SOUTH, 0, params)); bar.setName(param(BorderLayout.SOUTH, 1, params)); return bar; } public static JLabel messageBox(Container container) { JLabel label = new JLabel(""); label.setName("mess"); container.add(label); SwingUtil.container = container; return label; } private static Container container = null; public static Function<String> messRedirection = null; public static void message(String text) { if (underTest) println(text); else if (messRedirection != null) messRedirection.apply(text); else { Container rootContainer = underTest ? container : getRootContainer(container); JLabel mess = findFirstComponent(rootContainer, "mess"); if (mess != null) mess.setText(text); else alert(text); } } public static void longToast(String text) { Toast.makeText(Activity.getInstance(), text, Toast.LENGTH_LONG).show(true); } public static void alert(Object...params) { JOptionPane.showMessageDialog( container, param_String("", 0, params), param_String("Alert", 1, params), param_Integer(JOptionPane.PLAIN_MESSAGE, 2, params)); } public static boolean question(Object...params) { return JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog( container, param_String("Are you sure", 0, params), param_String("Question", 1, params), param_Integer(JOptionPane.OK_CANCEL_OPTION, 2, params)); } public static void handleException(Exception ex) { if (ex != null) { AlertDialog.alerter(new Activity(), "Exception", ex); // String message = ex.getMessage(); // if (nullOrEmpty(message)) // message = String.valueOf(ex); // message(message); } } public static String resourceFrom(String path, String encoding) { if (notNullOrEmpty(path)) { InputStream is = null; try { is = SwingUtil.class.getResourceAsStream(path); BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName(encoding))); return readAll(rd); } catch (Exception e) { if (is != null) try { is.close(); } catch (Exception e1) {} } } return null; } public static ImageIcon iconFrom(String path) { if (notNullOrEmpty(path)) { URL url = SwingUtil.class.getResource(path); return new ImageIcon(url); } else return null; } public interface CustomActionType { public int index(); public String resourceName(); public String iconName(); public String name(int state); public String description(); } public static class CustomAction extends AbstractAction { public static boolean actionBlocked = false; public static void blocked(Job<Void> job, Object[] params) throws Exception { actionBlocked = true; job.perform(null, params); actionBlocked = false; } private CustomActionType type = null; public CustomActionType getType() { return type; } public void setType(CustomActionType type) { this.type = type; putValue(SMALL_ICON, iconFrom(this.type.iconName())); putValue(SHORT_DESCRIPTION, this.type.description()); // putValue(MNEMONIC_KEY, KeyEvent.CHAR_UNDEFINED); } public CustomAction(CustomActionType type) { super(null); setType(type); } public CustomAction(String text) { super(text); } @Override public void actionPerformed(ActionEvent ae) { if (actionBlocked || (getType() == null && getValue(CustomAction.NAME) == null)) return; message(""); Log.d(TAG, type == null ? ae.getActionCommand() : type.toString()); action_Performed(ae); } protected void action_Performed(ActionEvent ae) { if (actionBlocked) return; } } public static void toggle(CustomAction toggleAction, Job<Boolean> job, Object...params) { String name1 = toggleAction.getType().name(1); String name2 = toggleAction.getType().name(2); Object name = toggleAction.getValue(Action.NAME); name = name != null && name.equals(name1) ? name2 : name1; toggleAction.putValue(Action.NAME, name); try { boolean toggle = name.equals(name2); job.perform(toggle, params); } catch (Exception e) { Log.e(TAG, "toggle", e); } } /** * @param <T> type of container * @param container if T is <code>JPanel</code> then <code>JButton</code> are added else <code>JMenuItem</code> * @param params button specifications * <table border="1"> * <tr><th>index</th><th>description</th></tr> * <tr><td>0</td><td>button text</td></tr> * <tr><td>1</td><td>action (<code>EventListener</code>)</td></tr> * <tr><td>2</td><td>button name</td></tr> * <tr><td>3</td><td>button tooltip text</td></tr> * <tr><td>4</td><td>enabled (<code>Boolean</code>)</td></tr> * <tr><td>5</td><td>mnemonic (<code>Integer</code>)</td></tr> * <tr><td>6</td><td>selected (<code>Boolean</code>)</td></tr> * <tr><td>7</td><td>accelerator (<code>KeyStroke</code>)</td></tr> * </table> * @return */ public static <T extends JComponent> T addButtons(T container, Object... params) { AbstractButton button = null; ButtonGroup group = null; for (int i = 0; i < params.length; i++) { boolean multi = params[i] instanceof Object[]; Object[] parms = multi ? (Object[])param(null, i, params) : params; String text = param_String("-", 0, parms); String name = param_String("button" + i, 2, parms); if ("-".equals(text)) { group = (ButtonGroup)param(null, 1, parms); if (param_Boolean(true, 2, parms)) { if (container instanceof JPanel) { LayoutManager lm = container.getLayout(); int axis = lm instanceof BoxLayout ? ((BoxLayout)lm).getAxis() : -1; switch (axis) { case BoxLayout.LINE_AXIS: case BoxLayout.X_AXIS: container.add(Box.createHorizontalStrut(param_Integer(0, 3, parms))); break; case BoxLayout.PAGE_AXIS: case BoxLayout.Y_AXIS: container.add(Box.createVerticalStrut(param_Integer(0, 3, parms))); break; default: container.add(new JLabel(param_String(" ", 3, parms))); break; } } else if (container instanceof JPopupMenu) ((JPopupMenu)container).addSeparator(); else ((JMenu)container).addSeparator(); } } else if ("+".equals(text) || "+".equals(name)) { JMenu menu = param(null, 1, parms); menu.setName(name); container.add(menu); } else if (notNullOrEmpty(text)) { boolean minus = text.startsWith("-"); boolean check = text.startsWith("-check "); boolean radio = text.startsWith("-radio "); if (container instanceof JPanel) { if (minus) { if (check) button = new JCheckBox(text.substring(7)); else if (radio) { button = new JRadioButton(text.substring(7)); if (group != null) group.add(button); } else continue; } else button = new JButton(text); } else { if (minus) { if (check) button = new JCheckBoxMenuItem(text.substring(7)); else if (radio) { button = new JRadioButtonMenuItem(text.substring(7)); if (group != null) group.add(button); } else continue; } else button = new JMenuItem(text); } Object o = param(null, 1, parms); EventListener evl = o instanceof EventListener ? (EventListener)o : null; if (evl instanceof ItemListener) button.addItemListener((ItemListener)evl); if (evl instanceof ActionListener) button.addActionListener((ActionListener)evl); if (evl instanceof CustomAction) { CustomAction act = (CustomAction)evl; button.setAction(act); button.setText(act.getValue(CustomAction.SHORT_DESCRIPTION).toString()); button.setName(name); } else { button.setName(name); button.setActionCommand(name); button.setToolTipText(param_String("", 3, parms)); button.setEnabled(param_Boolean(true, 4, parms)); button.setMnemonic(param_Integer(0, 5, parms)); button.setSelected(param_Boolean(false, 6, parms)); KeyStroke ks = param(KeyStroke.getKeyStroke(' '), 7, parms); if (isType(JMenuItem.class, button)) ((JMenuItem)button).setAccelerator(ks); } container.add(button); } if (!multi) break; } return container; } public static JMenu newMenu(String name, Object... params) { return addButtons(new JMenu(name), params); } public static JPopupMenu newPopupMenu(Object... params) { JPopupMenu popupMenu = addButtons(new JPopupMenu(), params); for (int i = 0; i < params.length; i++) { boolean multi = params[i] instanceof Object[]; Object[] parms = multi ? (Object[])param(null, i, params) : params; PopupMenuListener popupMenuListener = param(null, 8, parms); if (popupMenuListener != null) popupMenu.addPopupMenuListener(popupMenuListener); } return popupMenu; } /** * @param params * @return */ public static MouseListener newPopupAdapter(Object... params) { return new PopupAdapter(newPopupMenu(params)); } /** * @param params * @return */ public static DropdownAdapter newDropdownAdapter(Object... params) { return new DropdownAdapter(newPopupMenu(params)); } /** * */ public static class PopupMenuAdapter implements PopupMenuListener { public void popupMenuCanceled(PopupMenuEvent e) { // println("Canceled"); } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { // println("Becoming invisible"); } public void popupMenuWillBecomeVisible(PopupMenuEvent e) { // println("Becoming visible"); } } /** * */ public static class DropdownAdapter extends MouseAdapter { JPopupMenu popupMenu; public DropdownAdapter(JPopupMenu popupMenu) { this.popupMenu = popupMenu; } /* (non-Javadoc) * @see java.awt.event.MouseAdapter#mousePressed(java.awt.event.MouseEvent) */ @Override public void mousePressed(MouseEvent e) { maybeShowPopup(e); } /* (non-Javadoc) * @see java.awt.event.MouseAdapter#mouseReleased(java.awt.event.MouseEvent) */ @Override public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } /** * @param e */ protected void maybeShowPopup(MouseEvent e) { Component c = e.getComponent(); if (c.isEnabled()) { popupMenu.show(c, 0, c.getHeight()); } } } public static boolean isCtrlKeyHeld(InputEvent ev) { return (ev.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK; } public static void mouseEventOutput(String eventDescription, MouseEvent e) { println(eventDescription + " (" + e.getX() + "," + e.getY() + ")" + " with button " + e.getButton() + " detected on " + e.getComponent().getClass().getName()); } public static MouseEvent popupEvent = null; /** * */ public static class PopupAdapter extends DropdownAdapter { public PopupAdapter(JPopupMenu popup) { super(popup); } @Override protected void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { popupEvent = e; popupMenu.show(e.getComponent(), e.getX(), e.getY()); } } } public static JComponent attachDropdownMenu(JComponent component, JPopupMenu popupMenu) { component.setComponentPopupMenu(popupMenu); component.addMouseListener(new DropdownAdapter(popupMenu)); return component; } public static JComponent addDropdownAdapter(JComponent component, DropdownAdapter dropdownAdapter) { component.setComponentPopupMenu(dropdownAdapter.popupMenu); component.addMouseListener(dropdownAdapter); return component; } public static JComponent removeDropdownAdapter(JComponent component, DropdownAdapter dropdownAdapter) { component.setComponentPopupMenu(null); component.removeMouseListener(dropdownAdapter); return component; } /** * @param <C> * @param container * @param cmd * @return */ @SuppressWarnings("unchecked") public static <C extends AbstractButton> C findButtonByActionCommand(Container container, String cmd) { for (Component comp : container.getComponents()) if (comp instanceof AbstractButton) { try { C btn = (C)comp; String command = btn.getActionCommand(); if (command != null && command.equals(cmd)) return btn; } catch (Exception e) { break; } } else if (comp instanceof Container) { C btn = SwingUtil.<C>findButtonByActionCommand((Container)comp, cmd); if (btn != null) return btn; } return null; } public static void addSelectAllObserver(JTextComponent jtc) { jtc.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { ((JTextComponent)e.getSource()).selectAll(); } public void focusLost(FocusEvent arg0) { } }); } public static void setLongText(JTextComponent tc, String text) { tc.setText(text); int length = tc.getDocument().getLength(); tc.setCaretPosition(length); } public static String trimPath(String path, int width, Font font, JComponent jc) { FontMetrics fm = jc.getFontMetrics(font); if (width > 0 && fm != null) { int strWidth = fm.stringWidth(path); if (strWidth > width) { StringBuilder sb = new StringBuilder(path); String prefix = "..."; while (fm.stringWidth(prefix + sb.toString()) > width) { sb.delete(0, 1); } path = prefix + sb.toString(); } } return path; } public static int[] textMeasures(String text, Font font) { AffineTransform affinetransform = new AffineTransform(); FontRenderContext frc = new FontRenderContext(affinetransform, true, true); int textwidth = (int)(font.getStringBounds(text, frc).getWidth()); int textheight = (int)(font.getStringBounds(text, frc).getHeight()); return ints(textwidth, textheight); } public static Font monoSpaced(Object... params) { return new Font("Monospaced", param(0, 0, params), param(12, 1, params)); } public static void adjustButtonSize(AbstractButton btn, int...tlbr) { String text = btn.getText(); if (text.length() > -1) { Insets insets = isAvailable(3, tlbr) ? new Insets(param(0,0,tlbr), param(0,1,tlbr), param(0,2,tlbr), param(0,3,tlbr)) : btn.getInsets(); int[] meas = textMeasures(text, btn.getFont()); btn.setPreferredSize(new Dimension(2 + meas[0] + insets.left + insets.right, meas[1] + insets.top + insets.bottom)); btn.setMargin(insets); } } public static void printContainer(String message, Container container, Object...params) { Boolean diag = param_Boolean(DIAG_OFF, 0, params); if (diag == null) return; StringBuilder sb = new StringBuilder(); sb.append(message + " :" + TAB + stringValueOf(container.getName()) + TAB + stringValueOf(container.getClass()) + TAB + stringValueOf(container.getLayout()) + NEWLINE); iterateContainer(container, sb, 1); diag_print(diag, sb.toString()); } public static void iterateContainer(Container container, final StringBuilder sb, int indent) { iterateComponents(container, new ComponentFunction<Integer>() { public Integer apply(Component comp, Object[] parms) { Integer indent = param_Integer(0, 0, parms); String indentString = ""; for (int i = 0; i < indent; i++) indentString += " "; String size = comp.getSize().toString(); sb.append(String.format("%s%s%s\tsize%s\n", indentString, comp.getName() == null ? "" : comp.getName() + " : ", comp.getClass(), size.substring(size.indexOf("[")))); return ++indent; } }, indent); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static class MapEditorComponent extends JTable { private DefaultTableModel model; public MapEditorComponent(final Map map, Object...options) { final Object[] keys = sortedSet(map.keySet()).toArray(); model = new DefaultTableModel(keys.length, 2) { @Override public Object getValueAt(int row, int col) { if (col == 0) return keys[row]; else return map.get(keys[row]); } @Override public void setValueAt(Object value, int row, int col) { if (col == 1) map.put(keys[row], value); } @Override public Class<?> getColumnClass(int col) { if (col == 1) { return String.class; } return super.getColumnClass(col); } @Override public boolean isCellEditable(int row, int col) { if (col == 0) return false; else return true; } }; setModel(model); setName("table"); column0background = getTableHeader().getBackground(); setTableHeader(null); setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1)); setRowSelectionAllowed(false); setColumnSelectionAllowed(false); getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer()); editors = new TableCellEditor[keys.length]; for (int i = 0; i < keys.length; i++) if (isAvailable(i, options)) { Object[] items = (Object[]) options[i]; editors[i] = new DefaultCellEditor(new JComboBox(items)); } } TableCellEditor[] editors; @Override public TableCellEditor getCellEditor(int row, int col) { TableCellEditor editor = editors[row]; if (editor != null) return editor; else return super.getCellEditor(row,col); } Color column0background; class CustomRenderer extends DefaultTableCellRenderer { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); cellComponent.setBackground(column0background); return cellComponent; } } } @SuppressWarnings({ "rawtypes", "unchecked" }) public static DefaultListModel defaultListModel(final Collection<?> collection) { return new DefaultListModel() { { for (Object item : collection) addElement(item); } }; } @SuppressWarnings("rawtypes") public static class Memory extends DefaultComboBoxModel { @SuppressWarnings({ "unchecked" }) public static void update(final JComboBox cb, Object...params) { Object value = param(null, 0, params); Object value2 = param(null, 1, params); if (value instanceof Boolean) { Memory model = new Memory(stringValueOf(value2)); cb.setModel(model); if ((Boolean)value && model.getSize() > 0) { Object el = model.getElementAt(0); model.setSelectedItem(el); } final JTextField tf = comboEdit(cb); tf.addMouseListener(newPopupAdapter( objects("+", newMenu("Memory", objects("add", new ActionListener() { public void actionPerformed(ActionEvent ae) { Memory.update(cb, tf.getText()); } }), objects("remove", new ActionListener() { public void actionPerformed(ActionEvent ae) { Memory.update(cb, null, tf.getText()); } }) ) ) )); cb.setEditable(true); } else { boolean add = value != null; Object removal = add ? value : value2; Memory memory = (Memory)cb.getModel(); if (memory.contains(removal)) cb.removeItem(removal); if (add) { cb.addItem(value); cb.setSelectedItem(value); } } } ArrayDeque<Object> deque = null; int capacity = 10; public int getCapacity() { return capacity; } public void setCapacity(int capacity) { this.capacity = capacity; } String name = ""; public String getName() { return name; } public void setName(String name) { this.name = name; } public Memory() { } public Memory(String name, Object... params) { this.name = name; capacity = getSetting(name + ".memory.capacity", capacity); ValList values = (ValList) getListSetting(name + ".memory", vlist()); deque = new ArrayDeque<Object>(values); for (Object p : params) addElement(p); } public void contentsChanged() { Object[] values = deque.toArray(); putListSetting(name + ".memory", asList(values)); } Object selectedObject = null; @Override public void setSelectedItem(Object anItem) { super.setSelectedItem(anItem); selectedObject = anItem; } public boolean contains(Object o) { return deque.contains(o); } @Override public int getSize() { return deque.size(); } @Override public Object getElementAt(int index) { Object el = null; Iterator<Object> it = deque.iterator(); int i = 0; while (i <= index && it.hasNext()) { el = it.next(); if (i >= index) break; i++; } return el; } @Override public void addElement(Object obj) { deque.addFirst(obj.toString()); while (getSize() > capacity) deque.removeLast(); fireIntervalAdded(this, 1, 1); if ( getSize() == 1 && selectedObject == null && obj != null ) { setSelectedItem(obj); } contentsChanged(); } @Override public void removeElement(Object obj) { Iterator<Object> it = deque.iterator(); int index = 0; while (it.hasNext()) { Object el = it.next(); if (obj.equals(el)) { deque.remove(el); fireIntervalRemoved(this, index, index); break; } index++; } contentsChanged(); } @Override public void insertElementAt(Object obj, int index) { throw new UnsupportedOperationException("Not implemented"); } @Override public void removeElementAt(int index) { throw new UnsupportedOperationException("Not implemented"); } @Override public void removeAllElements() { throw new UnsupportedOperationException("Not implemented"); } @Override public String toString() { Writer writer = write(null, "["); writer = write_assoc(writer, "name", this.name); writer = write_assoc(writer, "capacity", this.capacity, 1); writer = write_assoc(writer, "deque", this.deque, 1); return write(writer, "]").toString(); } } public static boolean hasNoSelection(JTable table) { ListSelectionModel sm = table.getSelectionModel(); return sm.isSelectionEmpty(); } public static void setColumnWidthsAsPercentages(JTable table, Object...percentages) { double factor = 10000; TableColumnModel model = table.getColumnModel(); int columnCount = model.getColumnCount(); if (columnCount > 0) { Double percentage = 1.0 / columnCount; for (int i = 0; i < columnCount; i++) { TableColumn column = model.getColumn(i); double val = param_Double(percentage, i, percentages) * factor; column.setPreferredWidth((int) val); } } } public static JScrollPane scrollableViewport(JTable table, Object...params) { Dimension size = param(null,0,params); if (size != null) table.setPreferredScrollableViewportSize(size); boolean fills = param_Boolean(false, 1, params); table.setFillsViewportHeight(fills); return new JScrollPane(table); } public static void selectRowAndScrollToVisible(JTable table, int...rows) { if (!isAvailable(0, rows)) return; int row1; if (rows.length < 2) row1 = rows[0]; else row1 = rows[1]; table.getSelectionModel().setSelectionInterval(rows[0], row1); Rectangle cellRect = table.getCellRect(rows[0], 0, true); table.scrollRectToVisible(cellRect); } public static void setMaximumDimension(Component component, Integer...fac) { Dimension size = component.getPreferredSize(); int fWidth = param(1, 0, fac); int fHeight = param(1, 1, fac); component.setMaximumSize(new Dimension(size.width * fWidth, size.height * fHeight)); } public static Dimension scaledDimension(Dimension size, Double...scaleFac) { Double fWidth = param(1.0, 0, scaleFac); Double fHeight = param(1.0, 1, scaleFac); size = new Dimension( (int)Math.round(size.width * fWidth), (int)Math.round(size.height * fHeight)); return size; } public static void scaleSize(Component component, Double...scaleFac) { Dimension size = scaledDimension(component.getSize(), scaleFac); if (component instanceof JComponent) component.setPreferredSize(size); else component.setSize(size); } public static JPanel surroundingBox(JComponent contents, String title, Object...params) { JPanel box = new JPanel(); int titleJustification = param_Integer(TitledBorder.DEFAULT_JUSTIFICATION, 0, params); int titlePosition = param_Integer(TitledBorder.DEFAULT_POSITION, 1, params) ; box.setBorder( BorderFactory.createTitledBorder( BorderFactory.createEtchedBorder(), title, titleJustification, titlePosition ) ); box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS)); box.add( contents ); box.add( Box.createVerticalStrut(10) ); return box; } public static Dimension sizeOfScreen() { return Toolkit.getDefaultToolkit().getScreenSize(); } public static Point centerOfScreen() { Dimension screenSize = sizeOfScreen(); return new Point(screenSize.width / 2, screenSize.height / 2); } public static JSplitPane splitPane(int orientation, Object...params) { JSplitPane splitPane = new JSplitPane(orientation); splitPane.setResizeWeight(0.5); splitPane.setOneTouchExpandable(true); splitPane.addPropertyChangeListener("dividerLocation", param((PropertyChangeListener)null,0,params)); return splitPane; } public static String readFromUrlWithProgress(String url, String encoding) throws IOException { InputStream is = null; try { is = new URL(url).openStream(); ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(null, url, is); BufferedReader rd = new BufferedReader(new InputStreamReader(pmis, Charset.forName(encoding))); return readAll(rd); } finally { if (is != null) is.close(); } } public static int urlContentLength(String fileURL) { try { URL url = new URL(fileURL); URLConnection urlConnection = url.openConnection(); if (urlConnection != null) { return urlConnection.getContentLength(); } } catch (Exception e) { Log.e(TAG, "urlContentLength", e); } return -1; } public static class ScanTask extends Task<Void> { public ScanTask(Component parent, String title, InputStream is, Job<Void> goAlong, Job<Void> followUp, Object...params) { super(null, followUp, params); this.goAlong = goAlong; if (followUp != null) sb = new StringBuilder(); pmis = new ProgressMonitorInputStream(parent, title, is); progressMonitor = pmis.getProgressMonitor(); progressMonitor.setMillisToDecideToPopup(0); progressMonitor.setMillisToPopup(0); progressMonitor.setProgress(0); in = new Scanner(pmis); execute(); } ProgressMonitorInputStream pmis; ProgressMonitor progressMonitor; @Override protected Void doInBackground() throws Exception { while (in.hasNextLine()) { String line = in.nextLine(); if (goAlong != null) goAlong.perform(null, objects(line, params)); if (sb != null) { sb.append(line); sb.append("\n"); } } in.close(); return null; } Scanner in; Job<Void> goAlong; StringBuilder sb = null; @Override protected void done() { if (followUp != null) try { followUp.perform(null, objects(sb.toString(), params)); cancel(true); } catch (Exception e) { Log.e(TAG, "follow-up", e); } } } }