2021년 11월 21일 일요일

Java Swing Lined Text API

 1. Java Swing Lined Text API

package com.home.swing;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.MatteBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.*;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;

public class JSText {

	public JTextPane textPane;
	public JScrollPane ctrl;
	public LineNumber lineNumber;

	public JSText() {
		textPane = new JTextPane();
		lineNumber = new LineNumber(textPane);
		ctrl = new JScrollPane(textPane);
		ctrl.setRowHeaderView( lineNumber );
	}
	public JSText(String fontName, int fontSize) {
		this();
		textPane.setFont(new Font( fontName, Font.PLAIN, fontSize)); //Font.BOLD
	}

	public JTextPane getTextPane() { return textPane; }
	public JScrollPane getScrollPane() { return ctrl; }
	
	public static class LineNumber extends JPanel
	implements CaretListener, DocumentListener, PropertyChangeListener
	{
		private static final long serialVersionUID = 1L;
		public final static float LEFT = 0.0f;
		public final static float CENTER = 0.5f;
		public final static float RIGHT = 1.0f;
	
		private final Border OUTER = new MatteBorder(0, 0, 0, 2, Color.GRAY);
	
		private final static int HEIGHT = Integer.MAX_VALUE - 1000000;
	
		//  Text component this TextTextLineNumber component is in sync with
	
		private JTextComponent component;
	
		//  Properties that can be changed
	
		private boolean updateFont;
		private int borderGap;
		private Color currentLineForeground;
		private float digitAlignment;
		private int minimumDisplayDigits;
	
		//  Keep history information to reduce the number of times the component
		//  needs to be repainted
	
	    private int lastDigits;
	    private int lastHeight;
	    private int lastLine;
	
		private HashMap<String, FontMetrics> fonts;
	
		/**
		 *	Create a line number component for a text component. This minimum
		 *  display width will be based on 3 digits.
		 *
		 *  @param component  the related text component
		 */
		public LineNumber(JTextComponent component)
		{
			this(component, 3);
		}
	
		public LineNumber(JTextComponent component, int minimumDisplayDigits)
		{
			this.component = component;
	
			setFont( component.getFont() );
	
			setBorderGap( 5 );
			setCurrentLineForeground( Color.RED );
			setDigitAlignment( RIGHT );
			setMinimumDisplayDigits( minimumDisplayDigits );
	
			component.getDocument().addDocumentListener(this);
			component.addCaretListener( this );
			component.addPropertyChangeListener("font", this);
		}
	
		public boolean getUpdateFont()
		{
			return updateFont;
		}
	
		public void setUpdateFont(boolean updateFont)
		{
			this.updateFont = updateFont;
		}
	
		public int getBorderGap()
		{
			return borderGap;
		}
	
		public void setBorderGap(int borderGap)
		{
			this.borderGap = borderGap;
			Border inner = new EmptyBorder(0, borderGap, 0, borderGap);
			setBorder( new CompoundBorder(OUTER, inner) );
			lastDigits = 0;
			setPreferredWidth();
		}
	
		public Color getCurrentLineForeground()
		{
			return currentLineForeground == null ? getForeground() : currentLineForeground;
		}
	
		public void setCurrentLineForeground(Color currentLineForeground)
		{
			this.currentLineForeground = currentLineForeground;
		}
	
		public float getDigitAlignment()
		{
			return digitAlignment;
		}
	
		public void setDigitAlignment(float digitAlignment)
		{
			this.digitAlignment =
				digitAlignment > 1.0f ? 1.0f : digitAlignment < 0.0f ? -1.0f : digitAlignment;
		}
	
		public int getMinimumDisplayDigits()
		{
			return minimumDisplayDigits;
		}
	
		public void setMinimumDisplayDigits(int minimumDisplayDigits)
		{
			this.minimumDisplayDigits = minimumDisplayDigits;
			setPreferredWidth();
		}
	
		private void setPreferredWidth()
		{
			Element root = component.getDocument().getDefaultRootElement();
			int lines = root.getElementCount();
			int digits = Math.max(String.valueOf(lines).length(), minimumDisplayDigits);
	
			//  Update sizes when number of digits in the line number changes
	
			if (lastDigits != digits)
			{
				lastDigits = digits;
				FontMetrics fontMetrics = getFontMetrics( getFont() );
				int width = fontMetrics.charWidth( '0' ) * digits;
				Insets insets = getInsets();
				int preferredWidth = insets.left + insets.right + width;
	
				Dimension d = getPreferredSize();
				d.setSize(preferredWidth, HEIGHT);
				setPreferredSize( d );
				setSize( d );
			}
		}
	
		/**
		 *  Draw the line numbers
		 */
		@SuppressWarnings("deprecation")
		@Override
		public void paintComponent(Graphics g)
		{
			super.paintComponent(g);
	
			FontMetrics fontMetrics = component.getFontMetrics( component.getFont() );
			Insets insets = getInsets();
			int availableWidth = getSize().width - insets.left - insets.right;
	
			Rectangle clip = g.getClipBounds();
			int rowStartOffset = component.viewToModel( new Point(0, clip.y) );
			int endOffset = component.viewToModel( new Point(0, clip.y + clip.height) );
	
			while (rowStartOffset <= endOffset)
			{
				try
	            {
	    			if (isCurrentLine(rowStartOffset))
	    				g.setColor( getCurrentLineForeground() );
	    			else
	    				g.setColor( getForeground() );
	
	    			String lineNumber = getTextLineNumber(rowStartOffset);
	    			int stringWidth = fontMetrics.stringWidth( lineNumber );
	    			int x = getOffsetX(availableWidth, stringWidth) + insets.left;
					int y = getOffsetY(rowStartOffset, fontMetrics);
	    			g.drawString(lineNumber, x, y);
	
	    			rowStartOffset = Utilities.getRowEnd(component, rowStartOffset) + 1;
				}
				catch(Exception e) {break;}
			}
		}
	
		private boolean isCurrentLine(int rowStartOffset)
		{
			int caretPosition = component.getCaretPosition();
			Element root = component.getDocument().getDefaultRootElement();
	
			if (root.getElementIndex( rowStartOffset ) == root.getElementIndex(caretPosition))
				return true;
			else
				return false;
		}
	
		protected String getTextLineNumber(int rowStartOffset)
		{
			Element root = component.getDocument().getDefaultRootElement();
			int index = root.getElementIndex( rowStartOffset );
			Element line = root.getElement( index );
	
			if (line.getStartOffset() == rowStartOffset)
				return String.valueOf(index + 1);
			else
				return "";
		}
	
		private int getOffsetX(int availableWidth, int stringWidth)
		{
			return (int)((availableWidth - stringWidth) * digitAlignment);
		}
	
		private int getOffsetY(int rowStartOffset, FontMetrics fontMetrics)
			throws BadLocationException
		{
			Rectangle r = component.modelToView( rowStartOffset );
			int lineHeight = fontMetrics.getHeight();
			int y = r.y + r.height;
			int descent = 0;
	
			if (r.height == lineHeight)  // default font is being used
			{
				descent = fontMetrics.getDescent();
			}
			else  // We need to check all the attributes for font changes
			{
				if (fonts == null)
					fonts = new HashMap<String, FontMetrics>();
	
				Element root = component.getDocument().getDefaultRootElement();
				int index = root.getElementIndex( rowStartOffset );
				Element line = root.getElement( index );
	
				for (int i = 0; i < line.getElementCount(); i++)
				{
					Element child = line.getElement(i);
					AttributeSet as = child.getAttributes();
					String fontFamily = (String)as.getAttribute(StyleConstants.FontFamily);
					Integer fontSize = (Integer)as.getAttribute(StyleConstants.FontSize);
					String key = fontFamily + fontSize;
	
					FontMetrics fm = fonts.get( key );
	
					if (fm == null)
					{
						Font font = new Font(fontFamily, Font.PLAIN, fontSize);
						fm = component.getFontMetrics( font );
						fonts.put(key, fm);
					}
	
					descent = Math.max(descent, fm.getDescent());
				}
			}
	
			return y - descent;
		}
	
		//
		//  Implement CaretListener interface
		//
		@Override
		public void caretUpdate(CaretEvent e)
		{
			int caretPosition = component.getCaretPosition();
			Element root = component.getDocument().getDefaultRootElement();
			int currentLine = root.getElementIndex( caretPosition );
			if (lastLine != currentLine)
			{
	//			repaint();
				getParent().repaint();
				lastLine = currentLine;
			}
		}
	
		//
		//  Implement DocumentListener interface
		//
		@Override
		public void changedUpdate(DocumentEvent e)
		{
			documentChanged();
		}
	
		@Override
		public void insertUpdate(DocumentEvent e)
		{
			documentChanged();
		}
	
		@Override
		public void removeUpdate(DocumentEvent e)
		{
			documentChanged();
		}
	
		private void documentChanged()
		{
			SwingUtilities.invokeLater(new Runnable()
			{
				@SuppressWarnings("deprecation")
				@Override
				public void run()
				{
					try
					{
						int endPos = component.getDocument().getLength();
						Rectangle rect = component.modelToView(endPos);
	
						if (rect != null && rect.y != lastHeight)
						{
							setPreferredWidth();
	//						repaint();
							getParent().repaint();
							lastHeight = rect.y;
						}
					}
					catch (BadLocationException ex) { /* nothing to do */ }
				}
			});
		}
	
		@Override
		public void propertyChange(PropertyChangeEvent evt)
		{
			if (evt.getNewValue() instanceof Font)
			{
				if (updateFont)
				{
					Font newFont = (Font) evt.getNewValue();
					setFont(newFont);
					lastDigits = 0;
					setPreferredWidth();
				}
				else
				{
	//				repaint();
					getParent().repaint();
				}
			}
		}
	}	
}

