Popular Posts
Enable SSL connection for Jsoup import org.jsoup.Connection; import org.jsoup.Jsoup; import javax.net.ssl.*; import java.io.IOException; import java.security.KeyManagement... Join related table and count rows or sum sql server 2005 count rows: SELECT * FROM Table1 LEFT JOIN     (SELECT Level1ID, COUNT(Level2ID) AS Total FROM Table2 GROUP BY Level1ID) AS... Append soap header into axis When axis generate classese of web service, it won't include the request of soap header. Here is a way to append soap header manually i...
Blog Archive
Stats
JDateField
package bruce.lib.swing;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;

import bruce.lib.swing.JDatePickPane.PickDate;

/**
 * @author Bruce (NaNashi)
 * 
 */
public class JDateField extends JPanel {

    private JButton btnPopup;
    private JTextField txtInput;
    private Calendar c;

    private String format;
    private String[] dayDisplayNames;
    private Locale locale;
    private Icon leftArrow;
    private Icon rightArrow;
    private boolean isCloseOnClick;

    public JDateField() {
        super(new GridBagLayout());

        this.locale = Locale.getDefault();
        this.format = JDatePickPane.DEFAULT_DATE_FORMAT;

        this.leftArrow = JDatePickPane.getImageIcon("/bruce/lib/swing/img/Arrow.blue.left.png", 20, 20);
        this.rightArrow = JDatePickPane.getImageIcon("/bruce/lib/swing/img/Arrow.blue.right.png", 20, 20);

        this.txtInput = new JTextField();
        this.txtInput.setEditable(false);
        this.add(this.txtInput, new GridBagConstraints(0, 0, 1, 1, 1, 0, 10, 2, new Insets(1, 1, 1, 1), 0, 0));

        try {
            btnPopup = new JButton(new ImageIcon(this.getClass().getResource("/bruce/lib/swing/img/calendar-date-icon.png")));
            btnPopup.setBorder(BorderFactory.createEmptyBorder());
            btnPopup.setBorderPainted(false);
        } catch (Exception e) {
            btnPopup = new JButton("P");
        }
        btnPopup.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                popup();
            }
        });
        this.add(btnPopup, new GridBagConstraints(1, 0, 1, 1, 0, 0, 10, 2, new Insets(1, 1, 1, 1), 0, 0));
    }

    public JDateField(int columns) {
        this();
        this.txtInput.setColumns(columns);
    }

    public JDateField(Calendar c) {
        this();
        this.setSelectedDateText(c);
    }

    public JDateField(Calendar c, int columns) {
        this(c);
        this.txtInput.setColumns(columns);
    }

    private void popup() {
        JDatePickDialog dialog = new JDatePickDialog(this.txtInput);
        dialog.setTodayFormat(this.format);
        dialog.setDayName(this.dayDisplayNames);
        dialog.setUILocale(this.locale);
        dialog.setLeftArrow(this.leftArrow);
        dialog.setRightArrow(this.rightArrow);

        dialog.setDateSelected(new PickDate() {
            @Override
            public void pick(Calendar c) {
                setSelectedDateText(c);
            }
        });

        try {
            dialog.view(txtInput.getText().trim());
        } catch (Exception ex) {
            dialog.view();
        }
    }

    public void setFormat(String format) {
        this.format = format;
        this.setSelectedDateText(this.c);
    }

    public String getFormat() {
        return this.format == null ? JDatePickPane.DEFAULT_DATE_FORMAT : this.format;
    }

    public String[] getDayDisplayNames() {
        return dayDisplayNames;
    }

    public void setDayDisplayNames(String[] dayDisplayNames) {
        this.dayDisplayNames = dayDisplayNames;
    }

    public Locale getUILocale() {
        return locale;
    }

    public void setUILocale(Locale locale) {
        this.locale = locale;
    }

    public Icon getLeftArrow() {
        return leftArrow;
    }

    public void setLeftArrow(Icon leftArrow) {
        this.leftArrow = leftArrow;
    }

    public Icon getRightArrow() {
        return rightArrow;
    }

    public void setRightArrow(Icon rightArrow) {
        this.rightArrow = rightArrow;
    }

    public void setCloseOnClick(boolean isCloseOnClick) {
        this.isCloseOnClick = isCloseOnClick;
    }

    public boolean isCloseOnClick() {
        return isCloseOnClick;
    }

    public int getColumns() {
        return this.txtInput.getColumns();
    }

    public void setColumns(int columns) {
        this.txtInput.setColumns(columns);
    }

    public void setButtonVisible(boolean b) {
        this.btnPopup.setVisible(b);
        if (b) {
            MouseListener[] ls = this.txtInput.getMouseListeners();
            for (MouseListener l : ls) {
                this.txtInput.removeMouseListener(l);
            }
        } else {
            this.txtInput.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    popup();
                }
            });
        }
    }

    public void setSelectedDateText(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        this.setSelectedDateText(c);
    }

    public void setSelectedDateText(Calendar c) {
        this.c = c;
        if (this.format == null) {
            this.txtInput.setText(String.format("%tF", c));
        } else {
            try {
                SimpleDateFormat f = new SimpleDateFormat(this.format);
                this.txtInput.setText(f.format(c.getTime()));
            } catch (Exception ex) {
                this.txtInput.setText(String.format("%tF", c));
            }
        }
    }

    public Calendar getSelectedCalender() {
        return this.c == null ? Calendar.getInstance() : this.c;
    }

}
package bruce.lib.swing;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JDialog;

