1 package twitter.gui.action;
4 import java.awt.Desktop;
5 import java.awt.Dimension;
8 import java.awt.event.ActionEvent;
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;
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;
23 import java.util.TreeSet;
24 import java.util.concurrent.Executors;
25 import java.util.concurrent.ScheduledExecutorService;
26 import java.util.concurrent.ScheduledFuture;
27 import java.util.concurrent.TimeUnit;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32 import javax.swing.ImageIcon;
34 import javax.swing.JEditorPane;
35 import javax.swing.JFrame;
36 import javax.swing.JLabel;
37 import javax.swing.JOptionPane;
38 import javax.swing.JPanel;
39 import javax.swing.JScrollPane;
40 import javax.swing.JTabbedPane;
41 import javax.swing.JTable;
42 import javax.swing.JTextPane;
43 import javax.swing.table.TableCellRenderer;
44 import javax.swing.table.TableModel;
45 import javax.swing.text.Style;
46 import javax.swing.text.StyleConstants;
47 import javax.swing.text.html.HTMLDocument;
48 import javax.swing.text.html.StyleSheet;
49 import twitter.action.TweetDirectMessageGetter;
50 import twitter.action.TweetGetter;
51 import twitter.action.TweetMentionGetter;
52 import twitter.action.TweetSearchResultGetter;
53 import twitter.action.TweetSendDirectMessageGetter;
54 import twitter.action.TweetTimelineGetter;
56 import twitter.gui.component.TweetCommentRenderer;
57 import twitter.gui.component.TweetTabbedTable;
58 import twitter.gui.component.TweetTableModel;
59 import twitter.gui.form.AboutDialog;
60 import twitter.gui.form.AccountDialog;
61 import twitter.gui.form.ConfigurationDialog;
62 import twitter.gui.form.DirectMessageDialog;
63 import twitter.gui.form.KeywordSearchDialog;
64 import twitter.manage.TweetConfiguration;
65 import twitter.manage.TweetManager;
66 import twitter.task.ExistTimerIDException;
67 import twitter.task.TimerID;
68 import twitter.task.TweetTaskException;
69 import twitter.task.TweetTaskManager;
70 import twitter.task.TweetUpdateTask;
71 import twitter4j.Status;
72 import twitter4j.TwitterException;
80 public class TweetMainAction {
83 * 一定時間毎にtweet情報をアップデートするタスク
88 private class TweetAutoUpdateTask implements Runnable {
90 TweetAutoUpdateTask() {
94 // 一定時間ごとにTweet情報をアップデート
96 /*if (currentGetTimelinePeriodNum == 0) {
98 actionTweetTableUpdate();
100 currentGetTimelinePeriodNum = (currentGetTimelinePeriodNum + 1)
101 % getTimelinePeriodNum;
103 if (currentGetMentionPeriodNum == 0) {
105 //actionMentionTableUpdate();
107 currentGetMentionPeriodNum = (currentGetMentionPeriodNum + 1)
108 % getMentionPeriodNum;
110 if (currentGetDirectMessagePeriodNum == 0) {
111 // DirectMessageテーブルの情報を更新
112 actionDirectMessageTableUpdate();
114 currentGetDirectMessagePeriodNum = (currentGetDirectMessagePeriodNum + 1)
115 % getDirectMessagePeriodNum;
117 if (currentGetSendDirectMessagePeriodNum == 0) {
118 // SendDirectMessageテーブルの情報を更新
119 actionSendDirectMessageTableUpdate();
121 currentGetSendDirectMessagePeriodNum = (currentGetSendDirectMessagePeriodNum + 1)
122 % getSendDirectMessagePeriodNum;*/
127 } catch (Exception e1) {
128 e1.printStackTrace();
134 * 一定時間毎にtweet情報をアップデートする
139 private class TweetAutoUpdateTimer {
141 private ScheduledFuture<?> future;
142 private final ScheduledExecutorService scheduler;
143 private final Runnable task;
144 private long time = 0;
146 public TweetAutoUpdateTimer() {
147 task = new TweetAutoUpdateTask();
148 scheduler = Executors.newSingleThreadScheduledExecutor();
154 public void reset() {
156 if (future != null) {
157 future = scheduler.scheduleAtFixedRate(task, time, time,
165 public void shutdown() {
166 scheduler.shutdown();
170 * 一定時間毎にTweetUpdateTaskを実行
175 public void start(long time) {
176 future = scheduler.scheduleAtFixedRate(task, 2, time,
185 if (future != null) {
191 public static final String BASIC_SETTING_FILENAME = TweetConfiguration.BASIC_SETTING_FILENAME;
193 private static final Pattern convURLLinkPtn = Pattern.compile(
194 "(http://|https://){1}[\\w\\.\\-/:\\#\\?\\=\\&\\;\\%\\~\\+]+",
195 Pattern.CASE_INSENSITIVE);
196 // default char encoding
197 private static final String DEFAULT_CHARACTER_ENCODING = "UTF-8";
198 // 設定ファイルを保存するディレクトリ名
199 public static final String PROPERTIES_DIRECTORY = "properties";
200 // search twitterのクエリ
201 private static final String SEARCH_QUERY = "search?q=";
202 // search twitterのURL
203 private static final String SEARCH_TWITTER_URL = "http://search.twitter.com/";
204 // Direct Messageタブに表示する文字
205 public static final String TAB_DIRECT_MESSAGE_STRING = "Message";
207 public static final String TAB_MENTION_STRING = "Mention";
209 public static final String TAB_TIMELINE_STRING = "Timeline";
210 //Send Direct Messageタブに表示する文字
211 public static final String TAB_SEND_DIRECT_MESSAGE_STRING = "Send";
212 // テーブルのデータ量が以下の値を超えたら古いデータから削除
213 private static final int TABLE_ELEMENT_MAX_SIZE = 200;
215 private static final String TWITTER_URL = "http://twitter.com/";
217 private TweetAutoUpdateTimer autoUpdateTimer = null;
219 private ConfigurationDialog configurationDialog = null;
220 private int currentGetDirectMessagePeriodNum = 0;
221 private int currentGetMentionPeriodNum = 0;
222 private int currentGetSendDirectMessagePeriodNum = 0;
223 private int currentGetTimelinePeriodNum = 0;
225 private Status currentStatus = null;
227 private JPanel detailInfoPanel = null;
228 // ダイレクトメッセージ送信用ダイアログ
229 private DirectMessageDialog directMessageDialog = null;
230 //Twitter全体からキーワード検索ダイアログ
231 private KeywordSearchDialog keywordSearchDialog = null;
232 // directMessageを表示するテーブル
233 private JTable directMessageTable = null;
234 // directMessageのtweetを表示するテーブルモデル
235 private TweetTableModel directMessageTableModel = null;
237 private int updatePeriod = 1;
238 // DirectMessageの取得間隔
239 private int getDirectMessagePeriodNum = 10;
241 private int getMentionPeriodNum = 5;
242 // SendDirectMessageの取得間隔
243 private int getSendDirectMessagePeriodNum = 30;
245 private int getTimelinePeriodNum = 1;
247 private Color newTableColor = new Color(224, 255, 255);
249 private String tlFontName = "Takao Pゴシック";
251 private int tlFontSize = 13;
253 private String detailFontName = "Takao Pゴシック";
255 private int detailFontSize = 13;
257 private int tableElementHeight = 50;
259 private int mainFrameWidth = 729;
261 private int mainFrameHeight = 629;
263 private JFrame mainFrame = null;
264 // メインのtweetを表示するテーブル
265 private JTable mainTweetTable = null;
267 private JTable mentionTable = null;
268 // mentionのtweetを表示するテーブルモデル
269 private TweetTableModel mentionTableModel = null;
271 private Properties property = null;
272 // 現在テーブルで選択しているユーザ画像のURL
273 private URL selectedUserImageURL = null;
274 // 現在テーブルで選択しているユーザの名前
275 private String selectedUsername = null;
276 // sendDirectMessageを表示するテーブル
277 private JTable sendDirectMessageTable = null;
278 // sendDirectMessageのtweetを表示するテーブル
279 private TweetTableModel sendDirectMessageTableModel = null;
281 private JLabel statusBarLabel = null;
283 private JTextPane tweetBoxPane = null;
284 //自分がつぶやきを書く領域のスクロールペーン
285 private JScrollPane tweetBoxScrollPane = null;
287 private JTabbedPane tweetMainTab = null;
289 private TweetManager tweetManager = null;
290 // tweetを表示するTextPane
291 private JEditorPane tweetMessageBox = null;
292 // つぶやくことができる文字数を表示するラベル
293 private JLabel tweetMessageCountLabel = null;
294 // メインのtweetを表示するテーブルモデル
295 private TweetTableModel tweetTableModel = null;
296 private int uncheckedDirectMessageCount = 0;
297 private int uncheckedMentionTweetCount = 0;
300 private JLabel userImageLabel = null;
301 private JLabel userNameLabel = null;
302 private JLabel updateTimeLabel = null;
303 private JLabel followerLabel = null;
304 private JLabel followingLabel = null;
305 private JLabel locationLabel = null;
306 private JEditorPane clientNameLabel = null;
307 private JLabel updateLabel = null;
308 private JEditorPane userIntroBox = null;
309 private JEditorPane userWebBox = null;
311 // 新しく取得したtweetでまだ参照していない数
312 private int uncheckedTimelineTweetCount = 0;
313 private AboutDialog aboutDialog = null;
315 private AccountDialog accountDialog;
317 private List<TweetTabbedTable> tweetTabbedTableList = new ArrayList<TweetTabbedTable>();
318 //ツイートテーブルの情報を一定間隔で更新するクラスを作成
319 private TweetTaskManager tweetTaskManager = new TweetTaskManager();
320 //ここは一時的に追加している部分 タブにすでに存在しているテーブルの数
321 private int ALREADY_TWEET_TAB_NUM = 4;
326 * @param tweetManager
327 * @param statusBarLabel
328 * @param tweetTableModel
329 * @param mentionTableModel
330 * @param directMessageTableModel
331 * @param sendDirectMessageTableModel
332 * @param mainTweetTable
333 * @param mentionTable
334 * @param directMessageTable
335 * @param sendDirectMessageTable
336 * @param tweetBoxPane
337 * @param tweetBoxScrollPane
338 * @param tweetMessageCountLabel
339 * @param detailInfoPanel
340 * @param tweetMainTab
341 * @param tweetMessageBox
342 * @param userImageLabel
343 * @param userNameLabel
344 * @param updateTimeLabel
345 * @param followerLabel
346 * @param followingLabel
347 * @param locationLabel
348 * @param clientNameLabel
350 * @param userIntroBox
353 public TweetMainAction(JFrame mainFrame,
354 TweetManager tweetManager,
355 JLabel statusBarLabel,
356 TweetTableModel tweetTableModel,
357 TweetTableModel mentionTableModel,
358 TweetTableModel directMessageTableModel,
359 TweetTableModel sendDirectMessageTableModel,
360 JTable mainTweetTable,
362 JTable directMessageTable,
363 JTable sendDirectMessageTable,
364 JTextPane tweetBoxPane,
365 JScrollPane tweetBoxScrollPane,
366 JLabel tweetMessageCountLabel,
367 JPanel detailInfoPanel,
368 JTabbedPane tweetMainTab,
369 JEditorPane tweetMessageBox,
370 JLabel userImageLabel,
371 JLabel userNameLabel,
372 JLabel updateTimeLabel,
373 JLabel followerLabel,
374 JLabel followingLabel,
375 JLabel locationLabel,
376 JEditorPane clientNameLabel,
378 JEditorPane userIntroBox,
379 JEditorPane userWebBox) {
380 this.mainFrame = mainFrame;
381 this.tweetManager = tweetManager;
382 this.statusBarLabel = statusBarLabel;
383 this.tweetTableModel = tweetTableModel;
384 this.mentionTableModel = mentionTableModel;
385 this.directMessageTableModel = directMessageTableModel;
386 this.sendDirectMessageTableModel = sendDirectMessageTableModel;
387 this.mainTweetTable = mainTweetTable;
388 this.mentionTable = mentionTable;
389 this.directMessageTable = directMessageTable;
390 this.sendDirectMessageTable = sendDirectMessageTable;
391 this.tweetBoxPane = tweetBoxPane;
392 this.tweetMessageCountLabel = tweetMessageCountLabel;
393 this.detailInfoPanel = detailInfoPanel;
394 this.tweetMainTab = tweetMainTab;
395 this.tweetMessageBox = tweetMessageBox;
396 this.tweetBoxScrollPane = tweetBoxScrollPane;
399 this.userImageLabel = userImageLabel;
400 this.userNameLabel = userNameLabel;
401 this.updateTimeLabel = updateTimeLabel;
402 this.userIntroBox = userIntroBox;
403 this.followerLabel = followerLabel;
404 this.followingLabel = followingLabel;
405 this.locationLabel = locationLabel;
406 this.userWebBox = userWebBox;
407 this.clientNameLabel = clientNameLabel;
408 this.updateLabel = updateLabel;
413 } catch (FileNotFoundException e) {
415 } catch (IOException e) {
419 updateFontInformationToComponent();
422 mainFrame.setSize(this.mainFrameWidth, this.mainFrameHeight);
423 mainFrame.setPreferredSize(new Dimension(this.mainFrameWidth, this.mainFrameHeight));
427 public void updateFontInformationToComponent() {
430 if (this.tlFontName != null) {
431 tlFont = new Font(this.tlFontName, Font.PLAIN, this.tlFontSize);
433 Font detailFont = null;
434 if (this.detailFontName != null) {
435 detailFont = new Font(this.detailFontName, Font.PLAIN,
436 this.detailFontSize);
438 this.mainTweetTable.setFont(tlFont);
439 this.mentionTable.setFont(tlFont);
440 this.directMessageTable.setFont(tlFont);
441 this.sendDirectMessageTable.setFont(tlFont);
443 // tweetメッセージボックスのフォントはhtmlレベルで変更する必要がある
444 this.tweetMessageBox.setFont(detailFont);
446 HTMLDocument doc = (HTMLDocument) this.tweetMessageBox.getDocument();
447 StyleSheet[] style = doc.getStyleSheet().getStyleSheets();
448 for (int i = style.length - 1; i >= 0; i--) {
449 Style body = style[i].getStyle("body");
451 StyleConstants.setFontFamily(body, detailFont.getFontName());
452 StyleConstants.setFontSize(body, detailFont.getSize());
456 } catch (Exception e) {
463 * @param timerID TimerIDクラスで生成したタイマーID
464 * @param period 情報更新間隔[sec]
465 * @param tweetGetter 実行するアクション
466 * @param tabTitle 追加するタブのタイトル
468 public void actionAddTab(String timerID, int period, TweetGetter tweetGetter, String tabTitle) {
469 int numOfTab = this.tweetTabbedTableList.size();
471 //TODO:ここはあとで変更する必要がある.なぜなら既に追加されているタブの数は変わる可能性があるから
472 int alreadyExistTabNum = ALREADY_TWEET_TAB_NUM;
478 final TweetTabbedTable table = new TweetTabbedTable(tweetGetter, tabTitle,
479 this.tweetMainTab, numOfTab + alreadyExistTabNum,
480 this.tableElementHeight, this.tweetManager,
481 this, newTableColor, tableElementHeight, timerID);
483 this.tweetTaskManager.addTask(timerID, new TweetUpdateTask() {
486 public void runTask() throws TweetTaskException {
488 table.updateTweetTable();
492 this.tweetTaskManager.startTask(timerID, period * 1000L);
495 table.addTableToTab();
497 this.tweetTabbedTableList.add(table);
498 //searchTable.updateTweetTable();
499 } catch (TweetTaskException ex) {
500 Logger.getLogger(TweetMainAction.class.getName()).log(Level.SEVERE, null, ex);
507 * @param period 情報更新間隔[sec]
509 public void actionAddMentionTab(int period) {
510 TimerID timerID = TimerID.getInstance();
511 String id = TimerID.createMentionID();
513 //既にIDが存在していたらここで例外発生
516 actionAddTab(id, period, new TweetMentionGetter(tweetManager),
517 TweetMainAction.TAB_MENTION_STRING);
518 } catch (ExistTimerIDException ex) {
519 JOptionPane.showMessageDialog(null, "そのタブは既に存在しています",
520 "Error", JOptionPane.ERROR_MESSAGE);
528 public void actionAddTimelineTab(int period) {
529 TimerID timerID = TimerID.getInstance();
530 String id = TimerID.createTimelineID();
532 //既にIDが存在していたらここで例外発生
535 actionAddTab(id, period, new TweetTimelineGetter(tweetManager),
536 TweetMainAction.TAB_TIMELINE_STRING);
537 } catch (ExistTimerIDException ex) {
538 JOptionPane.showMessageDialog(null, "そのタブは既に存在しています",
539 "Error", JOptionPane.ERROR_MESSAGE);
545 * @param period 更新間隔[sec]
547 public void actionAddDirectMessageTab(int period) {
548 TimerID timerID = TimerID.getInstance();
549 String id = TimerID.createDirectMessageID();
551 //既にIDが存在していたらここで例外発生
554 actionAddTab(id, period, new TweetDirectMessageGetter(tweetManager),
555 TweetMainAction.TAB_DIRECT_MESSAGE_STRING);
556 } catch (ExistTimerIDException ex) {
557 JOptionPane.showMessageDialog(null, "そのタブは既に存在しています",
558 "Error", JOptionPane.ERROR_MESSAGE);
566 public void actionAddSendDirectMessageTab(int period) {
567 TimerID timerID = TimerID.getInstance();
568 String id = TimerID.createSendDirectMessageID();
570 //既にIDが存在していたらここで例外発生
573 actionAddTab(id, period, new TweetSendDirectMessageGetter(tweetManager),
574 TweetMainAction.TAB_SEND_DIRECT_MESSAGE_STRING);
575 } catch (ExistTimerIDException ex) {
576 JOptionPane.showMessageDialog(null, "そのタブは既に存在しています",
577 "Error", JOptionPane.ERROR_MESSAGE);
583 * ツイート検索結果を表示するタブを新しく追加
585 * @param period 更新周期[sec] 0以下の場合は更新しない
587 public void actionAddNewSearchResultTab(String searchWord, int period) {
588 TimerID timerID = TimerID.getInstance();
589 String id = TimerID.createSearchTimerID(searchWord);
591 //既にIDが存在していたらここで例外発生
594 actionAddTab(id, period, new TweetSearchResultGetter(this.tweetManager, searchWord), searchWord);
595 } catch (ExistTimerIDException ex) {
596 JOptionPane.showMessageDialog(null, "そのタブは既に存在しています",
597 "Error", JOptionPane.ERROR_MESSAGE);
604 public void actionBasicSettingDialog() {
605 // ダイレクトメッセージ送信用ダイアログを開く
606 Point loc = getConfigurationDialog().getLocation();
607 loc.translate(20, 20);
608 ConfigurationDialog dialog = getConfigurationDialog();
609 dialog.setLocation(loc);
610 dialog.setVisible(true);
616 public void actionCopySelectedStatusToTweetBoxPane() {
618 String username = this.currentStatus.getUser().getScreenName();
620 String message = this.currentStatus.getText();
621 this.tweetBoxPane.setText("RT: @" + username + ": " + message);
629 public void actionDetailInfoButton(ActionEvent e) {
630 if (detailInfoPanel.isVisible()) {
631 detailInfoPanel.setVisible(false);
633 detailInfoPanel.setVisible(true);
638 * 書き込みメッセージボックスの表示ONOFFボタンを押した時の動作
641 public void actionShowTweetboxButton(ActionEvent e) {
642 if( this.tweetBoxScrollPane.isVisible() ) {
643 this.tweetBoxScrollPane.setVisible(false);
645 this.tweetBoxScrollPane.setVisible(true);
650 * DirectMessageテーブルの更新
652 public void actionDirectMessageTableUpdate() {
655 int remainingHits = tweetManager.getRateLimitStatus().getRemainingHits();
656 if (remainingHits <= 0) {
657 information("API制限です.リクエストの残数が0となりました.");
664 List<Status> directMessages = tweetManager.getNewDirectMessages();
665 // まだ見ていないdirectMessage数を追加
666 uncheckedDirectMessageCount += directMessages.size();
667 // まだ見ていないmentionの数をタブに表示
668 if (uncheckedDirectMessageCount > 0) {
669 tweetMainTab.setTitleAt(2, TAB_DIRECT_MESSAGE_STRING + "("
670 + uncheckedDirectMessageCount + ")");
672 for (Status t : directMessages) {
673 directMessageTableModel.insertTweet(t);
674 directMessageTable.setRowHeight(0, tableElementHeight);
677 directMessageTableModel.removeOldTweet(TABLE_ELEMENT_MAX_SIZE);
679 directMessageTableModel.refreshTime();
680 } catch (TwitterException e1) {
681 e1.printStackTrace();
682 } catch (Exception e) {
690 public void actionRemoveFocusedTabbedTable() {
691 int selected = this.tweetMainTab.getSelectedIndex();
693 int deleteTabIndex = selected - this.ALREADY_TWEET_TAB_NUM;
694 if( deleteTabIndex >= 0 ) {
696 this.tweetMainTab.remove(deleteTabIndex + this.ALREADY_TWEET_TAB_NUM);
697 int tabSetNum = this.tweetTabbedTableList.get(deleteTabIndex).getTabSetNum();
699 String timerID = this.tweetTabbedTableList.get(deleteTabIndex).getTimerID();
702 this.tweetTabbedTableList.remove(deleteTabIndex);
705 tabSetNum -= this.ALREADY_TWEET_TAB_NUM;
706 //削除した分,既存のタブ番号を1つずつずらさなければならない
707 int tabNum = this.tweetTabbedTableList.size();
708 for(int i = tabSetNum; i < tabNum; i++) {
709 TweetTabbedTable table = this.tweetTabbedTableList.get( i );
710 table.setTabSetNum( table.getTabSetNum() - 1);
714 this.tweetTaskManager.shutdownTask( timerID );
716 TimerID idManager = TimerID.getInstance();
717 idManager.removeID(timerID);
726 public void actionExitButton(ActionEvent e) {
733 public void actionMentionTableUpdate() {
736 int remainingHits = tweetManager.getRateLimitStatus().getRemainingHits();
737 if (remainingHits <= 0) {
738 information("API制限です.リクエストの残数が0となりました.");
745 List<Status> mention = tweetManager.getNewMentionData();
746 // まだ見ていないmention数を追加
747 uncheckedMentionTweetCount += mention.size();
748 // まだ見ていないmentionの数をタブに表示
749 if (uncheckedMentionTweetCount > 0) {
750 tweetMainTab.setTitleAt(1, TAB_MENTION_STRING + "("
751 + uncheckedMentionTweetCount + ")");
753 for (Status t : mention) {
754 mentionTableModel.insertTweet(t);
755 mentionTable.setRowHeight(0, tableElementHeight);
758 TableCellRenderer renderer2 = mentionTable.getCellRenderer(0, 2);
759 if (renderer2 instanceof TweetCommentRenderer) {
760 if (this.uncheckedMentionTweetCount - 1 >= 0) {
761 ((TweetCommentRenderer) renderer2).updateNewCellRow(
762 this.uncheckedMentionTweetCount, newTableColor);
764 ((TweetCommentRenderer) renderer2).updateNewCellRow(-1,
769 mentionTableModel.removeOldTweet(TABLE_ELEMENT_MAX_SIZE);
771 mentionTableModel.refreshTime();
772 } catch (TwitterException e1) {
773 e1.printStackTrace();
780 public void actionOpenStatusURL() {
783 String userName = this.currentStatus.getUser().getScreenName();
785 long statusID = this.currentStatus.getId();
786 Desktop.getDesktop().browse(
787 new URI(TWITTER_URL + userName + "/statuses/" + statusID));
788 } catch (Exception ex) {
789 ex.printStackTrace();
790 JOptionPane.showMessageDialog(null, "エラーによりブラウザを起動できませんでした.",
791 "Error", JOptionPane.ERROR_MESSAGE);
798 public void actionOpenUserURL() {
800 String userName = this.currentStatus.getUser().getScreenName();
801 Desktop.getDesktop().browse(new URI(TWITTER_URL + userName));
802 } catch (Exception ex) {
803 ex.printStackTrace();
804 JOptionPane.showMessageDialog(null, "エラーによりブラウザを起動できませんでした.",
805 "Error", JOptionPane.ERROR_MESSAGE);
812 public void actionRefreshTime() {
813 tweetTableModel.refreshTime();
814 mentionTableModel.refreshTime();
815 directMessageTableModel.refreshTime();
816 sendDirectMessageTableModel.refreshTime();
819 for(TweetTabbedTable t : this.tweetTabbedTableList ) {
820 TweetTableModel model = t.getModel();
821 if( model != null ) {
828 * TweetMessageBox内にある#ハッシュタグ の部分をa hrefリンクに変換
832 public String actionReplaceTweetMessageBoxHashTab(String message) {
834 Pattern userPtn = Pattern.compile("#[0-9A-Z_]+",
835 Pattern.CASE_INSENSITIVE);
836 Matcher matcher = userPtn.matcher(message);
838 * if( matcher.matches() ) { matcher. }
841 Set<String> findList = new TreeSet<String>();
842 while (matcher.find()) {
843 findList.add(matcher.group(0));
846 for (String f : findList) {
848 message = message.replaceAll(f, "<a href=\""
849 + SEARCH_TWITTER_URL + SEARCH_QUERY
850 + URLEncoder.encode(f, DEFAULT_CHARACTER_ENCODING)
851 + "\">" + f + "</a>");
852 } catch (UnsupportedEncodingException e) {
860 * TweetMessageBox内にあるリンクをa hrefリンクに変換
864 public String actionReplaceTweetMessageBoxURLLink(String message) {
865 Matcher matcher = convURLLinkPtn.matcher(message);
866 return matcher.replaceAll("<a href=\"$0\">$0</a>");
870 * @ユーザ名の部分をa hrefリンクに変換
873 public String actionReplaceTweetMessageBoxUserInfo(String message) {
875 Pattern userPtn = Pattern.compile("@[0-9A-Z_]+",
876 Pattern.CASE_INSENSITIVE);
877 Matcher matcher = userPtn.matcher(message);
879 Set<String> findList = new TreeSet<String>();
880 while (matcher.find()) {
881 findList.add(matcher.group(0));
883 // 指定したユーザ名をすべてリンクへ変更
884 for (String f : findList) {
885 message = message.replaceAll(f, "<a href=\"" + TWITTER_URL
886 + f.substring(1) + "\">" + f + "</a>");
892 * まだ見ていないdirectMessage数を0にする
894 public void actionResetUncheckedDirectMessageCount() {
895 uncheckedDirectMessageCount = 0;
896 tweetMainTab.setTitleAt(2, TAB_DIRECT_MESSAGE_STRING);
900 * まだ見ていないmention数を0にする
902 public void actionResetUncheckedMentionTweetCount() {
903 uncheckedMentionTweetCount = 0;
904 tweetMainTab.setTitleAt(1, TAB_MENTION_STRING);
910 public void actionResetUncheckedTimelineTweetCount() {
911 uncheckedTimelineTweetCount = 0;
912 tweetMainTab.setTitleAt(0, TAB_TIMELINE_STRING);
916 * 現在選択しているステータスを公式Retweet
918 public void actionRetweet() {
919 // 選択しているtweetのstatus id
920 long statusID = this.currentStatus.getId();
922 String username = this.currentStatus.getUser().getScreenName();
924 String message = this.currentStatus.getText();
926 if (message.length() > 30) {
927 message = message.substring(0, 30) + " ...(以下略)";
929 // Retweetしていいかどうかの確認
930 int ret = JOptionPane.showConfirmDialog(mainFrame, username + " さんの発言:"
931 + message + "\nをRetweetしますか?", "Retweetの確認",
932 JOptionPane.YES_NO_OPTION);
933 if (ret == JOptionPane.YES_OPTION) {
936 this.tweetManager.retweet(statusID);
937 } catch (TwitterException e) {
938 JOptionPane.showMessageDialog(null, "エラーによりRetweetできませんでした.",
939 "Retweet Error", JOptionPane.ERROR_MESSAGE);
949 public void updateTableHeight(int height) {
950 this.tableElementHeight = height;
951 mainTweetTable.setRowHeight(tableElementHeight);
952 mentionTable.setRowHeight(tableElementHeight);
953 directMessageTable.setRowHeight(tableElementHeight);
954 sendDirectMessageTable.setRowHeight(tableElementHeight);
958 * SendDirectMessageテーブルを更新
960 public void actionSendDirectMessageTableUpdate() {
963 int remainingHits = tweetManager.getRateLimitStatus().getRemainingHits();
964 if (remainingHits <= 0) {
965 information("API制限です.リクエストの残数が0となりました.");
970 List<Status> sendDirectMessages = tweetManager.getNewSendDirectMessages();
972 //TODO:ここはnullぽが頻発している.修正の必要あり
974 for (Status t : sendDirectMessages) {
975 sendDirectMessageTableModel.insertTweet(t);
976 sendDirectMessageTable.setRowHeight(0, tableElementHeight);
978 }catch(NullPointerException e2) {
979 e2.printStackTrace();
982 sendDirectMessageTableModel.removeOldTweet(TABLE_ELEMENT_MAX_SIZE);
984 sendDirectMessageTableModel.refreshTime();
985 } catch (TwitterException e1) {
986 e1.printStackTrace();
993 public void actionShowDirectMessageDialog() {
994 // ダイレクトメッセージ送信用ダイアログを開く
995 Point loc = getDirectMessageDialog().getLocation();
996 //loc.translate(20, 20);
997 DirectMessageDialog dialog = getDirectMessageDialog();
998 //dialog.setLocation(loc);
999 dialog.setLocationRelativeTo(null);
1000 dialog.setVisible(true);
1001 dialog.setUserInformation(this.selectedUsername,
1002 this.selectedUserImageURL, this.tweetManager);
1008 public void actionShowAboutDialog() {
1009 Point loc = getDirectMessageDialog().getLocation();
1010 //loc.translate(20, 20);
1011 AboutDialog dialog = getAboutDialog();
1012 dialog.setLocationRelativeTo(null);
1013 //dialog.setLocation(loc);
1014 dialog.setVisible(true);
1020 public void actionShowAccountDialog() {
1021 Point loc = getDirectMessageDialog().getLocation();
1022 //loc.translate(20, 20);
1023 AccountDialog dialog = getAccountDialog();
1024 dialog.setLocationRelativeTo(null);
1025 // dialog.setLocation(loc);
1026 dialog.setVisible(true);
1030 * Twitter全体からキーワード検索ダイアログを表示
1032 public void actionShowKeywordSearchDialog() {
1033 Point loc = getDirectMessageDialog().getLocation();
1034 KeywordSearchDialog dialog = getKeywordSearchDialog();
1035 dialog.setLocationRelativeTo(null);
1036 dialog.setVisible(true);
1040 * tweetBoxPaneに書かれた文字をつぶやく
1042 public void actionTweet() {
1043 tweetManager.tweet(tweetBoxPane.getText());
1044 tweetBoxPane.setText(""); // テキストをクリア
1050 public void actionTweetTableUpdate() {
1053 int remainingHits = tweetManager.getRateLimitStatus().getRemainingHits();
1054 if (remainingHits <= 0) {
1055 information("API制限です.リクエストの残数が0となりました.");
1060 List<Status> tweet = tweetManager.getNewTimelineData();
1062 uncheckedTimelineTweetCount += tweet.size();
1063 // まだチェックしていないtweetの数をタブにも表示
1064 if (uncheckedTimelineTweetCount > 0) {
1065 tweetMainTab.setTitleAt(0, TAB_TIMELINE_STRING + "("
1066 + uncheckedTimelineTweetCount + ")");
1069 for (Status t : tweet) {
1070 tweetTableModel.insertTweet(t);
1071 mainTweetTable.setRowHeight(0, tableElementHeight);
1074 TableCellRenderer renderer = mainTweetTable.getCellRenderer(0, 2);
1075 if (renderer instanceof TweetCommentRenderer) {
1076 if (this.uncheckedTimelineTweetCount - 1 >= 0) {
1077 ((TweetCommentRenderer) renderer).updateNewCellRow(
1078 this.uncheckedTimelineTweetCount, newTableColor);
1080 ((TweetCommentRenderer) renderer).updateNewCellRow(-1,
1085 tweetTableModel.removeOldTweet(TABLE_ELEMENT_MAX_SIZE);
1087 // 取得したコメント数をステータスバーに表示
1088 information(uncheckedTimelineTweetCount
1089 + " 件の新しいツイートを取得しました. (APIリクエスト残数は" + remainingHits
1092 tweetTableModel.refreshTime();
1093 } catch (TwitterException e1) {
1094 e1.printStackTrace();
1103 public void actionUpdateButton(java.awt.event.ActionEvent e) {
1106 actionTweetTableUpdate();
1107 // Mentionテーブルの情報を更新
1108 actionMentionTableUpdate();
1109 // DirectMessageテーブルの情報を更新
1110 actionDirectMessageTableUpdate();
1111 // SendDirectMessageテーブルの情報を更新
1112 actionSendDirectMessageTableUpdate();
1114 //新しく追加したタブ上に存在するテーブルの情報を更新
1115 for(TweetTabbedTable t : this.tweetTabbedTableList ) {
1116 t.updateTweetTable();
1118 } catch (Exception e1) {
1119 e1.printStackTrace();
1128 public void actionUpdateTweetMessageCount() {
1129 int len = 140 - (tweetBoxPane.getText().length());
1133 tweetMessageCountLabel.setText(len + "");
1141 public ConfigurationDialog getConfigurationDialog() {
1142 if (configurationDialog == null) {
1143 configurationDialog = new ConfigurationDialog(mainFrame, this);
1145 return configurationDialog;
1149 * twitter全体からキーワード検索ダイアログを表示
1152 public KeywordSearchDialog getKeywordSearchDialog() {
1153 if( keywordSearchDialog == null ) {
1154 keywordSearchDialog = new KeywordSearchDialog(mainFrame, true, this);
1156 return keywordSearchDialog;
1163 public AccountDialog getAccountDialog() {
1164 if( accountDialog == null ) {
1165 accountDialog = new AccountDialog(mainFrame, true, tweetManager, this);
1167 return accountDialog;
1171 * ダイレクトメッセージ送信用ダイアログを取得
1175 public DirectMessageDialog getDirectMessageDialog() {
1176 if (directMessageDialog == null) {
1177 directMessageDialog = new DirectMessageDialog(mainFrame);
1178 directMessageDialog.setTitle("ダイレクトメッセージを送信");
1180 return directMessageDialog;
1184 * テーブルで選択したツイートを詳細情報としてセット
1187 public void setDetailInformationFromTable(JTable table) {
1188 int sc = table.getSelectedRowCount();
1189 String infoMessage = "";
1192 Status st = getTweetTableInformation(table, table.getModel());
1193 infoMessage = st.getText();
1194 // tweetMessageBox内のURLをhtmlリンクへ変換
1195 infoMessage = actionReplaceTweetMessageBoxURLLink(infoMessage);
1196 // @ユーザ情報をhtmlリンクへ変換
1197 infoMessage = actionReplaceTweetMessageBoxUserInfo(infoMessage);
1198 // #ハッシュタグ情報をhtmlリンクへ変換
1199 infoMessage = actionReplaceTweetMessageBoxHashTab(infoMessage);
1200 // 詳細情報にテーブルで選択した人のツイート情報を表示
1201 tweetMessageBox.setText(infoMessage);
1203 userImageLabel.setIcon(new ImageIcon(st.getUser().getProfileImageURL()));
1205 userNameLabel.setText(st.getUser().getName()
1206 + " / " + st.getUser().getScreenName());
1208 updateTimeLabel.setText(DateFormat.getInstance().format( st.getCreatedAt() ));
1210 userIntroBox.setText(st.getUser().getDescription());
1212 followerLabel.setText(st.getUser().getFollowersCount()
1215 followingLabel.setText(st.getUser().getFriendsCount()
1218 locationLabel.setText(st.getUser().getLocation());
1220 if (st.getUser().getURL() != null) {
1221 userWebBox.setText("<a href=\""
1222 + st.getUser().getURL() + "\">"
1223 + st.getUser().getScreenName()
1224 + "のWebを開く" + "</a>");
1226 userWebBox.setText("");
1229 clientNameLabel.setText(" via " + st.getSource());
1231 updateLabel.setText(st.getUser().getStatusesCount()
1240 public AboutDialog getAboutDialog() {
1241 if (aboutDialog == null) {
1242 aboutDialog = new AboutDialog(mainFrame, true);
1248 * updatePeriodを取得します。
1250 * @return updatePeriod
1252 public int getUpdatePeriod() {
1253 return updatePeriod;
1257 * updatePeriodを設定します。
1259 * @param updatePeriod
1262 public void setUpdatePeriod(int updatePeriod) {
1263 this.updatePeriod = updatePeriod;
1267 * getDirectMessagePeriodNumを取得します。
1269 * @return getDirectMessagePeriodNum
1271 public int getGetDirectMessagePeriodNum() {
1272 return getDirectMessagePeriodNum;
1276 * getMentionPeriodNumを取得します。
1278 * @return getMentionPeriodNum
1280 public int getGetMentionPeriodNum() {
1281 return getMentionPeriodNum;
1285 * getSendDirectMessagePeriodNumを取得します。
1287 * @return getSendDirectMessagePeriodNum
1289 public int getGetSendDirectMessagePeriodNum() {
1290 return getSendDirectMessagePeriodNum;
1294 * getTimelinePeriodNumを取得します。
1296 * @return getTimelinePeriodNum
1298 public int getGetTimelinePeriodNum() {
1299 return getTimelinePeriodNum;
1303 * テーブルで選択した場所のTweet情報を取得
1307 public Status getTweetTableInformation(JTable table, TableModel model) {
1308 int index = table.convertRowIndexToModel(table.getSelectedRow());
1309 Status status = null;
1310 if (model instanceof TweetTableModel) {
1311 status = ((TweetTableModel) model).getTweetStatus(index);
1312 // 現在選択したセルのユーザ名を保存しておく
1313 this.selectedUsername = status.getUser().getScreenName();
1314 // 現在選択したセルのユーザURLを保存しておく
1315 this.selectedUserImageURL = status.getUser().getProfileImageURL();
1316 // 選択したStatusを保存しておく
1317 this.currentStatus = status;
1327 private void information(String message) {
1328 statusBarLabel.setText(message);
1334 * @throws IOException
1335 * @throws FileNotFoundException
1337 public void loadProperties() throws FileNotFoundException, IOException {
1338 if (property == null) {
1339 this.property = new Properties();
1341 property.load(new FileInputStream("./" + PROPERTIES_DIRECTORY + "/"
1342 + BASIC_SETTING_FILENAME));
1344 String gtpn = this.property.getProperty("getTimelinePeriodNum");
1345 String gmpn = this.property.getProperty("getMentionPeriodNum");
1346 String gdmpn = this.property.getProperty("getDirectMessagePeriodNum");
1347 String gsdmpn = this.property.getProperty("getSendDirectMessagePeriodNum");
1348 String up = this.property.getProperty("updatePeriod");
1349 String ntrgb = this.property.getProperty("newTableColorRGB");
1351 this.tlFontName = this.property.getProperty("tlFontName");
1352 this.detailFontName = this.property.getProperty("detailFontName");
1354 String tfs = this.property.getProperty("tlFontSize");
1355 String dfs = this.property.getProperty("detailFontSize");
1356 String teh = this.property.getProperty("tableElementHeight");
1359 String mfw = this.property.getProperty("mainFrameWidth");
1360 String mfh = this.property.getProperty("mainFrameHeight");
1363 this.getTimelinePeriodNum = Integer.parseInt(gtpn);
1364 this.getMentionPeriodNum = Integer.parseInt(gmpn);
1365 this.getDirectMessagePeriodNum = Integer.parseInt(gdmpn);
1366 this.getSendDirectMessagePeriodNum = Integer.parseInt(gsdmpn);
1367 this.updatePeriod = Integer.parseInt(up);
1368 this.newTableColor = new Color(Integer.parseInt(ntrgb));
1369 this.tlFontSize = Integer.parseInt(tfs);
1370 this.detailFontSize = Integer.parseInt(dfs);
1371 this.tableElementHeight = Integer.parseInt(teh);
1372 this.mainFrameWidth = Integer.parseInt(mfw);
1373 this.mainFrameHeight = Integer.parseInt(mfh);
1374 } catch (NumberFormatException e) {
1375 e.printStackTrace();
1380 * Tweet情報の自動更新のタイムをリセット
1382 public void resetTweetAutoUpdate() {
1383 if (this.autoUpdateTimer != null) {
1384 this.autoUpdateTimer.reset();
1391 * @throws IOException
1393 public void saveProperties() throws IOException {
1395 File logDir = new File("./" + PROPERTIES_DIRECTORY);
1396 if (!logDir.exists()) {
1397 // ディレクトリが存在しないので作成する
1398 if (logDir.mkdir() == false) {
1399 throw new IOException(PROPERTIES_DIRECTORY
1400 + "ディレクトリを作成できませんでした.");
1403 if (property == null) {
1404 this.property = new Properties();
1407 this.property.setProperty("getTimelinePeriodNum",
1408 this.getTimelinePeriodNum + "");
1409 this.property.setProperty("getMentionPeriodNum",
1410 this.getMentionPeriodNum + "");
1411 this.property.setProperty("getDirectMessagePeriodNum",
1412 this.getDirectMessagePeriodNum + "");
1413 this.property.setProperty("getSendDirectMessagePeriodNum",
1414 this.getSendDirectMessagePeriodNum + "");
1415 this.property.setProperty("updatePeriod", this.updatePeriod + "");
1416 this.property.setProperty("newTableColorRGB", newTableColor.getRGB()
1418 this.property.setProperty("tlFontName", this.tlFontName);
1419 this.property.setProperty("tlFontSize", this.tlFontSize + "");
1420 this.property.setProperty("detailFontName", this.detailFontName);
1421 this.property.setProperty("detailFontSize", this.detailFontSize + "");
1422 this.property.setProperty("tableElementHeight", this.tableElementHeight
1426 if( this.mainFrame.getExtendedState() == JFrame.NORMAL ) {
1427 this.mainFrameWidth = this.mainFrame.getWidth();
1428 this.mainFrameHeight = this.mainFrame.getHeight();
1430 this.property.setProperty("mainFrameWidth", this.mainFrameWidth + "");
1431 this.property.setProperty("mainFrameHeight", this.mainFrameHeight + "");
1433 property.store(new FileOutputStream("./" + PROPERTIES_DIRECTORY + "/"
1434 + BASIC_SETTING_FILENAME), null);
1438 * getDirectMessagePeriodNumを設定します。
1440 * @param getDirectMessagePeriodNum
1441 * getDirectMessagePeriodNum
1443 public void setGetDirectMessagePeriodNum(int getDirectMessagePeriodNum) {
1444 this.getDirectMessagePeriodNum = getDirectMessagePeriodNum;
1448 * getMentionPeriodNumを設定します。
1450 * @param getMentionPeriodNum
1451 * getMentionPeriodNum
1453 public void setGetMentionPeriodNum(int getMentionPeriodNum) {
1454 this.getMentionPeriodNum = getMentionPeriodNum;
1458 * getSendDirectMessagePeriodNumを設定します。
1460 * @param getSendDirectMessagePeriodNum
1461 * getSendDirectMessagePeriodNum
1463 public void setGetSendDirectMessagePeriodNum(
1464 int getSendDirectMessagePeriodNum) {
1465 this.getSendDirectMessagePeriodNum = getSendDirectMessagePeriodNum;
1469 * getTimelinePeriodNumを設定します。
1471 * @param getTimelinePeriodNum
1472 * getTimelinePeriodNum
1474 public void setGetTimelinePeriodNum(int getTimelinePeriodNum) {
1475 this.getTimelinePeriodNum = getTimelinePeriodNum;
1483 public void startTweetAutoUpdate() {
1484 if (this.autoUpdateTimer == null) {
1485 this.autoUpdateTimer = new TweetAutoUpdateTimer();
1488 this.autoUpdateTimer.stop();
1490 this.autoUpdateTimer.start(updatePeriod * 60);
1494 * newTableColorを取得します。
1496 * @return newTableColor
1498 public Color getNewTableColor() {
1499 return newTableColor;
1503 * newTableColorを設定します。
1505 * @param newTableColor
1508 public void setNewTableColor(Color newTableColor) {
1509 this.newTableColor = newTableColor;
1515 * @return tlFontName
1517 public String getTlFontName() {
1527 public void setTlFontName(String tlFontName) {
1528 this.tlFontName = tlFontName;
1534 * @return tlFontSize
1536 public int getTlFontSize() {
1546 public void setTlFontSize(int tlFontSize) {
1547 this.tlFontSize = tlFontSize;
1551 * detailFontNameを取得します。
1553 * @return detailFontName
1555 public String getDetailFontName() {
1556 return detailFontName;
1560 * detailFontNameを設定します。
1562 * @param detailFontName
1565 public void setDetailFontName(String detailFontName) {
1566 this.detailFontName = detailFontName;
1570 * detailFontSizeを取得します。
1572 * @return detailFontSize
1574 public int getDetailFontSize() {
1575 return detailFontSize;
1579 * detailFontSizeを設定します。
1581 * @param detailFontSize
1584 public void setDetailFontSize(int detailFontSize) {
1585 this.detailFontSize = detailFontSize;
1589 * tableElementHeightを取得します。
1591 * @return tableElementHeight
1593 public int getTableElementHeight() {
1594 return tableElementHeight;
1598 * tableElementHeightを設定します。
1600 * @param tableElementHeight
1601 * tableElementHeight
1603 public void setTableElementHeight(int tableElementHeight) {
1604 this.tableElementHeight = tableElementHeight;