Java Swing Table API

1. Java Swing Table API

package com.home.swing;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.Map;
import java.util.TreeMap;

public class JSTable {

    public JTable ctrl;
    Runnable selectedHandler;
    int selectedRow = -1;
    Map<Integer,Color> rowFgColor = new TreeMap<>();
    Map<Integer,Color> rowBgColor = new TreeMap<>();

    static class StripedTableCellRenderer extends DefaultTableCellRenderer {
        public Component getTableCellRendererComponent (JTable table, Object value, boolean selected, boolean focused, int row, int column) {
            setEnabled(table == null || table.isEnabled());
            if ((row % 2) == 0) setBackground(Color.green);
            else setBackground(Color.lightGray);
            super.getTableCellRendererComponent(table, value, selected, focused, row, column);
            return this;
        }
    }
    class ColoredTableCellRenderer extends DefaultTableCellRenderer {
        public Component getTableCellRendererComponent (JTable table, Object value, boolean selected, boolean focused, int row, int column) {
            setEnabled(table == null || table.isEnabled());
            Color fg = rowFgColor.get(row);
            Color bg = rowBgColor.get(row);
            if ( fg != null ) { setForeground(fg); } else setForeground(Color.black);
            if ( bg != null ) { setBackground(bg); } else setBackground(Color.white);
            super.getTableCellRendererComponent(table, value, selected, focused, row, column);
            return this;
        }
    }