import bruce.lib.swing.JDatePickPane.PickDate;

/**
 * @author Bruce (NaNashi)
 * 
 */
public class JDatePickDialog extends JDialog {

    private boolean isCloseOnClick;

    public JDatePickDialog() {
        this.init();

        Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
        this.setLocation(new Point((size.width - this.getWidth()) / 2, (size.height - this.getHeight()) / 2));
    }

    public JDatePickDialog(Component c) {
        this.setUndecorated(true);
        this.init();

        this.getContent().setBorder(BorderFactory.createEtchedBorder());

        this.addWindowFocusListener(new WindowFocusListener() {
            @Override
            public void windowLostFocus(WindowEvent e) {
                setVisible(false);
                dispose();
            }

            @Override
            public void windowGainedFocus(WindowEvent e) {
                // TODO Auto-generated method stub

            }
        });

        if (c != null) {
            Point p = c.getLocationOnScreen();
            this.setLocation(new Point(p.x, p.y + c.getHeight()));
        } else {
            Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
            this.setLocation((int) (dim.getWidth() - this.getWidth()) / 2, (int) (dim.getHeight() - this.getHeight()) / 2);
        }
    }

    private void init() {
        this.isCloseOnClick = true;

        this.setContentPane(new JDatePickPane());

        this.setDateSelected(new PickDate() {
            @Override
            public void pick(Calendar c) {
                // 預設值
            }
        });

        this.pack();
    }

    private JDatePickPane getContent() {
        return (JDatePickPane) this.getContentPane();
    }

    public void setCloseOnClick(boolean isCloseOnClick) {
        this.isCloseOnClick = isCloseOnClick;
    }

    public boolean isCloseOnClick() {
        return isCloseOnClick;
    }

    // ========== panel method ================
    /**
     * 選取日期的觸發動作
     * 
     * @param pick
     */
    public void setDateSelected(final PickDate pick) {
        PickDate pd = new PickDate() {
            @Override
            public void pick(Calendar c) {
                pick.pick(c);
                if (isCloseOnClick) {
                    setVisible(false);
                    dispose();
                }
            }
        };
        this.getContent().setDateSelected(pd);
    }

    /**
     * 目前選取日期
     * 
     * @return
     */
    public Calendar getSelectedCalendar() {
        return this.getContent().getSelectedCalendar();
    }

    /**
     * 設定選取的日期
     * 
     * @param c
     */
    public void setSelectedCalendar(Calendar c) {
        this.getContent().setSelectedCalendar(c);
    }

    /**
     * 取得星期的顯示名稱
     * 
     * @return
     */
    public String[] getDayNames() {
        return this.getContent().getDayNames();
    }

    /**
     * 設定星期的顯示名稱
     * 
     * @param names
     */
    public void setDayName(String[] names) {
        this.getContent().setDayName(names);
    }

    /**
     * 設定今天的顯示格式
     * 
     * @param format
     */
    public void setTodayFormat(String format) {
        this.getContent().setTodayFormat(format);
    }

    public String getTodayFormat() {
        return this.getContent().getTodayFormat();
    }

    public void setUILocale(Locale l) {
        this.getContent().setUILocale(l);
    }

