3.304.X (2020-XX-XX)
・G国亡国に伴い JinParser 2.102.2 に対応。
・ログイン管理画面の廃止。
+ ・発言エディタの廃止。
・JinArchiverによるXMLアーカイブファイルのビューア機能。
3.303.106 (2019-05-07)
import jp.sfjp.jindolf.dxchg.CsvExporter;
import jp.sfjp.jindolf.dxchg.WebIPCDialog;
import jp.sfjp.jindolf.dxchg.WolfBBS;
-import jp.sfjp.jindolf.editor.TalkPreview;
import jp.sfjp.jindolf.glyph.AnchorHitEvent;
import jp.sfjp.jindolf.glyph.AnchorHitListener;
import jp.sfjp.jindolf.glyph.Discussion;
private static final Logger LOGGER = Logger.getAnonymousLogger();
private static final String ERRTITLE_LAF = "Look&Feel";
- private static final String ERRFORM_LAFLOAD =
- "このLook&Feel[{0}]を読み込む事ができません。";
private static final String ERRFORM_LAFGEN =
"このLook&Feel[{0}]を生成する事ができません。";
reloadVillageListButton.setEnabled(false);
TopFrame topFrame = this.windowManager.getTopFrame();
- TalkPreview talkPreview = this.windowManager.getTalkPreview();
OptionPanel optionPanel = this.windowManager.getOptionPanel();
FindPanel findPanel = this.windowManager.getFindPanel();
FilterPanel filterPanel = this.windowManager.getFilterPanel();
ConfigStore config = this.appSetting.getConfigStore();
- JsObject draft = config.loadDraftConfig();
- talkPreview.putJson(draft);
-
JsObject history = config.loadHistoryConfig();
findPanel.putJson(history);
FontInfo fontInfo = this.appSetting.getFontInfo();
periodTab.setFontInfo(fontInfo);
- talkPreview.setFontInfo(fontInfo);
optionPanel.getFontChooser().setFontInfo(fontInfo);
ProxyInfo proxyInfo = this.appSetting.getProxyInfo();
}
/**
- * 発言エディタを表示する。
- */
- private void actionTalkPreview(){
- TalkPreview talkPreview = this.windowManager.getTalkPreview();
- toggleWindow(talkPreview);
- return;
- }
-
- /**
* オプション設定画面を表示する。
*/
private void actionOption(){
this.topView.getTabBrowser().setFontInfo(newFontInfo);
- TalkPreview talkPreview = this.windowManager.getTalkPreview();
OptionPanel optionPanel = this.windowManager.getOptionPanel();
FontChooser fontChooser = optionPanel.getFontChooser();
- talkPreview.setFontInfo(newFontInfo);
fontChooser.setFontInfo(newFontInfo);
return;
case ActionManager.CMD_SHOWFILT:
actionShowFilter();
break;
- case ActionManager.CMD_SHOWEDIT:
- actionTalkPreview();
- break;
case ActionManager.CMD_SHOWLOG:
actionShowLog();
break;
configStore.saveHistoryConfig(findConf);
}
- TalkPreview talkPreview = this.windowManager.getTalkPreview();
- JsObject draftConf = talkPreview.getJson();
- if( ! talkPreview.hasConfChanged(draftConf) ){
- configStore.saveDraftConfig(draftConf);
- }
-
this.appSetting.saveConfig();
LOGGER.info("VMごとアプリケーションを終了します。");
/** 検索履歴ファイル。 */
public static final File HIST_FILE = new File("searchHistory.json");
- /** 原稿ファイル。 */
- public static final File DRAFT_FILE = new File("draft.json");
/** ネットワーク設定ファイル。 */
public static final File NETCONFIG_FILE = new File("netconfig.json");
/** 台詞表示設定ファイル。 */
}
/**
- * 原稿ファイルを読み込む。
- *
- * @return 原稿データ。原稿を読まないもしくは読めない場合はnull
- */
- public JsObject loadDraftConfig(){
- JsObject result = loadJsObject(DRAFT_FILE);
- return result;
- }
-
- /**
* ネットワーク設定ファイルを読み込む。
*
* @return ネットワーク設定データ。
}
/**
- * 原稿ファイルに書き込む。
- *
- * @param root 原稿データ
- * @return 書き込まなかったもしくは書き込めなかった場合はfalse
- */
- public boolean saveDraftConfig(JsComposition<?> root){
- boolean result = saveJson(DRAFT_FILE, root);
- return result;
- }
-
- /**
* ネットワーク設定ファイルに書き込む。
*
* @param root ネットワーク設定
+++ /dev/null
-/*
- * baloon border
- *
- * License : The MIT License
- * Copyright(c) 2008 olyutorskii
- */
-
-package jp.sfjp.jindolf.editor;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Insets;
-import java.awt.LayoutManager;
-import java.awt.RenderingHints;
-import javax.swing.JComponent;
-import javax.swing.border.Border;
-
-/**
- * フキダシ風Border。
- */
-public class BalloonBorder implements Border{
-
- private static final int RADIUS = 5;
-
-
- /**
- * コンストラクタ。
- */
- public BalloonBorder(){
- super();
- return;
- }
-
-
- /**
- * 隙間が透明なフキダシ装飾を任意のコンポーネントに施す。
- * @param inner 装飾対象のコンポーネント
- * @return 装飾されたコンポーネント
- */
- public static JComponent decorateTransparentBorder(JComponent inner){
- JComponent result = new TransparentContainer(inner);
-
- Border border = new BalloonBorder();
- result.setBorder(border);
-
- return result;
- }
-
- /**
- * {@inheritDoc}
- * @param comp {@inheritDoc}
- * @return {@inheritDoc}
- */
- @Override
- public Insets getBorderInsets(Component comp){
- Insets insets = new Insets(RADIUS, RADIUS, RADIUS, RADIUS);
- return insets;
- }
-
- /**
- * {@inheritDoc}
- * 必ずfalseを返す(このBorderは透明)。
- * @return {@inheritDoc}
- */
- @Override
- public boolean isBorderOpaque(){
- return false;
- }
-
- /**
- * {@inheritDoc}
- * @param comp {@inheritDoc}
- * @param g {@inheritDoc}
- * @param x {@inheritDoc}
- * @param y {@inheritDoc}
- * @param width {@inheritDoc}
- * @param height {@inheritDoc}
- */
- @Override
- public void paintBorder(Component comp,
- Graphics g,
- int x, int y,
- int width, int height ){
- final int diameter = RADIUS * 2;
- final int innerWidth = width - diameter;
- final int innerHeight = height - diameter;
-
- Graphics2D g2d = (Graphics2D) g;
-
- Color bgColor = comp.getBackground();
- g2d.setColor(bgColor);
-
- Object antiAliaseHint =
- g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON );
-
- g2d.fillRect(x + RADIUS, y,
- innerWidth, RADIUS);
- g2d.fillRect(x, y + RADIUS,
- RADIUS, innerHeight);
- g2d.fillRect(x + RADIUS + innerWidth, y + RADIUS,
- RADIUS, innerHeight);
- g2d.fillRect(x + RADIUS, y + RADIUS + innerHeight,
- innerWidth, RADIUS);
-
- int right = 90; // 90 degree right angle
-
- g2d.fillArc(x + innerWidth, y,
- diameter, diameter, right * 0, right);
- g2d.fillArc(x, y,
- diameter, diameter, right * 1, right);
- g2d.fillArc(x, y + innerHeight,
- diameter, diameter, right * 2, right);
- g2d.fillArc(x + innerWidth, y + innerHeight,
- diameter, diameter, right * 3, right);
-
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAliaseHint);
-
- return;
- }
-
- /**
- * 透明コンテナ。
- * 1つの子を持ち、背景色操作を委譲する。
- * つまりこのコンテナにBorderを設定すると子の背景色が反映される。
- */
- @SuppressWarnings("serial")
- private static class TransparentContainer extends JComponent{
-
- private final JComponent inner;
-
- /**
- * コンストラクタ。
- * @param inner 内部コンポーネント
- */
- public TransparentContainer(JComponent inner){
- super();
-
- this.inner = inner;
-
- setOpaque(false);
-
- LayoutManager layout = new BorderLayout();
- setLayout(layout);
- add(this.inner, BorderLayout.CENTER);
-
- return;
- }
-
- /**
- * {@inheritDoc}
- * 子の背景色を返す。
- * @return {@inheritDoc}
- */
- @Override
- public Color getBackground(){
- Color bg = this.inner.getBackground();
- return bg;
- }
-
- /**
- * {@inheritDoc}
- * 背景色指定をフックし、子の背景色を指定する。
- * @param bg {@inheritDoc}
- */
- @Override
- public void setBackground(Color bg){
- this.inner.setBackground(bg);
- return;
- }
- }
-
-}
+++ /dev/null
-/*
- * エディタ集合の操作
- *
- * License : The MIT License
- * Copyright(c) 2008 olyutorskii
- */
-
-package jp.sfjp.jindolf.editor;
-
-import java.awt.Dimension;
-import java.awt.EventQueue;
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.LayoutManager;
-import java.awt.Rectangle;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.util.ArrayList;
-import java.util.List;
-import javax.swing.JPanel;
-import javax.swing.Scrollable;
-import javax.swing.SwingConstants;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-import javax.swing.text.JTextComponent;
-import javax.swing.text.NavigationFilter;
-import javax.swing.text.Position.Bias;
-
-/**
- * エディタ集合の操作。
- * ※ このクラスはすべてシングルスレッドモデルで作られている。
- */
-@SuppressWarnings("serial")
-public class EditArray extends JPanel
- implements Scrollable,
- FocusListener {
-
- private static final int MAX_EDITORS = 50;
-
- private final List<TalkEditor> editorList = new ArrayList<>();
- private boolean onAdjusting = false;
-
- private final NavigationFilter keyNavigator = new CustomNavigation();
- private final DocumentListener documentListener = new DocWatcher();
-
- private TalkEditor activeEditor;
-
- private Font textFont;
-
- /**
- * コンストラクタ。
- */
- public EditArray(){
- super();
-
- setOpaque(false);
-
- LayoutManager layout = new GridBagLayout();
- setLayout(layout);
-
- TalkEditor firstEditor = incrementTalkEditor();
- setActiveEditor(firstEditor);
-
- return;
- }
-
- /**
- * 個別エディタの生成を行う。
- * @return エディタ
- */
- private TalkEditor createTalkEditor(){
- TalkEditor editor = new TalkEditor();
- editor.setNavigationFilter(this.keyNavigator);
- editor.addTextFocusListener(this);
- Document document = editor.getDocument();
- document.addDocumentListener(this.documentListener);
-
- if(this.textFont == null){
- this.textFont = editor.getTextFont();
- }else{
- editor.setTextFont(this.textFont);
- }
-
- return editor;
- }
-
- /**
- * エディタ集合を一つ増やす。
- * @return 増えたエディタ
- */
- private TalkEditor incrementTalkEditor(){
- TalkEditor editor = createTalkEditor();
-
- GridBagConstraints constraints = new GridBagConstraints();
-
- constraints.gridx = 0;
- constraints.gridy = GridBagConstraints.RELATIVE;
-
- constraints.gridwidth = GridBagConstraints.REMAINDER;
- constraints.gridheight = 1;
-
- constraints.weightx = 1.0;
- constraints.weighty = 0.0;
-
- constraints.fill = GridBagConstraints.HORIZONTAL;
- constraints.anchor = GridBagConstraints.NORTHEAST;
-
- add(editor, constraints);
-
- this.editorList.add(editor);
-
- int sequenceNumber = this.editorList.size();
- editor.setSequenceNumber(sequenceNumber);
-
- return editor;
- }
-
- /**
- * 1から始まる通し番号指定でエディタを取得する。
- * 存在しない通し番号が指定された場合は新たにエディタが追加される。
- * @param sequenceNumber 通し番号
- * @return エディタ
- */
- private TalkEditor getTalkEditor(int sequenceNumber){
- while(this.editorList.size() < sequenceNumber){
- incrementTalkEditor();
- }
-
- TalkEditor result = this.editorList.get(sequenceNumber - 1);
-
- return result;
- }
-
- /**
- * 指定したエディタの次の通し番号を持つエディタを返す。
- * エディタがなければ追加される。
- * @param editor エディタ
- * @return 次のエディタ
- */
- private TalkEditor nextEditor(TalkEditor editor){
- int sequenceNumber = editor.getSequenceNumber();
- TalkEditor nextEditor = getTalkEditor(sequenceNumber + 1);
- return nextEditor;
- }
-
- /**
- * 指定したエディタの前の通し番号を持つエディタを返す。
- * @param editor エディタ
- * @return 前のエディタ。
- * 最初のエディタ(通し番号1)が指定されればnullを返す。
- */
- private TalkEditor prevEditor(TalkEditor editor){
- int sequenceNumber = editor.getSequenceNumber();
- if(sequenceNumber <= 1) return null;
- TalkEditor prevEditor = getTalkEditor(sequenceNumber - 1);
- return prevEditor;
- }
-
- /**
- * 指定したエディタがエディタ集合の最後のエディタか判定する。
- * @param editor エディタ
- * @return 最後のエディタならtrue
- */
- private boolean isLastEditor(TalkEditor editor){
- int seqNo = editor.getSequenceNumber();
- int size = this.editorList.size();
- if(seqNo >= size) return true;
- return false;
- }
-
- /**
- * Documentからその持ち主であるエディタを取得する。
- * @param document Documentインスタンス
- * @return 持ち主のエディタ。見つからなければnull。
- */
- private TalkEditor getEditorFromDocument(Document document){
- for(TalkEditor editor : this.editorList){
- if(editor.getDocument() == document) return editor;
- }
- return null;
- }
-
- /**
- * エディタ集合から任意のエディタを除く。
- * ただし最初のエディタは消去不可。
- * @param editor エディタ
- */
- private void removeEditor(TalkEditor editor){
- if(editor.getParent() != this) return;
-
- int seqNo = editor.getSequenceNumber();
- if(seqNo <= 1) return;
- TalkEditor prevEditor = prevEditor(editor);
- if(editor.isActive()){
- setActiveEditor(prevEditor);
- }
- if(editor.hasEditorFocus()){
- prevEditor.requestEditorFocus();
- }
-
- this.editorList.remove(seqNo - 1);
-
- editor.setNavigationFilter(null);
- editor.removeTextFocusListener(this);
- Document document = editor.getDocument();
- document.removeDocumentListener(this.documentListener);
- editor.clearText();
-
- remove(editor);
- revalidate();
-
- int renumber = 1;
- for(TalkEditor newEditor : this.editorList){
- newEditor.setSequenceNumber(renumber++);
- }
-
- return;
- }
-
- /**
- * エディタ間文字調整タスクをディスパッチスレッドとして事後投入する。
- * エディタ間文字調整タスクが実行中であれば何もしない。
- * きっかけとなったエディタ上でIME操作が確定していなければ何もしない。
- * @param triggerEvent ドキュメント変更イベント
- */
- private void detachAdjustTask(DocumentEvent triggerEvent){
- if(this.onAdjusting) return;
-
- Document document = triggerEvent.getDocument();
- final TalkEditor triggerEditor = getEditorFromDocument(document);
- if(triggerEditor.onIMEoperation()) return;
-
- this.onAdjusting = true;
-
- EventQueue.invokeLater(new Runnable(){
- @Override
- public void run(){
- try{
- adjustTask(triggerEditor);
- }finally{
- EditArray.this.onAdjusting = false;
- }
- return;
- }
- });
-
- return;
- }
-
- /**
- * エディタ間文字調整タスク本体。
- * @param triggerEditor タスク実行のきっかけとなったエディタ
- */
- private void adjustTask(TalkEditor triggerEditor){
- int initCaretPos = triggerEditor.getCaretPosition();
-
- TalkEditor newFocus = null;
- int newCaretPos = -1;
-
- TalkEditor current = triggerEditor;
- for(;;){
- TalkEditor next;
-
- if( ! isLastEditor(current) ){
- next = nextEditor(current);
- String nextContents = next.getText();
- int nextLength = nextContents.length();
-
- current.appendTail(nextContents);
- String rest = current.chopRest();
- int restLength;
- if(rest == null) restLength = 0;
- else restLength = rest.length();
-
- int chopLength = nextLength - restLength;
- if(chopLength > 0){
- next.chopHead(chopLength);
- }else if(chopLength < 0){
- rest = rest.substring(0, -chopLength);
- next.appendHead(rest);
- }else{
- if(newFocus == null){
- newFocus = current;
- newCaretPos = initCaretPos;
- }
- break;
- }
- }else{
- String rest = current.chopRest();
- if(rest == null || this.editorList.size() >= MAX_EDITORS){
- if(newFocus == null){
- newFocus = current;
- if(current.getTextLength() >= initCaretPos){
- newCaretPos = initCaretPos;
- }else{
- newCaretPos = current.getTextLength();
- }
- }
- break;
- }
- next = nextEditor(current);
- next.appendHead(rest);
- }
-
- if(newFocus == null){
- int currentLength = current.getTextLength();
- if(initCaretPos >= currentLength){
- initCaretPos -= currentLength;
- }else{
- newFocus = current;
- newCaretPos = initCaretPos;
- }
- }
-
- current = next;
- }
-
- if(newFocus != null){
- newFocus.requestEditorFocus();
- newFocus.setCaretPosition(newCaretPos);
- }
-
- adjustEditorsTail();
-
- return;
- }
-
- /**
- * エディタ集合末尾の空エディタを切り詰める。
- * ただし最初のエディタ(通し番号1)は削除されない。
- * フォーカスを持つエディタが削除された場合は、
- * 削除されなかった最後のエディタにフォーカスが移る。
- */
- private void adjustEditorsTail(){
- int editorNum = this.editorList.size();
- if(editorNum <= 0) return;
- TalkEditor lastEditor = this.editorList.get(editorNum - 1);
-
- TalkEditor prevlostEditor = null;
-
- boolean lostFocusedEditor = false;
-
- for(;;){
- int textLength = lastEditor.getTextLength();
- int seqNo = lastEditor.getSequenceNumber();
-
- if(lostFocusedEditor){
- prevlostEditor = lastEditor;
- }
-
- if(textLength > 0) break;
- if(seqNo <= 1) break;
-
- if(lastEditor.hasEditorFocus()) lostFocusedEditor = true;
- removeEditor(lastEditor);
-
- lastEditor = prevEditor(lastEditor); // TODO ちょっと変
- }
-
- if(prevlostEditor != null){
- int textLength = prevlostEditor.getTextLength();
- prevlostEditor.requestEditorFocus();
- prevlostEditor.setCaretPosition(textLength);
- }
-
- return;
- }
-
- /**
- * フォーカスを持つエディタを取得する。
- * @return エディタ
- */
- public TalkEditor getFocusedTalkEditor(){
- for(TalkEditor editor : this.editorList){
- if(editor.hasEditorFocus()) return editor;
- }
- return null;
- }
-
- /**
- * フォーカスを持つエディタの次エディタがあればフォーカスを移し、
- * カレット位置を0にする。
- */
- // TODO エディタのスクロール位置調整が必要。
- public void forwardEditor(){
- TalkEditor editor = getFocusedTalkEditor();
- if(isLastEditor(editor)) return;
- TalkEditor next = nextEditor(editor);
- next.setCaretPosition(0);
- next.requestEditorFocus();
- return;
- }
-
- /**
- * フォーカスを持つエディタの前エディタがあればフォーカスを移し、
- * カレット位置を末尾に置く。
- */
- public void backwardEditor(){
- TalkEditor editor = getFocusedTalkEditor();
- TalkEditor prev = prevEditor(editor);
- if(prev == null) return;
- int length = prev.getTextLength();
- prev.setCaretPosition(length);
- prev.requestEditorFocus();
- return;
- }
-
- /**
- * 任意のエディタをアクティブにする。
- * 同時にアクティブなエディタは一つのみ。
- * @param editor アクティブにするエディタ
- */
- private void setActiveEditor(TalkEditor editor){
- if(this.activeEditor != null){
- this.activeEditor.setActive(false);
- }
-
- this.activeEditor = editor;
-
- if(this.activeEditor != null){
- this.activeEditor.setActive(true);
- }
-
- fireChangeActive();
-
- return;
- }
-
- /**
- * アクティブなエディタを返す。
- * @return アクティブなエディタ。
- */
- public TalkEditor getActiveEditor(){
- return this.activeEditor;
- }
-
- /**
- * 全発言を連結した文字列を返す。
- * @return 連結文字列
- */
- public CharSequence getAllText(){
- StringBuilder result = new StringBuilder();
-
- for(TalkEditor editor : this.editorList){
- String text = editor.getText();
- result.append(text);
- }
-
- return result;
- }
-
- /**
- * 先頭エディタの0文字目から字を詰め込む。
- * 2番目移行のエディタへはみ出すかもしれない。
- * @param seq 詰め込む文字列
- */
- public void setAllText(CharSequence seq){
- TalkEditor firstEditor = getTalkEditor(1);
- Document doc = firstEditor.getDocument();
- try{
- doc.insertString(0, seq.toString(), null);
- }catch(BadLocationException e){
- assert false;
- }
- return;
- }
-
- /**
- * 全エディタをクリアする。
- */
- public void clearAllEditor(){
- int editorNum = this.editorList.size();
- if(editorNum <= 0) return;
-
- TalkEditor lastEditor = this.editorList.get(editorNum - 1);
- for(;;){
- removeEditor(lastEditor);
- lastEditor = prevEditor(lastEditor);
- if(lastEditor == null) break;
- }
-
- TalkEditor firstEditor = getTalkEditor(1);
- firstEditor.clearText();
- setActiveEditor(firstEditor);
-
- return;
- }
-
- /**
- * テキスト編集用フォントを指定する。
- * @param textFont フォント
- */
- public void setTextFont(Font textFont){
- this.textFont = textFont;
- for(TalkEditor editor : this.editorList){
- editor.setTextFont(this.textFont);
- editor.repaint();
- }
- revalidate();
- return;
- }
-
- /**
- * テキスト編集用フォントを取得する。
- * @return フォント
- */
- public Font getTextFont(){
- return this.textFont;
- }
-
- /**
- * アクティブエディタ変更通知用リスナの登録。
- * @param listener リスナ
- */
- public void addChangeListener(ChangeListener listener){
- this.listenerList.add(ChangeListener.class, listener);
- return;
- }
-
- /**
- * アクティブエディタ変更通知用リスナの削除。
- * @param listener リスナ
- */
- public void removeChangeListener(ChangeListener listener){
- this.listenerList.remove(ChangeListener.class, listener);
- return;
- }
-
- /**
- * アクティブエディタ変更通知を行う。
- */
- private void fireChangeActive(){
- ChangeEvent event = new ChangeEvent(this);
-
- ChangeListener[] listeners =
- this.listenerList.getListeners(ChangeListener.class);
- for(ChangeListener listener : listeners){
- listener.stateChanged(event);
- }
-
- return;
- }
-
- /**
- * {@inheritDoc}
- * エディタのフォーカス取得とともにアクティブ状態にする。
- * @param event {@inheritDoc}
- */
- @Override
- public void focusGained(FocusEvent event){
- Object source = event.getSource();
- if( ! (source instanceof JTextComponent) ) return;
- JTextComponent textComp = (JTextComponent) source;
-
- Document document = textComp.getDocument();
- TalkEditor editor = getEditorFromDocument(document);
-
- setActiveEditor(editor);
-
- return;
- }
-
- /**
- * {@inheritDoc}
- * @param event {@inheritDoc}
- */
- @Override
- public void focusLost(FocusEvent event){
- // NOTHING
- return;
- }
-
- /**
- * {@inheritDoc}
- * @return {@inheritDoc}
- */
- @Override
- public Dimension getPreferredScrollableViewportSize(){
- Dimension result = getPreferredSize();
- return result;
- }
-
- /**
- * {@inheritDoc}
- * 横スクロールバーを極力出さないようレイアウトでがんばる。
- * @return {@inheritDoc}
- */
- @Override
- public boolean getScrollableTracksViewportWidth(){
- return true;
- }
-
- /**
- * {@inheritDoc}
- * 縦スクロールバーを出しても良いのでレイアウトでがんばらない。
- * @return {@inheritDoc}
- */
- @Override
- public boolean getScrollableTracksViewportHeight(){
- return false;
- }
-
- /**
- * {@inheritDoc}
- * @param visibleRect {@inheritDoc}
- * @param orientation {@inheritDoc}
- * @param direction {@inheritDoc}
- * @return {@inheritDoc}
- */
- @Override
- public int getScrollableBlockIncrement(Rectangle visibleRect,
- int orientation,
- int direction ){
- if(orientation == SwingConstants.VERTICAL){
- return visibleRect.height;
- }
- return 10;
- }
-
- /**
- * {@inheritDoc}
- * @param visibleRect {@inheritDoc}
- * @param orientation {@inheritDoc}
- * @param direction {@inheritDoc}
- * @return {@inheritDoc}
- */
- @Override
- public int getScrollableUnitIncrement(Rectangle visibleRect,
- int orientation,
- int direction ){
- return 30; // TODO フォント高の1.5倍くらい?
- }
-
- /**
- * エディタ内のカーソル移動を監視するための、
- * カスタム化したナビゲーションフィルター。
- * 必要に応じてエディタ間カーソル移動を行う。
- */
- private class CustomNavigation extends NavigationFilter{
-
- /**
- * コンストラクタ。
- */
- public CustomNavigation(){
- super();
- return;
- }
-
- /**
- * {@inheritDoc}
- * カーソル移動が行き詰まった場合、
- * 隣接するエディタ間でカーソル移動を行う。
- * @param text {@inheritDoc}
- * @param pos {@inheritDoc}
- * @param bias {@inheritDoc}
- * @param direction {@inheritDoc}
- * @param biasRet {@inheritDoc}
- * @return {@inheritDoc}
- * @throws javax.swing.text.BadLocationException {@inheritDoc}
- */
- @Override
- public int getNextVisualPositionFrom(JTextComponent text,
- int pos,
- Bias bias,
- int direction,
- Bias[] biasRet )
- throws BadLocationException {
- int result = super.getNextVisualPositionFrom(text,
- pos,
- bias,
- direction,
- biasRet );
- if(result != pos) return result;
-
- switch(direction){
- case SwingConstants.WEST:
- case SwingConstants.NORTH:
- backwardEditor();
- break;
- case SwingConstants.EAST:
- case SwingConstants.SOUTH:
- forwardEditor();
- break;
- default:
- assert false;
- }
-
- return result;
- }
- }
-
- /**
- * エディタの内容変更を監視し、随時エディタ間調整を行う。
- */
- private class DocWatcher implements DocumentListener{
-
- /**
- * コンストラクタ。
- */
- public DocWatcher(){
- super();
- return;
- }
-
- /**
- * {@inheritDoc}
- * @param event {@inheritDoc}
- */
- @Override
- public void changedUpdate(DocumentEvent event){
- detachAdjustTask(event);
- return;
- }
-
- /**
- * {@inheritDoc}
- * @param event {@inheritDoc}
- */
- @Override
- public void insertUpdate(DocumentEvent event){
- detachAdjustTask(event);
- return;
- }
-
- /**
- * {@inheritDoc}
- * @param event {@inheritDoc}
- */
- @Override
- public void removeUpdate(DocumentEvent event){
- detachAdjustTask(event);
- return;
- }
- }
-
-}
+++ /dev/null
-/*
- * 原稿作成支援エディタ
- *
- * License : The MIT License
- * Copyright(c) 2008 olyutorskii
- */
-
-package jp.sfjp.jindolf.editor;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.LayoutManager;
-import java.awt.Rectangle;
-import java.awt.event.FocusListener;
-import javax.swing.BorderFactory;
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-import javax.swing.border.Border;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-import javax.swing.text.NavigationFilter;
-import javax.swing.text.PlainDocument;
-import javax.swing.text.Segment;
-import jp.sfjp.jindolf.dxchg.TextPopup;
-
-/**
- * 原稿作成支援エディタ。
- * 文字数行数管理などを行う。
- * 200文字もしくは10行まで入力可能。
- * ※ 10回目に出現する改行文字は許される。
- * ※ 2010-11-27以降、G国では5行制限が10行に緩和された。
- */
-@SuppressWarnings("serial")
-public class TalkEditor
- extends JPanel
- implements DocumentListener {
-
- private static final int MAX_CHARS = 200;
- private static final int MAX_LINES = 10;
-
- private static final Color COLOR_ACTIVATED = Color.GRAY;
-
-
- private final PlainDocument document = new PlainDocument();
-
- private int sequenceNumber;
-
- private boolean isActive = false;
-
- private final JLabel seqCount = new JLabel();
- private final JLabel talkStat = new JLabel();
- private final TextEditor textEditor = new TextEditor();
-
- private Font textFont;
-
-
- /**
- * コンストラクタ。
- * 通し番号は0が指定される。
- */
- public TalkEditor(){
- this(0);
- return;
- }
-
- /**
- * コンストラクタ。
- * @param seqNumber 通し番号
- */
- @SuppressWarnings("LeakingThisInConstructor")
- private TalkEditor(int seqNumber){
- super();
-
- setOpaque(true);
-
- this.document.addDocumentListener(this);
-
- this.seqCount.setForeground(Color.WHITE);
- this.talkStat.setForeground(Color.WHITE);
- this.seqCount.setOpaque(false);
- this.talkStat.setOpaque(false);
-
- this.textEditor.setMargin(new Insets(3, 3, 3, 3));
- this.textEditor.setDocument(this.document);
-
- JPopupMenu popup = new TextPopup();
- this.textEditor.setComponentPopupMenu(popup);
-
- this.textFont = this.textEditor.getFont();
-
- setSequenceNumber(seqNumber);
- updateStat();
- setActive(false);
-
- design();
-
- return;
- }
-
-
- /**
- * 指定された文字列の指定された位置から、
- * 最大何文字まで1発言におさめる事ができるか判定する。
- * @param source 検査対象
- * @param start 検査開始位置
- * @return 1発言に納めていい長さ。
- */
- public static int choplimit(CharSequence source, int start){
- int length = source.length();
- if(start >= length) return 0;
-
- int chars = 0;
- int lines = 0;
-
- for(int pos = start; pos < length; pos++){
- chars++;
- if(chars >= MAX_CHARS) break;
- char ch = source.charAt(pos);
- if(ch == '\n'){
- lines++;
- if(lines >= MAX_LINES) break;
- }
- }
-
- return chars;
- }
-
- /**
- * レイアウトを行う。
- */
- private void design(){
- LayoutManager layout = new GridBagLayout();
- GridBagConstraints constraints = new GridBagConstraints();
-
- setLayout(layout);
-
- constraints.gridx = 0;
- constraints.gridy = 0;
- constraints.gridwidth = 1;
- constraints.gridheight = 1;
- constraints.weightx = 0.0;
- constraints.weighty = 0.0;
- constraints.fill = GridBagConstraints.NONE;
- constraints.anchor = GridBagConstraints.NORTHWEST;
- constraints.insets = new Insets(0, 0, 1, 3);
- add(this.seqCount, constraints);
-
- constraints.gridx = 1;
- constraints.gridy = 0;
- constraints.gridwidth = 1;
- constraints.gridheight = 2;
- constraints.weightx = 1.0;
- constraints.weighty = 0.0;
- constraints.fill = GridBagConstraints.HORIZONTAL;
- constraints.anchor = GridBagConstraints.NORTHWEST;
- constraints.insets = new Insets(0, 0, 0, 0);
- JComponent decorated =
- BalloonBorder.decorateTransparentBorder(this.textEditor);
- add(decorated, constraints);
-
- constraints.gridx = 0;
- constraints.gridy = 1;
- constraints.gridwidth = 1;
- constraints.gridheight = 1;
- constraints.weightx = 0.0;
- constraints.weighty = 0.0;
- constraints.fill = GridBagConstraints.NONE;
- constraints.anchor = GridBagConstraints.NORTHEAST;
- constraints.insets = new Insets(0, 0, 0, 3);
- add(this.talkStat, constraints);
-
- Border border = BorderFactory.createEmptyBorder(5, 5, 5, 5);
- setBorder(border);
-
- return;
- }
-
- /**
- * テキスト編集用フォントを指定する。
- * @param textFont フォント
- */
- public void setTextFont(Font textFont){
- this.textFont = textFont;
- this.textEditor.setFont(this.textFont);
- this.textEditor.repaint();
- revalidate();
- return;
- }
-
- /**
- * テキスト編集用フォントを取得する。
- * @return フォント
- */
- public Font getTextFont(){
- return this.textFont;
- }
-
- /**
- * テキストコンポーネントにNavigationFilterを設定する。
- * @param navigator ナビゲーションフィルタ
- */
- public void setNavigationFilter(NavigationFilter navigator){
- this.textEditor.setNavigationFilter(navigator);
- return;
- }
-
- /**
- * 通し番号を取得する。
- * @return 通し番号
- */
- public int getSequenceNumber(){
- return this.sequenceNumber;
- }
-
- /**
- * 通し番号を設定する。
- * @param seqNumber 通し番号
- */
- public void setSequenceNumber(int seqNumber){
- this.sequenceNumber = seqNumber;
- String seqText = "=== #" + this.sequenceNumber + " ===";
- this.seqCount.setText(seqText);
- return;
- }
-
- /**
- * Documentを取得する。
- * @return 管理中のDocument
- */
- public Document getDocument(){
- return this.document;
- }
-
- /**
- * 現在のエディタの文字列内容を取得する。
- * @return 文字列内容
- */
- public String getText(){
- int length = this.document.getLength();
- String result = "";
- try{
- result = this.document.getText(0, length);
- }catch(BadLocationException e){
- assert false;
- }
- return result;
- }
-
- /**
- * 現在のエディタの文字列長を取得する。
- * @return 文字列長
- */
- public int getTextLength(){
- return this.document.getLength();
- }
-
- /**
- * 現在の行数を取得する。
- * ※ 改行文字の総数より一つ多い場合もある。
- * @return 行数
- */
- private int getTextLines(){
- int lines = 0;
-
- Segment segment = new Segment();
- segment.setPartialReturn(true);
-
- boolean hasLineContents = false;
- int pos = 0;
- int remain = getTextLength();
- while(remain > 0){
- try{
- this.document.getText(pos, remain, segment);
- }catch(BadLocationException e){
- assert false;
- }
-
- for(;;){
- char ch = segment.current();
- if(ch == Segment.DONE) break;
-
- if(ch == '\n'){
- if( ! hasLineContents ){
- lines++;
- }
- hasLineContents = false;
- }else if( ! hasLineContents ){
- hasLineContents = true;
- lines++;
- }
-
- segment.next();
- }
-
- pos += segment.count;
- remain -= segment.count;
- }
-
- return lines;
- }
-
- /**
- * エディタ先頭に文字列を挿入する。
- * @param text 挿入文字列
- */
- public void appendHead(CharSequence text){
- if(text == null) return;
- if(text.length() <= 0) return;
-
- try{
- this.document.insertString(0, text.toString(), null);
- }catch(BadLocationException e){
- assert false;
- }
-
- return;
- }
-
- /**
- * エディタ末尾に文字列を追加する。
- * @param text 追加文字列
- */
- public void appendTail(CharSequence text){
- if(text == null) return;
- if(text.length() <= 0) return;
-
- int offset = getTextLength();
- try{
- this.document.insertString(offset, text.toString(), null);
- }catch(BadLocationException e){
- assert false;
- }
-
- return;
- }
-
- /**
- * エディタ先頭から文字列を削除する。
- * @param chopLength 削除文字数
- */
- public void chopHead(int chopLength){
- if(chopLength <= 0) return;
-
- int modLength;
- int textLength = getTextLength();
- if(chopLength > textLength) modLength = textLength;
- else modLength = chopLength;
-
- try{
- this.document.remove(0, modLength);
- }catch(BadLocationException e){
- assert false;
- }
-
- return;
- }
-
- /**
- * テキストを空にする。
- */
- public void clearText(){
- int textLength = this.document.getLength();
- try{
- this.document.remove(0, textLength);
- }catch(BadLocationException e){
- assert false;
- }
- return;
- }
-
- /**
- * アクティブ状態を指定する。
- * アクティブ状態の場合、背景色が変わる。
- * @param isActiveArg trueならアクティブ状態
- */
- public void setActive(boolean isActiveArg){
- this.isActive = isActiveArg;
-
- if(this.isActive){
- setOpaque(true);
- setBackground(COLOR_ACTIVATED);
- Dimension size = getSize();
- Rectangle bounds = new Rectangle(size);
- scrollRectToVisible(bounds);
- this.textEditor.scrollCaretToVisible();
- }else{
- setOpaque(false);
- }
-
- repaint();
-
- return;
- }
-
- /**
- * アクティブ状態を取得する。
- * @return アクティブ状態ならtrue
- */
- public boolean isActive(){
- return this.isActive;
- }
-
- /**
- * エディタが現在IME操作中か判定する。
- * @return IME操作中ならtrue
- */
- public boolean onIMEoperation(){
- boolean result = this.textEditor.onIMEoperation();
- return result;
- }
-
- /**
- * エディタの現在のカーソル位置を取得する。
- * @return 0から始まるカーソル位置
- */
- public int getCaretPosition(){
- int caretPos = this.textEditor.getCaretPosition();
- return caretPos;
- }
-
- /**
- * エディタのカーソル位置を設定する。
- * @param pos 0から始まるカーソル位置
- * @throws java.lang.IllegalArgumentException 範囲外のカーソル位置指定
- */
- public void setCaretPosition(int pos) throws IllegalArgumentException{
- this.textEditor.setCaretPosition(pos);
- return;
- }
-
- /**
- * 集計情報表示(文字数、行数)を更新する。
- */
- private void updateStat(){
- if(onIMEoperation()) return;
-
- int charTotal = getTextLength();
- int lineNumber = getTextLines();
-
- StringBuilder statistics = new StringBuilder();
- statistics.append(charTotal)
- .append("字 ")
- .append(lineNumber)
- .append("行");
- this.talkStat.setText(statistics.toString());
-
- return;
- }
-
- /**
- * このテキストエディタに収まらない末尾文章を切り出す。
- * @return 最小の末尾文書。余裕があり切り出す必要がなければnullを返す。
- */
- public String chopRest(){
- String text = getText();
- int textLength = getTextLength();
- int choppedlen = choplimit(text, 0);
-
- int restLength = textLength - choppedlen;
- if(restLength <= 0) return null;
-
- String rest = null;
- try{
- rest = this.document.getText(choppedlen, restLength);
- this.document.remove(choppedlen, restLength);
- }catch(BadLocationException e){
- assert false;
- }
-
- return rest;
- }
-
- /**
- * テキストエディタにフォーカスを設定する。
- * @return 絶対失敗する場合はfalse
- */
- public boolean requestEditorFocus(){
- boolean result = this.textEditor.requestFocusInWindow();
- return result;
- }
-
- /**
- * テキストエディタがフォーカスを保持しているか判定する。
- * @return フォーカスを保持していればtrue
- */
- public boolean hasEditorFocus(){
- boolean result = this.textEditor.hasFocus();
- return result;
- }
-
- /**
- * 子エディタのフォーカス監視リスナを登録する。
- * @param listener FocusListener
- */
- public void addTextFocusListener(FocusListener listener){
- this.textEditor.addFocusListener(listener);
- return;
- }
-
- /**
- * 子エディタからフォーカス監視リスナを外す。
- * @param listener FocusListener
- */
- public void removeTextFocusListener(FocusListener listener){
- this.textEditor.removeFocusListener(listener);
- return;
- }
-
- /**
- * {@inheritDoc}
- * 集計情報を更新する。
- * @param event {@inheritDoc}
- */
- // TODO いつ呼ばれるのか不明
- @Override
- public void changedUpdate(DocumentEvent event){
- updateStat();
- return;
- }
-
- /**
- * {@inheritDoc}
- * 集計情報を更新する。
- * @param event {@inheritDoc}
- */
- @Override
- public void insertUpdate(DocumentEvent event){
- updateStat();
- return;
- }
-
- /**
- * {@inheritDoc}
- * 集計情報を更新する。
- * @param event {@inheritDoc}
- */
- @Override
- public void removeUpdate(DocumentEvent event){
- updateStat();
- return;
- }
-
-}
+++ /dev/null
-/*
- * 発言エディットパネル
- *
- * 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 アンカーの表記揺れの指摘
-}
+++ /dev/null
-/*
- * 原稿作成支援用テキストコンポーネント
- *
- * License : The MIT License
- * Copyright(c) 2008 olyutorskii
- */
-
-package jp.sfjp.jindolf.editor;
-
-import java.awt.Rectangle;
-import java.awt.event.InputMethodEvent;
-import java.awt.event.InputMethodListener;
-import java.nio.CharBuffer;
-import java.text.AttributedCharacterIterator;
-import javax.swing.JTextArea;
-import javax.swing.text.AbstractDocument;
-import javax.swing.text.AttributeSet;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-import javax.swing.text.DocumentFilter;
-import javax.swing.text.DocumentFilter.FilterBypass;
-import javax.swing.text.PlainDocument;
-
-/**
- * 原稿作成支援用テキストコンポーネント。
- */
-@SuppressWarnings("serial")
-public class TextEditor extends JTextArea
- implements InputMethodListener {
-
- private static final int MAX_DOCUMENT = 10 * 1000;
-
- private final DocumentFilter documentFilter = new CustomFilter();
-
- private boolean onIMEoperation = false;
-
- /**
- * コンストラクタ。
- */
- @SuppressWarnings("LeakingThisInConstructor")
- public TextEditor(){
- super();
-
- setLineWrap(true);
- setWrapStyleWord(false);
-
- Document document = new PlainDocument();
- setDocument(document);
-
- addInputMethodListener(this);
-
- return;
- }
-
- /**
- * エディタが現在IME操作中か判定する。
- * @return IME操作中ならtrue
- */
- public boolean onIMEoperation(){
- return this.onIMEoperation;
- }
-
- /**
- * 現在のカーソルが表示されるようスクロールエリアを操作する。
- */
- public void scrollCaretToVisible(){
- int caretPosition = getCaretPosition();
-
- Rectangle caretBounds;
- try{
- caretBounds = modelToView(caretPosition);
- }catch(BadLocationException e){
- assert false;
- return;
- }
-
- scrollRectToVisible(caretBounds);
-
- return;
- }
-
- /**
- * {@inheritDoc}
- * Document変更をフックしてフィルタを仕込む。
- * @param document {@inheritDoc}
- */
- @Override
- public final void setDocument(Document document){
- Document oldDocument = getDocument();
- if(oldDocument instanceof AbstractDocument){
- AbstractDocument abstractDocument =
- (AbstractDocument) oldDocument;
- abstractDocument.setDocumentFilter(null);
- }
-
- super.setDocument(document);
-
- if(document instanceof AbstractDocument){
- AbstractDocument abstractDocument = (AbstractDocument) document;
- abstractDocument.setDocumentFilter(this.documentFilter);
- }
-
- return;
- }
-
- /**
- * {@inheritDoc}
- * このエディタ中の指定領域が表示されるようスクロールエリアを操作する。
- * キーボードフォーカスを保持しないときは無視。
- * @param rect {@inheritDoc}
- */
- @Override
- public void scrollRectToVisible(Rectangle rect){
- if( ! hasFocus() ) return;
- super.scrollRectToVisible(rect);
- return;
- }
-
- /**
- * {@inheritDoc}
- * @param event {@inheritDoc}
- */
- @Override
- public void caretPositionChanged(InputMethodEvent event){
- // NOTHING
- return;
- }
-
- /**
- * {@inheritDoc}
- * このテキストエディタで現在IMEの変換中か否か判定する処理を含む。
- * @param event {@inheritDoc}
- */
- @Override
- public void inputMethodTextChanged(InputMethodEvent event){
- int committed = event.getCommittedCharacterCount();
- AttributedCharacterIterator aci = event.getText();
- if(aci == null){
- this.onIMEoperation = false;
- return;
- }
- int begin = aci.getBeginIndex();
- int end = aci.getEndIndex();
- int span = end - begin;
-
- if(committed >= span) this.onIMEoperation = false;
- else this.onIMEoperation = true;
-
- return;
- }
-
- /**
- * 入力文字列に制限を加えるDocumentFilter。
- * \n,\f 以外の制御文字はタブも含め入力禁止。
- * U+FFFF はjava.textパッケージで特別扱いなのでこれも入力禁止。
- * ※ ただしIME操作中は制限なし。
- */
- private class CustomFilter extends DocumentFilter{
-
- /**
- * コンストラクタ。
- */
- public CustomFilter(){
- super();
- return;
- }
-
- /**
- * 入力禁止文字の判定。
- * @param ch 検査対象文字
- * @return 入力禁止ならfalse。ただしIME操作中は必ずtrue。
- */
- private boolean isValid(char ch){
- if(onIMEoperation()) return true;
-
- if(ch == '\n') return true;
- // if(ch == '\f') return true;
-
- if(ch == '\uffff') return false;
- if(Character.isISOControl(ch)) return false;
-
- // if( ! CodeX0208.isValid(ch) ) return false;
- if(Character.isHighSurrogate(ch)) return false;
- if(Character.isLowSurrogate(ch) ) return false;
-
- return true;
- }
-
- /**
- * 与えられた文字列から入力禁止文字を除いた文字列に変換する。
- * @param input 検査対象文字列
- * @return 除去済み文字列
- */
- private String filter(CharSequence input){
- if(onIMEoperation()) return input.toString();
-
- int length = input.length();
- CharBuffer buf = CharBuffer.allocate(length);
-
- for(int pos = 0; pos < length; pos++){
- char ch = input.charAt(pos);
- if(ch == '\u2211') ch = '\u03a3'; // Σ変換
- if(ch == '\u00ac') ch = '\uffe2'; // ¬変換
- // if(ch == 0x005c ) ch = '\u00a5';
- // バックスラッシュから円へ
- if(isValid(ch)) buf.append(ch);
- }
-
- buf.flip();
- return buf.toString();
- }
-
- /**
- * {@inheritDoc}
- * @param fb {@inheritDoc}
- * @param offset {@inheritDoc}
- * @param text {@inheritDoc}
- * @param attrs {@inheritDoc}
- * @throws javax.swing.text.BadLocationException {@inheritDoc}
- */
- @Override
- public void insertString(FilterBypass fb,
- int offset,
- String text,
- AttributeSet attrs)
- throws BadLocationException{
- String filtered = filter(text);
-
- if( ! onIMEoperation() ){
- Document document = fb.getDocument();
- int docLength = document.getLength();
- int rest = MAX_DOCUMENT - docLength;
- if(rest < 0){
- return;
- }else if(rest < filtered.length()){
- filtered = filtered.substring(0, rest);
- }
- }
-
- fb.insertString(offset, filtered, attrs);
-
- return;
- }
-
- /**
- * {@inheritDoc}
- * @param fb {@inheritDoc}
- * @param offset {@inheritDoc}
- * @param length {@inheritDoc}
- * @param text {@inheritDoc}
- * @param attrs {@inheritDoc}
- * @throws javax.swing.text.BadLocationException {@inheritDoc}
- */
- @Override
- public void replace(FilterBypass fb,
- int offset,
- int length,
- String text,
- AttributeSet attrs)
- throws BadLocationException{
- String filtered = filter(text);
-
- if( ! onIMEoperation() ){
- Document document = fb.getDocument();
- int docLength = document.getLength();
- docLength -= length;
- int rest = MAX_DOCUMENT - docLength;
- if(rest < 0){
- return;
- }else if(rest < filtered.length()){
- filtered = filtered.substring(0, rest);
- }
- }
-
- fb.replace(offset, length, filtered, attrs);
-
- return;
- }
- }
-
- // TODO 禁則チェック。20文字を超える長大なブレーク禁止文字列の出現の監視。
- // TODO 連続したホワイトスペースに対する警告。
- // TODO 先頭もしくは末尾のホワイトスペース出現に対する警告。
- // TODO 改行記号の表示
- // TODO 改発言記号の導入
-}
+++ /dev/null
-/*
- * パッケージ情報
- *
- * License : The MIT License
- * Copyright(c) 2011 olyutorskii
- */
-
-/**
- * 発言エディタ関連の一連のクラス。
- */
-
-package jp.sfjp.jindolf.editor;
-
-/* EOF */
/** アクション{@value}。 */
public static final String CMD_SHOWFILT = "SHOWFILT";
/** アクション{@value}。 */
- public static final String CMD_SHOWEDIT = "SHOWEDIT";
- /** アクション{@value}。 */
public static final String CMD_SHOWLOG = "SHOWLOG";
/** アクション{@value}。 */
public static final String CMD_HELPDOC = "HELPDOC";
buildMenuItem(CMD_WEBDAY, "この日をブラウザで表示...", KeyEvent.VK_B);
buildMenuItem(CMD_OPTION, "オプション...", KeyEvent.VK_O);
buildMenuItem(CMD_SHOWFILT, "発言フィルタ", KeyEvent.VK_F);
- buildMenuItem(CMD_SHOWEDIT, "発言エディタ", KeyEvent.VK_E);
buildMenuItem(CMD_SHOWLOG, "ログ表示", KeyEvent.VK_S);
buildMenuItem(CMD_HELPDOC, "ヘルプ表示", KeyEvent.VK_H);
buildMenuItem(CMD_SHOWPORTAL, "ポータルサイト...", KeyEvent.VK_P);
buildToolButton(CMD_SEARCHPREV, "↑前候補", ICON_SEARCH_PREV);
buildToolButton(CMD_SEARCHNEXT, "↓次候補", ICON_SEARCH_NEXT);
buildToolButton(CMD_SHOWFILT, "発言フィルタ", ICON_FILTER);
- buildToolButton(CMD_SHOWEDIT, "発言エディタ", ICON_EDITOR);
return;
}
getMenuItem(CMD_SEARCHPREV).setIcon(ICON_SEARCH_PREV);
getMenuItem(CMD_SEARCHNEXT).setIcon(ICON_SEARCH_NEXT);
getMenuItem(CMD_SHOWFILT) .setIcon(ICON_FILTER);
- getMenuItem(CMD_SHOWEDIT) .setIcon(ICON_EDITOR);
return;
}
this.menuPreference.add(this.menuLook);
this.menuTool.add(getMenuItem(CMD_SHOWFILT));
- this.menuTool.add(getMenuItem(CMD_SHOWEDIT));
this.menuTool.add(getMenuItem(CMD_SHOWLOG));
this.menuHelp.add(getMenuItem(CMD_HELPDOC));
toolBar.add(getToolButton(CMD_SEARCHPREV));
toolBar.addSeparator();
toolBar.add(getToolButton(CMD_SHOWFILT));
- toolBar.add(getToolButton(CMD_SHOWEDIT));
return toolBar;
}
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import jp.sfjp.jindolf.VerInfo;
-import jp.sfjp.jindolf.editor.TalkPreview;
import jp.sfjp.jindolf.log.LogFrame;
import jp.sfjp.jindolf.summary.DaySummary;
import jp.sfjp.jindolf.summary.VillageDigest;
getFrameTitle("発言フィルタ");
private static final String TITLE_LOGGER =
getFrameTitle("ログ表示");
- private static final String TITLE_EDITOR =
- getFrameTitle("発言エディタ");
private static final String TITLE_OPTION =
getFrameTitle("オプション設定");
private static final String TITLE_FIND =
private FilterPanel filterPanel;
private LogFrame logFrame;
- private TalkPreview talkPreview;
private OptionPanel optionPanel;
private FindPanel findPanel;
private VillageDigest villageDigest;
/**
* ウィンドウタイトルに前置詞をつける。
+ *
* @param text 元タイトル
* @return タイトル文字列
*/
/**
* 発言フィルタウィンドウを生成する。
+ *
* @return 発言フィルタウィンドウ
*/
protected FilterPanel createFilterPanel(){
/**
* 発言フィルタウィンドウを返す。
+ *
* @return 発言フィルタウィンドウ
*/
public FilterPanel getFilterPanel(){
/**
* ログウィンドウを生成する。
+ *
* @return ログウィンドウ
*/
protected LogFrame createLogFrame(){
/**
* ログウィンドウを返す。
+ *
* @return ログウィンドウ
*/
public LogFrame getLogFrame(){
}
/**
- * 発言エディタウィンドウを生成する。
- * @return 発言エディタウィンドウ
- */
- protected TalkPreview createTalkPreview(){
- TalkPreview result;
-
- result = new TalkPreview();
- result.setTitle(TITLE_EDITOR);
- result.pack();
- result.setSize(700, 500);
- result.setVisible(false);
-
- this.windowSet.add(result);
-
- return result;
- }
-
- /**
- * 発言エディタウィンドウを返す。
- * @return 発言エディタウィンドウ
- */
- public TalkPreview getTalkPreview(){
- if(this.talkPreview == null){
- this.talkPreview = createTalkPreview();
- }
- return this.talkPreview;
- }
-
- /**
* オプション設定ウィンドウを生成する。
+ *
* @return オプション設定ウィンドウ
*/
protected OptionPanel createOptionPanel(){
/**
* オプション設定ウィンドウを返す。
+ *
* @return オプション設定ウィンドウ
*/
public OptionPanel getOptionPanel(){
/**
* 検索ウィンドウを生成する。
+ *
* @return 検索ウィンドウ
*/
protected FindPanel createFindPanel(){
/**
* 検索ウィンドウを返す。
+ *
* @return 検索ウィンドウ
*/
public FindPanel getFindPanel(){
/**
* 村ダイジェストウィンドウを生成する。
+ *
* @return 村ダイジェストウィンドウ
*/
protected VillageDigest createVillageDigest(){
/**
* 村ダイジェストウィンドウを返す。
+ *
* @return 村ダイジェストウィンドウ
*/
public VillageDigest getVillageDigest(){
/**
* 発言集計ウィンドウを生成する。
+ *
* @return 発言集計ウィンドウ
*/
protected DaySummary createDaySummary(){
/**
* 発言集計ウィンドウを返す。
+ *
* @return 発言集計ウィンドウ
*/
public DaySummary getDaySummary(){
/**
* ヘルプウィンドウを生成する。
+ *
* @return ヘルプウィンドウ
*/
protected HelpFrame createHelpFrame(){
/**
* ヘルプウィンドウを返す。
+ *
* @return ヘルプウィンドウ
*/
public HelpFrame getHelpFrame(){
/**
* トップフレームを生成する。
+ *
* @return トップフレーム
*/
protected TopFrame createTopFrame(){
/**
* トップフレームを返す。
+ *
* @return トップフレーム
*/
public TopFrame getTopFrame(){