-/*\r
- * 発言エディットパネル\r
- *\r
- * Copyright(c) 2008 olyutorskii\r
- * $Id: TalkPreview.java 953 2009-12-06 16:42:14Z olyutorskii $\r
- */\r
-\r
-package jp.sourceforge.jindolf;\r
-\r
-import java.awt.BorderLayout;\r
-import java.awt.Color;\r
-import java.awt.Container;\r
-import java.awt.Font;\r
-import java.awt.GridBagConstraints;\r
-import java.awt.GridBagLayout;\r
-import java.awt.Insets;\r
-import java.awt.LayoutManager;\r
-import java.awt.event.ActionEvent;\r
-import java.awt.event.ActionListener;\r
-import java.io.File;\r
-import javax.swing.BorderFactory;\r
-import javax.swing.JButton;\r
-import javax.swing.JComponent;\r
-import javax.swing.JFrame;\r
-import javax.swing.JLabel;\r
-import javax.swing.JOptionPane;\r
-import javax.swing.JPanel;\r
-import javax.swing.JPopupMenu;\r
-import javax.swing.JScrollPane;\r
-import javax.swing.JSplitPane;\r
-import javax.swing.JViewport;\r
-import javax.swing.border.BevelBorder;\r
-import javax.swing.border.Border;\r
-import javax.swing.border.TitledBorder;\r
-import javax.swing.event.ChangeEvent;\r
-import javax.swing.event.ChangeListener;\r
-import javax.swing.text.JTextComponent;\r
-import jp.sourceforge.jindolf.json.JsArray;\r
-import jp.sourceforge.jindolf.json.JsObject;\r
-import jp.sourceforge.jindolf.json.JsString;\r
-import jp.sourceforge.jindolf.json.JsValue;\r
-\r
-/**\r
- * 発言エディットパネル。\r
- */\r
-@SuppressWarnings("serial")\r
-public class TalkPreview extends JFrame\r
- implements ActionListener, ChangeListener{\r
-\r
- private static final String FRAMETITLE = "発言エディタ - " + Jindolf.TITLE;\r
- private static final Color COLOR_EDITORBACK = Color.BLACK;\r
- private static final String DRAFT_FILE = "draft.json";\r
-\r
- private final JTextComponent freeMemo = new TextEditor();\r
-\r
- private final EditArray editArray = new EditArray();\r
-\r
- private final JButton cutButton = new JButton("カット");\r
- private final JButton copyButton = new JButton("コピー");\r
- private final JButton clearButton = new JButton("クリア");\r
- private final JButton cutAllButton = new JButton("全カット");\r
- private final JButton copyAllButton = new JButton("全コピー");\r
- private final JButton clearAllButton = new JButton("全クリア");\r
- private final JButton closeButton = new JButton("閉じる");\r
- private final TitledBorder numberBorder =\r
- BorderFactory.createTitledBorder("");\r
- private final JComponent singleGroup = buildSingleGroup();\r
- private final JComponent multiGroup = buildMultiGroup();\r
- private final JLabel letsBrowser =\r
- new JLabel("投稿はWebブラウザからどうぞ");\r
-\r
- private JsObject loadedDraft = null;\r
-\r
- /**\r
- * コンストラクタ。\r
- */\r
- public TalkPreview(){\r
- super(FRAMETITLE);\r
-\r
- GUIUtils.modifyWindowAttributes(this, true, false, true);\r
-\r
- setDefaultCloseOperation(HIDE_ON_CLOSE);\r
-\r
- this.cutButton .addActionListener(this);\r
- this.copyButton .addActionListener(this);\r
- this.clearButton .addActionListener(this);\r
- this.cutAllButton .addActionListener(this);\r
- this.copyAllButton .addActionListener(this);\r
- this.clearAllButton .addActionListener(this);\r
- this.closeButton .addActionListener(this);\r
-\r
- this.editArray.addChangeListener(this);\r
-\r
- Container content = getContentPane();\r
- design(content);\r
-\r
- setBorderNumber(1);\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * レイアウトを行う。\r
- * @param content コンテナ\r
- */\r
- private void design(Container content){\r
- JComponent freeNotePanel = buildFreeNotePanel();\r
-\r
- JScrollPane scrollPane = new JScrollPane();\r
- scrollPane.setHorizontalScrollBarPolicy(\r
- JScrollPane.HORIZONTAL_SCROLLBAR_NEVER\r
- );\r
- JViewport viewPort = new JViewport();\r
- viewPort.setBackground(COLOR_EDITORBACK);\r
- viewPort.setView(this.editArray);\r
- scrollPane.setViewport(viewPort);\r
-\r
- LayoutManager layout;\r
- Border border;\r
-\r
- JComponent editPanel = new JPanel();\r
- layout = new BorderLayout();\r
- editPanel.setLayout(layout);\r
- editPanel.add(scrollPane, BorderLayout.CENTER);\r
- JComponent buttonPanel = buildButtonPanel();\r
- editPanel.add(buttonPanel, BorderLayout.EAST);\r
- border = BorderFactory.createTitledBorder("発言編集");\r
- editPanel.setBorder(border);\r
-\r
- JSplitPane split = new JSplitPane();\r
- split.setOrientation(JSplitPane.HORIZONTAL_SPLIT);\r
- split.setContinuousLayout(false);\r
- split.setDividerSize(10);\r
- split.setDividerLocation(200);\r
- split.setOneTouchExpandable(true);\r
- split.setLeftComponent(freeNotePanel);\r
- split.setRightComponent(editPanel);\r
-\r
- Border inside = BorderFactory.createBevelBorder(BevelBorder.LOWERED);\r
- Border outside = BorderFactory.createEmptyBorder(2, 5, 2, 2);\r
- border = BorderFactory.createCompoundBorder(inside, outside);\r
- this.letsBrowser.setBorder(border);\r
-\r
- layout = new BorderLayout();\r
- content.setLayout(layout);\r
- content.add(split, BorderLayout.CENTER);\r
- content.add(this.letsBrowser, BorderLayout.SOUTH);\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * ボタン群を生成する。\r
- * @return ボタン群\r
- */\r
- private JComponent buildButtonPanel(){\r
- JPanel panel = new JPanel();\r
-\r
- LayoutManager layout = new GridBagLayout();\r
- GridBagConstraints constraints = new GridBagConstraints();\r
-\r
- panel.setLayout(layout);\r
-\r
- constraints.weightx = 1.0;\r
- constraints.weighty = 0.0;\r
- constraints.fill = GridBagConstraints.NONE;\r
- constraints.anchor = GridBagConstraints.WEST;\r
- constraints.gridx = 1;\r
- constraints.gridy = GridBagConstraints.RELATIVE;\r
- constraints.gridwidth = 1;\r
- constraints.gridheight = 1;\r
-\r
-\r
- constraints.insets = new Insets(3, 3, 3, 3);\r
- panel.add(this.singleGroup, constraints);\r
-\r
- constraints.insets = new Insets(10, 3, 3, 3);\r
- panel.add(this.multiGroup, constraints);\r
-\r
- constraints.weighty = 1.0;\r
- constraints.anchor = GridBagConstraints.SOUTH;\r
- constraints.insets = new Insets(3, 3, 10, 3);\r
- panel.add(this.closeButton, constraints);\r
-\r
- return panel;\r
- }\r
-\r
- /**\r
- * アクティブ発言操作ボタン群を生成する。\r
- * @return ボタン群\r
- */\r
- private JComponent buildSingleGroup(){\r
- JComponent panel = new JPanel();\r
-\r
- LayoutManager layout = new GridBagLayout();\r
- GridBagConstraints constraints = new GridBagConstraints();\r
-\r
- panel.setLayout(layout);\r
-\r
- constraints.weightx = 1.0;\r
- constraints.weighty = 0.0;\r
- constraints.fill = GridBagConstraints.HORIZONTAL;\r
- constraints.gridx = 1;\r
- constraints.gridy = GridBagConstraints.RELATIVE;\r
- constraints.gridwidth = 1;\r
- constraints.gridheight = 1;\r
- constraints.insets = new Insets(3, 3, 3, 3);\r
-\r
- panel.add(this.cutButton, constraints);\r
- panel.add(this.copyButton, constraints);\r
- panel.add(this.clearButton, constraints);\r
-\r
- panel.setBorder(this.numberBorder);\r
-\r
- return panel;\r
- }\r
-\r
- /**\r
- * 全発言操作ボタン群を生成する。\r
- * @return ボタン群\r
- */\r
- private JComponent buildMultiGroup(){\r
- JComponent panel = new JPanel();\r
-\r
- LayoutManager layout = new GridBagLayout();\r
- GridBagConstraints constraints = new GridBagConstraints();\r
-\r
- panel.setLayout(layout);\r
-\r
- constraints.weightx = 1.0;\r
- constraints.weighty = 0.0;\r
- constraints.fill = GridBagConstraints.HORIZONTAL;\r
- constraints.gridx = 1;\r
- constraints.gridy = GridBagConstraints.RELATIVE;\r
- constraints.gridwidth = 1;\r
- constraints.gridheight = 1;\r
- constraints.insets = new Insets(3, 3, 3, 3);\r
-\r
- panel.add(this.cutAllButton, constraints);\r
- panel.add(this.copyAllButton, constraints);\r
- panel.add(this.clearAllButton, constraints);\r
-\r
- Border border = BorderFactory.createTitledBorder("全発言を");\r
- panel.setBorder(border);\r
-\r
- return panel;\r
- }\r
-\r
- /**\r
- * フリーノート部を生成する。\r
- * @return フリーノート部\r
- */\r
- private JComponent buildFreeNotePanel(){\r
- Insets margin = new Insets(3, 3, 3, 3);\r
- this.freeMemo.setMargin(margin);\r
- JPopupMenu popup = new TextPopup();\r
- this.freeMemo.setComponentPopupMenu(popup);\r
-\r
- JScrollPane scrollPane = new JScrollPane();\r
- scrollPane.setHorizontalScrollBarPolicy(\r
- JScrollPane.HORIZONTAL_SCROLLBAR_NEVER\r
- );\r
- JViewport viewPort = new JViewport();\r
- viewPort.setView(this.freeMemo);\r
- scrollPane.setViewport(viewPort);\r
-\r
- JComponent panel = new JPanel();\r
-\r
- LayoutManager layout = new GridBagLayout();\r
- GridBagConstraints constraints = new GridBagConstraints();\r
-\r
- panel.setLayout(layout);\r
-\r
- constraints.weightx = 1.0;\r
- constraints.weighty = 1.0;\r
- constraints.fill = GridBagConstraints.BOTH;\r
- constraints.insets = new Insets(1, 1, 1, 1);\r
- panel.add(scrollPane, constraints);\r
-\r
- Border border = BorderFactory.createTitledBorder("フリーメモ");\r
- panel.setBorder(border);\r
-\r
- return panel;\r
- }\r
-\r
- /**\r
- * アクティブ発言の通し番号表示を更新。\r
- * @param num 通し番号\r
- */\r
- private void setBorderNumber(int num){\r
- String title = "発言#"+num+" を";\r
- this.numberBorder.setTitle(title);\r
- this.singleGroup.revalidate();\r
- this.singleGroup.repaint();\r
- return;\r
- }\r
-\r
- /**\r
- * テキスト編集用フォントを指定する。\r
- * 描画属性は無視される。\r
- * @param fontInfo フォント設定\r
- */\r
- public void setFontInfo(FontInfo fontInfo){\r
- setTextFont(fontInfo.getFont());\r
- return;\r
- }\r
-\r
- /**\r
- * テキスト編集用フォントを指定する。\r
- * @param textFont フォント\r
- */\r
- public void setTextFont(Font textFont){\r
- this.freeMemo.setFont(textFont);\r
- this.editArray.setTextFont(textFont);\r
- return;\r
- }\r
-\r
- /**\r
- * テキスト編集用フォントを取得する。\r
- * @return フォント\r
- */\r
- public Font getTextFont(){\r
- return this.editArray.getTextFont();\r
- }\r
-\r
- /**\r
- * 発言クリア操作の確認ダイアログを表示する。\r
- * @return OKなら0, Cancelなら2\r
- */\r
- private int warnClear(){\r
- int result = JOptionPane.showConfirmDialog(\r
- this,\r
- "本当に発言をクリアしてもよいですか?",\r
- "発言クリア確認",\r
- JOptionPane.OK_CANCEL_OPTION,\r
- JOptionPane.QUESTION_MESSAGE );\r
- return result;\r
- }\r
-\r
- /**\r
- * 原稿のロード。\r
- */\r
- public void loadDraft(){\r
- JsValue value = ConfigFile.loadJson(new File(DRAFT_FILE));\r
- if(value == null) return;\r
-\r
- if( ! (value instanceof JsObject) ) return;\r
- JsObject root = (JsObject) value;\r
-\r
- value = root.getValue("freeMemo");\r
- if(value instanceof JsString){\r
- JsString memo = (JsString) value;\r
- this.freeMemo.setText(memo.toRawString());\r
- }\r
-\r
- value = root.getValue("drafts");\r
- if( ! (value instanceof JsArray) ) return;\r
- JsArray array = (JsArray) value;\r
-\r
- StringBuilder draftAll = new StringBuilder();\r
- for(JsValue elem : array){\r
- if( ! (elem instanceof JsString) ) continue;\r
- JsString draft = (JsString) elem;\r
- draftAll.append(draft.toRawString());\r
- }\r
- this.editArray.clearAllEditor();\r
- this.editArray.setAllText(draftAll);\r
-\r
- this.loadedDraft = root;\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * 原稿のセーブ。\r
- */\r
- public void saveDraft(){\r
- AppSetting setting = Jindolf.getAppSetting();\r
- if( ! setting.useConfigPath() ) return;\r
- File configPath = setting.getConfigPath();\r
- if(configPath == null) return;\r
-\r
- JsObject root = new JsObject();\r
- JsString memo = new JsString(this.freeMemo.getText());\r
- root.putValue("freeMemo", memo);\r
-\r
- JsArray array = new JsArray();\r
- JsString text = new JsString(this.editArray.getAllText());\r
- array.add(text);\r
- root.putValue("drafts", array);\r
-\r
- if(this.loadedDraft != null){\r
- if(this.loadedDraft.equals(root)) return;\r
- }\r
-\r
- ConfigFile.saveJson(new File(DRAFT_FILE), root);\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * アクティブな発言をカットしクリップボードへコピーする。\r
- */\r
- private void actionCutActive(){\r
- actionCopyActive();\r
- actionClearActive(false);\r
- return;\r
- }\r
-\r
- /**\r
- * アクティブな発言をクリップボードにコピーする。\r
- */\r
- private void actionCopyActive(){\r
- TalkEditor activeEditor = this.editArray.getActiveEditor();\r
- if(activeEditor == null) return;\r
-\r
- CharSequence text = activeEditor.getText();\r
- ClipboardAction.copyToClipboard(text);\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * アクティブな発言をクリアする。\r
- * @param confirm trueなら確認ダイアログを出す\r
- */\r
- private void actionClearActive(boolean confirm){\r
- if(confirm && warnClear() != 0 ) return;\r
-\r
- TalkEditor activeEditor = this.editArray.getActiveEditor();\r
- if(activeEditor == null) return;\r
-\r
- activeEditor.clearText();\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * 全発言をカットしクリップボードへコピーする。\r
- */\r
- private void actionCutAll(){\r
- actionCopyAll();\r
- actionClearAll(false);\r
- return;\r
- }\r
-\r
- /**\r
- * 全発言をクリップボードにコピーする。\r
- */\r
- private void actionCopyAll(){\r
- CharSequence text = this.editArray.getAllText();\r
- ClipboardAction.copyToClipboard(text);\r
- return;\r
- }\r
-\r
- /**\r
- * 全発言をクリアする。\r
- * @param confirm trueなら確認ダイアログを出す\r
- */\r
- private void actionClearAll(boolean confirm){\r
- if(confirm && warnClear() != 0 ) return;\r
- this.editArray.clearAllEditor();\r
- return;\r
- }\r
-\r
- /**\r
- * 上位ウィンドウをクローズする。\r
- */\r
- private void actionClose(){\r
- setVisible(false);\r
- return;\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- * 各種ボタン操作の処理。\r
- * @param event {@inheritDoc}\r
- */\r
- public void actionPerformed(ActionEvent event){\r
- Object source = event.getSource();\r
- if (source == this.cutButton) actionCutActive();\r
- else if(source == this.copyButton) actionCopyActive();\r
- else if(source == this.clearButton) actionClearActive(true);\r
- else if(source == this.cutAllButton) actionCutAll();\r
- else if(source == this.copyAllButton) actionCopyAll();\r
- else if(source == this.clearAllButton) actionClearAll(true);\r
- else if(source == this.closeButton) actionClose();\r
- return;\r
- }\r
-\r
- /**\r
- * アクティブなエディタが変更された時の処理。\r
- * @param event イベント情報\r
- */\r
- public void stateChanged(ChangeEvent event){\r
- TalkEditor activeEditor = this.editArray.getActiveEditor();\r
- int seqNo = activeEditor.getSequenceNumber();\r
- setBorderNumber(seqNo);\r
- return;\r
- }\r
-\r
- // TODO アンドゥ・リドゥ機能\r
- // TODO バルーンの雰囲気を選択できるようにしたい。(白、赤、青、灰)\r
- // TODO アンカーの表記揺れの指摘\r
-}\r
+/*
+ * 発言エディットパネル
+ *
+ * License : The MIT License
+ * Copyright(c) 2008 olyutorskii
+ */
+
+package jp.sfjp.jindolf.editor;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JViewport;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.Border;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.text.JTextComponent;
+import jp.sfjp.jindolf.dxchg.ClipboardAction;
+import jp.sfjp.jindolf.dxchg.TextPopup;
+import jp.sfjp.jindolf.glyph.FontInfo;
+import jp.sfjp.jindolf.util.GUIUtils;
+import jp.sourceforge.jovsonz.JsArray;
+import jp.sourceforge.jovsonz.JsComposition;
+import jp.sourceforge.jovsonz.JsObject;
+import jp.sourceforge.jovsonz.JsString;
+import jp.sourceforge.jovsonz.JsTypes;
+import jp.sourceforge.jovsonz.JsValue;
+
+/**
+ * 発言エディットパネル。
+ */
+@SuppressWarnings("serial")
+public class TalkPreview extends JFrame
+ implements ActionListener, ChangeListener{
+
+ /** 原稿ファイル。 */
+ public static final File DRAFT_FILE = new File("draft.json");
+
+ private static final Color COLOR_EDITORBACK = Color.BLACK;
+
+ private final JTextComponent freeMemo = new TextEditor();
+
+ private final EditArray editArray = new EditArray();
+
+ private final JButton cutButton = new JButton("カット");
+ private final JButton copyButton = new JButton("コピー");
+ private final JButton clearButton = new JButton("クリア");
+ private final JButton cutAllButton = new JButton("全カット");
+ private final JButton copyAllButton = new JButton("全コピー");
+ private final JButton clearAllButton = new JButton("全クリア");
+ private final JButton closeButton = new JButton("閉じる");
+ private final TitledBorder numberBorder =
+ BorderFactory.createTitledBorder("");
+ private final JComponent singleGroup = buildSingleGroup();
+ private final JComponent multiGroup = buildMultiGroup();
+ private final JLabel letsBrowser =
+ new JLabel("投稿はWebブラウザからどうぞ");
+
+ private JsObject loadedDraft = null;
+
+ /**
+ * コンストラクタ。
+ */
+ @SuppressWarnings("LeakingThisInConstructor")
+ public TalkPreview(){
+ super();
+
+ GUIUtils.modifyWindowAttributes(this, true, false, true);
+
+ setDefaultCloseOperation(HIDE_ON_CLOSE);
+
+ this.cutButton .addActionListener(this);
+ this.copyButton .addActionListener(this);
+ this.clearButton .addActionListener(this);
+ this.cutAllButton .addActionListener(this);
+ this.copyAllButton .addActionListener(this);
+ this.clearAllButton .addActionListener(this);
+ this.closeButton .addActionListener(this);
+
+ this.editArray.addChangeListener(this);
+
+ Container content = getContentPane();
+ design(content);
+
+ setBorderNumber(1);
+
+ return;
+ }
+
+ /**
+ * レイアウトを行う。
+ * @param content コンテナ
+ */
+ private void design(Container content){
+ JComponent freeNotePanel = buildFreeNotePanel();
+
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.setHorizontalScrollBarPolicy(
+ JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
+ );
+ JViewport viewPort = new JViewport();
+ viewPort.setBackground(COLOR_EDITORBACK);
+ viewPort.setView(this.editArray);
+ scrollPane.setViewport(viewPort);
+
+ LayoutManager layout;
+ Border border;
+
+ JComponent editPanel = new JPanel();
+ layout = new BorderLayout();
+ editPanel.setLayout(layout);
+ editPanel.add(scrollPane, BorderLayout.CENTER);
+ JComponent buttonPanel = buildButtonPanel();
+ editPanel.add(buttonPanel, BorderLayout.EAST);
+ border = BorderFactory.createTitledBorder("発言編集");
+ editPanel.setBorder(border);
+
+ JSplitPane split = new JSplitPane();
+ split.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
+ split.setContinuousLayout(false);
+ split.setDividerSize(10);
+ split.setDividerLocation(200);
+ split.setOneTouchExpandable(true);
+ split.setLeftComponent(freeNotePanel);
+ split.setRightComponent(editPanel);
+
+ Border inside = BorderFactory.createBevelBorder(BevelBorder.LOWERED);
+ Border outside = BorderFactory.createEmptyBorder(2, 5, 2, 2);
+ border = BorderFactory.createCompoundBorder(inside, outside);
+ this.letsBrowser.setBorder(border);
+
+ layout = new BorderLayout();
+ content.setLayout(layout);
+ content.add(split, BorderLayout.CENTER);
+ content.add(this.letsBrowser, BorderLayout.SOUTH);
+
+ return;
+ }
+
+ /**
+ * ボタン群を生成する。
+ * @return ボタン群
+ */
+ private JComponent buildButtonPanel(){
+ JPanel panel = new JPanel();
+
+ LayoutManager layout = new GridBagLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ panel.setLayout(layout);
+
+ constraints.weightx = 1.0;
+ constraints.weighty = 0.0;
+ constraints.fill = GridBagConstraints.NONE;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.gridx = 1;
+ constraints.gridy = GridBagConstraints.RELATIVE;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+
+
+ constraints.insets = new Insets(3, 3, 3, 3);
+ panel.add(this.singleGroup, constraints);
+
+ constraints.insets = new Insets(10, 3, 3, 3);
+ panel.add(this.multiGroup, constraints);
+
+ constraints.weighty = 1.0;
+ constraints.anchor = GridBagConstraints.SOUTH;
+ constraints.insets = new Insets(3, 3, 10, 3);
+ panel.add(this.closeButton, constraints);
+
+ return panel;
+ }
+
+ /**
+ * アクティブ発言操作ボタン群を生成する。
+ * @return ボタン群
+ */
+ private JComponent buildSingleGroup(){
+ JComponent panel = new JPanel();
+
+ LayoutManager layout = new GridBagLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ panel.setLayout(layout);
+
+ constraints.weightx = 1.0;
+ constraints.weighty = 0.0;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.gridx = 1;
+ constraints.gridy = GridBagConstraints.RELATIVE;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(3, 3, 3, 3);
+
+ panel.add(this.cutButton, constraints);
+ panel.add(this.copyButton, constraints);
+ panel.add(this.clearButton, constraints);
+
+ panel.setBorder(this.numberBorder);
+
+ return panel;
+ }
+
+ /**
+ * 全発言操作ボタン群を生成する。
+ * @return ボタン群
+ */
+ private JComponent buildMultiGroup(){
+ JComponent panel = new JPanel();
+
+ LayoutManager layout = new GridBagLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ panel.setLayout(layout);
+
+ constraints.weightx = 1.0;
+ constraints.weighty = 0.0;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.gridx = 1;
+ constraints.gridy = GridBagConstraints.RELATIVE;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.insets = new Insets(3, 3, 3, 3);
+
+ panel.add(this.cutAllButton, constraints);
+ panel.add(this.copyAllButton, constraints);
+ panel.add(this.clearAllButton, constraints);
+
+ Border border = BorderFactory.createTitledBorder("全発言を");
+ panel.setBorder(border);
+
+ return panel;
+ }
+
+ /**
+ * フリーノート部を生成する。
+ * @return フリーノート部
+ */
+ private JComponent buildFreeNotePanel(){
+ Insets margin = new Insets(3, 3, 3, 3);
+ this.freeMemo.setMargin(margin);
+ JPopupMenu popup = new TextPopup();
+ this.freeMemo.setComponentPopupMenu(popup);
+
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.setHorizontalScrollBarPolicy(
+ JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
+ );
+ JViewport viewPort = new JViewport();
+ viewPort.setView(this.freeMemo);
+ scrollPane.setViewport(viewPort);
+
+ JComponent panel = new JPanel();
+
+ LayoutManager layout = new GridBagLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ panel.setLayout(layout);
+
+ constraints.weightx = 1.0;
+ constraints.weighty = 1.0;
+ constraints.fill = GridBagConstraints.BOTH;
+ constraints.insets = new Insets(1, 1, 1, 1);
+ panel.add(scrollPane, constraints);
+
+ Border border = BorderFactory.createTitledBorder("フリーメモ");
+ panel.setBorder(border);
+
+ return panel;
+ }
+
+ /**
+ * アクティブ発言の通し番号表示を更新。
+ * @param num 通し番号
+ */
+ private void setBorderNumber(int num){
+ String title = "発言#"+num+" を";
+ this.numberBorder.setTitle(title);
+ this.singleGroup.revalidate();
+ this.singleGroup.repaint();
+ return;
+ }
+
+ /**
+ * テキスト編集用フォントを指定する。
+ * 描画属性は無視される。
+ * @param fontInfo フォント設定
+ */
+ public void setFontInfo(FontInfo fontInfo){
+ setTextFont(fontInfo.getFont());
+ return;
+ }
+
+ /**
+ * テキスト編集用フォントを指定する。
+ * @param textFont フォント
+ */
+ public void setTextFont(Font textFont){
+ this.freeMemo.setFont(textFont);
+ this.editArray.setTextFont(textFont);
+ return;
+ }
+
+ /**
+ * テキスト編集用フォントを取得する。
+ * @return フォント
+ */
+ public Font getTextFont(){
+ return this.editArray.getTextFont();
+ }
+
+ /**
+ * 発言クリア操作の確認ダイアログを表示する。
+ * @return OKなら0, Cancelなら2
+ */
+ private int warnClear(){
+ int result = JOptionPane.showConfirmDialog(
+ this,
+ "本当に発言をクリアしてもよいですか?",
+ "発言クリア確認",
+ JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE );
+ return result;
+ }
+
+ /**
+ * JSON形式の原稿情報を返す。
+ * @return JSON形式の原稿情報
+ */
+ public JsObject getJson(){
+ JsObject result = new JsObject();
+ JsString memo = new JsString(this.freeMemo.getText());
+ result.putValue("freeMemo", memo);
+
+ JsArray array = new JsArray();
+ JsString text = new JsString(this.editArray.getAllText());
+ array.add(text);
+ result.putValue("drafts", array);
+
+ return result;
+ }
+
+ /**
+ * JSON形式の原稿情報を反映させる。
+ * @param root JSON形式の原稿情報。nullが来たら何もしない
+ */
+ public void putJson(JsObject root){
+ if(root == null) return;
+
+ JsValue value;
+
+ value = root.getValue("freeMemo");
+ if(value.getJsTypes() == JsTypes.STRING){
+ JsString memo = (JsString) value;
+ this.freeMemo.setText(memo.toRawString());
+ }
+
+ value = root.getValue("drafts");
+ if(value.getJsTypes() != JsTypes.ARRAY) return;
+ JsArray array = (JsArray) value;
+
+ StringBuilder draftAll = new StringBuilder();
+ for(JsValue elem : array){
+ if(elem.getJsTypes() != JsTypes.STRING) continue;
+ JsString draft = (JsString) elem;
+ draftAll.append(draft.toRawString());
+ }
+ this.editArray.clearAllEditor();
+ this.editArray.setAllText(draftAll);
+
+ this.loadedDraft = root;
+
+ return;
+ }
+
+ /**
+ * 起動時の原稿と等価か判定する。
+ * @param conf 比較対象
+ * @return 等価ならtrue
+ */
+ public boolean hasConfChanged(JsComposition<?> conf){
+ if(this.loadedDraft != null){
+ if(this.loadedDraft.equals(conf)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * アクティブな発言をカットしクリップボードへコピーする。
+ */
+ private void actionCutActive(){
+ actionCopyActive();
+ actionClearActive(false);
+ return;
+ }
+
+ /**
+ * アクティブな発言をクリップボードにコピーする。
+ */
+ private void actionCopyActive(){
+ TalkEditor activeEditor = this.editArray.getActiveEditor();
+ if(activeEditor == null) return;
+
+ CharSequence text = activeEditor.getText();
+ ClipboardAction.copyToClipboard(text);
+
+ return;
+ }
+
+ /**
+ * アクティブな発言をクリアする。
+ * @param confirm trueなら確認ダイアログを出す
+ */
+ private void actionClearActive(boolean confirm){
+ if(confirm && warnClear() != 0 ) return;
+
+ TalkEditor activeEditor = this.editArray.getActiveEditor();
+ if(activeEditor == null) return;
+
+ activeEditor.clearText();
+
+ return;
+ }
+
+ /**
+ * 全発言をカットしクリップボードへコピーする。
+ */
+ private void actionCutAll(){
+ actionCopyAll();
+ actionClearAll(false);
+ return;
+ }
+
+ /**
+ * 全発言をクリップボードにコピーする。
+ */
+ private void actionCopyAll(){
+ CharSequence text = this.editArray.getAllText();
+ ClipboardAction.copyToClipboard(text);
+ return;
+ }
+
+ /**
+ * 全発言をクリアする。
+ * @param confirm trueなら確認ダイアログを出す
+ */
+ private void actionClearAll(boolean confirm){
+ if(confirm && warnClear() != 0 ) return;
+ this.editArray.clearAllEditor();
+ return;
+ }
+
+ /**
+ * 上位ウィンドウをクローズする。
+ */
+ private void actionClose(){
+ setVisible(false);
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * 各種ボタン操作の処理。
+ * @param event {@inheritDoc}
+ */
+ @Override
+ public void actionPerformed(ActionEvent event){
+ Object source = event.getSource();
+ if (source == this.cutButton) actionCutActive();
+ else if(source == this.copyButton) actionCopyActive();
+ else if(source == this.clearButton) actionClearActive(true);
+ else if(source == this.cutAllButton) actionCutAll();
+ else if(source == this.copyAllButton) actionCopyAll();
+ else if(source == this.clearAllButton) actionClearAll(true);
+ else if(source == this.closeButton) actionClose();
+ return;
+ }
+
+ /**
+ * アクティブなエディタが変更された時の処理。
+ * @param event イベント情報
+ */
+ @Override
+ public void stateChanged(ChangeEvent event){
+ TalkEditor activeEditor = this.editArray.getActiveEditor();
+ int seqNo = activeEditor.getSequenceNumber();
+ setBorderNumber(seqNo);
+ return;
+ }
+
+ // TODO アンドゥ・リドゥ機能
+ // TODO バルーンの雰囲気を選択できるようにしたい。(白、赤、青、灰)
+ // TODO アンカーの表記揺れの指摘
+}