    public Locale getUILocale() {
        return this.getContent().getUILocale();
    }

    public void setLeftArrow(Icon icon) {
        this.getContent().setLeftArrow(icon);
    }

    public void setRightArrow(Icon icon) {
        this.getContent().setRightArrow(icon);
    }

    /**
     * 顯示選擇的日期
     * 
     * @param c
     */
    public void view(Calendar c) {
        this.getContent().view(c);
        this.setVisible(true);
    }

    public void view(String date) throws ParseException {
        SimpleDateFormat f = new SimpleDateFormat(this.getContent().getTodayFormat());
        Calendar c = Calendar.getInstance();
        c.setTime(f.parse(date));
        this.getContent().setSelectedCalendar(c);
        this.view(c);
    }

    /**
     * 顯示今天的日期
     */
    public void view() {
        this.getContent().view();
        this.setVisible(true);
    }
}
package bruce.lib.swing;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

/**
 * @author Bruce (NaNashi)
 * 
 */
public class JDatePickPane extends JPanel {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";

    public static Icon getImageIcon(String location, double width, double height) {
        try {
            BufferedImage icon = ImageIO.read(String.class.getResource(location));
            // resize image
            AffineTransform transform = AffineTransform.getScaleInstance(width / icon.getWidth(), height / icon.getHeight());
            AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
            return new ImageIcon(op.filter(icon, null));
        } catch (Exception e) {
            return null;
        }
    }

    public interface PickDate {
        void pick(Calendar c);
    }

    class DayCell extends JButton {
        private long stamp;