    public JSTable(String[] colNames, int[] widths, int[] aligns, Runnable handler) {
        DefaultTableModel tableModel = new DefaultTableModel(colNames,0);
        ctrl = new JTable(tableModel) {
            private static final long serialVersionUID = 1L;
            public boolean isCellEditable(int row, int column) {
                return false;
            };
        };
        int colCount = ctrl.getModel().getColumnCount();
        if( widths != null ) {
            for (int col = 0; col < colCount && col < widths.length; col++) {
                ctrl.getColumnModel().getColumn(col).setPreferredWidth(widths[col]);
            }
        }
        if( aligns != null ) {
            for( int col = 0; col < colCount && col < aligns.length; col++ ) {
                //DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
                ColoredTableCellRenderer centerRenderer = new ColoredTableCellRenderer();
                if( aligns[col] < 0 ) centerRenderer.setHorizontalAlignment( SwingConstants.LEFT );
                if( aligns[col] == 0 ) centerRenderer.setHorizontalAlignment( SwingConstants.CENTER );
                if( aligns[col] > 0 ) centerRenderer.setHorizontalAlignment( SwingConstants.RIGHT );
                ctrl.getColumnModel().getColumn(col).setCellRenderer(centerRenderer);
            }
        }
        selectedHandler = handler;
        ctrl.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
            public void valueChanged(ListSelectionEvent event) {
                if( selectedRow != ctrl.getSelectedRow() ) {
                    selectedRow = ctrl.getSelectedRow();
                    selectedHandler.run();
                }
            }
        });
    }
    public void addRow( String[] row) {
        DefaultTableModel model = (DefaultTableModel) ctrl.getModel();
        model.addRow(row);
    }

    public String[] getSelectedRow() {
        int count = ctrl.getModel().getColumnCount();
        String[] row = new String[count];
        for( int r = 0; r < count; r++ ) {
            row[r] = ctrl.getValueAt( ctrl.getSelectedRow(), r).toString();
        }
        return row;
    }

    public String getValue(int row, int col) {
        return ctrl.getValueAt( row, col).toString();
    }
    public void setValue(int row, int col, String value) {
        ctrl.setValueAt( value, row, col);
    }
    public void setRowColor(int row, Color fg, Color bg) {
        rowFgColor.put(row,fg);
        rowBgColor.put(row,bg);
    }
}

