OSDN Git Service

設定ファイルの保存,及び読み込み部分がうまく動かなかったのを修正.
[nt-manager/nt-manager.git] / src / twitter / gui / action / TweetMainAction.java
1 package twitter.gui.action;
2
3 import java.awt.Color;
4 import java.awt.Desktop;
5 import java.awt.Dimension;
6 import java.awt.Font;
7 import java.awt.Point;
8 import java.awt.event.ActionEvent;
9 import java.io.File;
10 import java.io.FileInputStream;
11 import java.io.FileNotFoundException;
12 import java.io.FileOutputStream;
13 import java.io.IOException;
14 import java.io.UnsupportedEncodingException;
15 import java.net.URI;
16 import java.net.URL;
17 import java.net.URLEncoder;
18 import java.text.DateFormat;
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Properties;
22 import java.util.Set;
23 import java.util.TreeSet;
24 import java.util.logging.Level;
25 import java.util.logging.Logger;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28 import javax.swing.ImageIcon;
29
30 import javax.swing.JEditorPane;
31 import javax.swing.JFrame;
32 import javax.swing.JLabel;
33 import javax.swing.JOptionPane;
34 import javax.swing.JPanel;
35 import javax.swing.JScrollPane;
36 import javax.swing.JTabbedPane;
37 import javax.swing.JTable;
38 import javax.swing.JTextPane;
39 import javax.swing.table.TableModel;
40 import javax.swing.text.Style;
41 import javax.swing.text.StyleConstants;
42 import javax.swing.text.html.HTMLDocument;
43 import javax.swing.text.html.StyleSheet;
44 import twitter.action.TweetDirectMessageGetter;
45 import twitter.action.TweetGetter;
46 import twitter.action.TweetMentionGetter;
47 import twitter.action.TweetSearchResultGetter;
48 import twitter.action.TweetSendDirectMessageGetter;
49 import twitter.action.TweetTimelineGetter;
50
51 import twitter.gui.component.TweetTabbedTable;
52 import twitter.gui.component.TweetTableModel;
53 import twitter.gui.form.AboutDialog;
54 import twitter.gui.form.AccountDialog;
55 import twitter.gui.form.ConfigurationDialog;
56 import twitter.gui.form.DirectMessageDialog;
57 import twitter.gui.form.KeywordSearchDialog;
58 import twitter.manage.TweetConfiguration;
59 import twitter.manage.TweetManager;
60 import twitter.task.ExistTimerIDException;
61 import twitter.task.TimerID;
62 import twitter.task.TweetTaskException;
63 import twitter.task.TweetTaskManager;
64 import twitter.task.TweetUpdateTask;
65 import twitter4j.Status;
66 import twitter4j.TwitterException;
67
68 /**
69  * GUIのアクション部分
70  * 
71  * @author nishio
72  * 
73  */
74 public class TweetMainAction {
75
76     // 基本設定を保存するファイル名
77     public static final String BASIC_SETTING_FILENAME = TweetConfiguration.BASIC_SETTING_FILENAME;
78     // httpのパターン
79     private static final Pattern convURLLinkPtn = Pattern.compile(
80             "(http://|https://){1}[\\w\\.\\-/:\\#\\?\\=\\&\\;\\%\\~\\+]+",
81             Pattern.CASE_INSENSITIVE);
82     // default char encoding
83     private static final String DEFAULT_CHARACTER_ENCODING = "UTF-8";
84     // 設定ファイルを保存するディレクトリ名
85     public static final String PROPERTIES_DIRECTORY = "properties";
86     // search twitterのクエリ
87     private static final String SEARCH_QUERY = "search?q=";
88     // search twitterのURL
89     private static final String SEARCH_TWITTER_URL = "http://search.twitter.com/";
90     // Direct Messageタブに表示する文字
91     public static final String TAB_DIRECT_MESSAGE_STRING = "Message";
92     // Mentionタブに表示する文字
93     public static final String TAB_MENTION_STRING = "Mention";
94     // タイムラインタブに表示する文字
95     public static final String TAB_TIMELINE_STRING = "Timeline";
96     //Send Direct Messageタブに表示する文字
97     public static final String TAB_SEND_DIRECT_MESSAGE_STRING = "Send";
98     // テーブルのデータ量が以下の値を超えたら古いデータから削除
99     private static final int TABLE_ELEMENT_MAX_SIZE = 200;
100     // twitterの公式URL
101     private static final String TWITTER_URL = "http://twitter.com/";
102     // 基本設定用ダイアログ
103     private ConfigurationDialog configurationDialog = null;
104     // 現在選択しているStatus情報
105     private Status currentStatus = null;
106     // 詳細情報パネル
107     private JPanel detailInfoPanel = null;
108     // ダイレクトメッセージ送信用ダイアログ
109     private DirectMessageDialog directMessageDialog = null;
110     //Twitter全体からキーワード検索ダイアログ
111     private KeywordSearchDialog keywordSearchDialog = null;
112     // 新しく取得した部分のテーブルカラー
113     private Color newTableColor = new Color(224, 255, 255);
114     // TLのフォント名
115     private String tlFontName = "Takao Pゴシック";
116     // TLのフォントサイズ
117     private int tlFontSize = 13;
118     // 詳細情報のフォント名
119     private String detailFontName = "Takao Pゴシック";
120     // 詳細情報のフォントサイズ
121     private int detailFontSize = 13;
122     // テーブル1要素の高さ
123     private int tableElementHeight = 50;
124     //メインフレームの幅
125     private int mainFrameWidth = 729;
126     //メインフレームの高さ
127     private int mainFrameHeight = 629;
128     // MainFrame
129     private JFrame mainFrame = null;
130     // 設定
131     private Properties property = null;
132     // 現在テーブルで選択しているユーザ画像のURL
133     private URL selectedUserImageURL = null;
134     // 現在テーブルで選択しているユーザの名前
135     private String selectedUsername = null;
136     // ステータス表示ラベル
137     private JLabel statusBarLabel = null;
138     // 自分がつぶやきをかく領域
139     private JTextPane tweetBoxPane = null;
140     //自分がつぶやきを書く領域のスクロールペーン
141     private JScrollPane tweetBoxScrollPane = null;
142     // tweet情報などを表示するタブ
143     private JTabbedPane tweetMainTab = null;
144     // Tweet管理
145     private TweetManager tweetManager = null;
146     // tweetを表示するTextPane
147     private JEditorPane tweetMessageBox = null;
148     // つぶやくことができる文字数を表示するラベル
149     private JLabel tweetMessageCountLabel = null;
150     private int uncheckedDirectMessageCount = 0;
151     private int uncheckedMentionTweetCount = 0;
152
153     //Tweetの詳細情報を表示する部分
154     private JLabel userImageLabel = null;
155     private JLabel userNameLabel = null;
156     private JLabel updateTimeLabel = null;
157     private JLabel followerLabel = null;
158     private JLabel followingLabel = null;
159     private JLabel locationLabel = null;
160     private JEditorPane clientNameLabel = null;
161     private JLabel updateLabel = null;
162     private JEditorPane userIntroBox = null;
163     private JEditorPane userWebBox = null;
164
165     // 新しく取得したtweetでまだ参照していない数
166     private int uncheckedTimelineTweetCount = 0;
167     private AboutDialog aboutDialog = null;
168     //アカウント情報表示ダイアログ
169     private AccountDialog accountDialog;
170     //ツイートを表示するテーブル管理
171     private List<TweetTabbedTable> tweetTabbedTableList = new ArrayList<TweetTabbedTable>();
172     //ツイートテーブルの情報を一定間隔で更新するクラスを作成
173     private TweetTaskManager tweetTaskManager = new TweetTaskManager();
174
175     //情報更新間隔[sec]
176     private int getTimelinePeriod = 60;
177     private int getMentionPeriod = 60 * 3;
178     private int getDirectMessagePeriod = 60 * 15;
179     private int getSendDirectMessagePeriod = 60 * 30;
180
181     /**
182      *
183      * @param mainFrame
184      * @param tweetManager
185      * @param statusBarLabel
186      * @param tweetTableModel
187      * @param mentionTableModel
188      * @param directMessageTableModel
189      * @param sendDirectMessageTableModel
190      * @param mainTweetTable
191      * @param mentionTable
192      * @param directMessageTable
193      * @param sendDirectMessageTable
194      * @param tweetBoxPane
195      * @param tweetBoxScrollPane
196      * @param tweetMessageCountLabel
197      * @param detailInfoPanel
198      * @param tweetMainTab
199      * @param tweetMessageBox
200      * @param userImageLabel
201      * @param userNameLabel
202      * @param updateTimeLabel
203      * @param followerLabel
204      * @param followingLabel
205      * @param locationLabel
206      * @param clientNameLabel
207      * @param updateLabel
208      * @param userIntroBox
209      * @param userWebBox
210      */
211     public TweetMainAction(JFrame mainFrame,
212             TweetManager tweetManager,
213             JLabel statusBarLabel,
214             JTextPane tweetBoxPane,
215             JScrollPane tweetBoxScrollPane,
216             JLabel tweetMessageCountLabel,
217             JPanel detailInfoPanel,
218             JTabbedPane tweetMainTab,
219             JEditorPane tweetMessageBox,
220             JLabel userImageLabel,
221             JLabel userNameLabel,
222             JLabel updateTimeLabel,
223             JLabel followerLabel,
224             JLabel followingLabel,
225             JLabel locationLabel,
226             JEditorPane clientNameLabel,
227             JLabel updateLabel,
228             JEditorPane userIntroBox,
229             JEditorPane userWebBox) {
230         this.mainFrame = mainFrame;
231         this.tweetManager = tweetManager;
232         this.statusBarLabel = statusBarLabel;
233         this.tweetBoxPane = tweetBoxPane;
234         this.tweetMessageCountLabel = tweetMessageCountLabel;
235         this.detailInfoPanel = detailInfoPanel;
236         this.tweetMainTab = tweetMainTab;
237         this.tweetMessageBox = tweetMessageBox;
238         this.tweetBoxScrollPane = tweetBoxScrollPane;
239
240         //詳細情報部分
241         this.userImageLabel = userImageLabel;
242         this.userNameLabel = userNameLabel;
243         this.updateTimeLabel = updateTimeLabel;
244         this.userIntroBox = userIntroBox;
245         this.followerLabel = followerLabel;
246         this.followingLabel = followingLabel;
247         this.locationLabel = locationLabel;
248         this.userWebBox = userWebBox;
249         this.clientNameLabel = clientNameLabel;
250         this.updateLabel = updateLabel;
251
252         // 設定ファイルの読み込み
253         try {
254             loadProperties();
255         } catch (FileNotFoundException e) {
256             e.printStackTrace();
257         } catch (IOException e) {
258             e.printStackTrace();
259         }
260         // フォント情報を反映
261         updateFontInformationToComponent();
262
263         //フレームの大きさを反映
264         mainFrame.setSize(this.mainFrameWidth, this.mainFrameHeight);
265         mainFrame.setPreferredSize(new Dimension(this.mainFrameWidth, this.mainFrameHeight));
266     }
267
268     // フォント情報をコンポーネントに反映
269     public void updateFontInformationToComponent() {
270         try {
271             Font tlFont = null;
272             if (this.tlFontName != null) {
273                 tlFont = new Font(this.tlFontName, Font.PLAIN, this.tlFontSize);
274             }
275             Font detailFont = null;
276             if (this.detailFontName != null) {
277                 detailFont = new Font(this.detailFontName, Font.PLAIN,
278                         this.detailFontSize);
279             }
280
281             //すべてのテーブルにフォント情報を反映
282             for( TweetTabbedTable t : this.tweetTabbedTableList) {
283                 t.getTable().setFont(tlFont);
284             }
285
286             // tweetメッセージボックスのフォントはhtmlレベルで変更する必要がある
287             this.tweetMessageBox.setFont(detailFont);
288             // htmlフォント変更
289             HTMLDocument doc = (HTMLDocument) this.tweetMessageBox.getDocument();
290             StyleSheet[] style = doc.getStyleSheet().getStyleSheets();
291             for (int i = style.length - 1; i >= 0; i--) {
292                 Style body = style[i].getStyle("body");
293                 if (body != null) {
294                     StyleConstants.setFontFamily(body, detailFont.getFontName());
295                     StyleConstants.setFontSize(body, detailFont.getSize());
296                 }
297             }
298
299         } catch (Exception e) {
300             e.printStackTrace();
301         }
302     }
303
304     /**
305      * 新しいタブを追加
306      * @param timerID TimerIDクラスで生成したタイマーID
307      * @param period 情報更新間隔[sec]
308      * @param tweetGetter 実行するアクション
309      * @param tabTitle 追加するタブのタイトル
310      */
311     public void actionAddTab(String timerID, int period, TweetGetter tweetGetter, String tabTitle) {
312         int numOfTab = this.tweetTabbedTableList.size();
313         //すでに追加されているタブの数
314
315         //周期的に情報を更新する
316         if( period > 0 ) {
317             try {
318                 //テーブルを作成
319                 final TweetTabbedTable table = new TweetTabbedTable(tweetGetter, tabTitle,
320                         this.tweetMainTab, numOfTab,
321                         this.tableElementHeight, this.tweetManager,
322                         this, newTableColor, tableElementHeight, timerID);
323
324                 this.tweetTaskManager.addTask(timerID, new TweetUpdateTask() {
325
326                     @Override
327                     public void runTask() throws TweetTaskException {
328                         //ツイート情報を一定間隔で更新
329                         table.updateTweetTable();
330                     }
331                 });
332                 //更新開始
333                 this.tweetTaskManager.startTask(timerID, period * 1000L);
334
335                 //タブにテーブルを追加
336                 table.addTableToTab();
337                 //タブリストに追加
338                 this.tweetTabbedTableList.add(table);
339                 //searchTable.updateTweetTable();
340             } catch (TweetTaskException ex) {
341                 Logger.getLogger(TweetMainAction.class.getName()).log(Level.SEVERE, null, ex);
342             }
343         }
344
345         //フォント情報を更新
346         this.updateFontInformationToComponent();
347         //テーブルの高さをすべて更新
348         this.updateTableHeight( this.getTableElementHeight() );
349     }
350
351     /**
352      * mentionタブを追加する
353      * @param period 情報更新間隔[sec]
354      */
355     public void actionAddMentionTab(int period) {
356         TimerID timerID = TimerID.getInstance();
357         String id = TimerID.createMentionID();
358         try {
359             //既にIDが存在していたらここで例外発生
360             timerID.addID(id);
361             //検索結果を表示するタブを生成
362             actionAddTab(id, period, new TweetMentionGetter(tweetManager),
363                     TweetMainAction.TAB_MENTION_STRING);
364         } catch (ExistTimerIDException ex) {
365             JOptionPane.showMessageDialog(null, "そのタブは既に存在しています",
366                     "Error", JOptionPane.ERROR_MESSAGE);
367         }
368     }
369
370     /**
371      * timelineタブを追加する
372      * @param period[sec]
373      */
374     public void actionAddTimelineTab(int period) {
375         TimerID timerID = TimerID.getInstance();
376         String id = TimerID.createTimelineID();
377         try {
378             //既にIDが存在していたらここで例外発生
379             timerID.addID(id);
380             //検索結果を表示するタブを生成
381             actionAddTab(id, period, new TweetTimelineGetter(tweetManager),
382                     TweetMainAction.TAB_TIMELINE_STRING);
383         } catch (ExistTimerIDException ex) {
384             JOptionPane.showMessageDialog(null, "そのタブは既に存在しています",
385                     "Error", JOptionPane.ERROR_MESSAGE);
386         }
387     }
388
389     /**
390      * ダイレクトメッセージタブを追加する
391      * @param period 更新間隔[sec]
392      */
393     public void actionAddDirectMessageTab(int period) {
394         TimerID timerID = TimerID.getInstance();
395         String id = TimerID.createDirectMessageID();
396         try {
397             //既にIDが存在していたらここで例外発生
398             timerID.addID(id);
399             //検索結果を表示するタブを生成
400             actionAddTab(id, period, new TweetDirectMessageGetter(tweetManager),
401                     TweetMainAction.TAB_DIRECT_MESSAGE_STRING);
402         } catch (ExistTimerIDException ex) {
403             JOptionPane.showMessageDialog(null, "そのタブは既に存在しています",
404                     "Error", JOptionPane.ERROR_MESSAGE);
405         }
406     }
407
408     /**
409      * SendDMタブを追加する
410      * @param period
411      */
412     public void actionAddSendDirectMessageTab(int period) {
413         TimerID timerID = TimerID.getInstance();
414         String id = TimerID.createSendDirectMessageID();
415         try {
416             //既にIDが存在していたらここで例外発生
417             timerID.addID(id);
418             //検索結果を表示するタブを生成
419             actionAddTab(id, period, new TweetSendDirectMessageGetter(tweetManager),
420                     TweetMainAction.TAB_SEND_DIRECT_MESSAGE_STRING);
421         } catch (ExistTimerIDException ex) {
422             JOptionPane.showMessageDialog(null, "そのタブは既に存在しています",
423                     "Error", JOptionPane.ERROR_MESSAGE);
424         }
425     }
426
427
428     /**
429      * ツイート検索結果を表示するタブを新しく追加
430      * @param searchWord
431      * @param period 更新周期[sec] 0以下の場合は更新しない
432      */
433     public void actionAddNewSearchResultTab(String searchWord, int period) {
434         TimerID timerID = TimerID.getInstance();
435         String id = TimerID.createSearchTimerID(searchWord);
436         try {
437             //既にIDが存在していたらここで例外発生
438             timerID.addID(id);
439             //検索結果を表示するタブを生成
440             actionAddTab(id, period, new TweetSearchResultGetter(this.tweetManager, searchWord), searchWord);
441         } catch (ExistTimerIDException ex) {
442             JOptionPane.showMessageDialog(null, "そのタブは既に存在しています",
443                     "Error", JOptionPane.ERROR_MESSAGE);
444         }
445     }
446
447     /**
448      * 基本設定ダイアログを開く
449      */
450     public void actionBasicSettingDialog() {
451         // ダイレクトメッセージ送信用ダイアログを開く
452         Point loc = getConfigurationDialog().getLocation();
453         loc.translate(20, 20);
454         ConfigurationDialog dialog = getConfigurationDialog();
455         dialog.setLocation(loc);
456         dialog.setVisible(true);
457     }
458
459     /**
460      * 選択したtweetをRT
461      */
462     public void actionCopySelectedStatusToTweetBoxPane() {
463         // コメントしたユーザ名
464         String username = this.currentStatus.getUser().getScreenName();
465         // コメント
466         String message = this.currentStatus.getText();
467         this.tweetBoxPane.setText("RT: @" + username + ": " + message);
468     }
469
470     /**
471      * 詳細情報表示ボタンを押した時の動作
472      *
473      * @param e
474      */
475     public void actionDetailInfoButton(ActionEvent e) {
476         if (detailInfoPanel.isVisible()) {
477             detailInfoPanel.setVisible(false);
478         } else {
479             detailInfoPanel.setVisible(true);
480         }
481     }
482
483     /**
484      * 書き込みメッセージボックスの表示ONOFFボタンを押した時の動作
485      * @param e
486      */
487     public void actionShowTweetboxButton(ActionEvent e) {
488         if( this.tweetBoxScrollPane.isVisible() ) {
489             this.tweetBoxScrollPane.setVisible(false);
490         }else {
491             this.tweetBoxScrollPane.setVisible(true);
492         }
493     }
494
495     /**
496      * 選択しているタブを削除
497      */
498     public void actionRemoveFocusedTabbedTable() {
499         int selected = this.tweetMainTab.getSelectedIndex();
500         int deleteTabIndex = selected;
501         
502         if( deleteTabIndex >= 0 ) {
503             //タブを削除
504             this.tweetMainTab.remove(deleteTabIndex);
505             int tabSetNum = this.tweetTabbedTableList.get(deleteTabIndex).getTabSetNum();
506             //タブのタイマーID
507             String timerID = this.tweetTabbedTableList.get(deleteTabIndex).getTimerID();
508
509             //削除
510             this.tweetTabbedTableList.remove(deleteTabIndex);
511
512             //削除した分,既存のタブ番号を1つずつずらさなければならない
513             int tabNum = this.tweetTabbedTableList.size();
514             for(int i = tabSetNum; i < tabNum; i++) {
515                 TweetTabbedTable table = this.tweetTabbedTableList.get( i );
516                 table.setTabSetNum( table.getTabSetNum() - 1);
517             }
518
519             //自動更新しているタブを削除
520             this.tweetTaskManager.shutdownTask( timerID );
521             //ID削除
522             TimerID idManager = TimerID.getInstance();
523             idManager.removeID(timerID);
524         }
525     }
526
527     /**
528      * 終了ボタンを押した時の動作
529      *
530      * @param e
531      */
532     public void actionExitButton(ActionEvent e) {
533         System.exit(0);
534     }
535
536     /**
537      * 選択した発言をブラウザで開く
538      */
539     public void actionOpenStatusURL() {
540         try {
541             // ユーザ名
542             String userName = this.currentStatus.getUser().getScreenName();
543             // 発言のstatusID
544             long statusID = this.currentStatus.getId();
545             Desktop.getDesktop().browse(
546                     new URI(TWITTER_URL + userName + "/statuses/" + statusID));
547         } catch (Exception ex) {
548             ex.printStackTrace();
549             JOptionPane.showMessageDialog(null, "エラーによりブラウザを起動できませんでした.",
550                     "Error", JOptionPane.ERROR_MESSAGE);
551         }
552     }
553
554     /**
555      * 選択したユーザ情報をブラウザで開く
556      */
557     public void actionOpenUserURL() {
558         try {
559             String userName = this.currentStatus.getUser().getScreenName();
560             Desktop.getDesktop().browse(new URI(TWITTER_URL + userName));
561         } catch (Exception ex) {
562             ex.printStackTrace();
563             JOptionPane.showMessageDialog(null, "エラーによりブラウザを起動できませんでした.",
564                     "Error", JOptionPane.ERROR_MESSAGE);
565         }
566     }
567
568     /**
569      * Tweet取得時間情報を更新
570      */
571     public void actionRefreshTime() {
572         //タブに存在する時間情報を更新
573         for(TweetTabbedTable t : this.tweetTabbedTableList ) {
574             TweetTableModel model = t.getModel();
575             if( model != null ) {
576                 model.refreshTime();
577             }
578         }
579     }
580
581     /**
582      * TweetMessageBox内にある#ハッシュタグ の部分をa hrefリンクに変換
583      *
584      * @param message
585      */
586     public String actionReplaceTweetMessageBoxHashTab(String message) {
587         // #で始まる情報
588         Pattern userPtn = Pattern.compile("#[0-9A-Z_]+",
589                 Pattern.CASE_INSENSITIVE);
590         Matcher matcher = userPtn.matcher(message);
591         /*
592          * if( matcher.matches() ) { matcher. }
593          */
594         // #で始まる情報一覧を抜き出す
595         Set<String> findList = new TreeSet<String>();
596         while (matcher.find()) {
597             findList.add(matcher.group(0));
598         }
599         // 指定した情報をすべてリンクへ変更
600         for (String f : findList) {
601             try {
602                 message = message.replaceAll(f, "<a href=\""
603                         + SEARCH_TWITTER_URL + SEARCH_QUERY
604                         + URLEncoder.encode(f, DEFAULT_CHARACTER_ENCODING)
605                         + "\">" + f + "</a>");
606             } catch (UnsupportedEncodingException e) {
607                 e.printStackTrace();
608             }
609         }
610         return message;
611     }
612
613     /**
614      * TweetMessageBox内にあるリンクをa hrefリンクに変換
615      *
616      * @param message
617      */
618     public String actionReplaceTweetMessageBoxURLLink(String message) {
619         Matcher matcher = convURLLinkPtn.matcher(message);
620         return matcher.replaceAll("<a href=\"$0\">$0</a>");
621     }
622
623     /**
624      * @ユーザ名の部分をa hrefリンクに変換
625      * @param message
626      */
627     public String actionReplaceTweetMessageBoxUserInfo(String message) {
628         // @で始まる情報
629         Pattern userPtn = Pattern.compile("@[0-9A-Z_]+",
630                 Pattern.CASE_INSENSITIVE);
631         Matcher matcher = userPtn.matcher(message);
632         // @で始まるユーザ名一覧を抜き出す
633         Set<String> findList = new TreeSet<String>();
634         while (matcher.find()) {
635             findList.add(matcher.group(0));
636         }
637         // 指定したユーザ名をすべてリンクへ変更
638         for (String f : findList) {
639             message = message.replaceAll(f, "<a href=\"" + TWITTER_URL
640                     + f.substring(1) + "\">" + f + "</a>");
641         }
642         return message;
643     }
644
645     /**
646      * まだ見ていないdirectMessage数を0にする
647      */
648     public void actionResetUncheckedDirectMessageCount() {
649         uncheckedDirectMessageCount = 0;
650         tweetMainTab.setTitleAt(2, TAB_DIRECT_MESSAGE_STRING);
651     }
652
653     /**
654      * まだ見ていないmention数を0にする
655      */
656     public void actionResetUncheckedMentionTweetCount() {
657         uncheckedMentionTweetCount = 0;
658         tweetMainTab.setTitleAt(1, TAB_MENTION_STRING);
659     }
660
661     /**
662      * まだ見ていないtweet数を0にする
663      */
664     public void actionResetUncheckedTimelineTweetCount() {
665         uncheckedTimelineTweetCount = 0;
666         tweetMainTab.setTitleAt(0, TAB_TIMELINE_STRING);
667     }
668
669     /**
670      * 現在選択しているステータスを公式Retweet
671      */
672     public void actionRetweet() {
673         // 選択しているtweetのstatus id
674         long statusID = this.currentStatus.getId();
675         // コメントしたユーザ名
676         String username = this.currentStatus.getUser().getScreenName();
677         // コメント
678         String message = this.currentStatus.getText();
679         // 発言が長すぎる場合,後半をカット
680         if (message.length() > 30) {
681             message = message.substring(0, 30) + " ...(以下略)";
682         }
683         // Retweetしていいかどうかの確認
684         int ret = JOptionPane.showConfirmDialog(mainFrame, username + " さんの発言:"
685                 + message + "\nをRetweetしますか?", "Retweetの確認",
686                 JOptionPane.YES_NO_OPTION);
687         if (ret == JOptionPane.YES_OPTION) {
688             try {
689                 // Retweetを行う
690                 this.tweetManager.retweet(statusID);
691             } catch (TwitterException e) {
692                 JOptionPane.showMessageDialog(null, "エラーによりRetweetできませんでした.",
693                         "Retweet Error", JOptionPane.ERROR_MESSAGE);
694             }
695         }
696     }
697
698     /**
699      * テーブルの高さを更新
700      *
701      * @param height
702      */
703     public void updateTableHeight(int height) {
704         this.tableElementHeight = height;
705         for( TweetTabbedTable t : this.tweetTabbedTableList) {
706             t.getTable().setRowHeight(tableElementHeight);
707         }
708     }
709
710     /**
711      * ダイレクトメッセージダイアログ表示
712      */
713     public void actionShowDirectMessageDialog() {
714         // ダイレクトメッセージ送信用ダイアログを開く
715         Point loc = getDirectMessageDialog().getLocation();
716         //loc.translate(20, 20);
717         DirectMessageDialog dialog = getDirectMessageDialog();
718         //dialog.setLocation(loc);
719         dialog.setLocationRelativeTo(null);
720         dialog.setVisible(true);
721         dialog.setUserInformation(this.selectedUsername,
722                 this.selectedUserImageURL, this.tweetManager);
723     }
724
725     /**
726      * Aboutダイアログを表示
727      */
728     public void actionShowAboutDialog() {
729         Point loc = getDirectMessageDialog().getLocation();
730         //loc.translate(20, 20);
731         AboutDialog dialog = getAboutDialog();
732         dialog.setLocationRelativeTo(null);
733         //dialog.setLocation(loc);
734         dialog.setVisible(true);
735     }
736
737     /**
738      * アカウントダイアログを表示
739      */
740     public void actionShowAccountDialog() {
741         Point loc = getDirectMessageDialog().getLocation();
742         //loc.translate(20, 20);
743         AccountDialog dialog = getAccountDialog();
744         dialog.setLocationRelativeTo(null);
745        // dialog.setLocation(loc);
746         dialog.setVisible(true);
747     }
748
749     /**
750      * Twitter全体からキーワード検索ダイアログを表示
751      */
752     public void actionShowKeywordSearchDialog() {
753         Point loc = getDirectMessageDialog().getLocation();
754         KeywordSearchDialog dialog = getKeywordSearchDialog();
755         dialog.setLocationRelativeTo(null);
756         dialog.setVisible(true);
757     }
758
759     /**
760      * tweetBoxPaneに書かれた文字をつぶやく
761      */
762     public void actionTweet() {
763         tweetManager.tweet(tweetBoxPane.getText());
764         tweetBoxPane.setText(""); // テキストをクリア
765     }
766
767     /**
768      * Tweet情報を更新
769      *
770      * @param e
771      */
772     public void actionUpdateButton(java.awt.event.ActionEvent e) {
773         try {
774             //タブ上に存在するテーブルの情報を更新
775             for(TweetTabbedTable t : this.tweetTabbedTableList ) {
776                 t.updateTweetTable();
777             }
778
779             // API残り回数を取得
780             int remainingHits = tweetManager.getRateLimitStatus().getRemainingHits();
781             // 取得したコメント数をステータスバーに表示
782             //TODO:ここの???部分を更新
783             information("???"
784                     + " 件の新しいツイートを取得しました. (APIリクエスト残数は" + remainingHits
785                     + "回です)");
786         } catch (Exception e1) {
787             e1.printStackTrace();
788         }
789     }
790
791     /**
792      * つぶやける残り文字数の更新
793      *
794      * @param e
795      */
796     public void actionUpdateTweetMessageCount() {
797         int len = 140 - (tweetBoxPane.getText().length());
798         if (len < 0) {
799             len = 0;
800         }
801         tweetMessageCountLabel.setText(len + "");
802     }
803
804     /**
805      * 基本設定用ダイアログを取得
806      *
807      * @return
808      */
809     public ConfigurationDialog getConfigurationDialog() {
810         if (configurationDialog == null) {
811             configurationDialog = new ConfigurationDialog(mainFrame, this);
812         }
813         return configurationDialog;
814     }
815
816     /**
817      * twitter全体からキーワード検索ダイアログを表示
818      * @return
819      */
820     public KeywordSearchDialog getKeywordSearchDialog() {
821         if( keywordSearchDialog == null ) {
822             keywordSearchDialog = new KeywordSearchDialog(mainFrame, true, this);
823         }
824         return keywordSearchDialog;
825     }
826
827     /**
828      * アカウント情報設定ダイアログを取得
829      * @return
830      */
831     public AccountDialog getAccountDialog() {
832         if( accountDialog == null ) {
833             accountDialog = new AccountDialog(mainFrame, true, tweetManager, this);
834         }
835         return accountDialog;
836     }
837
838     /**
839      * ダイレクトメッセージ送信用ダイアログを取得
840      *
841      * @return
842      */
843     public DirectMessageDialog getDirectMessageDialog() {
844         if (directMessageDialog == null) {
845             directMessageDialog = new DirectMessageDialog(mainFrame);
846             directMessageDialog.setTitle("ダイレクトメッセージを送信");
847         }
848         return directMessageDialog;
849     }
850
851     /**
852      * テーブルで選択したツイートを詳細情報としてセット
853      * @param table
854      */
855     public void setDetailInformationFromTable(JTable table) {
856         int sc = table.getSelectedRowCount();
857         String infoMessage = "";
858
859         if (sc == 1) {
860             Status st = getTweetTableInformation(table, table.getModel());
861             infoMessage = st.getText();
862             // tweetMessageBox内のURLをhtmlリンクへ変換
863             infoMessage = actionReplaceTweetMessageBoxURLLink(infoMessage);
864             // @ユーザ情報をhtmlリンクへ変換
865             infoMessage = actionReplaceTweetMessageBoxUserInfo(infoMessage);
866             // #ハッシュタグ情報をhtmlリンクへ変換
867             infoMessage = actionReplaceTweetMessageBoxHashTab(infoMessage);
868             // 詳細情報にテーブルで選択した人のツイート情報を表示
869             tweetMessageBox.setText(infoMessage);
870             // user icon
871             userImageLabel.setIcon(new ImageIcon(st.getUser().getProfileImageURL()));
872             // user name and id
873             userNameLabel.setText(st.getUser().getName()
874                     + " / " + st.getUser().getScreenName());
875             // update Time
876             updateTimeLabel.setText(DateFormat.getInstance().format( st.getCreatedAt() ));
877             // ユーザ自己紹介文
878             userIntroBox.setText(st.getUser().getDescription());
879             // フォローされている数
880             followerLabel.setText(st.getUser().getFollowersCount()
881                     + "");
882             // フォローしている数
883             followingLabel.setText(st.getUser().getFriendsCount()
884                     + "");
885             // 現在地
886             locationLabel.setText(st.getUser().getLocation());
887             // Web
888             if (st.getUser().getURL() != null) {
889                 userWebBox.setText("<a href=\""
890                         + st.getUser().getURL() + "\">"
891                         + st.getUser().getScreenName()
892                         + "のWebを開く" + "</a>");
893             } else {
894                 userWebBox.setText("");
895             }
896             // client
897             clientNameLabel.setText(" via " + st.getSource());
898             // Update
899             updateLabel.setText(st.getUser().getStatusesCount()
900                     + "");
901         }
902     }
903
904     /**
905      *
906      * @return
907      */
908     public AboutDialog getAboutDialog() {
909         if (aboutDialog == null) {
910             aboutDialog = new AboutDialog(mainFrame, true);
911         }
912         return aboutDialog;
913     }
914
915     /**
916      * テーブルで選択した場所のTweet情報を取得
917      *
918      * @return
919      */
920     public Status getTweetTableInformation(JTable table, TableModel model) {
921         int index = table.convertRowIndexToModel(table.getSelectedRow());
922         Status status = null;
923         if (model instanceof TweetTableModel) {
924             status = ((TweetTableModel) model).getTweetStatus(index);
925             // 現在選択したセルのユーザ名を保存しておく
926             this.selectedUsername = status.getUser().getScreenName();
927             // 現在選択したセルのユーザURLを保存しておく
928             this.selectedUserImageURL = status.getUser().getProfileImageURL();
929             // 選択したStatusを保存しておく
930             this.currentStatus = status;
931         }
932         return status;
933     }
934
935     /**
936      * ステータスバーに情報を表示する
937      *
938      * @param message
939      */
940     private void information(String message) {
941         statusBarLabel.setText(message);
942     }
943
944     /**
945      * 設定ファイルを読み込む
946      *
947      * @throws IOException
948      * @throws FileNotFoundException
949      */
950     public void loadProperties() throws FileNotFoundException, IOException {
951         if (property == null) {
952             this.property = new Properties();
953         }
954         property.load(new FileInputStream("./" + PROPERTIES_DIRECTORY + "/"
955                 + BASIC_SETTING_FILENAME));
956         // 設定読み込み
957         String gtp = this.property.getProperty("getTimelinePeriod");
958         String gmp = this.property.getProperty("getMentionPeriod");
959         String gdmp = this.property.getProperty("getDirectMessagePeriod");
960         String gsdmp = this.property.getProperty("getSendDirectMessagePeriod");
961
962         String ntrgb = this.property.getProperty("newTableColorRGB");
963
964         this.tlFontName = this.property.getProperty("tlFontName");
965         this.detailFontName = this.property.getProperty("detailFontName");
966
967         String tfs = this.property.getProperty("tlFontSize");
968         String dfs = this.property.getProperty("detailFontSize");
969         String teh = this.property.getProperty("tableElementHeight");
970
971         //メインフレームの大きさ
972         String mfw = this.property.getProperty("mainFrameWidth");
973         String mfh = this.property.getProperty("mainFrameHeight");
974
975         try {
976             this.newTableColor = new Color(Integer.parseInt(ntrgb));
977             this.tlFontSize = Integer.parseInt(tfs);
978             this.detailFontSize = Integer.parseInt(dfs);
979             this.tableElementHeight = Integer.parseInt(teh);
980             this.mainFrameWidth = Integer.parseInt(mfw);
981             this.mainFrameHeight = Integer.parseInt(mfh);
982
983             //更新間隔
984             this.getTimelinePeriod = Integer.parseInt(gtp);
985             this.getMentionPeriod = Integer.parseInt(gmp);
986             this.getDirectMessagePeriod = Integer.parseInt(gdmp);
987             this.getSendDirectMessagePeriod = Integer.parseInt(gsdmp);
988         } catch (NumberFormatException e) {
989             e.printStackTrace();
990         }
991     }
992
993     /**
994      * 設定ファイルを保存する
995      *
996      * @throws IOException
997      */
998     public void saveProperties() throws IOException {
999         // 設定ファイルディレクトリを作成
1000         File logDir = new File("./" + PROPERTIES_DIRECTORY);
1001         if (!logDir.exists()) {
1002             // ディレクトリが存在しないので作成する
1003             if (logDir.mkdir() == false) {
1004                 throw new IOException(PROPERTIES_DIRECTORY
1005                         + "ディレクトリを作成できませんでした.");
1006             }
1007         }
1008         if (property == null) {
1009             this.property = new Properties();
1010         }
1011
1012         //情報更新間隔
1013         this.property.setProperty("getTimelinePeriod", this.getTimelinePeriod + "");
1014         this.property.setProperty("getMentionPeriod", this.getMentionPeriod + "");
1015         this.property.setProperty("getDirectMessagePeriod", this.getDirectMessagePeriod + "");
1016         this.property.setProperty("getSendDirectMessagePeriod", this.getSendDirectMessagePeriod + "");
1017
1018         this.property.setProperty("newTableColorRGB", newTableColor.getRGB()
1019                 + "");
1020         this.property.setProperty("tlFontName", this.tlFontName);
1021         this.property.setProperty("tlFontSize", this.tlFontSize + "");
1022         this.property.setProperty("detailFontName", this.detailFontName);
1023         this.property.setProperty("detailFontSize", this.detailFontSize + "");
1024         this.property.setProperty("tableElementHeight", this.tableElementHeight
1025                 + "");
1026
1027         //main frame size
1028         if( this.mainFrame.getExtendedState() == JFrame.NORMAL ) {
1029             this.mainFrameWidth = this.mainFrame.getWidth();
1030             this.mainFrameHeight = this.mainFrame.getHeight();
1031         }
1032         this.property.setProperty("mainFrameWidth", this.mainFrameWidth + "");
1033         this.property.setProperty("mainFrameHeight", this.mainFrameHeight + "");
1034         // プロパティのリストを保存
1035         property.store(new FileOutputStream("./" + PROPERTIES_DIRECTORY + "/"
1036                 + BASIC_SETTING_FILENAME), null);
1037     }
1038
1039     /**
1040      * newTableColorを取得します。
1041      *
1042      * @return newTableColor
1043      */
1044     public Color getNewTableColor() {
1045         return newTableColor;
1046     }
1047
1048     /**
1049      * newTableColorを設定します。
1050      *
1051      * @param newTableColor
1052      *            newTableColor
1053      */
1054     public void setNewTableColor(Color newTableColor) {
1055         this.newTableColor = newTableColor;
1056     }
1057
1058     /**
1059      * tlFontNameを取得します。
1060      *
1061      * @return tlFontName
1062      */
1063     public String getTlFontName() {
1064         return tlFontName;
1065     }
1066
1067     /**
1068      * tlFontNameを設定します。
1069      *
1070      * @param tlFontName
1071      *            tlFontName
1072      */
1073     public void setTlFontName(String tlFontName) {
1074         this.tlFontName = tlFontName;
1075     }
1076
1077     /**
1078      * tlFontSizeを取得します。
1079      *
1080      * @return tlFontSize
1081      */
1082     public int getTlFontSize() {
1083         return tlFontSize;
1084     }
1085
1086     /**
1087      * tlFontSizeを設定します。
1088      *
1089      * @param tlFontSize
1090      *            tlFontSize
1091      */
1092     public void setTlFontSize(int tlFontSize) {
1093         this.tlFontSize = tlFontSize;
1094     }
1095
1096     /**
1097      * detailFontNameを取得します。
1098      *
1099      * @return detailFontName
1100      */
1101     public String getDetailFontName() {
1102         return detailFontName;
1103     }
1104
1105     /**
1106      * detailFontNameを設定します。
1107      *
1108      * @param detailFontName
1109      *            detailFontName
1110      */
1111     public void setDetailFontName(String detailFontName) {
1112         this.detailFontName = detailFontName;
1113     }
1114
1115     /**
1116      * detailFontSizeを取得します。
1117      *
1118      * @return detailFontSize
1119      */
1120     public int getDetailFontSize() {
1121         return detailFontSize;
1122     }
1123
1124     /**
1125      * detailFontSizeを設定します。
1126      *
1127      * @param detailFontSize
1128      *            detailFontSize
1129      */
1130     public void setDetailFontSize(int detailFontSize) {
1131         this.detailFontSize = detailFontSize;
1132     }
1133
1134     /**
1135      * tableElementHeightを取得します。
1136      *
1137      * @return tableElementHeight
1138      */
1139     public int getTableElementHeight() {
1140         return tableElementHeight;
1141     }
1142
1143     /**
1144      * tableElementHeightを設定します。
1145      *
1146      * @param tableElementHeight
1147      *            tableElementHeight
1148      */
1149     public void setTableElementHeight(int tableElementHeight) {
1150         this.tableElementHeight = tableElementHeight;
1151     }
1152
1153     /**
1154      * @return the getTimelinePeriod
1155      */
1156     public int getGetTimelinePeriod() {
1157         return getTimelinePeriod;
1158     }
1159
1160     /**
1161      * @param getTimelinePeriod the getTimelinePeriod to set
1162      */
1163     public void setGetTimelinePeriod(int getTimelinePeriod) {
1164         this.getTimelinePeriod = getTimelinePeriod;
1165     }
1166
1167     /**
1168      * @return the getMentionPeriod
1169      */
1170     public int getGetMentionPeriod() {
1171         return getMentionPeriod;
1172     }
1173
1174     /**
1175      * @param getMentionPeriod the getMentionPeriod to set
1176      */
1177     public void setGetMentionPeriod(int getMentionPeriod) {
1178         this.getMentionPeriod = getMentionPeriod;
1179     }
1180
1181     /**
1182      * @return the getDirectMessagePeriod
1183      */
1184     public int getGetDirectMessagePeriod() {
1185         return getDirectMessagePeriod;
1186     }
1187
1188     /**
1189      * @param getDirectMessagePeriod the getDirectMessagePeriod to set
1190      */
1191     public void setGetDirectMessagePeriod(int getDirectMessagePeriod) {
1192         this.getDirectMessagePeriod = getDirectMessagePeriod;
1193     }
1194
1195     /**
1196      * @return the getSendDirectMessagePeriod
1197      */
1198     public int getGetSendDirectMessagePeriod() {
1199         return getSendDirectMessagePeriod;
1200     }
1201
1202     /**
1203      * @param getSendDirectMessagePeriod the getSendDirectMessagePeriod to set
1204      */
1205     public void setGetSendDirectMessagePeriod(int getSendDirectMessagePeriod) {
1206         this.getSendDirectMessagePeriod = getSendDirectMessagePeriod;
1207     }
1208 }