        DayCell(Calendar c, Calendar currentMonth, Calendar selected) {
            super(String.valueOf(c.get(Calendar.DATE)));

            stopWatch("Day Cell");

            this.stamp = c.getTimeInMillis();
            Calendar now = Calendar.getInstance();
            if (c.get(Calendar.YEAR) == now.get(Calendar.YEAR) && c.get(Calendar.MONTH) == now.get(Calendar.MONTH) && c.get(Calendar.DATE) == now.get(Calendar.DATE)) {
                this.setBorder(BorderFactory.createLineBorder(Color.BLUE));
                this.setForeground(Color.BLUE);
                this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));
            } else if (c.get(Calendar.YEAR) != currentMonth.get(Calendar.YEAR) || c.get(Calendar.MONTH) != currentMonth.get(Calendar.MONTH)) {
                this.setForeground(Color.GRAY);
                this.setBorder(BorderFactory.createEtchedBorder());
            } else {
                this.setBorder(BorderFactory.createEtchedBorder());
            }
            if (c.get(Calendar.YEAR) == selected.get(Calendar.YEAR) && c.get(Calendar.MONTH) == selected.get(Calendar.MONTH) && c.get(Calendar.DATE) == selected.get(Calendar.DATE)) {
                this.setBorder(BorderFactory.createLineBorder(Color.RED));
                this.setForeground(Color.RED);
                this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));
            }

            this.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseExited(MouseEvent e) {
                    setBackground(null);
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    setBackground(Color.white);
                }
            });
            this.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JDatePickPane pick = (JDatePickPane) getParent().getParent();
                    pick.selectedDate.setTimeInMillis(stamp);

                    pick.view(pick.selectedDate);

                    if (pick.pickAtion != null) {
                        pick.pickAtion.pick(pick.selectedDate);
                    }
                }
            });
        }
    }

    class MonthCell extends JButton {
        private long stamp;

        public MonthCell(Calendar c, Calendar selected) {
            super(c.getDisplayName(Calendar.MONTH, Calendar.SHORT, loc));

            stopWatch("Month Cell");

            this.stamp = c.getTimeInMillis();
            this.setBorder(BorderFactory.createEtchedBorder());
            this.setPreferredSize(new Dimension(50, 50));

            Calendar now = Calendar.getInstance();
            if (c.get(Calendar.YEAR) == now.get(Calendar.YEAR) && c.get(Calendar.MONTH) == now.get(Calendar.MONTH)) {
                this.setBorder(BorderFactory.createLineBorder(Color.BLUE));
                this.setForeground(Color.BLUE);
                this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));

            } else {
                this.setBorder(BorderFactory.createEtchedBorder());
            }
            if (c.get(Calendar.YEAR) == selected.get(Calendar.YEAR) && c.get(Calendar.MONTH) == selected.get(Calendar.MONTH)) {
                this.setBorder(BorderFactory.createLineBorder(Color.RED));
                this.setForeground(Color.RED);
                this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));
            }

            this.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseExited(MouseEvent e) {
                    setBackground(null);
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    setBackground(Color.white);
                }
            });
            this.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Calendar c = Calendar.getInstance();
                    c.setTimeInMillis(stamp);

                    JDatePickPane pick = (JDatePickPane) getParent().getParent();
                    pick.view(c);
                }
            });
        }
    }

    class YearCell extends JButton {
        private long stamp;

        public YearCell(Calendar c, Calendar selected) {
            super(String.valueOf(c.get(Calendar.YEAR)));

            stopWatch("Year Cell");

            this.stamp = c.getTimeInMillis();
            this.setBorder(BorderFactory.createEtchedBorder());
            this.setPreferredSize(new Dimension(50, 50));

            Calendar now = Calendar.getInstance();
            if (c.get(Calendar.YEAR) == now.get(Calendar.YEAR)) {
                this.setBorder(BorderFactory.createLineBorder(Color.BLUE));
                this.setForeground(Color.BLUE);
                this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));

            } else {
                this.setBorder(BorderFactory.createEtchedBorder());
            }
            if (c.get(Calendar.YEAR) == selected.get(Calendar.YEAR)) {
                this.setBorder(BorderFactory.createLineBorder(Color.RED));
                this.setForeground(Color.RED);
                this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));
            }

            this.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseExited(MouseEvent e) {
                    setBackground(null);
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    setBackground(Color.white);
                }
            });
            this.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Calendar c = Calendar.getInstance();
                    c.setTimeInMillis(stamp);

                    JDatePickPane pick = (JDatePickPane) getParent().getParent();
                    pick.viewMonth(c);
                }
            });
        }
    }

    private String format;

    private Calendar selectedDate;

    private PickDate pickAtion;

    private String[] dayDisplayNames;

    private Locale loc;

    private Icon leftArrow;
    private Icon rightArrow;

    public JDatePickPane() {
        this.selectedDate = Calendar.getInstance();
        this.setLayout(new BorderLayout());
        this.selectedDate = Calendar.getInstance();
        this.loc = Locale.getDefault();
        this.format = JDatePickPane.DEFAULT_DATE_FORMAT;

        this.leftArrow = getImageIcon("/bruce/lib/swing/img/Arrow.blue.left.png", 20, 20);
        this.rightArrow = getImageIcon("/bruce/lib/swing/img/Arrow.blue.right.png", 20, 20);

        this.view();
    }

    private void putToday() {
        stopWatch("Today Bar");

        JPanel panel = new JPanel(new FlowLayout());
        String today = String.format("%tF", Calendar.getInstance());
        try {
            if (this.format != null) {
                SimpleDateFormat f = new SimpleDateFormat(this.format);
                today = f.format(new Date());
            }
        } catch (Exception e) {
        }
        final JLabel lbToday = new JLabel(today);
        lbToday.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                lbToday.setFont(lbToday.getFont().deriveFont(Font.BOLD, lbToday.getFont().getSize()));
            }

            @Override
            public void mouseExited(MouseEvent e) {
                lbToday.setFont(lbToday.getFont().deriveFont(Font.PLAIN, lbToday.getFont().getSize()));
            }

            @Override
            public void mouseClicked(MouseEvent e) {
                selectedDate = Calendar.getInstance();
                view(selectedDate);

                if (pickAtion != null) {
                    pickAtion.pick(selectedDate);
                }
            }
        });
        panel.add(lbToday);
        this.add(panel, BorderLayout.SOUTH);
    }

    private void setYearBarText(JLabel label, Calendar c) {
        label.setText(String.format("%d - %d", //
                c.get(Calendar.YEAR) - c.get(Calendar.YEAR) % 12 + 1,//
                c.get(Calendar.YEAR) - c.get(Calendar.YEAR) % 12 + 12));
    }

    private void putYearBar(final Calendar c) {
        stopWatch("Year Bar");

        JPanel panel = new JPanel(new BorderLayout());

        final JLabel lbPeriod = new JLabel();
        lbPeriod.setHorizontalAlignment(SwingConstants.CENTER);
        this.setYearBarText(lbPeriod, c);
        panel.add(lbPeriod, BorderLayout.CENTER);

        JButton btnLeft = this.leftArrow == null ? new JButton("<") : new JButton(this.leftArrow);
        btnLeft.setBorderPainted(false);
        btnLeft.setBorder(BorderFactory.createEmptyBorder());
        btnLeft.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Calendar s = (Calendar) c.clone();
                s.add(Calendar.YEAR, -12);

                setYearBarText(lbPeriod, c);
                viewYear(s);
            }
        });
        panel.add(btnLeft, BorderLayout.WEST);

        JButton btnRight = this.rightArrow == null ? new JButton(">") : new JButton(this.rightArrow);
        btnRight.setBorderPainted(false);
        btnRight.setBorder(BorderFactory.createEmptyBorder());
        btnRight.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Calendar s = (Calendar) c.clone();
                s.add(Calendar.YEAR, 12);

                setYearBarText(lbPeriod, c);
                viewYear(s);
            }
        });
        panel.add(btnRight, BorderLayout.EAST);

        this.add(panel, BorderLayout.NORTH);
    }

    private void setMonthBarText(JButton label, Calendar c) {
        label.setText(String.valueOf(c.get(Calendar.YEAR)));
    }

    private void putMonthBar(final Calendar c) {
        stopWatch("Month Bar");

        JPanel panel = new JPanel(new BorderLayout());

        final JButton btnPeriod = new JButton();
        btnPeriod.setHorizontalAlignment(SwingConstants.CENTER);
        btnPeriod.setBorder(BorderFactory.createEmptyBorder());
        btnPeriod.setBorderPainted(false);

        this.setMonthBarText(btnPeriod, c);
        btnPeriod.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                viewYear(c);
            }
        });
        btnPeriod.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                btnPeriod.setFont(btnPeriod.getFont().deriveFont(Font.BOLD, btnPeriod.getFont().getSize()));
            }

            @Override
            public void mouseExited(MouseEvent e) {
                btnPeriod.setFont(btnPeriod.getFont().deriveFont(Font.PLAIN, btnPeriod.getFont().getSize()));
            }
        });
        panel.add(btnPeriod, BorderLayout.CENTER);

        JButton btnLeft = this.leftArrow == null ? new JButton("<") : new JButton(this.leftArrow);
        btnLeft.setBorderPainted(false);
        btnLeft.setBorder(BorderFactory.createEmptyBorder());
        btnLeft.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Calendar s = (Calendar) c.clone();
                s.add(Calendar.YEAR, -1);

                setMonthBarText(btnPeriod, c);
                viewMonth(s);
            }
        });
        panel.add(btnLeft, BorderLayout.WEST);

        JButton btnRight = this.rightArrow == null ? new JButton(">") : new JButton(this.rightArrow);
        btnRight.setBorderPainted(false);
        btnRight.setBorder(BorderFactory.createEmptyBorder());
        btnRight.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Calendar s = (Calendar) c.clone();
                s.add(Calendar.YEAR, 1);
                setMonthBarText(btnPeriod, c);

                viewMonth(s);
            }
        });
        panel.add(btnRight, BorderLayout.EAST);

        this.add(panel, BorderLayout.NORTH);
    }

    private void setDateBarText(JButton label, Calendar c) {
        label.setText(String.format("%s, %d", //
                c.getDisplayName(Calendar.MONTH, Calendar.LONG, loc),//
                c.get(Calendar.YEAR)));
    }

    private void putDateBar(final Calendar c) {
        stopWatch("Date Bar");

        JPanel panel = new JPanel(new BorderLayout());

        final JButton btnPeriod = new JButton();
        btnPeriod.setHorizontalAlignment(SwingConstants.CENTER);
        btnPeriod.setBorder(BorderFactory.createEmptyBorder());
        btnPeriod.setBorderPainted(false);

        this.setDateBarText(btnPeriod, c);
        btnPeriod.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                viewMonth(c);
            }
        });
        btnPeriod.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                btnPeriod.setFont(btnPeriod.getFont().deriveFont(Font.BOLD, btnPeriod.getFont().getSize()));
            }

            @Override
            public void mouseExited(MouseEvent e) {
                btnPeriod.setFont(btnPeriod.getFont().deriveFont(Font.PLAIN, btnPeriod.getFont().getSize()));
            }
        });
        panel.add(btnPeriod, BorderLayout.CENTER);

        JButton btnLeft = this.leftArrow == null ? new JButton("<") : new JButton(this.leftArrow);
        btnLeft.setBorderPainted(false);
        btnLeft.setBorder(BorderFactory.createEmptyBorder());
        btnLeft.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Calendar s = (Calendar) c.clone();
                s.add(Calendar.MONTH, -1);

                view(s);

                setDateBarText(btnPeriod, c);
            }
        });
        panel.add(btnLeft, BorderLayout.WEST);

        JButton btnRight = this.rightArrow == null ? new JButton(">") : new JButton(this.rightArrow);
        btnRight.setBorderPainted(false);
        btnRight.setBorder(BorderFactory.createEmptyBorder());
        btnRight.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Calendar s = (Calendar) c.clone();
                s.add(Calendar.MONTH, 1);

                view(s);

                setDateBarText(btnPeriod, c);
            }
        });
        panel.add(btnRight, BorderLayout.EAST);

        this.add(panel, BorderLayout.NORTH);
    }

    private void putYearContent(Calendar c) {
        stopWatch("Year Bar");

        JPanel panel = new JPanel(new GridLayout(3, 4));

        Calendar s = (Calendar) c.clone();
        s.set(Calendar.YEAR, s.get(Calendar.YEAR) - s.get(Calendar.YEAR) % 12);
        for (int i = 0; i < 12; i++) {
            s.add(Calendar.YEAR, 1);
            panel.add(new YearCell(s, this.selectedDate));
        }

        this.add(panel, BorderLayout.CENTER);
    }

    private void putMonthContent(Calendar c) {
        stopWatch("Month Bar");

        JPanel panel = new JPanel(new GridLayout(3, 4));

        Calendar s = (Calendar) c.clone();
        for (int i = 0; i < 12; i++) {
            s.set(Calendar.MONTH, i);
            panel.add(new MonthCell(s, this.selectedDate));
        }

        this.add(panel, BorderLayout.CENTER);
    }

    private void putDateContent(Calendar c) {
        stopWatch("Date Content");

        JPanel panel = new JPanel(new GridBagLayout());
        Insets insets = new Insets(1, 1, 1, 1);
        this.putHeaders(panel, insets);

        int rows = this.getMonthRowsCount(c);
        Calendar d = this.getFirstDate(c);

        for (int y = 1; y < rows + 1; y++) {
            for (int x = 1; x < 8; x++) {
                panel.add(new DayCell(d, c, this.selectedDate), new GridBagConstraints(x, y, 1, 1, 0, 0, 10, 1, insets, 10, 0));
                d.add(Calendar.DATE, 1);
            }
        }

        this.add(panel, BorderLayout.CENTER);
    }

    private void viewYear(Calendar c) {
        this.clear();
        this.putYearContent(c);
        this.putYearBar(c);
        this.pack();
    }

    private void viewMonth(Calendar c) {
        this.clear();
        this.putMonthContent(c);
        this.putMonthBar(c);

        this.pack();
    }

    /**
     * 處理星期顯示格
     * 
     * @param panel
     * @param insets
     */
    private void putHeaders(JPanel panel, Insets insets) {
        if (this.dayDisplayNames == null) {
            Calendar s = Calendar.getInstance();
            s.set(Calendar.DAY_OF_WEEK, 1);

            Color c = null;
            for (int i = 0; i < 7; i++) {
                // 星期表示法
                String h = s.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, loc);
                s.add(Calendar.DATE, 1);
                if (loc == Locale.TAIWAN || loc == Locale.CHINA || loc == Locale.CHINESE || loc == Locale.SIMPLIFIED_CHINESE || loc == Locale.TRADITIONAL_CHINESE) {
                    h = h.substring(h.length() - 1);
                } else if (loc == Locale.JAPAN || loc == Locale.JAPANESE) {
                    h = h.substring(0, 1);
                } else {
                    h = h.substring(0, 3);
                }

                switch (i) {
                case 0:
                    c = Color.red;
                    break;
                case 6:
                    c = Color.BLUE;
                    break;
                default:
                    c = Color.BLACK;
                    break;
                }
                panel.add(this.createHeader(h, c), new GridBagConstraints(i + 1, 0, 1, 1, 0, 0, 10, 1, insets, 10, 0));
            }
        } else {
            String[] headers = Arrays.copyOf(this.dayDisplayNames, 7);
            Color c = null;
            for (int i = 0; i < 7; i++) {
                switch (i) {
                case 0:
                    c = Color.red;
                    break;
                case 6:
                    c = Color.BLUE;
                    break;
                default:
                    c = Color.BLACK;
                    break;
                }
                panel.add(this.createHeader(headers[i], c), new GridBagConstraints(i + 1, 0, 1, 1, 0, 0, 10, 1, insets, 10, 0));
            }
        }
    }

    /**
     * 星期
     * 
     * @param text
     * @param fontColor
     * @return
     */
    private JLabel createHeader(String text, Color fontColor) {
        JLabel l = new JLabel(text, SwingConstants.CENTER);
        l.setBorder(BorderFactory.createEtchedBorder());
        l.setOpaque(true);
        l.setBackground(Color.WHITE);
        l.setForeground(fontColor);
        return l;
    }

    /**
     * 計算月份的列數
     * 
     * @param c
     * @return
     */
    private int getMonthRowsCount(Calendar c) {
        Calendar s = (Calendar) c.clone();
        s.set(Calendar.DATE, 1);
        return (int) Math.ceil((s.get(Calendar.DAY_OF_WEEK) + s.getActualMaximum(Calendar.DAY_OF_MONTH) - 1) / 7.0);
    }

    /**
     * 計算顯示的第一個日期
     * 
     * @param c
     * @return
     */
    private Calendar getFirstDate(Calendar c) {
        Calendar s = (Calendar) c.clone();
        s.set(Calendar.DATE, 1);
        s.add(Calendar.DATE, -1 * (s.get(Calendar.DAY_OF_WEEK) - 1));
        return s;
    }

    /**
     * 清除
     */
    private void clear() {
        stopWatch("Clear");

        for (int i = this.getComponentCount() - 1; i > -1; i--) {
            this.remove(i);
        }

        this.putToday();
        System.gc();
    }

    /**
     * 重整大小
     */
    private void pack() {
        stopWatch("Pack");

        this.revalidate();
        // resize
        Container cc = this.getParent();
        while (cc != null) {
            if (cc instanceof Window) {
                ((Window) cc).pack();
                break;
            }
            cc = cc.getParent();
        }
    }

    /**
     * 測試時間
     * 
     * @param what
     */
    private void stopWatch(String what) {
        // test time execute
        // System.out.printf("%2$s : %1$tY/%1$tm/%1$td %1$tH:%1$tM:%1$tS %1$tL%n",
        // new Date(), what);
    }

    /**
     * 選取日期的觸發動作
     * 
     * @param pick
     */
    public void setDateSelected(PickDate pick) {
        this.pickAtion = pick;
    }

    /**
     * 目前選取日期
     * 
     * @return
     */
    public Calendar getSelectedCalendar() {
        return (Calendar) this.selectedDate.clone();
    }

    /**
     * 設定選取的日期
     * 
     * @param c
     */
    public void setSelectedCalendar(Calendar c) {
        this.selectedDate = c;
    }

    /**
     * 取得星期的顯示名稱
     * 
     * @return
     */
    public String[] getDayNames() {
        return this.dayDisplayNames;
    }

    /**
     * 設定星期的顯示名稱
     * 
     * @param names
     */
    public void setDayName(String[] names) {
        this.dayDisplayNames = names;
        this.view(this.selectedDate);
    }

    /**
     * 設定今天的顯示格式
     * 
     * @param format
     */
    public void setTodayFormat(String format) {
        this.format = format;
        this.putToday();
    }

    public String getTodayFormat() {
        return this.format;
    }

    public void setUILocale(Locale l) {
        this.loc = l;
        this.view(this.selectedDate);
    }

    public Locale getUILocale() {
        return this.loc;
    }

    public void setLeftArrow(Icon icon) {
        this.leftArrow = icon;
        this.view(this.selectedDate);
    }

    public void setRightArrow(Icon icon) {
        this.rightArrow = icon;
        this.view(this.selectedDate);
    }

    /**
     * 顯示選擇的日期
     * 
     * @param c
     */
    public void view(Calendar c) {
        // claer
        this.clear();

        this.putDateBar(c);
        this.putDateContent(c);

        this.pack();
    }

    /**
     * 顯示今天的日期
     */
    public void view() {
        this.view(Calendar.getInstance());
    }
}