Popular Posts
javax.net.ssl.SSLHandshakeException: Connection closed by peer in Android 5.0 Lollipop Recently, there is a error occurs when access website via ssl connection like below although it worked fine several days ago. // Enable SSL... 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... Copy/Delete/Permission directory using System; using System.IO; using System.Security.AccessControl; namespace Bruce.Lib {     public class DirHelper     {         /// <...
Blog Archive
Stats
Cumulative sum
  1. SELECT * FROM pg_account;
  2.  
  3. SELECT
  4.     s.pg_id,
  5.     s.pg_name,
  6.     s.pg_entry,
  7.     SUM(NVL(c.pg_entry,0)) cumulative,
  8.     ROUND(s.pg_entry / (SELECT SUM(pg_entry) FROM pg_account)*100, 5) percentage,
  9.     ROUND(SUM(NVL(c.pg_entry,0))/(SELECT SUM(pg_entry) FROM pg_account)*100,5) cumulative_percentage
  10. FROM pg_account s, pg_account c
  11. WHERE s.pg_id > c.pg_id OR (s.pg_id = c.pg_id AND s.pg_entry = c.pg_entry)
  12. GROUP BY s.pg_id, s.pg_name, s.pg_entry
  13. ORDER BY s.pg_id
  14. ;
  15.  
  16. SELECT
  17.     s.pg_id,
  18.     s.pg_name,
  19.     s.pg_entry,
  20.     COUNT(c.pg_id) ranking
  21. FROM pg_account s, pg_account c
  22. WHERE s.pg_entry < c.pg_entry OR (s.pg_id = c.pg_id AND s.pg_entry = c.pg_entry)
  23. GROUP BY s.pg_id, s.pg_name, s.pg_entry, s.pg_entry
  24. ORDER BY s.pg_entry DESC
  25. ;
PG_ID                  PG_NAME              PG_ENTRY               
---------------------- -------------------- ---------------------- 
1                      Bruce                22                     
2                      James                72                     
3                      Yilin                65                     
4                      Ted                  77                     
5                      Charles              35                     
6                      Sean                 43                     
7                      Paul                 57                     
8                      Ken                  35                     
8 個資料列已選取

PG_ID                  PG_NAME              PG_ENTRY               CUMULATIVE             PERCENTAGE             CUMULATIVE_PERCENTAGE  
---------------------- -------------------- ---------------------- ---------------------- ---------------------- ---------------------- 
1                      Bruce                22                     22                     5.41872                5.41872                
2                      James                72                     94                     17.73399               23.15271               
3                      Yilin                65                     159                    16.00985               39.16256               
4                      Ted                  77                     236                    18.96552               58.12808               
5                      Charles              35                     271                    8.62069                66.74877               
6                      Sean                 43                     314                    10.59113               77.3399                
7                      Paul                 57                     371                    14.03941               91.37931               
8                      Ken                  35                     406                    8.62069                100                    
8 個資料列已選取

PG_ID                  PG_NAME              PG_ENTRY               RANKING                
---------------------- -------------------- ---------------------- ---------------------- 
4                      Ted                  77                     1                      
2                      James                72                     2                      
3                      Yilin                65                     3                      
7                      Paul                 57                     4                      
6                      Sean                 43                     5                      
5                      Charles              35                     6                      
8                      Ken                  35                     6                      
1                      Bruce                22                     8                      
8 個資料列已選取

Change network configuration (windows)
Manual setting
  1. @ECHO OFF
  2. set varAdapterName="Local Area Connection"
  3. set varIP=192.168.1.68
  4. set varMask=255.255.255.0
  5. set varGateway=192.168.1.1
  6. set varDNS1=192.168.1.1
  7. set varDNS2=192.168.1.1
  8.  
  9. ECHO Setting IP Address and Subnet Mask
  10. netsh int ip set address name = %varAdapterName% source = static addr = %varIP% mask = %varMask%
  11.  
  12. ECHO Setting Gateway
  13. netsh int ip set address name = %varAdapterName% gateway = %varGateway% gwmetric = 1
  14.  
  15. ECHO Setting Primary DNS
  16. netsh int ip set dns name = %varAdapterName% source = static addr = %varDNS1%
  17.  
  18. ECHO Setting Secondary DNS
  19. netsh int ip add dns name = %varAdapterName% addr = %varDNS2%
DHCP
  1. @set varAdapterName="Local Area Connection"
  2.  
  3. netsh interface ip set address name=%varAdapterName% source=dhcp
  4. netsh interface ip set dns name=%varAdapterName% source=dhcp register=primary
  5. netsh interface ip set wins name=%varAdapterName% source=dhcp
Select/update table where trigger against, ORA-04091 error occurs
  1. CREATE OR REPLACE
  2. TRIGGER udpate_sheet_processing 
  3. AFTER INSERT ON sheet_item 
  4. FOR EACH ROW
  5.  
  6.  
  7. DECLARE
  8.     PRAGMA AUTONOMOUS_TRANSACTION;  -- 自治事務 
  9.     v_sheet_id VARCHAR2(50);
  10.     v_processing_entry NUMBER(5);
  11.     CURSOR get_processing_amount IS
  12.         SELECT count(*)+1
  13.         FROM sheet_item
  14.         WHERE sheet_id = v_sheet_id
  15.     ;
  16.     
  17. BEGIN
  18.     v_sheet_id := :NEW.sheet_id;
  19.  
  20.     OPEN get_processing_amount;
  21.     FETCH get_processing_amount INTO v_processing_entry;
  22.     CLOSE get_processing_amount;
  23.  
  24.     UPDATE product_checksheet
  25.     SET sheet_processing_entry = v_processing_entry
  26.     WHERE sheet_id = v_sheet_id;
  27.     
  28.     COMMIT;  -- commit for update
  29. END;
MySQL remote access by root
my.cnf
  1. #bind-address = 127.0.0.1 (disable this setting for listening any address)
  1. mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root_password' WITH GRANT OPTION;
  2. mysql> FLUSH PRIVILEGES;