Java Swing API

 1. Java Swing API

package com.home.swing;

import com.home.java.IconApi;

import javax.swing.*;
import java.awt.*;
import java.io.IOException;

public class JS {

    public static void runLater( Runnable handler ) {
        SwingUtilities.invokeLater(handler);
    }
    public static Dimension getScreenSize() { return Toolkit.getDefaultToolkit().getScreenSize(); }
    public static Double getScreenSizeWidth() { return Toolkit.getDefaultToolkit().getScreenSize().getWidth(); }
    public static Double getScreenHeight() { return Toolkit.getDefaultToolkit().getScreenSize().getHeight(); }

    public static void setWindowIcon(Frame frame, String icon) { frame.setIconImage( IconApi.getBase64Image(icon) ); }
    public static void setWindowIconRes(Frame frame, String image) throws IOException {
        /*
        ClassLoader cl = frame.getClass().getClassLoader();
        InputStream is = cl.getResourceAsStream(image);
        if( is != null )
            frame.setIconImage(ImageIO.read(is));
        */
    }
    public static void setWindowTitle(Frame frame, String title) { frame.setTitle(title); }
    public static void setWindowCenter(Frame frame) {
        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        Dimension frm = frame.getSize();
        int xpos = (int)(screen.getWidth() / 2 - frm.getWidth() / 2);
        int ypos = (int)(screen.getHeight() / 2 - frm.getHeight() / 2);
        frame.setLocation(xpos, ypos);
    }
    public static void addTop(Frame frame, JComponent obj) { frame.add( obj, BorderLayout.NORTH); }
    public static void addCenter(Frame frame, JComponent obj) { frame.add( obj, BorderLayout.CENTER); }
    public static void addBottom(Frame frame, JComponent obj) { frame.add( obj, BorderLayout.SOUTH); }

    public static JMenuBar getMenuBar() {
        JMenuBar menubar = new JMenuBar();
        menubar.add(getFileMenu());
        return menubar;
    }
    public static JMenu getFileMenu() {
        JMenu menu = new JMenu("File");
        JMenuItem exit_item = new JMenuItem("Exit");
        exit_item.addActionListener((e) -> { System.exit(0); });
        menu.add(exit_item);
        return menu;
    }

    public static JSplitPane getHSplitPane(JComponent left, JComponent right) {
        JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right);
        split.setDividerLocation(400);
        split.setResizeWeight(1);
        return split;
    }
    public static JSplitPane getVSplitPane(JComponent left, JComponent right) {
        JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, left, right);
        split.setDividerLocation(400);
        split.setResizeWeight(1);
        return split;
    }

    public static JTabbedPane getTabbedPane() {
        JTabbedPane pane = new JTabbedPane();
        return pane;
    }
    public static void addTab( JTabbedPane pane, String name, JComponent node) {
        pane.add( name, node );
    }
}

[Java] Java Swing Application Example

 1. Java Swing Application Example



package com.home.app;

import com.formdev.flatlaf.FlatLightLaf;
import com.home.swing.JS;
import com.home.swing.JSTable;
import com.home.swing.JSText;
import com.home.swing.JSTree;

import javax.swing.*;
import java.awt.*;
import java.io.IOException;

public class SwingListViewer {

    JFrame frame;
    JSplitPane mainSp;
    JSplitPane leftSp;
    JTabbedPane leftBottom;
    JSTable list;
    JSTree detail;
    JSText hexdump;
    JLabel status;

    String[] tableCols = {"index", "time", "info"};
    int[] tableWidth = { 50, 200, 480 };
    int[] tableAlign = { 1, 0, -1 };

    public static void main( String[] args) throws IOException {
        FlatLightLaf.install(); //Must be called first of all Swing code.
        new SwingListViewer().start();
    }

