package open.dolphin.client;
import java.awt.Color;
import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import javax.swing.*;
import javax.swing.event.MenuEvent;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyledEditorKit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import open.dolphin.helper.MenuSupport;
import open.dolphin.infomodel.IInfoModel;
import open.dolphin.infomodel.PVTHealthInsuranceModel;
import open.dolphin.project.Project;
import open.dolphin.stampbox.StampBoxPlugin;
import open.dolphin.stampbox.StampTree;
import open.dolphin.stampbox.StmapTreeMenuBuilder;
import open.dolphin.stampbox.StmapTreePopupBuilder;
/**
* Mediator class to control Karte Window Menu.
*
* @author Kazushi Minagawa, Digital Globe, Inc.
*/
public final class ChartMediator extends MenuSupport implements UndoableEditListener, ActionListener {
public enum CompState{NONE, SOA, SOA_TEXT, SCHEMA, P, P_TEXT, STAMP};
private static final int[] FONT_SIZE = {10, 12, 13, 16, 18, 24, 36};
private static final String PERMANENT_FOCUS_OWNER = "permanentFocusOwner";
private int curSize; // FONT_SIZEのindex
// ChartPlugin
private final Chart chart;
// Current KarteTransferHandler
private IKarteTransferHandler curKarteTransherHandler;
// CurrentComponent
private JComponent currentFocusOwner;
// Undo Manager
private final UndoManager undoManager;
private Action undoAction;
private Action redoAction;
private final FocusPropertyChangeListener fpcl;
private static int defaultFontSizeIndex() {
int size = Project.getInt("karte.font.size.default");
for (int i=0; i < FONT_SIZE.length; i++) {
if (FONT_SIZE[i]==size) {
return i;
}
}
return 1;
}
/**
* Creates new ChartMediator
* @param owner
*/
public ChartMediator(Object owner) {
super(owner);
chart = (Chart)owner;
fpcl = new FocusPropertyChangeListener();
KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(fpcl);
undoManager = new UndoManager();
// fontsize
curSize = defaultFontSizeIndex();
}
class FocusPropertyChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (prop.equals(PERMANENT_FOCUS_OWNER)) {
Component comp = (Component)e.getNewValue();
if (comp!=null && (comp instanceof JComponent)) {
JComponent jc = (JComponent)comp;
Object obj = jc.getClientProperty("karteCompositor");
currentFocusOwner = obj!=null ? jc : currentFocusOwner;
TransferHandler tr = jc.getTransferHandler();
if (tr!=null && (tr instanceof IKarteTransferHandler)) {
setCurKarteTransferHandler((IKarteTransferHandler)tr);
}
}
}
}
}
public void setCurKarteTransferHandler(IKarteTransferHandler newTrans) {
//System.err.println("setCurKarteTransferHandler did enter");
IKarteTransferHandler old = this.curKarteTransherHandler;
this.curKarteTransherHandler = newTrans;
if (curKarteTransherHandler==old) {
return;
}
if (old!=null) {
old.exit(getActions());
}
enabledAction(GUIConst.ACTION_CUT, false);
enabledAction(GUIConst.ACTION_COPY, false);
enabledAction(GUIConst.ACTION_PASTE, false);
enabledAction(GUIConst.ACTION_UNDO, false);
enabledAction(GUIConst.ACTION_REDO, false);
enabledAction(GUIConst.ACTION_INSERT_TEXT, false);
enabledAction(GUIConst.ACTION_INSERT_SCHEMA, false);
enabledAction(GUIConst.ACTION_ATTACHMENT, false);
enabledAction(GUIConst.ACTION_INSERT_STAMP, false);
if (curKarteTransherHandler!=null) {
curKarteTransherHandler.enter(getActions());
}
}
@Override
public void registerActions(ActionMap map) {
super.registerActions(map);
undoAction = map.get(GUIConst.ACTION_UNDO);
redoAction = map.get(GUIConst.ACTION_REDO);
// 昇順降順を Preference から取得し設定しておく
boolean asc = Project.getBoolean(Project.DOC_HISTORY_ASCENDING, false);
if (asc) {
Action a = map.get(GUIConst.ACTION_ASCENDING);
JRadioButtonMenuItem rdi = (JRadioButtonMenuItem) a.getValue("menuItem");
rdi.setSelected(true);
} else {
Action desc = map.get(GUIConst.ACTION_DESCENDING);
JRadioButtonMenuItem rdi = (JRadioButtonMenuItem) desc.getValue("menuItem");
rdi.setSelected(true);
}
}
public void dispose() {
KeyboardFocusManager focusManager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.removePropertyChangeListener(fpcl);
}
@Override
public void actionPerformed(ActionEvent e) {
}
public JComponent getCurrentComponent() {
//return (curKarteTransherHandler!=null) ? curKarteTransherHandler.getComponent() : null;
return currentFocusOwner;
}
public JComponent getCurrentFocusOwner() {
return currentFocusOwner;
}
/**
* メニューリスナの実装。
* 挿入及びテキストメニューが選択された時の処理を行う。
* @param e
*/
@Override
public void menuSelected(MenuEvent e) {
// 挿入とテキストメニューにリスナが登録されている
JMenu selectedMenu = (JMenu) e.getSource();
String menuName = selectedMenu.getName();
//-----------------------------------
// 挿入メニューの時
// StampBox のツリーをメニューにする
//-----------------------------------
if (GUIConst.MENU_NAME_INSERT.equals(menuName)) {
selectedMenu.removeAll();
// 添付メニューを追加する
selectedMenu.add(createAttachmentMenu());
selectedMenu.addSeparator();
// StampBox の全ツリーを取得する
List<StampTree> trees = getStampBox().getAllTrees();
// ツリーをイテレートする
for (StampTree tree : trees) {
// ツリーのエンティティを取得する
String entity = tree.getEntity();
if (entity.equals(IInfoModel.ENTITY_DIAGNOSIS)) {
// 傷病名の時、傷病名メニューを構築し追加する
selectedMenu.add(createDiagnosisMenu(tree));
selectedMenu.addSeparator();
} else if (entity.equals(IInfoModel.ENTITY_TEXT)) {
// テキストの時、テキストメニューを構築し追加する
selectedMenu.add(createTextMenu(tree));
selectedMenu.addSeparator();
} else {
// 通常のPオーダの時
selectedMenu.add(createStampMenu(tree));
}
}
}
else if (GUIConst.MENU_NAME_TEXT.equals(menuName)) {
//-----------------------------------
// テキストメニューの場合、スタイルを制御する
//-----------------------------------
adjustStyleMenu();
}
}
@Override
public void menuDeselected(MenuEvent e) {
}
@Override
public void menuCanceled(MenuEvent e) {
}
private JMenuItem createAttachmentMenu() {
boolean enabled = false;
KartePane kartePane;
if (getChain() instanceof KarteEditor) {
KarteEditor editor = (KarteEditor)getChain();
kartePane = editor.getSOAPane();
enabled = (kartePane.getTextPane().isEditable());
}
getAction(GUIConst.ACTION_ATTACHMENT).setEnabled(enabled);
return new JMenuItem(getAction(GUIConst.ACTION_ATTACHMENT));
}
/**
* フォーマット関連メニューを調整する。
* @param kartePane
*/
private void adjustStyleMenu() {
boolean enabled = false;
KartePane kartePane;
if (getChain() instanceof KarteEditor) {
KarteEditor editor = (KarteEditor) getChain();
kartePane = editor.getSOAPane();
enabled = (kartePane.getTextPane().isEditable());
}
// サブメニューを制御する
getAction("size").setEnabled(enabled);
getAction("style").setEnabled(enabled);
getAction("justify").setEnabled(enabled);
getAction("color").setEnabled(enabled);
getAction("fontRed").setEnabled(enabled);
getAction("fontOrange").setEnabled(enabled);
getAction("fontYellow").setEnabled(enabled);
getAction("fontGreen").setEnabled(enabled);
getAction("fontBlue").setEnabled(enabled);
getAction("fontPurple").setEnabled(enabled);
getAction("fontGray").setEnabled(enabled);
getAction("fontLarger").setEnabled(enabled);
getAction("fontSmaller").setEnabled(enabled);
getAction("fontStandard").setEnabled(enabled);
getAction("fontBold").setEnabled(enabled);
getAction("fontItalic").setEnabled(enabled);
getAction("fontUnderline").setEnabled(enabled);
getAction("leftJustify").setEnabled(enabled);
getAction("centerJustify").setEnabled(enabled);
getAction("rightJustify").setEnabled(enabled);
}
/**
* スタンプTreeから傷病名メニューを構築する。
* @param insertMenu テキストメニュー
*/
private JMenu createDiagnosisMenu(StampTree stampTree) {
// chainの先頭がDiagnosisDocumentの時のみ使用可能とする
JMenu myMenu;
DiagnosisDocument diagnosis = null;
boolean enabled = false;
Object obj = getChain();
if (obj instanceof DiagnosisDocument) {
diagnosis = (DiagnosisDocument) obj;
//s.oh^ 2014/04/16 メニュー制御
//enabled = true;
enabled = !chart.isReadOnly();
//s.oh$
}
if (!enabled) {
// cjainの先頭がDiagnosisでない場合はめにゅーをdisableにする
myMenu = new JMenu(stampTree.getTreeName());
myMenu.setEnabled(false);
} else {
// 傷病名Tree、テーブル、ハンドラからメニューを構築する
JComponent comp = diagnosis.getDiagnosisTable();
TransferHandler handler = comp.getTransferHandler();
StmapTreeMenuBuilder builder = new StmapTreeMenuBuilder();
myMenu = builder.build(stampTree, comp, handler);
}
return myMenu;
}
/**
* スタンプTreeからテキストメニューを構築する。
* @param insertMenu テキストメニュー
*/
private JMenu createTextMenu(StampTree stampTree) {
// chain の先頭が KarteEditor でかつ SOAane が編集可の場合のみメニューが使える
JMenu myMenu;
boolean enabled = false;
KartePane kartePane = null;
Object obj = getChain();
if (obj instanceof KarteEditor) {
KarteEditor editor = (KarteEditor) obj;
kartePane = editor.getSOAPane();
if (kartePane != null) {
enabled = (kartePane.getTextPane().isEditable());
}
}
if (!enabled) {
myMenu = new JMenu(stampTree.getTreeName());
myMenu.setEnabled(false);
} else {
JComponent comp = getCurrentComponent();
if (comp == null) {
comp = kartePane.getTextPane();
}
TransferHandler handler = comp.getTransferHandler();
StmapTreeMenuBuilder builder = new StmapTreeMenuBuilder();
myMenu = builder.build(stampTree, comp, handler);
}
return myMenu;
}
/**
* スタンプメニューを構築する。
* @param insertMenu スタンプメニュー
*/
private JMenu createStampMenu(StampTree stampTree) {
// chain の先頭が KarteEditor でかつ Pane が編集可の場合のみメニューが使える
JMenu myMenu;
boolean enabled = false;
KartePane kartePane = null;
Object obj = getChain();
if (obj instanceof KarteEditor) {
KarteEditor editor = (KarteEditor) obj;
kartePane = editor.getPPane();
if (kartePane != null) {
enabled = (kartePane.getTextPane().isEditable());
}
}
if (!enabled) {
myMenu = new JMenu(stampTree.getTreeName());
myMenu.setEnabled(false);
} else {
// StampTree、JTextPane、Handler からメニューを構築する
JComponent comp = kartePane.getTextPane();
TransferHandler handler = comp.getTransferHandler();
StmapTreeMenuBuilder builder = new StmapTreeMenuBuilder();
myMenu = builder.build(stampTree, comp, handler);
}
return myMenu;
}
////////////////////////////////////////////////////////////////////////////
/**
* 引数のポップアップメニューへ傷病名メニューを追加する。
* @param popup 傷病名メニューを追加するポップアップメニュー
*/
public void addDiseaseMenu(JPopupMenu popup) {
// Chainの先頭がDiagnosisDocumentの時のみ追加する
boolean enabled = false;
DiagnosisDocument diagnosis = null;
Object obj = getChain();
if (obj instanceof DiagnosisDocument) {
diagnosis = (DiagnosisDocument) obj;
enabled = true;
}
StampTree stampTree = getStampBox().getStampTree(IInfoModel.ENTITY_DIAGNOSIS);
if (stampTree != null) {
if (!enabled) {
JMenu myMenu = new JMenu(stampTree.getTreeName());
myMenu.setEnabled(false);
popup.add(myMenu);
} else {
JComponent comp = diagnosis.getDiagnosisTable();
TransferHandler handler = comp.getTransferHandler();
StmapTreePopupBuilder builder = new StmapTreePopupBuilder();
builder.build(stampTree, popup, comp, handler);
}
}
}
/**
* 引数のポップアップメニューへテキストメニューを追加する。
* @param popup テキストメニューを追加するポップアップメニュー
*/
public void addTextMenu(JPopupMenu popup) {
boolean enabled = false;
KartePane kartePane = null;
Object obj = getChain();
if (obj instanceof KarteEditor) {
KarteEditor editor = (KarteEditor) obj;
kartePane = editor.getSOAPane();
if (kartePane != null) {
enabled = (kartePane.getTextPane().isEditable());
}
}
StampTree stampTree = getStampBox().getStampTree(IInfoModel.ENTITY_TEXT);
// ASP スタンプボックスで entity に対応する Tree がない場合がある
if (stampTree != null) {
if (!enabled) {
JMenu myMenu = new JMenu(stampTree.getTreeName());
myMenu.setEnabled(false);
popup.add(myMenu);
} else {
//s.oh^ 2013/03/15 不具合修正(テキストスタンプを追加できない)
//minagawa^ LSC 1.4 bug fix 元へ返す... テキストスタンプが所見欄にしか張り付かない 2013/06/24
JComponent comp = getCurrentComponent();
if (comp == null) {
comp = kartePane.getTextPane();
}
//JComponent comp = kartePane.getTextPane();
//minagawa$
//s.oh$
TransferHandler handler = comp.getTransferHandler();
StmapTreePopupBuilder builder = new StmapTreePopupBuilder();
builder.build(stampTree, popup, comp, handler);
}
}
}
/**
* PPane のコンテキストメニューまたはツールバーの stampIcon へスタンプメニューを追加する。
* @param menu Ppane のコンテキストメニュー
* @param kartePane PPnae
*/
public void addStampMenu(JPopupMenu menu, final KartePane kartePane) {
// 引数のPaneがPかつ編集可の時のみ追加する
// コンテキストメニューなのでこれはOK
if (kartePane != null && kartePane.getMyRole().equals(IInfoModel.ROLE_P) && kartePane.getTextPane().isEditable()) {
StampBoxPlugin stampBox = getStampBox();
List<StampTree> trees = stampBox.getAllTrees();
StmapTreeMenuBuilder builder = new StmapTreeMenuBuilder();
JComponent cmp = kartePane.getTextPane();
TransferHandler handler = cmp.getTransferHandler();
// StampBox内の全Treeをイテレートする
for (StampTree stampTree : trees) {
// 傷病名とテキストは別に作成するのでスキップする
String entity = stampTree.getEntity();
if (entity.equals(IInfoModel.ENTITY_DIAGNOSIS) || entity.equals(IInfoModel.ENTITY_TEXT)) {
continue;
}
JMenu subMenu = builder.build(stampTree, cmp, handler);
menu.add(subMenu);
}
}
}
/**
* 引数のポップアップメニューへスタンプメニューを追加する。
* このメソッドはツールバーの stamp icon の actionPerformed からコールされる。
* @param popup
*/
public void addStampMenu(JPopupMenu popup) {
boolean enabled = false;
KartePane kartePane = null;
Object obj = getChain();
if (obj instanceof KarteEditor) {
KarteEditor editor = (KarteEditor) obj;
kartePane = editor.getPPane();
if (kartePane != null) {
enabled = (kartePane.getTextPane().isEditable());
}
}
if (enabled) {
addStampMenu(popup, kartePane);
}
}
public StampTree getStampTree(String entity) {
StampTree stampTree = getStampBox().getStampTree(entity);
return stampTree;
}
public StampBoxPlugin getStampBox() {
return (StampBoxPlugin) chart.getContext().getPlugin("stampBox");
}
public boolean hasTree(String entity) {
StampBoxPlugin stBox = (StampBoxPlugin)chart.getContext().getPlugin("stampBox");
StampTree tree = stBox.getStampTree(entity);
return tree != null;
}
public void applyInsurance(PVTHealthInsuranceModel hm) {
Object target = getChain();
if (target != null) {
try {
Method m = target.getClass().getMethod("applyInsurance", new Class[]{hm.getClass()});
m.invoke(target, new Object[]{hm});
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
//e.printStackTrace();
}
}
}
//-----------------------------------------------------------------------------
@Override
public void cut() {
JComponent focusOwner = getCurrentFocusOwner();
if (focusOwner != null) {
Action a = focusOwner.getActionMap().get(TransferHandler.getCutAction().getValue(Action.NAME));
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
setCurKarteTransferHandler(null);
}
}
}
@Override
public void copy() {
JComponent focusOwner = getCurrentFocusOwner();
if (focusOwner != null) {
Action a = focusOwner.getActionMap().get(TransferHandler.getCopyAction().getValue(Action.NAME));
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
}
}
@Override
public void paste() {
JComponent focusOwner = getCurrentFocusOwner();
if (focusOwner != null) {
Action a = focusOwner.getActionMap().get(TransferHandler.getPasteAction().getValue(Action.NAME));
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
}
}
public void resetStyle() {
JComponent focusOwner = getCurrentFocusOwner();
if (focusOwner != null && focusOwner instanceof JTextPane) {
JTextPane pane = (JTextPane) focusOwner;
pane.setCharacterAttributes(SimpleAttributeSet.EMPTY, true);
}
}
@Override
public void undoableEditHappened(UndoableEditEvent e) {
undoManager.addEdit(e.getEdit());
updateUndoAction();
updateRedoAction();
}
public void undo() {
try {
undoManager.undo();
} catch (CannotUndoException ex) {
ex.printStackTrace(System.err);
}
updateUndoAction();
updateRedoAction();
}
public void redo() {
try {
undoManager.redo();
} catch (CannotRedoException ex) {
ex.printStackTrace(System.err);
}
updateRedoAction();
updateUndoAction();
}
private void updateUndoAction() {
if(undoManager.canUndo()) {
undoAction.setEnabled(true);
} else {
undoAction.setEnabled(false);
}
}
private void updateRedoAction() {
if(undoManager.canRedo()) {
redoAction.setEnabled(true);
} else {
redoAction.setEnabled(false);
}
}
public void fontLarger() {
JComponent focusOwner = getCurrentComponent();
if (focusOwner != null) {
if (curSize < 6) {
curSize++;
}
int size = FONT_SIZE[curSize];
Action a = focusOwner.getActionMap().get("font-size-" + size);
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
if (curSize == 6) {
enabledAction("fontLarger", false);
}
}
}
public void fontSmaller() {
JComponent focusOwner = getCurrentComponent();
if (focusOwner != null) {
if (curSize > 0) {
curSize--;
}
int size = FONT_SIZE[curSize];
Action a = focusOwner.getActionMap().get("font-size-" + size);
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
if (curSize == 0) {
enabledAction("fontSmaller", false);
}
}
}
public void fontStandard() {
JComponent focusOwner = getCurrentComponent();
if (focusOwner != null) {
curSize = defaultFontSizeIndex();
int size = FONT_SIZE[curSize];
Action a = focusOwner.getActionMap().get("font-size-" + size);
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
enabledAction("fontSmaller", true);
enabledAction("fontLarger", true);
}
}
public void fontBold() {
JComponent focusOwner = getCurrentComponent();
if (focusOwner != null) {
Action a = focusOwner.getActionMap().get("font-bold");
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
}
}
public void fontItalic() {
JComponent focusOwner = getCurrentComponent();
if (focusOwner != null) {
Action a = focusOwner.getActionMap().get("font-italic");
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
}
}
public void fontUnderline() {
JComponent focusOwner = getCurrentComponent();
if (focusOwner != null) {
Action a = focusOwner.getActionMap().get("font-underline");
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
}
}
public void leftJustify() {
JComponent focusOwner = getCurrentComponent();
if (focusOwner != null) {
Action a = focusOwner.getActionMap().get("left-justify");
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
}
}
public void centerJustify() {
JComponent focusOwner = getCurrentComponent();
if (focusOwner != null) {
Action a = focusOwner.getActionMap().get("center-justify");
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
}
}
public void rightJustify() {
JComponent focusOwner = getCurrentComponent();
if (focusOwner != null) {
Action a = focusOwner.getActionMap().get("right-justify");
if (a != null) {
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
null));
}
}
}
private void colorAction(Color color) {
JComponent focusOwner = getCurrentComponent();
if (focusOwner != null) {
Action a = new StyledEditorKit.ForegroundAction("color", color);
a.actionPerformed(new ActionEvent(focusOwner,
ActionEvent.ACTION_PERFORMED,
"foreground"));
}
}
public void fontRed() {
colorAction(ClientContext.getColor("color.set.default.red"));
}
public void fontOrange() {
colorAction(ClientContext.getColor("color.set.default.orange"));
}
public void fontYellow() {
colorAction(ClientContext.getColor("color.set.default.yellow"));
}
public void fontGreen() {
colorAction(ClientContext.getColor("color.set.default.green"));
}
public void fontBlue() {
colorAction(ClientContext.getColor("color.set.default.blue"));
}
public void fontPurple() {
colorAction(ClientContext.getColor("color.set.default.purpule"));
}
public void fontGray() {
colorAction(ClientContext.getColor("color.set.default.gray"));
}
public void fontBlack() {
colorAction(Color.BLACK);
}
}