4 * License : The MIT License
5 * Copyright(c) 2008 olyutorskii
8 package jp.sfjp.jindolf.editor;
10 import java.awt.BorderLayout;
11 import java.awt.Color;
12 import java.awt.Container;
14 import java.awt.GridBagConstraints;
15 import java.awt.GridBagLayout;
16 import java.awt.Insets;
17 import java.awt.LayoutManager;
18 import java.awt.event.ActionEvent;
19 import java.awt.event.ActionListener;
21 import javax.swing.BorderFactory;
22 import javax.swing.JButton;
23 import javax.swing.JComponent;
24 import javax.swing.JFrame;
25 import javax.swing.JLabel;
26 import javax.swing.JOptionPane;
27 import javax.swing.JPanel;
28 import javax.swing.JPopupMenu;
29 import javax.swing.JScrollPane;
30 import javax.swing.JSplitPane;
31 import javax.swing.JViewport;
32 import javax.swing.border.BevelBorder;
33 import javax.swing.border.Border;
34 import javax.swing.border.TitledBorder;
35 import javax.swing.event.ChangeEvent;
36 import javax.swing.event.ChangeListener;
37 import javax.swing.text.JTextComponent;
38 import jp.sfjp.jindolf.dxchg.ClipboardAction;
39 import jp.sfjp.jindolf.dxchg.TextPopup;
40 import jp.sfjp.jindolf.glyph.FontInfo;
41 import jp.sfjp.jindolf.util.GUIUtils;
42 import jp.sourceforge.jovsonz.JsArray;
43 import jp.sourceforge.jovsonz.JsComposition;
44 import jp.sourceforge.jovsonz.JsObject;
45 import jp.sourceforge.jovsonz.JsString;
46 import jp.sourceforge.jovsonz.JsTypes;
47 import jp.sourceforge.jovsonz.JsValue;
52 @SuppressWarnings("serial")
53 public class TalkPreview extends JFrame
54 implements ActionListener, ChangeListener{
57 public static final File DRAFT_FILE = new File("draft.json");
59 private static final Color COLOR_EDITORBACK = Color.BLACK;
61 private final JTextComponent freeMemo = new TextEditor();
63 private final EditArray editArray = new EditArray();
65 private final JButton cutButton = new JButton("カット");
66 private final JButton copyButton = new JButton("コピー");
67 private final JButton clearButton = new JButton("クリア");
68 private final JButton cutAllButton = new JButton("全カット");
69 private final JButton copyAllButton = new JButton("全コピー");
70 private final JButton clearAllButton = new JButton("全クリア");
71 private final JButton closeButton = new JButton("閉じる");
72 private final TitledBorder numberBorder =
73 BorderFactory.createTitledBorder("");
74 private final JComponent singleGroup = buildSingleGroup();
75 private final JComponent multiGroup = buildMultiGroup();
76 private final JLabel letsBrowser =
77 new JLabel("投稿はWebブラウザからどうぞ");
79 private JsObject loadedDraft = null;
84 @SuppressWarnings("LeakingThisInConstructor")
88 GUIUtils.modifyWindowAttributes(this, true, false, true);
90 setDefaultCloseOperation(HIDE_ON_CLOSE);
92 this.cutButton .addActionListener(this);
93 this.copyButton .addActionListener(this);
94 this.clearButton .addActionListener(this);
95 this.cutAllButton .addActionListener(this);
96 this.copyAllButton .addActionListener(this);
97 this.clearAllButton .addActionListener(this);
98 this.closeButton .addActionListener(this);
100 this.editArray.addChangeListener(this);
102 Container content = getContentPane();
112 * @param content コンテナ
114 private void design(Container content){
115 JComponent freeNotePanel = buildFreeNotePanel();
117 JScrollPane scrollPane = new JScrollPane();
118 scrollPane.setHorizontalScrollBarPolicy(
119 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
121 JViewport viewPort = new JViewport();
122 viewPort.setBackground(COLOR_EDITORBACK);
123 viewPort.setView(this.editArray);
124 scrollPane.setViewport(viewPort);
126 LayoutManager layout;
129 JComponent editPanel = new JPanel();
130 layout = new BorderLayout();
131 editPanel.setLayout(layout);
132 editPanel.add(scrollPane, BorderLayout.CENTER);
133 JComponent buttonPanel = buildButtonPanel();
134 editPanel.add(buttonPanel, BorderLayout.EAST);
135 border = BorderFactory.createTitledBorder("発言編集");
136 editPanel.setBorder(border);
138 JSplitPane split = new JSplitPane();
139 split.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
140 split.setContinuousLayout(false);
141 split.setDividerSize(10);
142 split.setDividerLocation(200);
143 split.setOneTouchExpandable(true);
144 split.setLeftComponent(freeNotePanel);
145 split.setRightComponent(editPanel);
147 Border inside = BorderFactory.createBevelBorder(BevelBorder.LOWERED);
148 Border outside = BorderFactory.createEmptyBorder(2, 5, 2, 2);
149 border = BorderFactory.createCompoundBorder(inside, outside);
150 this.letsBrowser.setBorder(border);
152 layout = new BorderLayout();
153 content.setLayout(layout);
154 content.add(split, BorderLayout.CENTER);
155 content.add(this.letsBrowser, BorderLayout.SOUTH);
164 private JComponent buildButtonPanel(){
165 JPanel panel = new JPanel();
167 LayoutManager layout = new GridBagLayout();
168 GridBagConstraints constraints = new GridBagConstraints();
170 panel.setLayout(layout);
172 constraints.weightx = 1.0;
173 constraints.weighty = 0.0;
174 constraints.fill = GridBagConstraints.NONE;
175 constraints.anchor = GridBagConstraints.WEST;
176 constraints.gridx = 1;
177 constraints.gridy = GridBagConstraints.RELATIVE;
178 constraints.gridwidth = 1;
179 constraints.gridheight = 1;
182 constraints.insets = new Insets(3, 3, 3, 3);
183 panel.add(this.singleGroup, constraints);
185 constraints.insets = new Insets(10, 3, 3, 3);
186 panel.add(this.multiGroup, constraints);
188 constraints.weighty = 1.0;
189 constraints.anchor = GridBagConstraints.SOUTH;
190 constraints.insets = new Insets(3, 3, 10, 3);
191 panel.add(this.closeButton, constraints);
197 * アクティブ発言操作ボタン群を生成する。
200 private JComponent buildSingleGroup(){
201 JComponent panel = new JPanel();
203 LayoutManager layout = new GridBagLayout();
204 GridBagConstraints constraints = new GridBagConstraints();
206 panel.setLayout(layout);
208 constraints.weightx = 1.0;
209 constraints.weighty = 0.0;
210 constraints.fill = GridBagConstraints.HORIZONTAL;
211 constraints.gridx = 1;
212 constraints.gridy = GridBagConstraints.RELATIVE;
213 constraints.gridwidth = 1;
214 constraints.gridheight = 1;
215 constraints.insets = new Insets(3, 3, 3, 3);
217 panel.add(this.cutButton, constraints);
218 panel.add(this.copyButton, constraints);
219 panel.add(this.clearButton, constraints);
221 panel.setBorder(this.numberBorder);
230 private JComponent buildMultiGroup(){
231 JComponent panel = new JPanel();
233 LayoutManager layout = new GridBagLayout();
234 GridBagConstraints constraints = new GridBagConstraints();
236 panel.setLayout(layout);
238 constraints.weightx = 1.0;
239 constraints.weighty = 0.0;
240 constraints.fill = GridBagConstraints.HORIZONTAL;
241 constraints.gridx = 1;
242 constraints.gridy = GridBagConstraints.RELATIVE;
243 constraints.gridwidth = 1;
244 constraints.gridheight = 1;
245 constraints.insets = new Insets(3, 3, 3, 3);
247 panel.add(this.cutAllButton, constraints);
248 panel.add(this.copyAllButton, constraints);
249 panel.add(this.clearAllButton, constraints);
251 Border border = BorderFactory.createTitledBorder("全発言を");
252 panel.setBorder(border);
261 private JComponent buildFreeNotePanel(){
262 Insets margin = new Insets(3, 3, 3, 3);
263 this.freeMemo.setMargin(margin);
264 JPopupMenu popup = new TextPopup();
265 this.freeMemo.setComponentPopupMenu(popup);
267 JScrollPane scrollPane = new JScrollPane();
268 scrollPane.setHorizontalScrollBarPolicy(
269 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
271 JViewport viewPort = new JViewport();
272 viewPort.setView(this.freeMemo);
273 scrollPane.setViewport(viewPort);
275 JComponent panel = new JPanel();
277 LayoutManager layout = new GridBagLayout();
278 GridBagConstraints constraints = new GridBagConstraints();
280 panel.setLayout(layout);
282 constraints.weightx = 1.0;
283 constraints.weighty = 1.0;
284 constraints.fill = GridBagConstraints.BOTH;
285 constraints.insets = new Insets(1, 1, 1, 1);
286 panel.add(scrollPane, constraints);
288 Border border = BorderFactory.createTitledBorder("フリーメモ");
289 panel.setBorder(border);
298 private void setBorderNumber(int num){
299 String title = "発言#"+num+" を";
300 this.numberBorder.setTitle(title);
301 this.singleGroup.revalidate();
302 this.singleGroup.repaint();
309 * @param fontInfo フォント設定
311 public void setFontInfo(FontInfo fontInfo){
312 setTextFont(fontInfo.getFont());
318 * @param textFont フォント
320 public void setTextFont(Font textFont){
321 this.freeMemo.setFont(textFont);
322 this.editArray.setTextFont(textFont);
330 public Font getTextFont(){
331 return this.editArray.getTextFont();
335 * 発言クリア操作の確認ダイアログを表示する。
336 * @return OKなら0, Cancelなら2
338 private int warnClear(){
339 int result = JOptionPane.showConfirmDialog(
341 "本当に発言をクリアしてもよいですか?",
343 JOptionPane.OK_CANCEL_OPTION,
344 JOptionPane.QUESTION_MESSAGE );
350 * @return JSON形式の原稿情報
352 public JsObject getJson(){
353 JsObject result = new JsObject();
354 JsString memo = new JsString(this.freeMemo.getText());
355 result.putValue("freeMemo", memo);
357 JsArray array = new JsArray();
358 JsString text = new JsString(this.editArray.getAllText());
360 result.putValue("drafts", array);
367 * @param root JSON形式の原稿情報。nullが来たら何もしない
369 public void putJson(JsObject root){
370 if(root == null) return;
374 value = root.getValue("freeMemo");
375 if(value.getJsTypes() == JsTypes.STRING){
376 JsString memo = (JsString) value;
377 this.freeMemo.setText(memo.toRawString());
380 value = root.getValue("drafts");
381 if(value.getJsTypes() != JsTypes.ARRAY) return;
382 JsArray array = (JsArray) value;
384 StringBuilder draftAll = new StringBuilder();
385 for(JsValue elem : array){
386 if(elem.getJsTypes() != JsTypes.STRING) continue;
387 JsString draft = (JsString) elem;
388 draftAll.append(draft.toRawString());
390 this.editArray.clearAllEditor();
391 this.editArray.setAllText(draftAll);
393 this.loadedDraft = root;
403 public boolean hasConfChanged(JsComposition<?> conf){
404 if(this.loadedDraft != null){
405 if(this.loadedDraft.equals(conf)) return true;
411 * アクティブな発言をカットしクリップボードへコピーする。
413 private void actionCutActive(){
415 actionClearActive(false);
420 * アクティブな発言をクリップボードにコピーする。
422 private void actionCopyActive(){
423 TalkEditor activeEditor = this.editArray.getActiveEditor();
424 if(activeEditor == null) return;
426 CharSequence text = activeEditor.getText();
427 ClipboardAction.copyToClipboard(text);
434 * @param confirm trueなら確認ダイアログを出す
436 private void actionClearActive(boolean confirm){
437 if(confirm && warnClear() != 0 ) return;
439 TalkEditor activeEditor = this.editArray.getActiveEditor();
440 if(activeEditor == null) return;
442 activeEditor.clearText();
448 * 全発言をカットしクリップボードへコピーする。
450 private void actionCutAll(){
452 actionClearAll(false);
459 private void actionCopyAll(){
460 CharSequence text = this.editArray.getAllText();
461 ClipboardAction.copyToClipboard(text);
467 * @param confirm trueなら確認ダイアログを出す
469 private void actionClearAll(boolean confirm){
470 if(confirm && warnClear() != 0 ) return;
471 this.editArray.clearAllEditor();
478 private void actionClose(){
486 * @param event {@inheritDoc}
489 public void actionPerformed(ActionEvent event){
490 Object source = event.getSource();
491 if (source == this.cutButton) actionCutActive();
492 else if(source == this.copyButton) actionCopyActive();
493 else if(source == this.clearButton) actionClearActive(true);
494 else if(source == this.cutAllButton) actionCutAll();
495 else if(source == this.copyAllButton) actionCopyAll();
496 else if(source == this.clearAllButton) actionClearAll(true);
497 else if(source == this.closeButton) actionClose();
502 * アクティブなエディタが変更された時の処理。
503 * @param event イベント情報
506 public void stateChanged(ChangeEvent event){
507 TalkEditor activeEditor = this.editArray.getActiveEditor();
508 int seqNo = activeEditor.getSequenceNumber();
509 setBorderNumber(seqNo);
514 // TODO バルーンの雰囲気を選択できるようにしたい。(白、赤、青、灰)