4 * License : The MIT License
5 * Copyright(c) 2008 olyutorskii
8 package jp.sfjp.jindolf.glyph;
10 import java.awt.Color;
11 import java.awt.Component;
12 import java.awt.Dimension;
13 import java.awt.Graphics;
14 import java.awt.Graphics2D;
15 import java.awt.Insets;
16 import java.awt.Point;
17 import java.awt.Rectangle;
18 import java.awt.RenderingHints;
19 import java.awt.event.ActionEvent;
20 import java.awt.event.ActionListener;
21 import java.awt.event.ComponentEvent;
22 import java.awt.event.ComponentListener;
23 import java.awt.event.MouseEvent;
24 import java.awt.font.FontRenderContext;
25 import java.io.IOException;
26 import java.util.EventListener;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.ListIterator;
30 import java.util.regex.Pattern;
31 import javax.swing.AbstractAction;
32 import javax.swing.Action;
33 import javax.swing.ActionMap;
34 import javax.swing.InputMap;
35 import javax.swing.JComponent;
36 import javax.swing.JMenuItem;
37 import javax.swing.JPopupMenu;
38 import javax.swing.JTextField;
39 import javax.swing.KeyStroke;
40 import javax.swing.Scrollable;
41 import javax.swing.SwingConstants;
42 import javax.swing.event.EventListenerList;
43 import javax.swing.event.MouseInputListener;
44 import javax.swing.text.DefaultEditorKit;
45 import jp.sfjp.jindolf.data.Anchor;
46 import jp.sfjp.jindolf.data.Avatar;
47 import jp.sfjp.jindolf.data.DialogPref;
48 import jp.sfjp.jindolf.data.Period;
49 import jp.sfjp.jindolf.data.RegexPattern;
50 import jp.sfjp.jindolf.data.SysEvent;
51 import jp.sfjp.jindolf.data.Talk;
52 import jp.sfjp.jindolf.data.Topic;
53 import jp.sfjp.jindolf.dxchg.ClipboardAction;
54 import jp.sfjp.jindolf.util.GUIUtils;
55 import jp.sfjp.jindolf.view.ActionManager;
56 import jp.sfjp.jindolf.view.TopicFilter;
61 * <p>表示に影響する要因は、Periodの中身、LayoutManagerによるサイズ変更、
62 * フォント属性の指定、フィルタリング操作、ドラッギングによる文字列選択操作、
65 @SuppressWarnings("serial")
66 public class Discussion extends JComponent
67 implements Scrollable, MouseInputListener, ComponentListener{
69 private static final Color COLOR_NORMALBG = Color.BLACK;
70 private static final Color COLOR_SIMPLEBG = Color.WHITE;
72 private static final int MARGINTOP = 50;
73 private static final int MARGINBOTTOM = 100;
75 private Period period;
76 private final List<TextRow> rowList = new LinkedList<>();
77 private final List<TalkDraw> talkDrawList = new LinkedList<>();
79 private TopicFilter topicFilter;
80 private TopicFilter.FilterContext filterContext;
81 private RegexPattern regexPattern;
83 private Point dragFrom;
85 private FontInfo fontInfo;
86 private final RenderingHints hints = new RenderingHints(null);
88 private DialogPref dialogPref;
90 private Dimension idealSize;
91 private int lastWidth = -1;
93 private final DiscussionPopup popup = new DiscussionPopup();
95 private final EventListenerList thisListenerList =
96 new EventListenerList();
98 private final Action copySelectedAction =
99 new ProxyAction(ActionManager.CMD_COPY);
104 @SuppressWarnings("LeakingThisInConstructor")
108 this.fontInfo = FontInfo.DEFAULT_FONTINFO;
109 this.dialogPref = new DialogPref();
111 this.hints.put(RenderingHints.KEY_ANTIALIASING,
112 RenderingHints.VALUE_ANTIALIAS_ON);
113 this.hints.put(RenderingHints.KEY_RENDERING,
114 RenderingHints.VALUE_RENDER_QUALITY);
115 updateRenderingHints();
119 addMouseListener(this);
120 addMouseMotionListener(this);
121 addComponentListener(this);
123 setComponentPopupMenu(this.popup);
126 ActionMap actionMap = getActionMap();
127 actionMap.put(DefaultEditorKit.copyAction, this.copySelectedAction);
136 * FontRenderContextが更新された後は必ず呼び出す必要がある。
138 private void updateRenderingHints(){
139 Object textAliaseValue;
140 FontRenderContext context = this.fontInfo.getFontRenderContext();
141 if(context.isAntiAliased()){
142 textAliaseValue = RenderingHints.VALUE_TEXT_ANTIALIAS_ON;
144 textAliaseValue = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF;
146 this.hints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
149 Object textFractionalValue;
150 if(context.usesFractionalMetrics()){
151 textFractionalValue = RenderingHints.VALUE_FRACTIONALMETRICS_ON;
153 textFractionalValue = RenderingHints.VALUE_FRACTIONALMETRICS_OFF;
155 this.hints.put(RenderingHints.KEY_FRACTIONALMETRICS,
156 textFractionalValue);
164 private void setColorDesign(){
166 if(this.dialogPref.isSimpleMode()){
167 fgColor = COLOR_SIMPLEBG;
169 fgColor = COLOR_NORMALBG;
172 setForeground(fgColor);
180 * @param newFontInfo フォント設定
182 public void setFontInfo(FontInfo newFontInfo){
183 this.fontInfo = newFontInfo;
185 updateRenderingHints();
187 for(TextRow row : this.rowList){
188 row.setFontInfo(this.fontInfo);
202 * @param newPref 発言表示設定
204 public void setDialogPref(DialogPref newPref){
205 this.dialogPref = newPref;
207 for(TextRow row : this.rowList){
208 if(row instanceof TalkDraw){
209 TalkDraw talkDraw = (TalkDraw) row;
210 talkDraw.setDialogPref(this.dialogPref);
211 }else if(row instanceof SysEventDraw){
212 SysEventDraw sysDraw = (SysEventDraw) row;
213 sysDraw.setDialogPref(this.dialogPref);
230 public Period getPeriod(){
236 * 新しいPeriodの表示内容はまだ反映されない。
237 * @param period 新しいPeriod
239 public final void setPeriod(Period period){
242 this.rowList.clear();
243 this.talkDrawList.clear();
247 if( this.period == period
248 && period.getTopics() == this.rowList.size() ){
253 this.period = period;
255 this.filterContext = null;
257 this.rowList.clear();
258 this.talkDrawList.clear();
259 for(Topic topic : this.period.getTopicList()){
261 if(topic instanceof Talk){
262 Talk talk = (Talk) topic;
263 TalkDraw talkDraw = new TalkDraw(talk,
266 this.talkDrawList.add(talkDraw);
268 }else if(topic instanceof SysEvent){
269 SysEvent sysEvent = (SysEvent) topic;
270 row = new SysEventDraw(sysEvent,
277 this.rowList.add(row);
291 * @param filter 発言フィルタ
293 public void setTopicFilter(TopicFilter filter){
294 this.topicFilter = filter;
302 public void filtering(){
303 if( this.topicFilter != null
304 && this.topicFilter.isSame(this.filterContext)){
308 if(this.topicFilter != null){
309 this.filterContext = this.topicFilter.getFilterContext();
311 this.filterContext = null;
326 public RegexPattern getRegexPattern(){
327 return this.regexPattern;
331 * 与えられた正規表現にマッチする文字列をハイライト描画する。
332 * @param newPattern 検索パターン
335 public int setRegexPattern(RegexPattern newPattern){
336 this.regexPattern = newPattern;
342 Pattern pattern = null;
343 if(this.regexPattern != null){
344 pattern = this.regexPattern.getPattern();
347 for(TalkDraw talkDraw : this.talkDrawList){
348 total += talkDraw.setRegex(pattern);
357 * 検索結果の次候補をハイライト表示する。
359 public void nextHotTarget(){
360 TalkDraw oldTalk = null;
362 TalkDraw newTalk = null;
364 TalkDraw firstTalk = null;
366 boolean findOld = true;
367 for(TalkDraw talkDraw : this.talkDrawList){
368 int matches = talkDraw.getRegexMatches();
369 if(firstTalk == null && matches > 0){
370 firstTalk = talkDraw;
373 int index = talkDraw.getHotTargetIndex();
374 if(index < 0) continue;
377 scrollRectWithMargin(talkDraw.getHotTargetRectangle());
378 if(oldIndex < matches - 1 && ! isFiltered(talkDraw) ){
380 newIndex = oldIndex + 1;
385 if(isFiltered(talkDraw)) continue;
386 if(matches <= 0) continue;
393 Rectangle showRect = null;
394 if(oldTalk == null && firstTalk != null){
395 firstTalk.setHotTargetIndex(0);
396 showRect = firstTalk.getHotTargetRectangle();
397 }else if( oldTalk != null
399 oldTalk.clearHotTarget();
400 newTalk.setHotTargetIndex(newIndex);
401 showRect = newTalk.getHotTargetRectangle();
404 if(showRect != null){
405 scrollRectWithMargin(showRect);
414 * 検索結果の前候補をハイライト表示する。
416 public void prevHotTarget(){
417 TalkDraw oldTalk = null;
419 TalkDraw newTalk = null;
421 TalkDraw firstTalk = null;
423 boolean findOld = true;
424 int size = this.talkDrawList.size();
425 ListIterator<TalkDraw> iterator =
426 this.talkDrawList.listIterator(size);
427 while(iterator.hasPrevious()){
428 TalkDraw talkDraw = iterator.previous();
429 int matches = talkDraw.getRegexMatches();
430 if(firstTalk == null && matches > 0){
431 firstTalk = talkDraw;
434 int index = talkDraw.getHotTargetIndex();
435 if(index < 0) continue;
438 scrollRectWithMargin(talkDraw.getHotTargetRectangle());
439 if(oldIndex > 0 && ! isFiltered(talkDraw) ){
441 newIndex = oldIndex - 1;
446 if(isFiltered(talkDraw)) continue;
447 if(matches <= 0) continue;
449 newIndex = matches - 1;
454 Rectangle showRect = null;
455 if(oldTalk == null && firstTalk != null){
456 int matches = firstTalk.getRegexMatches();
457 firstTalk.setHotTargetIndex(matches - 1);
458 showRect = firstTalk.getHotTargetRectangle();
459 }else if( oldTalk != null
461 oldTalk.clearHotTarget();
462 newTalk.setHotTargetIndex(newIndex);
463 showRect = newTalk.getHotTargetRectangle();
466 if(showRect != null){
467 scrollRectWithMargin(showRect);
478 public void clearHotTarget(){
479 for(TalkDraw talkDraw : this.talkDrawList){
480 talkDraw.clearHotTarget();
487 * 指定した領域に若干の上下マージンを付けて
489 * @param rectangle 指定領域
491 private void scrollRectWithMargin(Rectangle rectangle){
492 Rectangle show = new Rectangle(rectangle);
494 show.height += MARGINTOP + MARGINBOTTOM;
496 scrollRectToVisible(show);
504 private void clearSizeCache(){
505 this.idealSize = null;
512 * 指定した矩形がフィルタリング対象か判定する。
514 * @return フィルタリング対象ならtrue
516 private boolean isFiltered(TextRow row){
517 if(this.topicFilter == null) return false;
520 if(row instanceof TalkDraw){
521 topic = ((TalkDraw) row).getTalk();
522 }else if(row instanceof SysEventDraw){
523 topic = ((SysEventDraw) row).getSysEvent();
528 return this.topicFilter.isFiltered(topic);
532 * フィルタリング指定に従いTextRowを表示するか否か設定する。
534 private void filterTopics(){
535 for(TextRow row : this.rowList){
536 if(isFiltered(row)) row.setVisible(false);
537 else row.setVisible(true);
545 * @param width コンポーネント幅
547 private void setWidth(int width){
548 this.lastWidth = width;
549 Insets insets = getInsets();
550 int rowWidth = width - (insets.left + insets.right);
551 for(TextRow row : this.rowList){
552 row.setWidth(rowWidth);
561 * 子TextRowの縦位置レイアウトを行う。
563 * TextRowは必要に応じて移動させられるがリサイズされることはない。
565 private void layoutVertical(){
566 Rectangle unionRect = null;
567 Insets insets = getInsets();
568 int vertPos = insets.top;
570 for(TextRow row : this.rowList){
571 if( ! row.isVisible() ) continue;
573 row.setPos(insets.left, vertPos);
574 Rectangle rowBound = row.getBounds();
575 vertPos += rowBound.height;
577 if(unionRect == null){
578 unionRect = new Rectangle(rowBound);
580 unionRect.add(rowBound);
584 if(unionRect == null){
585 unionRect = new Rectangle(insets.left, insets.top, 0, 0);
588 if(this.idealSize == null){
589 this.idealSize = new Dimension();
592 int newWidth = insets.left + unionRect.width + insets.right;
593 int newHeight = insets.top + unionRect.height + insets.bottom;
595 this.idealSize.setSize(newWidth, newHeight);
597 setPreferredSize(this.idealSize);
608 public void layoutRows(){
609 int width = getWidth();
616 * @param g {@inheritDoc}
619 public void paintComponent(Graphics g){
620 Graphics2D g2 = (Graphics2D) g;
621 g2.setRenderingHints(this.hints);
623 Rectangle clipRect = g2.getClipBounds();
624 g2.fillRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
626 for(TextRow row : this.rowList){
627 if( ! row.isVisible() ) continue;
629 Rectangle rowRect = row.getBounds();
630 if( ! rowRect.intersects(clipRect) ) continue;
640 * @return {@inheritDoc}
643 public Dimension getPreferredScrollableViewportSize(){
644 return getPreferredSize();
649 * @return {@inheritDoc}
652 public boolean getScrollableTracksViewportWidth(){
658 * @return {@inheritDoc}
661 public boolean getScrollableTracksViewportHeight(){
667 * @param visibleRect {@inheritDoc}
668 * @param orientation {@inheritDoc}
669 * @param direction {@inheritDoc}
670 * @return {@inheritDoc}
673 public int getScrollableBlockIncrement(Rectangle visibleRect,
676 if(orientation == SwingConstants.VERTICAL){
677 return visibleRect.height;
679 return 30; // TODO フォント高 × 1.5 ぐらい?
684 * @param visibleRect {@inheritDoc}
685 * @param orientation {@inheritDoc}
686 * @param direction {@inheritDoc}
687 * @return {@inheritDoc}
690 public int getScrollableUnitIncrement(Rectangle visibleRect,
697 * 任意の発言の表示が占める画面領域を返す。
698 * 発言がフィルタリング対象の時はnullを返す。
702 public Rectangle getTalkBounds(Talk talk){
703 if( this.topicFilter != null
704 && this.topicFilter.isFiltered(talk)) return null;
706 for(TalkDraw talkDraw : this.talkDrawList){
707 if(talkDraw.getTalk() == talk){
708 Rectangle rect = talkDraw.getBounds();
718 * @param from ドラッグ開始位置
719 * @param to 現在のドラッグ位置
721 private void drag(Point from, Point to){
722 Rectangle dragRegion = new Rectangle();
723 dragRegion.setFrameFromDiagonal(from, to);
725 for(TextRow row : this.rowList){
726 if(isFiltered(row)) continue;
727 if( ! row.getBounds().intersects(dragRegion) ) continue;
737 private void clearSelect(){
738 for(TextRow row : this.rowList){
746 * 与えられた点座標を包含する発言を返す。
747 * @param pt 点座標(JComponent基準)
748 * @return 点座標を含む発言。含む発言がなければnullを返す。
751 private TalkDraw getHittedTalkDraw(Point pt){
752 for(TalkDraw talkDraw : this.talkDrawList){
753 if(isFiltered(talkDraw)) continue;
754 Rectangle bounds = talkDraw.getBounds();
755 if(bounds.contains(pt)) return talkDraw;
764 private void hitAnchor(Point pt){
765 TalkDraw talkDraw = getHittedTalkDraw(pt);
766 if(talkDraw == null) return;
768 Anchor anchor = talkDraw.getAnchor(pt);
769 if(anchor == null) return;
771 for(AnchorHitListener listener : getAnchorHitListeners()){
772 AnchorHitEvent event =
773 new AnchorHitEvent(this, talkDraw, anchor, pt);
774 listener.anchorHitted(event);
784 private void hitRegex(Point pt){
785 TalkDraw talkDraw = getHittedTalkDraw(pt);
786 if(talkDraw == null) return;
788 int index = talkDraw.getRegexMatchIndex(pt);
789 if(index < 0) return;
792 talkDraw.setHotTargetIndex(index);
800 * MouseInputListenerを参照せよ。
801 * @param event {@inheritDoc}
805 public void mouseClicked(MouseEvent event){
806 Point pt = event.getPoint();
807 if(event.getButton() == MouseEvent.BUTTON1){
817 * @param event {@inheritDoc}
820 public void mouseEntered(MouseEvent event){
821 // TODO ここでキーボードフォーカス処理が必要?
827 * @param event {@inheritDoc}
830 public void mouseExited(MouseEvent event){
837 * @param event {@inheritDoc}
840 public void mousePressed(MouseEvent event){
841 requestFocusInWindow();
843 if(event.getButton() == MouseEvent.BUTTON1){
845 this.dragFrom = event.getPoint();
854 * @param event {@inheritDoc}
857 public void mouseReleased(MouseEvent event){
858 if(event.getButton() == MouseEvent.BUTTON1){
859 this.dragFrom = null;
867 * @param event {@inheritDoc}
869 // TODO ドラッグ範囲がビューポートを超えたら自動的にスクロールしてほしい。
871 public void mouseDragged(MouseEvent event){
872 if(this.dragFrom == null) return;
873 Point dragTo = event.getPoint();
874 drag(this.dragFrom, dragTo);
880 * @param event {@inheritDoc}
883 public void mouseMoved(MouseEvent event){
889 * @param event {@inheritDoc}
892 public void componentShown(ComponentEvent event){
898 * @param event {@inheritDoc}
901 public void componentHidden(ComponentEvent event){
907 * @param event {@inheritDoc}
910 public void componentMoved(ComponentEvent event){
916 * @param event {@inheritDoc}
919 public void componentResized(ComponentEvent event){
920 int width = getWidth();
921 int height = getHeight();
922 if(width != this.lastWidth){
925 if( this.idealSize.width != width
926 || this.idealSize.height != height ){
936 public CharSequence getSelected(){
937 StringBuilder selected = new StringBuilder();
939 for(TextRow row : this.rowList){
940 if(isFiltered(row)) continue;
942 row.appendSelected(selected);
943 }catch(IOException e){
944 assert false; // ありえない
949 if(selected.length() <= 0) return null;
955 * 選択文字列をクリップボードにコピーする。
958 public CharSequence copySelected(){
959 CharSequence selected = getSelected();
960 if(selected == null) return null;
961 ClipboardAction.copyToClipboard(selected);
966 * 矩形の示す一発言をクリップボードにコピーする。
969 public CharSequence copyTalk(){
970 TalkDraw talkDraw = this.popup.lastPopupedTalkDraw;
971 if(talkDraw == null) return null;
972 Talk talk = talkDraw.getTalk();
974 StringBuilder selected = new StringBuilder();
976 Avatar avatar = talk.getAvatar();
977 selected.append(avatar.getName()).append(' ');
979 String anchor = talk.getAnchorNotation();
980 selected.append(anchor);
981 if(talk.hasTalkNo()){
982 selected.append(' ').append(talk.getAnchorNotation_G());
984 selected.append('\n');
986 selected.append(talk.getDialog());
987 if(selected.charAt(selected.length() - 1) != '\n'){
988 selected.append('\n');
991 ClipboardAction.copyToClipboard(selected);
997 * ポップアップメニュートリガ座標に発言があればそれを返す。
1000 public Talk getPopupedTalk(){
1001 TalkDraw talkDraw = this.popup.lastPopupedTalkDraw;
1002 if(talkDraw == null) return null;
1003 Talk talk = talkDraw.getTalk();
1008 * ポップアップメニュートリガ座標にアンカーがあればそれを返す。
1011 public Anchor getPopupedAnchor(){
1012 return this.popup.lastPopupedAnchor;
1019 public void updateUI(){
1021 this.popup.updateUI();
1029 * COPY処理を行うキーの設定をJTextFieldから流用する。
1030 * おそらくはCtrl-C。MacならCommand-Cかも。
1032 private void updateInputMap(){
1033 InputMap thisInputMap = getInputMap();
1035 InputMap sampleInputMap;
1036 sampleInputMap = new JTextField().getInputMap();
1037 KeyStroke[] strokes = sampleInputMap.allKeys();
1038 for(KeyStroke stroke : strokes){
1039 Object bind = sampleInputMap.get(stroke);
1040 if(bind.equals(DefaultEditorKit.copyAction)){
1041 thisInputMap.put(stroke, DefaultEditorKit.copyAction);
1049 * ActionListenerを追加する。
1050 * @param listener リスナー
1052 public void addActionListener(ActionListener listener){
1053 this.thisListenerList.add(ActionListener.class, listener);
1055 this.popup.menuCopy .addActionListener(listener);
1056 this.popup.menuSelTalk .addActionListener(listener);
1057 this.popup.menuJumpAnchor .addActionListener(listener);
1058 this.popup.menuWebTalk .addActionListener(listener);
1059 this.popup.menuSummary .addActionListener(listener);
1065 * ActionListenerを削除する。
1066 * @param listener リスナー
1068 public void removeActionListener(ActionListener listener){
1069 this.thisListenerList.remove(ActionListener.class, listener);
1071 this.popup.menuCopy .removeActionListener(listener);
1072 this.popup.menuSelTalk .removeActionListener(listener);
1073 this.popup.menuJumpAnchor .removeActionListener(listener);
1074 this.popup.menuWebTalk .removeActionListener(listener);
1075 this.popup.menuSummary .removeActionListener(listener);
1081 * ActionListenerを列挙する。
1082 * @return すべてのActionListener
1084 public ActionListener[] getActionListeners(){
1085 return this.thisListenerList.getListeners(ActionListener.class);
1089 * AnchorHitListenerを追加する。
1090 * @param listener リスナー
1092 public void addAnchorHitListener(AnchorHitListener listener){
1093 this.thisListenerList.add(AnchorHitListener.class, listener);
1098 * AnchorHitListenerを削除する。
1099 * @param listener リスナー
1101 public void removeAnchorHitListener(AnchorHitListener listener){
1102 this.thisListenerList.remove(AnchorHitListener.class, listener);
1107 * AnchorHitListenerを列挙する。
1108 * @return すべてのAnchorHitListener
1110 public AnchorHitListener[] getAnchorHitListeners(){
1111 return this.thisListenerList.getListeners(AnchorHitListener.class);
1116 * @param <T> {@inheritDoc}
1117 * @param listenerType {@inheritDoc}
1118 * @return {@inheritDoc}
1121 public <T extends EventListener> T[] getListeners(Class<T> listenerType){
1123 result = this.thisListenerList.getListeners(listenerType);
1125 if(result.length <= 0){
1126 result = super.getListeners(listenerType);
1133 * キーボード入力用ダミーAction。
1135 private class ProxyAction extends AbstractAction{
1137 private final String command;
1141 * @param command コマンド
1142 * @throws NullPointerException 引数がnull
1144 public ProxyAction(String command) throws NullPointerException{
1146 if(command == null) throw new NullPointerException();
1147 this.command = command;
1153 * @param event {@inheritDoc}
1156 public void actionPerformed(ActionEvent event){
1157 Object source = event.getSource();
1158 int id = event.getID();
1159 String actcmd = this.command;
1160 long when = event.getWhen();
1161 int modifiers = event.getModifiers();
1163 for(ActionListener listener : getActionListeners()){
1164 ActionEvent newEvent = new ActionEvent(source,
1169 listener.actionPerformed(newEvent);
1179 private class DiscussionPopup extends JPopupMenu{
1181 private final JMenuItem menuCopy =
1182 new JMenuItem("選択範囲をコピー");
1183 private final JMenuItem menuSelTalk =
1184 new JMenuItem("この発言をコピー");
1185 private final JMenuItem menuJumpAnchor =
1186 new JMenuItem("アンカーの示す先へジャンプ");
1187 private final JMenuItem menuWebTalk =
1188 new JMenuItem("この発言をブラウザで表示...");
1189 private final JMenuItem menuSummary =
1190 new JMenuItem("発言を集計...");
1192 private TalkDraw lastPopupedTalkDraw;
1193 private Anchor lastPopupedAnchor;
1198 public DiscussionPopup(){
1202 add(this.menuSelTalk);
1204 add(this.menuJumpAnchor);
1205 add(this.menuWebTalk);
1207 add(this.menuSummary);
1210 .setActionCommand(ActionManager.CMD_COPY);
1212 .setActionCommand(ActionManager.CMD_COPYTALK);
1214 .setActionCommand(ActionManager.CMD_JUMPANCHOR);
1216 .setActionCommand(ActionManager.CMD_WEBTALK);
1218 .setActionCommand(ActionManager.CMD_DAYSUMMARY);
1220 this.menuWebTalk.setIcon(GUIUtils.getWWWIcon());
1227 * @param comp {@inheritDoc}
1228 * @param x {@inheritDoc}
1229 * @param y {@inheritDoc}
1232 public void show(Component comp, int x, int y){
1233 Point point = new Point(x, y);
1235 this.lastPopupedTalkDraw = getHittedTalkDraw(point);
1236 if(this.lastPopupedTalkDraw != null){
1237 this.menuSelTalk.setEnabled(true);
1238 this.menuWebTalk.setEnabled(true);
1240 this.menuSelTalk.setEnabled(false);
1241 this.menuWebTalk.setEnabled(false);
1244 if(this.lastPopupedTalkDraw != null){
1245 this.lastPopupedAnchor =
1246 this.lastPopupedTalkDraw.getAnchor(point);
1248 this.lastPopupedAnchor = null;
1251 if(this.lastPopupedAnchor != null){
1252 this.menuJumpAnchor.setEnabled(true);
1254 this.menuJumpAnchor.setEnabled(false);
1257 if(getSelected() != null){
1258 this.menuCopy.setEnabled(true);
1260 this.menuCopy.setEnabled(false);
1263 super.show(comp, x, y);
1270 // Period変更を追跡するリスナ化