vi hot key guide

  • 第一部份:一般模式可用的按鈕說明,游標移動、複製貼上、搜尋取代等

    移動游標的方法
    h 或 向左方向鍵(←)游標向左移動一個字元
    j 或 向下方向鍵(↓)游標向下移動一個字元
    k 或 向上方向鍵(↑)游標向上移動一個字元
    l 或 向右方向鍵(→)游標向右移動一個字元
    如果你將右手放在鍵盤上的話,你會發現 hjkl 是排列在一起的,因此可以使用這四個按鈕來移動游標。 如果想要進行多次移動的話,例如向下移動 30 行,可以使用 "30j" 或 "30↓" 的組合按鍵, 亦即加上想要進行的次數(數字)後,按下動作即可!
    [Ctrl] + [f]螢幕『向下』移動一頁,相當於 [Page Down]按鍵 (常用)
    [Ctrl] + [b]螢幕『向上』移動一頁,相當於 [Page Up] 按鍵 (常用)
    [Ctrl] + [d]螢幕『向下』移動半頁
    [Ctrl] + [u]螢幕『向上』移動半頁
    +游標移動到非空白字元的下一列
    -游標移動到非空白字元的上一列
    n那個 n 表示『數字』,例如 20 。按下數字後再按空白鍵,游標會向右移動這一行的 n 個字元。例如 20 則游標會向後面移動 20 個字元距離。
    0 或功能鍵[Home]這是數字『 0 』:移動到這一行的最前面字元處 (常用)
    $ 或功能鍵[End]移動到這一行的最後面字元處(常用)
    H游標移動到這個螢幕的最上方那一行的第一個字元
    M游標移動到這個螢幕的中央那一行的第一個字元
    L游標移動到這個螢幕的最下方那一行的第一個字元
    G移動到這個檔案的最後一行(常用)
    nGn 為數字。移動到這個檔案的第 n 行。例如 20G 則會移動到這個檔案的第 20 行(可配合 :set nu)
    gg移動到這個檔案的第一行,相當於 1G 啊! (常用)
    nn 為數字。游標向下移動 n 行(常用)
    搜尋與取代
    /word向游標之下尋找一個名稱為 word 的字串。例如要在檔案內搜尋 vbird 這個字串,就輸入 /vbird 即可! (常用)
    ?word向游標之上尋找一個字串名稱為 word 的字串。
    n這個 n 是英文按鍵。代表『重複前一個搜尋的動作』。舉例來說, 如果剛剛我們執行 /vbird 去向下搜尋 vbird 這個字串,則按下 n 後,會向下繼續搜尋下一個名稱為 vbird 的字串。如果是執行 ?vbird 的話,那麼按下 n 則會向上繼續搜尋名稱為 vbird 的字串!
    N這個 N 是英文按鍵。與 n 剛好相反,為『反向』進行前一個搜尋動作。 例如 /vbird 後,按下 N 則表示『向上』搜尋 vbird 。
    使用 /word 配合 n 及 N 是非常有幫助的!可以讓你重複的找到一些你搜尋的關鍵字!
    :n1,n2s/word1/word2/gn1 與 n2 為數字。在第 n1 與 n2 行之間尋找 word1 這個字串,並將該字串取代為 word2 !舉例來說,在 100 到 200 行之間搜尋 vbird 並取代為 VBIRD 則:
    『:100,200s/vbird/VBIRD/g』。(常用)
    :1,$s/word1/word2/g從第一行到最後一行尋找 word1 字串,並將該字串取代為 word2 !(常用)
    :1,$s/word1/word2/gc從第一行到最後一行尋找 word1 字串,並將該字串取代為 word2 !且在取代前顯示提示字元給使用者確認 (confirm) 是否需要取代!(常用)
    刪除、複製與貼上
    x, X在一行字當中,x 為向後刪除一個字元 (相當於 [del] 按鍵), X 為向前刪除一個字元(相當於 [backspace] 亦即是倒退鍵) (常用)
    nxn 為數字,連續向後刪除 n 個字元。舉例來說,我要連續刪除 10 個字元, 『10x』。
    dd刪除游標所在的那一整列(常用)
    nddn 為數字。刪除游標所在的向下 n 列,例如 20dd 則是刪除 20 列 (常用)
    d1G刪除游標所在到第一行的所有資料
    dG刪除游標所在到最後一行的所有資料
    d$刪除游標所在處,到該行的最後一個字元
    d0那個是數字的 0 ,刪除游標所在處,到該行的最前面一個字元
    yy複製游標所在的那一行(常用)
    nyyn 為數字。複製游標所在的向下 n 列,例如 20yy 則是複製 20 列(常用)
    y1G複製游標所在列到第一列的所有資料
    yG複製游標所在列到最後一列的所有資料
    y0複製游標所在的那個字元到該行行首的所有資料
    y$複製游標所在的那個字元到該行行尾的所有資料
    p, Pp 為將已複製的資料在游標下一行貼上,P 則為貼在游標上一行! 舉例來說,我目前游標在第 20 行,且已經複製了 10 行資料。則按下 p 後, 那 10 行資料會貼在原本的 20 行之後,亦即由 21 行開始貼。但如果是按下 P 呢? 那麼原本的第 20 行會被推到變成 30 行。 (常用)
    J將游標所在列與下一列的資料結合成同一列
    c重複刪除多個資料,例如向下刪除 10 行,[ 10cj ]
    u復原前一個動作。(常用)
    [Ctrl]+r重做上一個動作。(常用)
    這個 u 與 [Ctrl]+r 是很常用的指令!一個是復原,另一個則是重做一次~ 利用這兩個功能按鍵,你的編輯,嘿嘿!很快樂的啦!
    .不要懷疑!這就是小數點!意思是重複前一個動作的意思。 如果你想要重複刪除、重複貼上等等動作,按下小數點『.』就好了! (常用)
  • 第二部份:一般模式切換到編輯模式的可用的按鈕說明

    進入插入或取代的編輯模式
    i, I進入插入模式(Insert mode):
    i 為『從目前游標所在處插入』, I 為『在目前所在行的第一個非空白字元處開始插入』。 (常用)
    a, A進入插入模式(Insert mode):
    a 為『從目前游標所在的下一個字元處開始插入』, A 為『從游標所在行的最後一個字元處開始插入』。(常用)
    o, O進入插入模式(Insert mode):
    這是英文字母 o 的大小寫。o 為『在目前游標所在的下一行處插入新的一行』; O 為在目前游標所在處的上一行插入新的一行!(常用)
    r, R進入取代模式(Replace mode):
    r 只會取代游標所在的那一個字元一次;R會一直取代游標所在的文字,直到按下 ESC 為止;(常用)
    上面這些按鍵中,在 vi 畫面的左下角處會出現『--INSERT--』或『--REPLACE--』的字樣。 由名稱就知道該動作了吧!!特別注意的是,我們上面也提過了,你想要在檔案裡面輸入字元時, 一定要在左下角處看到 INSERT 或 REPLACE 才能輸入喔!
    [Esc]退出編輯模式,回到一般模式中(常用)
  • 第三部份:一般模式切換到指令列模式的可用的按鈕說明

    指令列的儲存、離開等指令
    :w將編輯的資料寫入硬碟檔案中(常用)
    :w!若檔案屬性為『唯讀』時,強制寫入該檔案。不過,到底能不能寫入, 還是跟你對該檔案的檔案權限有關啊!
    :q離開 vi (常用)
    :q!若曾修改過檔案,又不想儲存,使用 ! 為強制離開不儲存檔案。
    注意一下啊,那個驚嘆號 (!) 在 vi 當中,常常具有『強制』的意思~
    :wq儲存後離開,若為 :wq! 則為強制儲存後離開 (常用)
    ZZ這是大寫的 Z 喔!若檔案沒有更動,則不儲存離開,若檔案已經被更動過,則儲存後離開!
    :w [filename]將編輯的資料儲存成另一個檔案(類似另存新檔)
    :r [filename]在編輯的資料中,讀入另一個檔案的資料。亦即將 『filename』 這個檔案內容加到游標所在行後面
    :n1,n2 w [filename]將 n1 到 n2 的內容儲存成 filename 這個檔案。
    :! command暫時離開 vi 到指令列模式下執行 command 的顯示結果!例如
    『:! ls /home』即可在 vi 當中察看 /home 底下以 ls 輸出的檔案資訊!
    vim 環境的變更
    :set nu顯示行號,設定之後,會在每一行的字首顯示該行的行號
    :set nonu與 set nu 相反,為取消行號!

