package open.dolphin.client;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import javax.swing.AbstractAction;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import open.dolphin.infomodel.BundleMed;
import open.dolphin.infomodel.ClaimItem;
import open.dolphin.infomodel.ModuleInfoBean;
import open.dolphin.infomodel.ModuleModel;
import open.dolphin.order.ClaimConst;
import open.dolphin.ui.MyJPopupMenu;
import open.dolphin.util.DailyDoseStringTool;
/**
* StampHolder を右クリックでいろいろいじる
* @author pns
*/
public class StampHolderPopupMenu extends MyJPopupMenu {
private static final long serialVersionUID = 1L;
private StampHolder ctx;
/** メニューに載せる処方日数のリスト */
private static final int[] BUNDLE_NUMS = {3,4,5,7,10,14,21,28,30,56,60};
/** メニューに載せる外用剤の量のリスト */
private static final int[] DOSES = {5,10,15,20,25,30,40,50,60,75,100,125,150,200,250};
/** メニューに載せる用法のリスト */
private static enum Admin {
once1 ("001000103","1日1回朝食後に"),
once2 ("001000105","1日1回昼食後に"),
once3 ("001000107","1日1回夕食後に"),
once4 ("001000111","1日1回就寝前に"),
twice1 ("001000202","1日2回朝夕食後に"),
twice2 ("001000214","1日2回朝食後及び就寝前に"),
thrice1("001000303","1日3回毎食後に");
public final String code, str;
private Admin(String code, String str) {
this.code = code;
this.str = str;
}
}
/** メニューに載せる外用回数のリスト */
private static enum Admin2 {
once("001000602", "1日1回外用"),
twice("001000603", "1日2回外用"),
thrice("001000604", "1日数回外用"),
onceTwice("001000614", "1日1〜2回外用"),
twiceThrice("001000615", "1日2〜3回外用");
public final String code, str;
private Admin2(String code, String str) {
this.code = code;
this.str = str;
}
}
public StampHolderPopupMenu(StampHolder ctx) {
this.ctx = ctx;
}
/**
* 外用剤,内服薬,それぞれに適切なメニュー項目を加える
*/
public void addStampChangeMenu() {
BundleMed bundle = (BundleMed) ctx.getStamp().getModel();
if (ClaimConst.RECEIPT_CODE_NAIYO.equals(bundle.getClassCode()) ||
ClaimConst.RECEIPT_CODE_TONYO.equals(bundle.getClassCode())) {
// 内服薬用の変更メニューを加える
addBundleChangeMenu();
} else {
// 外用剤用の変更メニューを加える
addDoseChangeMenu();
}
}
/**
* 内服薬の変更 menu を作る
* @return
*/
public void addBundleChangeMenu() {
// コメント追加
add(new PutCommentAction());
// 一般名処方
add(new PutGenericNameAction());
addSeparator();
// 処方日数メニュー
for (int n : BUNDLE_NUMS) {
add(new BundleChangeAction(n));
}
addSeparator();
// 用法メニュー
// for (Admin admin : Admin.values()) {
// add(new AdminChangeAction(admin));
// }
add(new AdminChangeAction(Admin.once1));
add(new AdminChangeAction(Admin.once2));
add(new AdminChangeAction(Admin.once3));
add(new AdminChangeAction(Admin.once4));
addSeparator();
add(new AdminChangeAction(Admin.twice1));
add(new AdminChangeAction(Admin.twice2));
addSeparator();
add(new AdminChangeAction(Admin.thrice1));
addSeparator();
// 量調整メニュー
add(new DoseChangeAction2("2"));
add(new DoseChangeAction2("3"));
add(new DoseChangeAction2("1/2"));
add(new DoseChangeAction2("1/3"));
}
/**
* 外用剤の変更 menu を作る
*/
public void addDoseChangeMenu() {
// コメント追加
add(new PutCommentAction());
// 外用剤の部位メニュー
add(new PutRegionAction());
// 一般名処方
add(new PutGenericNameAction());
addSeparator();
// 外用剤の量メニュー
for (int n : DOSES) {
add(new DoseChangeAction(n));
}
addSeparator();
// 外用回数変更メニュー
for (Admin2 admin : Admin2.values()) {
add(new AdminChangeAction2(admin));
}
}
/**
* StampHolder に通知
*/
public void propertyChanged(ModuleModel stamp) {
firePropertyChange(StampHolder.STAMP_MODIFIED, null, stamp);
}
/**
* ClaimItem の code から,1日何回投与かを判断して返す cf. order/AdminMaster.java
* @param code
* @return
*/
private int getTimes(String code) {
if (code.startsWith("0010001")) return 1;
if (code.startsWith("0010002")) return 2;
if (code.startsWith("0010003")) return 3;
return 0;
}
/**
* スタンプを複製して返す。bundle もコピーされる。ただし ClaimItem は空。
* @return
*/
private ModuleModel createModuleModel(ModuleModel src) {
ModuleInfoBean srcModuleInfo = src.getModuleInfo();
BundleMed srcBundle = (BundleMed) src.getModel();
// 複製
ModuleModel dist = new ModuleModel();
BundleMed distBundle = createBundleMed(srcBundle);
dist.setModel(distBundle);
ModuleInfoBean distModuleInfo = dist.getModuleInfo();
distModuleInfo.setEntity(srcModuleInfo.getEntity());
distModuleInfo.setStampRole(srcModuleInfo.getStampRole());
distModuleInfo.setStampName(srcModuleInfo.getStampName());
return dist;
}
/**
* BundleMed を複製して返す。ただし ClaimItem は空。
* @param src
* @return
*/
private BundleMed createBundleMed(BundleMed src) {
BundleMed dist = new BundleMed();
dist.setAdmin(src.getAdmin());
dist.setAdminCode(src.getAdminCode());
dist.setAdminCodeSystem(src.getAdminCodeSystem());
dist.setAdminMemo(src.getAdminMemo());
dist.setBundleNumber(src.getBundleNumber());
dist.setClassCode(src.getClassCode());
dist.setClassCodeSystem(src.getClassCodeSystem());
dist.setClassName(src.getClassName());
dist.setMemo(src.getMemo());
dist.setOrderName(src.getOrderName());
return dist;
}
/**
* ClaimItem を複製して返す
* @param src
* @return
*/
private ClaimItem createClaimItem(ClaimItem src) {
ClaimItem dist = new ClaimItem();
dist.setClassCode(src.getClassCode());
dist.setClassCodeSystem(src.getClassCodeSystem());
dist.setCode(src.getCode());
dist.setName(src.getName());
dist.setNumber(src.getNumber());
dist.setNumberCode(src.getNumberCode());
dist.setNumberCodeSystem(src.getNumberCodeSystem());
dist.setUnit(src.getUnit());
return dist;
}
/**
* オリジナルの ClaimItem[] を複製して返す
* @return
*/
private ClaimItem[] createClaimItemInArray() {
ClaimItem[] src = ((BundleMed)ctx.getStamp().getModel()).getClaimItem();
ArrayList<ClaimItem> dist = new ArrayList<ClaimItem>();
for(ClaimItem c : src) dist.add(createClaimItem(c));
return dist.toArray(new ClaimItem[dist.size()]);
}
/**
* 分数対応で文字列を double にして返す
* @param str
* @return
*/
public static double stringToDouble(String str) {
String[] num = str.split("/");
if (num.length == 1) return Double.parseDouble(str);
else return Double.parseDouble(num[0]) / Double.parseDouble(num[1]);
}
/**
* 処方日数を変更するアクション
*/
private class BundleChangeAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private int value;
public BundleChangeAction(int value) {
this.value = value;
BundleMed bundle = (BundleMed) ctx.getStamp().getModel();
String label = ClaimConst.RECEIPT_CODE_NAIYO.equals(bundle.getClassCode())? " 日分" : " 回分";
putValue(AbstractAction.NAME, String.valueOf(value) + label);
}
@Override
public void actionPerformed(ActionEvent e) {
// 変更されていなければそのまま帰る
BundleMed srcBundle = (BundleMed) ctx.getStamp().getModel();
if (srcBundle.getBundleNumber().equals(String.valueOf(value))) return;
// コピーして stamp を新たに作成
ModuleModel stamp = createModuleModel(ctx.getStamp());
BundleMed bundle = (BundleMed) stamp.getModel();
// ClaimItem をコピー
bundle.setClaimItem(createClaimItemInArray());
// 何日分の部分をセット
bundle.setBundleNumber(String.valueOf(value));
propertyChanged(stamp);
}
}
/**
* 内服の用法(1日3回毎食後など)を変更するアクション
*/
private class AdminChangeAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private Admin admin;
public AdminChangeAction(Admin admin) {
this.admin = admin;
putValue(AbstractAction.NAME, admin.str);
}
@Override
public void actionPerformed(ActionEvent e) {
// 変更されていなければそのまま帰る
BundleMed srcBundle = (BundleMed) ctx.getStamp().getModel();
if (admin.code.equals(srcBundle.getAdminCode())) return;
// 新たなスタンプ作成
ModuleModel stamp = createModuleModel(ctx.getStamp());
BundleMed bundle = (BundleMed) stamp.getModel();
bundle.setAdmin(admin.str);
bundle.setAdminCode(admin.code);
// 変更に応じて投与量が何倍になるか = factor
int srcTimes = getTimes(srcBundle.getAdminCode());
int distTimes = getTimes(admin.code);
double factor = (srcTimes==0)? 1 : (double)distTimes/srcTimes;
ArrayList<ClaimItem> list = new ArrayList<ClaimItem>();
// ClaimItem をチェックしながらコピー
for(ClaimItem src : srcBundle.getClaimItem()) {
ClaimItem dist = createClaimItem(src);
String str = dist.getName();
// 1日量文字列がある場合は,投与量を調節する
if (str.contains("日量")) {
double dose = DailyDoseStringTool.getDose(str) * factor;
dist.setName(DailyDoseStringTool.getString(str, dose));
}
list.add(dist);
}
// できた list を srcBundle に登録
bundle.setClaimItem(list.toArray(new ClaimItem[list.size()]));
propertyChanged(stamp);
}
}
/**
* 外用剤の外用回数(1日2回外用など)を変更するアクション
*/
private class AdminChangeAction2 extends AbstractAction {
private static final long serialVersionUID = 1L;
private Admin2 admin;
public AdminChangeAction2(Admin2 admin) {
this.admin = admin;
putValue(AbstractAction.NAME, admin.str);
}
@Override
public void actionPerformed(ActionEvent e) {
BundleMed srcBundle = (BundleMed) ctx.getStamp().getModel();
// 変更されていなければそのまま帰る
if (admin.code.equals(srcBundle.getAdminCode())) return;
ModuleModel stamp = createModuleModel(ctx.getStamp());
BundleMed bundle = (BundleMed) stamp.getModel();
bundle.setAdmin(admin.str);
bundle.setAdminCode(admin.code);
bundle.setClaimItem(createClaimItemInArray());
propertyChanged(stamp);
}
}
/**
* 外用剤の処方量を変更するアクション
*/
private class DoseChangeAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private int value;
public DoseChangeAction(int value) {
this.value = value;
ClaimItem[] item = ((BundleMed) ctx.getStamp().getModel()).getClaimItem();
putValue(AbstractAction.NAME, String.valueOf(value) + " " + item[0].getUnit());
}
@Override
public void actionPerformed(ActionEvent e) {
BundleMed srcBundle = (BundleMed)ctx.getStamp().getModel();
// 新たなスタンプ作成
ModuleModel stamp = createModuleModel(ctx.getStamp());
BundleMed bundle = (BundleMed) stamp.getModel();
ArrayList<ClaimItem> list = new ArrayList<ClaimItem>();
// ClaimItem をチェックしながらコピー
boolean changed = false;
String num = String.valueOf(value);
for(ClaimItem src : srcBundle.getClaimItem()) {
ClaimItem dist = createClaimItem(src);
if (src.getCode().startsWith("6") && !src.getNumber().equals(num)) {
dist.setNumber(num);
changed = true;
}
list.add(dist);
}
if (changed) {
// できた list を srcBundle に登録
bundle.setClaimItem(list.toArray(new ClaimItem[list.size()]));
propertyChanged(stamp);
}
}
}
/**
* 外用剤の部位を変更するアクション
*/
private class PutRegionAction extends AbstractAction {
private static final long serialVersionUID = 1L;
public PutRegionAction() {
putValue(AbstractAction.NAME, "部位・指示...");
}
@Override
public void actionPerformed(ActionEvent e) {
BundleMed srcBundle = (BundleMed)ctx.getStamp().getModel();
RegionView dialog = new RegionView(null, true);
dialog.setValue(srcBundle.getClaimItem());
// ダイアログ表示位置計算 できればスタンプの上に,上にスペースがなければ下に
Point p = ctx.getLocationOnScreen();
int y; p.y = (y = p.y - dialog.getHeight() - 10)>30? y: p.y + ctx.getHeight() + 10;
dialog.setLocation(p);
dialog.setVisible(true);
// キャンセルされた場合はそのまま帰る
if (dialog.isCancelled()) {
dialog.dispose();
return;
}
// 新たなスタンプ作成
ModuleModel stamp = createModuleModel(ctx.getStamp());
BundleMed bundle = (BundleMed) stamp.getModel();
// あらたな ClaimItem を作る
ArrayList<ClaimItem> list = new ArrayList<ClaimItem>();
// 部位 ClaimItem 以外をコピー 001000607,608,001,002 はマスター設定の問題で別扱い
for (ClaimItem src : srcBundle.getClaimItem()) {
if (!src.getCode().startsWith("0010008")
&& !src.getCode().startsWith("0010009")
&& !src.getCode().equals("001000607")
&& !src.getCode().equals("001000608")
&& !src.getCode().equals("001000001")
&& !src.getCode().equals("001000002")
) {
list.add(createClaimItem(src));
}
}
// 部位 ClaimItem は dialog からデータを取り込む
list.addAll(dialog.getValue());
// できた list を srcBundle に登録
bundle.setClaimItem(list.toArray(new ClaimItem[list.size()]));
dialog.dispose();
propertyChanged(stamp);
}
}
/**
* 内服薬の用量を変更するアクション。何倍にするかで指定する
*/
private class DoseChangeAction2 extends AbstractAction {
private static final long serialVersionUID = 1L;
private double value;
public DoseChangeAction2(String str) {
value = stringToDouble(str);
putValue(AbstractAction.NAME, "用量を " + String.valueOf(str) + " 倍に");
}
@Override
public void actionPerformed(ActionEvent e) {
BundleMed srcBundle = (BundleMed)ctx.getStamp().getModel();
// 新たなスタンプ作成
ModuleModel stamp = createModuleModel(ctx.getStamp());
BundleMed bundle = (BundleMed) stamp.getModel();
// あらたな ClaimItem を作る
ArrayList<ClaimItem> list = new ArrayList<ClaimItem>();
for (ClaimItem src : srcBundle.getClaimItem()) {
ClaimItem dist = createClaimItem(src);
// 薬剤コードがあれば,その量を調整
if (src.getCode().startsWith("6")) {
double num = Double.valueOf(src.getNumber());
String s = DailyDoseStringTool.doubleToString(num*value, src.getUnit());
dist.setNumber(String.valueOf(s));
}
// 1日量文字列があれば,その量を調節
String str = src.getName();
if (str.contains("日量")) {
double dose = DailyDoseStringTool.getDose(str);
dose *= value;
dist.setName(DailyDoseStringTool.getString(str, dose));
}
list.add(dist);
}
// できた list を srcBundle に登録
bundle.setClaimItem(list.toArray(new ClaimItem[list.size()]));
propertyChanged(stamp);
}
}
/**
* コメントを付けるアクション
*/
private class PutCommentAction extends AbstractAction {
private static final long serialVersionUID = 1L;
public PutCommentAction() {
putValue(AbstractAction.NAME, "コメント...");
}
@Override
public void actionPerformed(ActionEvent e) {
final JTextField tf = new JTextField(10);
String[] options = {"追加", "上書き", "キャンセル"};
JOptionPane pane = new JOptionPane(tf,
JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null,
options, options[0]) {
// 初期状態でボタンでなく,tf にフォーカスを取る
private static final long serialVersionUID = 1L;
@Override
public void selectInitialValue() {
tf.requestFocusInWindow();
}
};
JDialog dialog = pane.createDialog("コメント入力");
dialog.setModal(true);
// ダイアログ表示位置計算 できればスタンプの上に,上にスペースがなければ下に
Point p = ctx.getLocationOnScreen();
int y; p.y = (y = p.y - dialog.getHeight() - 10)>30? y: p.y + ctx.getHeight() + 10;
dialog.setLocation(p);
dialog.setVisible(true);
// getValue() の値 -1=エスケープでキャンセル,null=赤ボタンで消した, 文字=optionsの文字
Object ans = pane.getValue();
// キャンセルの場合はそのまま帰る
if (!options[0].equals(ans) && !options[1].equals(ans)) {
return;
}
// 新たなスタンプ作成
BundleMed srcBundle = (BundleMed)ctx.getStamp().getModel();
ModuleModel stamp = createModuleModel(ctx.getStamp());
BundleMed bundle = (BundleMed) stamp.getModel();
ArrayList<ClaimItem> list = new ArrayList<ClaimItem>();
// 既存のコメント以外はそのまま登録,追加登録の場合は既存のコメントも登録
for(ClaimItem src : srcBundle.getClaimItem()) {
if (!src.getCode().startsWith("810000001") || options[0].equals(ans)) {
list.add(createClaimItem(src));
}
}
// あらたな ClaimItem を作る
ClaimItem newComment = new ClaimItem();
newComment.setClassCode("2");
newComment.setClassCodeSystem("Claim003");
newComment.setCode("810000001");
newComment.setName(tf.getText());
newComment.setNumber(".");
newComment.setNumberCode(ClaimConst.YAKUZAI_TOYORYO); // = "10"
newComment.setNumberCodeSystem("Claim004");
// コメントを登録,ただしコメントに何も入力されていなければリストに追加しない
if (!tf.getText().trim().equals("")) {
list.add(newComment);
}
// できた list を srcBundle に登録
bundle.setClaimItem(list.toArray(new ClaimItem[list.size()]));
dialog.dispose();
propertyChanged(stamp);
}
}
/**
* 一般名記載コメントをつけるアクション
*/
private class PutGenericNameAction extends AbstractAction {
private static final long serialVersionUID = 1L;
public PutGenericNameAction() {
putValue(AbstractAction.NAME, "一般名記載");
}
@Override
public void actionPerformed(ActionEvent e) {
// 一般名処方 ClaimItem を作る
ClaimItem generic = new ClaimItem();
generic.setClassCode("2");
generic.setClassCodeSystem("Claim003");
generic.setCode("099209908");
generic.setName("一般名記載");
generic.setNumber(".");
generic.setNumberCode(ClaimConst.YAKUZAI_TOYORYO); // = "10"
generic.setNumberCodeSystem("Claim004");
// 新たなスタンプ作成
BundleMed srcBundle = (BundleMed)ctx.getStamp().getModel();
ModuleModel stamp = createModuleModel(ctx.getStamp());
BundleMed bundle = (BundleMed) stamp.getModel();
ArrayList<ClaimItem> list = new ArrayList<ClaimItem>();
// 薬を検索して,最初に見つかった薬の後に一般名処方を入れる
boolean found = false;
for(ClaimItem src : srcBundle.getClaimItem()) {
list.add(createClaimItem(src));
if (!found && src.getCode().startsWith("6")) {
list.add(generic);
found = true;
}
}
// できた list を srcBundle に登録
bundle.setClaimItem(list.toArray(new ClaimItem[list.size()]));
propertyChanged(stamp); }
}
}