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