    private void setTestData() {
        list.addRow(new String[] {"1", "2020.01.01 12:00:00", "Information 1" } );
        list.addRow(new String[] {"2", "2020.01.01 12:01:00", "Information 2" } );
        list.addRow(new String[] {"3", "2020.01.01 12:02:00", "Information 3" } );
        list.setRowColor(0, Color.BLUE, Color.LIGHT_GRAY);
        list.setRowColor(1, Color.WHITE, Color.BLACK);

        detail.addTreeToRoot("Tree1");
        detail.addTreeToRoot("Tree2");
    }
    private void start() throws IOException {

        frame = new JFrame("Swing Application Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JS.setWindowIconRes(frame, "res/appicon.ico");
        list = new JSTable(tableCols, tableWidth, tableAlign, this::listHandler );
        detail = new JSTree("Packet Details", this::treeHandler );
        hexdump = new JSText();
        leftBottom = JS.getTabbedPane();
        JS.addTab( leftBottom, "Hexdump", hexdump.ctrl);
        leftSp = JS.getVSplitPane(new JScrollPane(list.ctrl), leftBottom);
        mainSp = JS.getHSplitPane(leftSp, new JScrollPane(detail.ctrl));
        status = new JLabel("Ready");

        frame.getContentPane().add(JS.getMenuBar(), BorderLayout.NORTH);
        frame.getContentPane().add(mainSp, BorderLayout.CENTER);
        frame.getContentPane().add(status, BorderLayout.SOUTH);
        frame.pack();
        frame.setSize( new Dimension(600, 600));
        frame.setLocationRelativeTo(null);

        setTestData();
        frame.setVisible(true);
    }

    public void listHandler() {
        String[] paths = list.getSelectedRow();
        if( paths != null && paths.length > 0 ) {
            for( String path : paths )
                System.out.println( path + " -> " );
        }
    }
    public void treeHandler() {
        String[] paths = detail.getSelectedTreePath();
        if( paths != null && paths.length > 0 ) {
            for( String path : paths )
                System.out.println( path + " -> " );
        }
    }
}

2021년 9월 25일 토요일

[Python| Markdown file merge

Markdown File Merge

import os
import sys

def text_merge(folder):
    files = sorted(os.listdir(folder))
    with open( folder + ".md", "w", encoding="utf-8" ) as w:
        for f in files:
            path = os.path.join(folder,f)
            with open( path, "r", encoding='utf-8') as r:
                w.write(r.read())
                w.write('\n\n<div style="page-break-after: always;"></div><br>\n\n')
                print(path)
        
if __name__ == "__main__":
    if len(sys.argv) > 1:
        text_merge(sys.argv[1])

2021년 8월 22일 일요일

[Java] Change Encoding to UTF-8


Change Encoding to UTF-8

package com.zdiv.jlib.app.CharConv;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

import org.apache.commons.io.IOUtils;

public class CharConv {

    public static void main(String[] args) {
        String directory = "d:\\Ebook\\가림토txt\\객주\\";
        File dir = new File(directory);
        if( dir.exists() ) {
            File[] files = dir.listFiles();
            for( File f : files ) {
                if( ! f.isDirectory() ) {
                    String outFileName = f.getAbsolutePath() + ".out";
                    System.out.println(outFileName );
                    try {
                        String dataStr = IOUtils.toString(new FileInputStream(f), "CP949");
                        byte[] dataByte = dataStr.getBytes("UTF-8");
                        Files.write(Paths.get(outFileName), dataByte, StandardOpenOption.CREATE);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

2021년 8월 18일 수요일

[Python] Any to UTF-8

 Any codec to UTF-8

#-*- coding: utf-8 -*-

import sys    
import os

def file_enc(path):
    import chardet
    with open( path, "rb" ) as f:
        return chardet.detect(f.read()).get('encoding')
    
def py2_euc2utf(in_file, out_file):
    with open(in_file, "r") as f:
        euc = f.read().decode('cp949') #encode('cp949').decode('cp437')
        #euc = f.read().decode('euc_kr') #encode('cp949').decode('cp437')
        utf = euc.encode('utf-8')
        with open(out_file, "w") as w:
            w.write(utf)

def py3_euc2utf(in_file, out_file):
    with open(in_file, "r", encoding=file_enc(in_file)) as f:
        utf = f.read()
        with open(out_file, "w", encoding="utf-8") as w:
            w.write(utf)

def euc2utf(in_file, out_file):
    if sys.version_info.major == 3: py3_euc2utf(in_file,  out_file + '.py3')
    else: py2_euc2utf(in_file, out_file + '.py2')

    
def filelist(path):
    from os import listdir
    from os.path import isfile, join
    return [f for f in listdir(path) if isfile(join(path, f))]

if __name__ == "__main__":
    in_dir = r"d:/Ebook/가림토txt"
    out_dir = r"d:Ebook/가림토txt_utf"
    if not os.path.exists(out_dir):
        os.mkdir(out_dir)
    files = filelist(in_dir)
    for f in files:
        print(f, file_enc(os.path.join(in_dir,f)))
        try:
            euc2utf(os.path.join(in_dir,f),os.path.join(out_dir,f))
        except:
            print(f, "--------------> ERROR")