Mercurial Hosting > luan
view src/luan/modules/swing/SwingLuan.java @ 1980:2662ff07a6c8
drop files
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 27 Jun 2025 17:51:16 -0600 |
parents | 7278eb509524 |
children |
line wrap: on
line source
package luan.modules.swing; import java.lang.reflect.InvocationTargetException; import javax.swing.SwingUtilities; import javax.swing.KeyStroke; import javax.swing.Action; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.JViewport; import javax.swing.Timer; import javax.swing.event.ChangeListener; import javax.swing.event.ChangeEvent; import javax.swing.text.JTextComponent; import javax.swing.text.Document; import javax.swing.undo.UndoManager; import java.awt.Component; import java.awt.Rectangle; import java.awt.Point; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.WindowListener; import java.awt.event.WindowEvent; import java.awt.event.WindowAdapter; import java.awt.event.ComponentListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import goodjava.logging.Logger; import goodjava.logging.LoggerFactory; import luan.Luan; import luan.LuanFunction; import luan.LuanTable; import luan.LuanException; import luan.LuanRuntimeException; public class SwingLuan { private static final Logger logger = LoggerFactory.getLogger(SwingLuan.class); private static Luan luan; static { SwingUtilities.invokeLater(new Runnable() { public void run() { luan = new Luan(); } } ); } public static Luan luan() throws LuanException { if( !SwingUtilities.isEventDispatchThread() ) throw new LuanException("Not in swing thread"); if( luan==null ) throw new LuanException("Not initialized"); return luan; } public static void exception(LuanException e) { System.err.println(e.getLuanStackTraceString()); System.exit(1); } private static void exception(String msg) { exception( new LuanException(msg) ); } private static Runnable runnable(final LuanFunction fn) { return new Runnable() { public void run() { try { fn.call(luan()); } catch(LuanException e) { exception(e); } catch(LuanRuntimeException e) { exception(e.luanException); } } }; } public static void run(LuanFunction fn) throws InterruptedException, InvocationTargetException { SwingUtilities.invokeAndWait(runnable(fn)); } public static void runLater(LuanFunction fn) throws InterruptedException, InvocationTargetException { SwingUtilities.invokeLater(runnable(fn)); } public static ActionListener newActionListener(final LuanFunction fn) throws LuanException { if( fn == null ) exception("function is null"); if( !fn.canTake(1) ) exception("action listener function must take event parameter"); return new ActionListener() { @Override public void actionPerformed(ActionEvent event) { try { LuanTable t = new LuanTable(); Object source = event.getSource(); if( source instanceof JComponent ) { JComponent jcomponent = (JComponent)source; Object component = jcomponent.getClientProperty("luan"); if( component != null ) t.rawPut("source",component); } String action = event.getActionCommand(); if( action != null ) t.rawPut("action",action); fn.call(luan(),t); } catch(LuanException e) { //throw new LuanRuntimeException(e); exception(e); } } }; } public static WindowListener newCloseListener(final LuanFunction fn) { return new WindowAdapter() { @Override public void windowClosed(WindowEvent event) { try { fn.call(luan()); } catch(LuanException e) { exception(e); } } }; } public static WindowListener newWindowFocusListener(final LuanFunction fn) { return new WindowAdapter() { @Override public void windowGainedFocus(WindowEvent event) { try { fn.call(luan()); } catch(LuanException e) { exception(e); } } }; } public static ComponentListener newResizeListener(final LuanFunction fn) { return new ComponentAdapter() { @Override public void componentResized(ComponentEvent event) { try { fn.call(luan()); } catch(LuanException e) { exception(e); } } }; } public static void notifyAfterResizeStops(Component comp,final ComponentListener cl,int timeAfterStopped) { comp.addComponentListener( new ComponentAdapter() { ComponentEvent event; final Timer timer = new Timer( timeAfterStopped, new ActionListener() { @Override public void actionPerformed(ActionEvent _e) { cl.componentResized(event); } } ); { timer.setRepeats(false); } @Override public void componentResized(ComponentEvent event) { this.event = event; timer.restart(); } } ); } public static ComponentListener newMoveListener(final LuanFunction fn) { return new ComponentAdapter() { @Override public void componentMoved(ComponentEvent event) { try { fn.call(luan()); } catch(LuanException e) { exception(e); } } }; } public static ChangeListener newChangeListener(final LuanFunction fn) { return new ChangeListener() { @Override public void stateChanged(ChangeEvent event) { try { fn.call(luan()); } catch(LuanException e) { exception(e); } } }; } public static void notifyAfterMoveStops(Component comp,final ComponentListener cl,int timeAfterStopped) { comp.addComponentListener( new ComponentAdapter() { ComponentEvent event; final Timer timer = new Timer( timeAfterStopped, new ActionListener() { @Override public void actionPerformed(ActionEvent _e) { cl.componentMoved(event); } } ); { timer.setRepeats(false); } @Override public void componentMoved(ComponentEvent event) { this.event = event; timer.restart(); } } ); } public static void fixTextComponent(final JTextComponent tc) { tc.getInputMap().put(KeyStroke.getKeyStroke("meta Z"),"undo"); Action undoAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { UndoManager undoManager = (UndoManager)tc.getDocument().getProperty("undo"); if( undoManager.canUndo() ) undoManager.undo(); } }; tc.getActionMap().put("undo",undoAction); tc.getInputMap().put(KeyStroke.getKeyStroke("shift meta Z"),"redo"); Action redoAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { UndoManager undoManager = (UndoManager)tc.getDocument().getProperty("undo"); if( undoManager.canRedo() ) undoManager.redo(); } }; tc.getActionMap().put("redo",redoAction); } public static void scrollIntoViewVertically(JComponent component) throws LuanException { Rectangle bounds = component.getBounds(); int y1 = bounds.y; int dy = bounds.height; Component c; for( c = component.getParent(); !(c instanceof JViewport); c = c.getParent() ) { if( c == null ) throw new LuanException("Not inside a viewport"); bounds = c.getBounds(); y1 += bounds.y; } JViewport viewport = (JViewport)c; y1 -= viewport.getView().getBounds().y; int y2 = y1 + dy; Point p = viewport.getViewPosition(); int y1View = p.y; int y2View = y1View + viewport.getBounds().height; if( y1View > y1 ) { p.y = y1; viewport.setViewPosition(p); } else if ( y2View < y2 ) { p.y += y2 - y2View; viewport.setViewPosition(p); } } public static boolean isWordChar(char c) { return Character.isLetterOrDigit(c) || c=='_'; } public static abstract class SelectAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { JTextComponent comp = (JTextComponent) e.getSource(); int offset = comp.getCaretPosition(); String text = comp.getText(); if (offset < 0 || offset >= text.length()) { return; } if (!ok(text.charAt(offset))) { //select(offset, offset); return; } int start = offset; while (start > 0 && ok(text.charAt(start - 1))) start--; int end = offset; while (end < text.length() && ok(text.charAt(end))) end++; comp.select(start, end); } abstract boolean ok(char c); } public static final Action selectWordAction = new SelectAction() { @Override boolean ok(char c) { return isWordChar(c); } }; public static final Action selectWordAndDotsAction = new SelectAction() { @Override boolean ok(char c) { return isWordChar(c) || c=='.'; } }; }