鳥哥私房菜

JDateField
  1. package bruce.lib.swing;
  2.  
  3. import java.awt.GridBagConstraints;
  4. import java.awt.GridBagLayout;
  5. import java.awt.Insets;
  6. import java.awt.event.ActionEvent;
  7. import java.awt.event.ActionListener;
  8. import java.awt.event.MouseAdapter;
  9. import java.awt.event.MouseEvent;
  10. import java.awt.event.MouseListener;
  11. import java.text.SimpleDateFormat;
  12. import java.util.Calendar;
  13. import java.util.Date;
  14. import java.util.Locale;
  15.  
  16. import javax.swing.BorderFactory;
  17. import javax.swing.Icon;
  18. import javax.swing.ImageIcon;
  19. import javax.swing.JButton;
  20. import javax.swing.JPanel;
  21. import javax.swing.JTextField;
  22.  
  23. import bruce.lib.swing.JDatePickPane.PickDate;
  24.  
  25. /**
  26.  * @author Bruce (NaNashi)
  27.  * 
  28.  */
  29. public class JDateField extends JPanel {
  30.  
  31.     private JButton btnPopup;
  32.     private JTextField txtInput;
  33.     private Calendar c;
  34.  
  35.     private String format;
  36.     private String[] dayDisplayNames;
  37.     private Locale locale;
  38.     private Icon leftArrow;
  39.     private Icon rightArrow;
  40.     private boolean isCloseOnClick;
  41.  
  42.     public JDateField() {
  43.         super(new GridBagLayout());
  44.  
  45.         this.locale = Locale.getDefault();
  46.         this.format = JDatePickPane.DEFAULT_DATE_FORMAT;
  47.  
  48.         this.leftArrow = JDatePickPane.getImageIcon("/bruce/lib/swing/img/Arrow.blue.left.png", 20, 20);
  49.         this.rightArrow = JDatePickPane.getImageIcon("/bruce/lib/swing/img/Arrow.blue.right.png", 20, 20);
  50.  
  51.         this.txtInput = new JTextField();
  52.         this.txtInput.setEditable(false);
  53.         this.add(this.txtInput, new GridBagConstraints(0, 0, 1, 1, 1, 0, 10, 2, new Insets(1, 1, 1, 1), 0, 0));
  54.  
  55.         try {
  56.             btnPopup = new JButton(new ImageIcon(this.getClass().getResource("/bruce/lib/swing/img/calendar-date-icon.png")));
  57.             btnPopup.setBorder(BorderFactory.createEmptyBorder());
  58.             btnPopup.setBorderPainted(false);
  59.         } catch (Exception e) {
  60.             btnPopup = new JButton("P");
  61.         }
  62.         btnPopup.addActionListener(new ActionListener() {
  63.             @Override
  64.             public void actionPerformed(ActionEvent e) {
  65.                 popup();
  66.             }
  67.         });
  68.         this.add(btnPopup, new GridBagConstraints(1, 0, 1, 1, 0, 0, 10, 2, new Insets(1, 1, 1, 1), 0, 0));
  69.     }
  70.  
  71.     public JDateField(int columns) {
  72.         this();
  73.         this.txtInput.setColumns(columns);
  74.     }
  75.  
  76.     public JDateField(Calendar c) {
  77.         this();
  78.         this.setSelectedDateText(c);
  79.     }
  80.  
  81.     public JDateField(Calendar c, int columns) {
  82.         this(c);
  83.         this.txtInput.setColumns(columns);
  84.     }
  85.  
  86.     private void popup() {
  87.         JDatePickDialog dialog = new JDatePickDialog(this.txtInput);
  88.         dialog.setTodayFormat(this.format);
  89.         dialog.setDayName(this.dayDisplayNames);
  90.         dialog.setUILocale(this.locale);
  91.         dialog.setLeftArrow(this.leftArrow);
  92.         dialog.setRightArrow(this.rightArrow);
  93.  
  94.         dialog.setDateSelected(new PickDate() {
  95.             @Override
  96.             public void pick(Calendar c) {
  97.                 setSelectedDateText(c);
  98.             }
  99.         });
  100.  
  101.         try {
  102.             dialog.view(txtInput.getText().trim());
  103.         } catch (Exception ex) {
  104.             dialog.view();
  105.         }
  106.     }
  107.  
  108.     public void setFormat(String format) {
  109.         this.format = format;
  110.         this.setSelectedDateText(this.c);
  111.     }
  112.  
  113.     public String getFormat() {
  114.         return this.format == null ? JDatePickPane.DEFAULT_DATE_FORMAT : this.format;
  115.     }
  116.  
  117.     public String[] getDayDisplayNames() {
  118.         return dayDisplayNames;
  119.     }
  120.  
  121.     public void setDayDisplayNames(String[] dayDisplayNames) {
  122.         this.dayDisplayNames = dayDisplayNames;
  123.     }
  124.  
  125.     public Locale getUILocale() {
  126.         return locale;
  127.     }
  128.  
  129.     public void setUILocale(Locale locale) {
  130.         this.locale = locale;
  131.     }
  132.  
  133.     public Icon getLeftArrow() {
  134.         return leftArrow;
  135.     }
  136.  
  137.     public void setLeftArrow(Icon leftArrow) {
  138.         this.leftArrow = leftArrow;
  139.     }
  140.  
  141.     public Icon getRightArrow() {
  142.         return rightArrow;
  143.     }
  144.  
  145.     public void setRightArrow(Icon rightArrow) {
  146.         this.rightArrow = rightArrow;
  147.     }
  148.  
  149.     public void setCloseOnClick(boolean isCloseOnClick) {
  150.         this.isCloseOnClick = isCloseOnClick;
  151.     }
  152.  
  153.     public boolean isCloseOnClick() {
  154.         return isCloseOnClick;
  155.     }
  156.  
  157.     public int getColumns() {
  158.         return this.txtInput.getColumns();
  159.     }
  160.  
  161.     public void setColumns(int columns) {
  162.         this.txtInput.setColumns(columns);
  163.     }
  164.  
  165.     public void setButtonVisible(boolean b) {
  166.         this.btnPopup.setVisible(b);
  167.         if (b) {
  168.             MouseListener[] ls = this.txtInput.getMouseListeners();
  169.             for (MouseListener l : ls) {
  170.                 this.txtInput.removeMouseListener(l);
  171.             }
  172.         } else {
  173.             this.txtInput.addMouseListener(new MouseAdapter() {
  174.                 @Override
  175.                 public void mouseClicked(MouseEvent e) {
  176.                     popup();
  177.                 }
  178.             });
  179.         }
  180.     }
  181.  
  182.     public void setSelectedDateText(Date date) {
  183.         Calendar c = Calendar.getInstance();
  184.         c.setTime(date);
  185.         this.setSelectedDateText(c);
  186.     }
  187.  
  188.     public void setSelectedDateText(Calendar c) {
  189.         this.= c;
  190.         if (this.format == null) {
  191.             this.txtInput.setText(String.format("%tF", c));
  192.         } else {
  193.             try {
  194.                 SimpleDateFormat f = new SimpleDateFormat(this.format);
  195.                 this.txtInput.setText(f.format(c.getTime()));
  196.             } catch (Exception ex) {
  197.                 this.txtInput.setText(String.format("%tF", c));
  198.             }
  199.         }
  200.     }
  201.  
  202.     public Calendar getSelectedCalender() {
  203.         return this.== null ? Calendar.getInstance() : this.c;
  204.     }
  205.  
  206. }
  1. package bruce.lib.swing;
  2.  
  3. import java.awt.Component;
  4. import java.awt.Dimension;
  5. import java.awt.Point;
  6. import java.awt.Toolkit;
  7. import java.awt.event.WindowEvent;
  8. import java.awt.event.WindowFocusListener;
  9. import java.text.ParseException;
  10. import java.text.SimpleDateFormat;
  11. import java.util.Calendar;
  12. import java.util.Locale;
  13.  
  14. import javax.swing.BorderFactory;
  15. import javax.swing.Icon;
  16. import javax.swing.JDialog;
  17.  
  18. import bruce.lib.swing.JDatePickPane.PickDate;
  19.  
  20. /**
  21.  * @author Bruce (NaNashi)
  22.  * 
  23.  */
  24. public class JDatePickDialog extends JDialog {
  25.  
  26.     private boolean isCloseOnClick;
  27.  
  28.     public JDatePickDialog() {
  29.         this.init();
  30.  
  31.         Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
  32.         this.setLocation(new Point((size.width - this.getWidth()) / 2, (size.height - this.getHeight()) / 2));
  33.     }
  34.  
  35.     public JDatePickDialog(Component c) {
  36.         this.setUndecorated(true);
  37.         this.init();
  38.  
  39.         this.getContent().setBorder(BorderFactory.createEtchedBorder());
  40.  
  41.         this.addWindowFocusListener(new WindowFocusListener() {
  42.             @Override
  43.             public void windowLostFocus(WindowEvent e) {
  44.                 setVisible(false);
  45.                 dispose();
  46.             }
  47.  
  48.             @Override
  49.             public void windowGainedFocus(WindowEvent e) {
  50.                 // TODO Auto-generated method stub
  51.  
  52.             }
  53.         });
  54.  
  55.         if (!= null) {
  56.             Point p = c.getLocationOnScreen();
  57.             this.setLocation(new Point(p.x, p.+ c.getHeight()));
  58.         } else {
  59.             Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
  60.             this.setLocation((int) (dim.getWidth() - this.getWidth()) / 2, (int) (dim.getHeight() - this.getHeight()) / 2);
  61.         }
  62.     }
  63.  
  64.     private void init() {
  65.         this.isCloseOnClick = true;
  66.  
  67.         this.setContentPane(new JDatePickPane());
  68.  
  69.         this.setDateSelected(new PickDate() {
  70.             @Override
  71.             public void pick(Calendar c) {
  72.                 // 預設值
  73.             }
  74.         });
  75.  
  76.         this.pack();
  77.     }
  78.  
  79.     private JDatePickPane getContent() {
  80.         return (JDatePickPane) this.getContentPane();
  81.     }
  82.  
  83.     public void setCloseOnClick(boolean isCloseOnClick) {
  84.         this.isCloseOnClick = isCloseOnClick;
  85.     }
  86.  
  87.     public boolean isCloseOnClick() {
  88.         return isCloseOnClick;
  89.     }
  90.  
  91.     // ========== panel method ================
  92.     /**
  93.      * 選取日期的觸發動作
  94.      * 
  95.      * @param pick
  96.      */
  97.     public void setDateSelected(final PickDate pick) {
  98.         PickDate pd = new PickDate() {
  99.             @Override
  100.             public void pick(Calendar c) {
  101.                 pick.pick(c);
  102.                 if (isCloseOnClick) {
  103.                     setVisible(false);
  104.                     dispose();
  105.                 }
  106.             }
  107.         };
  108.         this.getContent().setDateSelected(pd);
  109.     }
  110.  
  111.     /**
  112.      * 目前選取日期
  113.      * 
  114.      * @return
  115.      */
  116.     public Calendar getSelectedCalendar() {
  117.         return this.getContent().getSelectedCalendar();
  118.     }
  119.  
  120.     /**
  121.      * 設定選取的日期
  122.      * 
  123.      * @param c
  124.      */
  125.     public void setSelectedCalendar(Calendar c) {
  126.         this.getContent().setSelectedCalendar(c);
  127.     }
  128.  
  129.     /**
  130.      * 取得星期的顯示名稱
  131.      * 
  132.      * @return
  133.      */
  134.     public String[] getDayNames() {
  135.         return this.getContent().getDayNames();
  136.     }
  137.  
  138.     /**
  139.      * 設定星期的顯示名稱
  140.      * 
  141.      * @param names
  142.      */
  143.     public void setDayName(String[] names) {
  144.         this.getContent().setDayName(names);
  145.     }
  146.  
  147.     /**
  148.      * 設定今天的顯示格式
  149.      * 
  150.      * @param format
  151.      */
  152.     public void setTodayFormat(String format) {
  153.         this.getContent().setTodayFormat(format);
  154.     }
  155.  
  156.     public String getTodayFormat() {
  157.         return this.getContent().getTodayFormat();
  158.     }
  159.  
  160.     public void setUILocale(Locale l) {
  161.         this.getContent().setUILocale(l);
  162.     }
  163.  
  164.     public Locale getUILocale() {
  165.         return this.getContent().getUILocale();
  166.     }
  167.  
  168.     public void setLeftArrow(Icon icon) {
  169.         this.getContent().setLeftArrow(icon);
  170.     }
  171.  
  172.     public void setRightArrow(Icon icon) {
  173.         this.getContent().setRightArrow(icon);
  174.     }
  175.  
  176.     /**
  177.      * 顯示選擇的日期
  178.      * 
  179.      * @param c
  180.      */
  181.     public void view(Calendar c) {
  182.         this.getContent().view(c);
  183.         this.setVisible(true);
  184.     }
  185.  
  186.     public void view(String date) throws ParseException {
  187.         SimpleDateFormat f = new SimpleDateFormat(this.getContent().getTodayFormat());
  188.         Calendar c = Calendar.getInstance();
  189.         c.setTime(f.parse(date));
  190.         this.getContent().setSelectedCalendar(c);
  191.         this.view(c);
  192.     }
  193.  
  194.     /**
  195.      * 顯示今天的日期
  196.      */
  197.     public void view() {
  198.         this.getContent().view();
  199.         this.setVisible(true);
  200.     }
  201. }
  1. package bruce.lib.swing;
  2.  
  3. import java.awt.BorderLayout;
  4. import java.awt.Color;
  5. import java.awt.Container;
  6. import java.awt.Dimension;
  7. import java.awt.FlowLayout;
  8. import java.awt.Font;
  9. import java.awt.GridBagConstraints;
  10. import java.awt.GridBagLayout;
  11. import java.awt.GridLayout;
  12. import java.awt.Insets;
  13. import java.awt.Window;
  14. import java.awt.event.ActionEvent;
  15. import java.awt.event.ActionListener;
  16. import java.awt.event.MouseAdapter;
  17. import java.awt.event.MouseEvent;
  18. import java.awt.geom.AffineTransform;
  19. import java.awt.image.AffineTransformOp;
  20. import java.awt.image.BufferedImage;
  21. import java.text.SimpleDateFormat;
  22. import java.util.Arrays;
  23. import java.util.Calendar;
  24. import java.util.Date;
  25. import java.util.Locale;
  26.  
  27. import javax.imageio.ImageIO;
  28. import javax.swing.BorderFactory;
  29. import javax.swing.Icon;
  30. import javax.swing.ImageIcon;
  31. import javax.swing.JButton;
  32. import javax.swing.JLabel;
  33. import javax.swing.JPanel;
  34. import javax.swing.SwingConstants;
  35.  
  36. /**
  37.  * @author Bruce (NaNashi)
  38.  * 
  39.  */
  40. public class JDatePickPane extends JPanel {
  41.  
  42.     public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
  43.  
  44.     public static Icon getImageIcon(String location, double width, double height) {
  45.         try {
  46.             BufferedImage icon = ImageIO.read(String.class.getResource(location));
  47.             // resize image
  48.             AffineTransform transform = AffineTransform.getScaleInstance(width / icon.getWidth(), height / icon.getHeight());
  49.             AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
  50.             return new ImageIcon(op.filter(icon, null));
  51.         } catch (Exception e) {
  52.             return null;
  53.         }
  54.     }
  55.  
  56.     public interface PickDate {
  57.         void pick(Calendar c);
  58.     }
  59.  
  60.     class DayCell extends JButton {
  61.         private long stamp;
  62.  
  63.         DayCell(Calendar c, Calendar currentMonth, Calendar selected) {
  64.             super(String.valueOf(c.get(Calendar.DATE)));
  65.  
  66.             stopWatch("Day Cell");
  67.  
  68.             this.stamp = c.getTimeInMillis();
  69.             Calendar now = Calendar.getInstance();
  70.             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)) {
  71.                 this.setBorder(BorderFactory.createLineBorder(Color.BLUE));
  72.                 this.setForeground(Color.BLUE);
  73.                 this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));
  74.             } else if (c.get(Calendar.YEAR) != currentMonth.get(Calendar.YEAR) || c.get(Calendar.MONTH) != currentMonth.get(Calendar.MONTH)) {
  75.                 this.setForeground(Color.GRAY);
  76.                 this.setBorder(BorderFactory.createEtchedBorder());
  77.             } else {
  78.                 this.setBorder(BorderFactory.createEtchedBorder());
  79.             }
  80.             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)) {
  81.                 this.setBorder(BorderFactory.createLineBorder(Color.RED));
  82.                 this.setForeground(Color.RED);
  83.                 this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));
  84.             }
  85.  
  86.             this.addMouseListener(new MouseAdapter() {
  87.                 @Override
  88.                 public void mouseExited(MouseEvent e) {
  89.                     setBackground(null);
  90.                 }
  91.  
  92.                 @Override
  93.                 public void mouseEntered(MouseEvent e) {
  94.                     setBackground(Color.white);
  95.                 }
  96.             });
  97.             this.addActionListener(new ActionListener() {
  98.                 @Override
  99.                 public void actionPerformed(ActionEvent e) {
  100.                     JDatePickPane pick = (JDatePickPane) getParent().getParent();
  101.                     pick.selectedDate.setTimeInMillis(stamp);
  102.  
  103.                     pick.view(pick.selectedDate);
  104.  
  105.                     if (pick.pickAtion != null) {
  106.                         pick.pickAtion.pick(pick.selectedDate);
  107.                     }
  108.                 }
  109.             });
  110.         }
  111.     }
  112.  
  113.     class MonthCell extends JButton {
  114.         private long stamp;
  115.  
  116.         public MonthCell(Calendar c, Calendar selected) {
  117.             super(c.getDisplayName(Calendar.MONTH, Calendar.SHORT, loc));
  118.  
  119.             stopWatch("Month Cell");
  120.  
  121.             this.stamp = c.getTimeInMillis();
  122.             this.setBorder(BorderFactory.createEtchedBorder());
  123.             this.setPreferredSize(new Dimension(50, 50));
  124.  
  125.             Calendar now = Calendar.getInstance();
  126.             if (c.get(Calendar.YEAR) == now.get(Calendar.YEAR) && c.get(Calendar.MONTH) == now.get(Calendar.MONTH)) {
  127.                 this.setBorder(BorderFactory.createLineBorder(Color.BLUE));
  128.                 this.setForeground(Color.BLUE);
  129.                 this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));
  130.  
  131.             } else {
  132.                 this.setBorder(BorderFactory.createEtchedBorder());
  133.             }
  134.             if (c.get(Calendar.YEAR) == selected.get(Calendar.YEAR) && c.get(Calendar.MONTH) == selected.get(Calendar.MONTH)) {
  135.                 this.setBorder(BorderFactory.createLineBorder(Color.RED));
  136.                 this.setForeground(Color.RED);
  137.                 this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));
  138.             }
  139.  
  140.             this.addMouseListener(new MouseAdapter() {
  141.                 @Override
  142.                 public void mouseExited(MouseEvent e) {
  143.                     setBackground(null);
  144.                 }
  145.  
  146.                 @Override
  147.                 public void mouseEntered(MouseEvent e) {
  148.                     setBackground(Color.white);
  149.                 }
  150.             });
  151.             this.addActionListener(new ActionListener() {
  152.                 @Override
  153.                 public void actionPerformed(ActionEvent e) {
  154.                     Calendar c = Calendar.getInstance();
  155.                     c.setTimeInMillis(stamp);
  156.  
  157.                     JDatePickPane pick = (JDatePickPane) getParent().getParent();
  158.                     pick.view(c);
  159.                 }
  160.             });
  161.         }
  162.     }
  163.  
  164.     class YearCell extends JButton {
  165.         private long stamp;
  166.  
  167.         public YearCell(Calendar c, Calendar selected) {
  168.             super(String.valueOf(c.get(Calendar.YEAR)));
  169.  
  170.             stopWatch("Year Cell");
  171.  
  172.             this.stamp = c.getTimeInMillis();
  173.             this.setBorder(BorderFactory.createEtchedBorder());
  174.             this.setPreferredSize(new Dimension(50, 50));
  175.  
  176.             Calendar now = Calendar.getInstance();
  177.             if (c.get(Calendar.YEAR) == now.get(Calendar.YEAR)) {
  178.                 this.setBorder(BorderFactory.createLineBorder(Color.BLUE));
  179.                 this.setForeground(Color.BLUE);
  180.                 this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));
  181.  
  182.             } else {
  183.                 this.setBorder(BorderFactory.createEtchedBorder());
  184.             }
  185.             if (c.get(Calendar.YEAR) == selected.get(Calendar.YEAR)) {
  186.                 this.setBorder(BorderFactory.createLineBorder(Color.RED));
  187.                 this.setForeground(Color.RED);
  188.                 this.setFont(this.getFont().deriveFont(Font.BOLD, this.getFont().getSize()));
  189.             }
  190.  
  191.             this.addMouseListener(new MouseAdapter() {
  192.                 @Override
  193.                 public void mouseExited(MouseEvent e) {
  194.                     setBackground(null);
  195.                 }
  196.  
  197.                 @Override
  198.                 public void mouseEntered(MouseEvent e) {
  199.                     setBackground(Color.white);
  200.                 }
  201.             });
  202.             this.addActionListener(new ActionListener() {
  203.                 @Override
  204.                 public void actionPerformed(ActionEvent e) {
  205.                     Calendar c = Calendar.getInstance();
  206.                     c.setTimeInMillis(stamp);
  207.  
  208.                     JDatePickPane pick = (JDatePickPane) getParent().getParent();
  209.                     pick.viewMonth(c);
  210.                 }
  211.             });
  212.         }
  213.     }
  214.  
  215.     private String format;
  216.  
  217.     private Calendar selectedDate;
  218.  
  219.     private PickDate pickAtion;
  220.  
  221.     private String[] dayDisplayNames;
  222.  
  223.     private Locale loc;
  224.  
  225.     private Icon leftArrow;
  226.     private Icon rightArrow;
  227.  
  228.     public JDatePickPane() {
  229.         this.selectedDate = Calendar.getInstance();
  230.         this.setLayout(new BorderLayout());
  231.         this.selectedDate = Calendar.getInstance();
  232.         this.loc = Locale.getDefault();
  233.         this.format = JDatePickPane.DEFAULT_DATE_FORMAT;
  234.  
  235.         this.leftArrow = getImageIcon("/bruce/lib/swing/img/Arrow.blue.left.png", 20, 20);
  236.         this.rightArrow = getImageIcon("/bruce/lib/swing/img/Arrow.blue.right.png", 20, 20);
  237.  
  238.         this.view();
  239.     }
  240.  
  241.     private void putToday() {
  242.         stopWatch("Today Bar");
  243.  
  244.         JPanel panel = new JPanel(new FlowLayout());
  245.         String today = String.format("%tF", Calendar.getInstance());
  246.         try {
  247.             if (this.format != null) {
  248.                 SimpleDateFormat f = new SimpleDateFormat(this.format);
  249.                 today = f.format(new Date());
  250.             }
  251.         } catch (Exception e) {
  252.         }
  253.         final JLabel lbToday = new JLabel(today);
  254.         lbToday.addMouseListener(new MouseAdapter() {
  255.             @Override
  256.             public void mouseEntered(MouseEvent e) {
  257.                 lbToday.setFont(lbToday.getFont().deriveFont(Font.BOLD, lbToday.getFont().getSize()));
  258.             }
  259.  
  260.             @Override
  261.             public void mouseExited(MouseEvent e) {
  262.                 lbToday.setFont(lbToday.getFont().deriveFont(Font.PLAIN, lbToday.getFont().getSize()));
  263.             }
  264.  
  265.             @Override
  266.             public void mouseClicked(MouseEvent e) {
  267.                 selectedDate = Calendar.getInstance();
  268.                 view(selectedDate);
  269.  
  270.                 if (pickAtion != null) {
  271.                     pickAtion.pick(selectedDate);
  272.                 }
  273.             }
  274.         });
  275.         panel.add(lbToday);
  276.         this.add(panel, BorderLayout.SOUTH);
  277.     }
  278.  
  279.     private void setYearBarText(JLabel label, Calendar c) {
  280.         label.setText(String.format("%d - %d", //
  281.                 c.get(Calendar.YEAR) - c.get(Calendar.YEAR) % 12 + 1,//
  282.                 c.get(Calendar.YEAR) - c.get(Calendar.YEAR) % 12 + 12));
  283.     }
  284.  
  285.     private void putYearBar(final Calendar c) {
  286.         stopWatch("Year Bar");
  287.  
  288.         JPanel panel = new JPanel(new BorderLayout());
  289.  
  290.         final JLabel lbPeriod = new JLabel();
  291.         lbPeriod.setHorizontalAlignment(SwingConstants.CENTER);
  292.         this.setYearBarText(lbPeriod, c);
  293.         panel.add(lbPeriod, BorderLayout.CENTER);
  294.  
  295.         JButton btnLeft = this.leftArrow == null ? new JButton("<") : new JButton(this.leftArrow);
  296.         btnLeft.setBorderPainted(false);
  297.         btnLeft.setBorder(BorderFactory.createEmptyBorder());
  298.         btnLeft.addActionListener(new ActionListener() {
  299.             @Override
  300.             public void actionPerformed(ActionEvent e) {
  301.                 Calendar s = (Calendar) c.clone();
  302.                 s.add(Calendar.YEAR, -12);
  303.  
  304.                 setYearBarText(lbPeriod, c);
  305.                 viewYear(s);
  306.             }
  307.         });
  308.         panel.add(btnLeft, BorderLayout.WEST);
  309.  
  310.         JButton btnRight = this.rightArrow == null ? new JButton(">") : new JButton(this.rightArrow);
  311.         btnRight.setBorderPainted(false);
  312.         btnRight.setBorder(BorderFactory.createEmptyBorder());
  313.         btnRight.addActionListener(new ActionListener() {
  314.             @Override
  315.             public void actionPerformed(ActionEvent e) {
  316.                 Calendar s = (Calendar) c.clone();
  317.                 s.add(Calendar.YEAR, 12);
  318.  
  319.                 setYearBarText(lbPeriod, c);
  320.                 viewYear(s);
  321.             }
  322.         });
  323.         panel.add(btnRight, BorderLayout.EAST);
  324.  
  325.         this.add(panel, BorderLayout.NORTH);
  326.     }
  327.  
  328.     private void setMonthBarText(JButton label, Calendar c) {
  329.         label.setText(String.valueOf(c.get(Calendar.YEAR)));
  330.     }
  331.  
  332.     private void putMonthBar(final Calendar c) {
  333.         stopWatch("Month Bar");
  334.  
  335.         JPanel panel = new JPanel(new BorderLayout());
  336.  
  337.         final JButton btnPeriod = new JButton();
  338.         btnPeriod.setHorizontalAlignment(SwingConstants.CENTER);
  339.         btnPeriod.setBorder(BorderFactory.createEmptyBorder());
  340.         btnPeriod.setBorderPainted(false);
  341.  
  342.         this.setMonthBarText(btnPeriod, c);
  343.         btnPeriod.addActionListener(new ActionListener() {
  344.             @Override
  345.             public void actionPerformed(ActionEvent e) {
  346.                 viewYear(c);
  347.             }
  348.         });
  349.         btnPeriod.addMouseListener(new MouseAdapter() {
  350.             @Override
  351.             public void mouseEntered(MouseEvent e) {
  352.                 btnPeriod.setFont(btnPeriod.getFont().deriveFont(Font.BOLD, btnPeriod.getFont().getSize()));
  353.             }
  354.  
  355.             @Override
  356.             public void mouseExited(MouseEvent e) {
  357.                 btnPeriod.setFont(btnPeriod.getFont().deriveFont(Font.PLAIN, btnPeriod.getFont().getSize()));
  358.             }
  359.         });
  360.         panel.add(btnPeriod, BorderLayout.CENTER);
  361.  
  362.         JButton btnLeft = this.leftArrow == null ? new JButton("<") : new JButton(this.leftArrow);
  363.         btnLeft.setBorderPainted(false);
  364.         btnLeft.setBorder(BorderFactory.createEmptyBorder());
  365.         btnLeft.addActionListener(new ActionListener() {
  366.             @Override
  367.             public void actionPerformed(ActionEvent e) {
  368.                 Calendar s = (Calendar) c.clone();
  369.                 s.add(Calendar.YEAR, -1);
  370.  
  371.                 setMonthBarText(btnPeriod, c);
  372.                 viewMonth(s);
  373.             }
  374.         });
  375.         panel.add(btnLeft, BorderLayout.WEST);
  376.  
  377.         JButton btnRight = this.rightArrow == null ? new JButton(">") : new JButton(this.rightArrow);
  378.         btnRight.setBorderPainted(false);
  379.         btnRight.setBorder(BorderFactory.createEmptyBorder());
  380.         btnRight.addActionListener(new ActionListener() {
  381.             @Override
  382.             public void actionPerformed(ActionEvent e) {
  383.                 Calendar s = (Calendar) c.clone();
  384.                 s.add(Calendar.YEAR, 1);
  385.                 setMonthBarText(btnPeriod, c);
  386.  
  387.                 viewMonth(s);
  388.             }
  389.         });
  390.         panel.add(btnRight, BorderLayout.EAST);
  391.  
  392.         this.add(panel, BorderLayout.NORTH);
  393.     }
  394.  
  395.     private void setDateBarText(JButton label, Calendar c) {
  396.         label.setText(String.format("%s, %d", //
  397.                 c.getDisplayName(Calendar.MONTH, Calendar.LONG, loc),//
  398.                 c.get(Calendar.YEAR)));
  399.     }
  400.  
  401.     private void putDateBar(final Calendar c) {
  402.         stopWatch("Date Bar");
  403.  
  404.         JPanel panel = new JPanel(new BorderLayout());
  405.  
  406.         final JButton btnPeriod = new JButton();
  407.         btnPeriod.setHorizontalAlignment(SwingConstants.CENTER);
  408.         btnPeriod.setBorder(BorderFactory.createEmptyBorder());
  409.         btnPeriod.setBorderPainted(false);
  410.  
  411.         this.setDateBarText(btnPeriod, c);
  412.         btnPeriod.addActionListener(new ActionListener() {
  413.             @Override
  414.             public void actionPerformed(ActionEvent e) {
  415.                 viewMonth(c);
  416.             }
  417.         });
  418.         btnPeriod.addMouseListener(new MouseAdapter() {
  419.             @Override
  420.             public void mouseEntered(MouseEvent e) {
  421.                 btnPeriod.setFont(btnPeriod.getFont().deriveFont(Font.BOLD, btnPeriod.getFont().getSize()));
  422.             }
  423.  
  424.             @Override
  425.             public void mouseExited(MouseEvent e) {
  426.                 btnPeriod.setFont(btnPeriod.getFont().deriveFont(Font.PLAIN, btnPeriod.getFont().getSize()));
  427.             }
  428.         });
  429.         panel.add(btnPeriod, BorderLayout.CENTER);
  430.  
  431.         JButton btnLeft = this.leftArrow == null ? new JButton("<") : new JButton(this.leftArrow);
  432.         btnLeft.setBorderPainted(false);
  433.         btnLeft.setBorder(BorderFactory.createEmptyBorder());
  434.         btnLeft.addActionListener(new ActionListener() {
  435.             @Override
  436.             public void actionPerformed(ActionEvent e) {
  437.                 Calendar s = (Calendar) c.clone();
  438.                 s.add(Calendar.MONTH, -1);
  439.  
  440.                 view(s);
  441.  
  442.                 setDateBarText(btnPeriod, c);
  443.             }
  444.         });
  445.         panel.add(btnLeft, BorderLayout.WEST);
  446.  
  447.         JButton btnRight = this.rightArrow == null ? new JButton(">") : new JButton(this.rightArrow);
  448.         btnRight.setBorderPainted(false);
  449.         btnRight.setBorder(BorderFactory.createEmptyBorder());
  450.         btnRight.addActionListener(new ActionListener() {
  451.             @Override
  452.             public void actionPerformed(ActionEvent e) {
  453.                 Calendar s = (Calendar) c.clone();
  454.                 s.add(Calendar.MONTH, 1);
  455.  
  456.                 view(s);
  457.  
  458.                 setDateBarText(btnPeriod, c);
  459.             }
  460.         });
  461.         panel.add(btnRight, BorderLayout.EAST);
  462.  
  463.         this.add(panel, BorderLayout.NORTH);
  464.     }
  465.  
  466.     private void putYearContent(Calendar c) {
  467.         stopWatch("Year Bar");
  468.  
  469.         JPanel panel = new JPanel(new GridLayout(3, 4));
  470.  
  471.         Calendar s = (Calendar) c.clone();
  472.         s.set(Calendar.YEAR, s.get(Calendar.YEAR) - s.get(Calendar.YEAR) % 12);
  473.         for (int i = 0; i < 12; i++) {
  474.             s.add(Calendar.YEAR, 1);
  475.             panel.add(new YearCell(s, this.selectedDate));
  476.         }
  477.  
  478.         this.add(panel, BorderLayout.CENTER);
  479.     }
  480.  
  481.     private void putMonthContent(Calendar c) {
  482.         stopWatch("Month Bar");
  483.  
  484.         JPanel panel = new JPanel(new GridLayout(3, 4));
  485.  
  486.         Calendar s = (Calendar) c.clone();
  487.         for (int i = 0; i < 12; i++) {
  488.             s.set(Calendar.MONTH, i);
  489.             panel.add(new MonthCell(s, this.selectedDate));
  490.         }
  491.  
  492.         this.add(panel, BorderLayout.CENTER);
  493.     }
  494.  
  495.     private void putDateContent(Calendar c) {
  496.         stopWatch("Date Content");
  497.  
  498.         JPanel panel = new JPanel(new GridBagLayout());
  499.         Insets insets = new Insets(1, 1, 1, 1);
  500.         this.putHeaders(panel, insets);
  501.  
  502.         int rows = this.getMonthRowsCount(c);
  503.         Calendar d = this.getFirstDate(c);
  504.  
  505.         for (int y = 1; y < rows + 1; y++) {
  506.             for (int x = 1; x < 8; x++) {
  507.                 panel.add(new DayCell(d, c, this.selectedDate), new GridBagConstraints(x, y, 1, 1, 0, 0, 10, 1, insets, 10, 0));
  508.                 d.add(Calendar.DATE, 1);
  509.             }
  510.         }
  511.  
  512.         this.add(panel, BorderLayout.CENTER);
  513.     }
  514.  
  515.     private void viewYear(Calendar c) {
  516.         this.clear();
  517.         this.putYearContent(c);
  518.         this.putYearBar(c);
  519.         this.pack();
  520.     }
  521.  
  522.     private void viewMonth(Calendar c) {
  523.         this.clear();
  524.         this.putMonthContent(c);
  525.         this.putMonthBar(c);
  526.  
  527.         this.pack();
  528.     }
  529.  
  530.     /**
  531.      * 處理星期顯示格
  532.      * 
  533.      * @param panel
  534.      * @param insets
  535.      */
  536.     private void putHeaders(JPanel panel, Insets insets) {
  537.         if (this.dayDisplayNames == null) {
  538.             Calendar s = Calendar.getInstance();
  539.             s.set(Calendar.DAY_OF_WEEK, 1);
  540.  
  541.             Color c = null;
  542.             for (int i = 0; i < 7; i++) {
  543.                 // 星期表示法
  544.                 String h = s.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, loc);
  545.                 s.add(Calendar.DATE, 1);
  546.                 if (loc == Locale.TAIWAN || loc == Locale.CHINA || loc == Locale.CHINESE || loc == Locale.SIMPLIFIED_CHINESE || loc == Locale.TRADITIONAL_CHINESE) {
  547.                     h = h.substring(h.length() - 1);
  548.                 } else if (loc == Locale.JAPAN || loc == Locale.JAPANESE) {
  549.                     h = h.substring(0, 1);
  550.                 } else {
  551.                     h = h.substring(0, 3);
  552.                 }
  553.  
  554.                 switch (i) {
  555.                 case 0:
  556.                     c = Color.red;
  557.                     break;
  558.                 case 6:
  559.                     c = Color.BLUE;
  560.                     break;
  561.                 default:
  562.                     c = Color.BLACK;
  563.                     break;
  564.                 }
  565.                 panel.add(this.createHeader(h, c), new GridBagConstraints(+ 1, 0, 1, 1, 0, 0, 10, 1, insets, 10, 0));
  566.             }
  567.         } else {
  568.             String[] headers = Arrays.copyOf(this.dayDisplayNames, 7);
  569.             Color c = null;
  570.             for (int i = 0; i < 7; i++) {
  571.                 switch (i) {
  572.                 case 0:
  573.                     c = Color.red;
  574.                     break;
  575.                 case 6:
  576.                     c = Color.BLUE;
  577.                     break;
  578.                 default:
  579.                     c = Color.BLACK;
  580.                     break;
  581.                 }
  582.                 panel.add(this.createHeader(headers[i], c), new GridBagConstraints(+ 1, 0, 1, 1, 0, 0, 10, 1, insets, 10, 0));
  583.             }
  584.         }
  585.     }
  586.  
  587.     /**
  588.      * 星期
  589.      * 
  590.      * @param text
  591.      * @param fontColor
  592.      * @return
  593.      */
  594.     private JLabel createHeader(String text, Color fontColor) {
  595.         JLabel l = new JLabel(text, SwingConstants.CENTER);
  596.         l.setBorder(BorderFactory.createEtchedBorder());
  597.         l.setOpaque(true);
  598.         l.setBackground(Color.WHITE);
  599.         l.setForeground(fontColor);
  600.         return l;
  601.     }
  602.  
  603.     /**
  604.      * 計算月份的列數
  605.      * 
  606.      * @param c
  607.      * @return
  608.      */
  609.     private int getMonthRowsCount(Calendar c) {
  610.         Calendar s = (Calendar) c.clone();
  611.         s.set(Calendar.DATE, 1);
  612.         return (int) Math.ceil((s.get(Calendar.DAY_OF_WEEK) + s.getActualMaximum(Calendar.DAY_OF_MONTH) - 1) / 7.0);
  613.     }
  614.  
  615.     /**
  616.      * 計算顯示的第一個日期
  617.      * 
  618.      * @param c
  619.      * @return
  620.      */
  621.     private Calendar getFirstDate(Calendar c) {
  622.         Calendar s = (Calendar) c.clone();
  623.         s.set(Calendar.DATE, 1);
  624.         s.add(Calendar.DATE, -1 * (s.get(Calendar.DAY_OF_WEEK) - 1));
  625.         return s;
  626.     }
  627.  
  628.     /**
  629.      * 清除
  630.      */
  631.     private void clear() {
  632.         stopWatch("Clear");
  633.  
  634.         for (int i = this.getComponentCount() - 1; i > -1; i--) {
  635.             this.remove(i);
  636.         }
  637.  
  638.         this.putToday();
  639.         System.gc();
  640.     }
  641.  
  642.     /**
  643.      * 重整大小
  644.      */
  645.     private void pack() {
  646.         stopWatch("Pack");
  647.  
  648.         this.revalidate();
  649.         // resize
  650.         Container cc = this.getParent();
  651.         while (cc != null) {
  652.             if (cc instanceof Window) {
  653.                 ((Window) cc).pack();
  654.                 break;
  655.             }
  656.             cc = cc.getParent();
  657.         }
  658.     }
  659.  
  660.     /**
  661.      * 測試時間
  662.      * 
  663.      * @param what
  664.      */
  665.     private void stopWatch(String what) {
  666.         // test time execute
  667.         // System.out.printf("%2$s : %1$tY/%1$tm/%1$td %1$tH:%1$tM:%1$tS %1$tL%n",
  668.         // new Date(), what);
  669.     }
  670.  
  671.     /**
  672.      * 選取日期的觸發動作
  673.      * 
  674.      * @param pick
  675.      */
  676.     public void setDateSelected(PickDate pick) {
  677.         this.pickAtion = pick;
  678.     }
  679.  
  680.     /**
  681.      * 目前選取日期
  682.      * 
  683.      * @return
  684.      */
  685.     public Calendar getSelectedCalendar() {
  686.         return (Calendar) this.selectedDate.clone();
  687.     }
  688.  
  689.     /**
  690.      * 設定選取的日期
  691.      * 
  692.      * @param c
  693.      */
  694.     public void setSelectedCalendar(Calendar c) {
  695.         this.selectedDate = c;
  696.     }
  697.  
  698.     /**
  699.      * 取得星期的顯示名稱
  700.      * 
  701.      * @return
  702.      */
  703.     public String[] getDayNames() {
  704.         return this.dayDisplayNames;
  705.     }
  706.  
  707.     /**
  708.      * 設定星期的顯示名稱
  709.      * 
  710.      * @param names
  711.      */
  712.     public void setDayName(String[] names) {
  713.         this.dayDisplayNames = names;
  714.         this.view(this.selectedDate);
  715.     }
  716.  
  717.     /**
  718.      * 設定今天的顯示格式
  719.      * 
  720.      * @param format
  721.      */
  722.     public void setTodayFormat(String format) {
  723.         this.format = format;
  724.         this.putToday();
  725.     }
  726.  
  727.     public String getTodayFormat() {
  728.         return this.format;
  729.     }
  730.  
  731.     public void setUILocale(Locale l) {
  732.         this.loc = l;
  733.         this.view(this.selectedDate);
  734.     }
  735.  
  736.     public Locale getUILocale() {
  737.         return this.loc;
  738.     }
  739.  
  740.     public void setLeftArrow(Icon icon) {
  741.         this.leftArrow = icon;
  742.         this.view(this.selectedDate);
  743.     }
  744.  
  745.     public void setRightArrow(Icon icon) {
  746.         this.rightArrow = icon;
  747.         this.view(this.selectedDate);
  748.     }
  749.  
  750.     /**
  751.      * 顯示選擇的日期
  752.      * 
  753.      * @param c
  754.      */
  755.     public void view(Calendar c) {
  756.         // claer
  757.         this.clear();
  758.  
  759.         this.putDateBar(c);
  760.         this.putDateContent(c);
  761.  
  762.         this.pack();
  763.     }
  764.  
  765.     /**
  766.      * 顯示今天的日期
  767.      */
  768.     public void view() {
  769.         this.view(Calendar.getInstance());
  770.     }
  771. }