package open.dolphin.client;
import java.awt.*;
import java.awt.event.*;
import java.beans.EventHandler;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import java.util.logging.Level;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.event.*;
import net.sf.jooreports.templates.DocumentTemplate;
import net.sf.jooreports.templates.DocumentTemplateFactory;
import open.dolphin.delegater.DocumentDelegater;
import open.dolphin.helper.PdfOfficeIconRenderer;
import open.dolphin.helper.SimpleWorker;
import open.dolphin.helper.UserDocumentHelper;
import open.dolphin.helper.WindowSupport;
import open.dolphin.impl.care.CareMapDocument;
import open.dolphin.impl.img.DefaultBrowserEx;
import open.dolphin.impl.img.ImageBrowserProxy;
import open.dolphin.impl.lbtest.LaboTestBean;
import open.dolphin.infomodel.*;
import open.dolphin.plugin.PluginLister;
import open.dolphin.plugin.PluginLoader;
import open.dolphin.project.Project;
import open.dolphin.util.AgeCalculater;
import open.dolphin.util.GUIDGenerator;
import open.dolphin.util.MMLDate;
/**
* 2号カルテ、傷病名、検査結果履歴等、患者の総合的データを提供するクラス。
*
* @author Kazushi Minagawa, Digital Globe, Inc.
*/
public class ChartImpl extends AbstractMainTool implements Chart, IInfoModel {
// Bound property name of Chart state
public static final String CHART_STATE = "chartStateProp";
// Bits of Chart state
public static final int BIT_OPEN = 0;
public static final int BIT_SAVE_CLAIM = 1;
public static final int BIT_MODIFY_CLAIM = 2;
// Chart インスタンスを管理するstatic 変数 masuda
private static final List<ChartImpl> allCharts = new CopyOnWriteArrayList<>();
// Logger
private static final boolean DEBUG=false;
private static final java.util.logging.Logger logger;
static {
logger = java.util.logging.Logger.getLogger(ChartImpl.class.getName());
logger.setLevel(DEBUG ? Level.FINE : Level.INFO);
}
// Document Plugin を格納する TabbedPane
private JTabbedPane tabbedPane;
// Active になっているDocument Plugin
private HashMap<String, ChartDocument> providers;
// 患者インスペクタ
private PatientInspector inspector;
// Window Menu をサポートする委譲クラス
private WindowSupport windowSupport;
// Toolbar
private JPanel myToolPanel;
// 検索状況等を表示する共通のパネル
private IStatusPanel statusPanel;
// 患者来院情報
private PatientVisitModel pvt;
// Read Only の時 true
private boolean readOnly;
// Chart のステート
private int chartState;
// Chart内のドキュメントに共通の MEDIATOR
private ChartMediator mediator;
// State Mgr
private StateMgr stateMgr;
// PPane に Dropされた病名タンプ
private List<ModuleInfoBean> droppedDiagnosis;
// MML送信 listener
private MmlMessageListener mmlListener;
// CLAIM 送信 listener
private ClaimMessageListener claimListener;
// このチャートの KarteBean
private KarteBean karte;
// GlassPane
private BlockGlass blockGlass;
// タイマー
private ScheduledExecutorService scheduler;
private ScheduledFuture<?> beeperHandle;
private long statred;
private final long delay = 10L;
// task
private int delayCount;
private ProgressMonitor monitor;
private Timer taskTimer;
// List of dirty documents
private List<UnsavedDocument> dirtyList;
/**
* Creates new ChartService
*/
public ChartImpl() {
}
/**
* オープンしている全インスタンスを保持するリストを返す。
* @return オープンしている ChartPlugin のリスト
*/
public static List<ChartImpl> getAllChart() {
return allCharts;
}
/**
* このチャートのカルテを返す。
* @return カルテ
*/
@Override
public KarteBean getKarte() {
return karte;
}
/**
* このチャートのカルテを設定する。
* @param karte このチャートのカルテ
*/
@Override
public void setKarte(KarteBean karte) {
this.karte = karte;
}
/**
* Chart の JFrame を返す。
* @return チャートウインドウno JFrame
*/
@Override
public JFrame getFrame() {
return windowSupport.getFrame();
}
/**
* Chart内ドキュメントが共通に使用する Status パネルを返す。
* @return IStatusPanel
*/
@Override
public IStatusPanel getStatusPanel() {
return statusPanel;
}
/**
* Chart内ドキュメントが共通に使用する Status パネルを設定する。
* @param statusPanel IStatusPanel
*/
@Override
public void setStatusPanel(IStatusPanel statusPanel) {
this.statusPanel = statusPanel;
}
/**
* 来院情報を設定する。
* @param pvt 来院情報
*/
@Override
public void setPatientVisit(PatientVisitModel pvt) {
this.pvt = pvt;
}
/**
* 来院情報を返す。
* @return 来院情報
*/
@Override
public PatientVisitModel getPatientVisit() {
return pvt;
}
/**
* ReadOnly かどうかを返す。
* @return ReadOnlyの時 true
*/
@Override
public boolean isReadOnly() {
return readOnly;
}
/**
* ReadOnly 属性を設定する。
* @param readOnly ReadOnly user の時 true
*/
@Override
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
/**
* このチャートが対象としている患者モデルを返す。
* @return チャートが対象としている患者モデル
*/
@Override
public PatientModel getPatient() {
return getKarte().getPatientModel();
}
/**
* チャートのステート属性を返す。
* @return チャートのステート属性
*/
@Override
public int getChartState() {
return chartState;
}
/**
* チャートのステートを設定する。
* @param chartState チャートステート
*/
@Override
public void setChartState(int chartState) {
}
/**
* チャート内で共通に使用する Mediator を返す。
* @return ChartMediator
*/
@Override
public ChartMediator getChartMediator() {
return mediator;
}
/**
* チャート内で共通に使用する Mediator を設定する。
* @param mediator ChartMediator
*/
public void setChartMediator(ChartMediator mediator) {
this.mediator = mediator;
}
/**
* Menu アクションを制御する。
* @param name
* @param enabled
*/
@Override
public void enabledAction(String name, boolean enabled) {
Action action = mediator.getAction(name);
if (action != null) {
action.setEnabled(enabled);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
/**
* 文書ヒストリオブジェクトを返す。
* @return 文書ヒストリオブジェクト DocumentHistory
*/
@Override
public DocumentHistory getDocumentHistory() {
return inspector.getDocumentHistory();
}
/**
* 引数で指定されたタブ番号のドキュメントを表示する。
* @param index
*/
@Override
public void showDocument(int index) {
int cnt = tabbedPane.getTabCount();
if (index >= 0 && index <= cnt - 1 && index != tabbedPane.getSelectedIndex()) {
tabbedPane.setSelectedIndex(index);
}
}
//s.oh^ 2014/04/03 文書の複製
public boolean isShowDocument(int idx) {
return tabbedPane.getSelectedIndex() == idx;
}
//s.oh$
/**
* Ppane にDropされた病名スタンプをリストに保存する。
* @param dropped Ppane にDropされた病名スタンプ
*/
@Override
public void addDroppedDiagnosis(ModuleInfoBean dropped) {
if (droppedDiagnosis==null) {
droppedDiagnosis = new ArrayList<>(2);
}
droppedDiagnosis.add(dropped);
int index = tabbedPane.getSelectedIndex();
String key = String.valueOf(index);
ChartDocument plugin = (ChartDocument) providers.get(key);
if (plugin.getContext() != null && plugin instanceof DiagnosisDocument) {
((DiagnosisDocument)plugin).addDroppedDiagnosis();
}
}
/**
* Ppane にDropされた病名スタンプをリストを返す。
* @return 病名スタンプリスト
*/
@Override
public List<ModuleInfoBean> getDroppedDiagnosisList() {
return droppedDiagnosis;
}
/**
* チャート内に未保存ドキュメントがあるかどうかを返す。
* @return 未保存ドキュメントがある時 true
*/
@Override
public boolean isDirty() {
boolean dirty = false;
if (providers != null && providers.size() > 0) {
Collection<ChartDocument> docs = providers.values();
for (ChartDocument doc : docs) {
if (doc.isDirty()) {
dirty = true;
break;
}
}
}
return dirty;
}
@Override
public void start() {
final SimpleWorker worker = new SimpleWorker<KarteBean, Void>() {
@Override
protected KarteBean doInBackground() throws Exception {
// Database から患者のカルテを取得する
int past = Project.getInt(Project.DOC_HISTORY_PERIOD, -12);
GregorianCalendar today = new GregorianCalendar();
today.add(GregorianCalendar.MONTH, past);
today.clear(Calendar.HOUR_OF_DAY);
today.clear(Calendar.MINUTE);
today.clear(Calendar.SECOND);
today.clear(Calendar.MILLISECOND);
DocumentDelegater ddl = new DocumentDelegater();
KarteBean karteBean = ddl.getKarte(getPatientVisit().getPatientModel().getId(), today.getTime());
return karteBean;
}
@Override
protected void succeeded(KarteBean karteBean) {
//-------------------------------------------------------------
karteBean.setPatientModel(null);
karteBean.setPatientModel(getPatientVisit().getPatientModel());
setKarte(karteBean);
//-------------------------------------------------------------
initComponents();
SwingUtilities.invokeLater(() -> {
getDocumentHistory().showHistory();
});
}
@Override
protected void cancelled() {
logger.info("Task cancelled");
}
@Override
protected void failed(java.lang.Throwable cause) {
logger.severe("Task failed");
logger.severe(cause.getMessage());
}
@Override
protected void startProgress() {
delayCount = 0;
taskTimer.start();
}
@Override
protected void stopProgress() {
taskTimer.stop();
monitor.close();
taskTimer = null;
monitor = null;
}
};
java.util.ResourceBundle bundle = ClientContext.getMyBundle(ChartImpl.class);
String message = bundle.getString("message.openKarte.progress");
String noteMessage = bundle.getString("note.openKarte.progress");
String resMaxEstimation = bundle.getString("maxEstimation.openKarte.progress");
String resTimerDelay = bundle.getString("timerDelay.openKarte.progress");
String pname = getPatientVisit().getPatientModel().getFullName();
MessageFormat msft = new MessageFormat(noteMessage);
String note = msft.format(new Object[]{pname});
int maxEstimation = Integer.parseInt(resMaxEstimation);
int dl = Integer.parseInt(resTimerDelay);
Component c = null;
monitor = new ProgressMonitor(c, message, note, 0, maxEstimation / dl);
taskTimer = new Timer(dl, (ActionEvent e) -> {
delayCount++;
if (monitor.isCanceled() && (!worker.isCancelled())) {
worker.cancel(true);
} else {
monitor.setProgress(delayCount);
}
});
worker.execute();
}
public void initComponents() {
//---------------------------------------------
// このチャート の Frame を生成し初期化する。
// Frame のタイトルを
// 患者氏名(カナ):患者ID に設定する
//---------------------------------------------
String patientName = getPatient().getFullName();
String kana = getPatient().getKanaName().replace(" ", " ");
String patientId = getPatient().getPatientId();
java.util.ResourceBundle bundle = ClientContext.getMyBundle(ChartImpl.class);
String inspectorFormat = bundle.getString("messageFormat.chart.frame");
MessageFormat msf0 = new MessageFormat(inspectorFormat);
String inspectorTitle = msf0.format(new Object[]{patientName,kana,patientId});
// Frame と MenuBar を生成する
windowSupport = WindowSupport.create(inspectorTitle);
// チャート用のメニューバーを得る
JMenuBar myMenuBar = windowSupport.getMenuBar();
// チャートの JFrame オブジェクトを得る
JFrame frame = windowSupport.getFrame();
// ChartMediator を生成する
mediator = new ChartMediator(this);
// 患者インスペクタを生成する
inspector = new PatientInspector(this);
inspector.getPanel().setBorder(BorderFactory.createEmptyBorder(7, 7, 5, 2)); // カット&トライ
// Status パネルを生成する
statusPanel = new StatusPanel();
// Status パネルに表示する情報を生成する
// カルテ登録日 Status パネルの右側に配置する
String rdFormat = bundle.getString("dateFormat.registered.rightInfo");
String rightInfoText = bundle.getString("messageFormat.rightInfo.chart");
String leftInfoText1 = bundle.getString("messageFormat.leftInfo.lastDocDate");
String leftInfoText2 = bundle.getString("messageFormat.leftInfo.newVisit");
Date date = getKarte().getCreated();
SimpleDateFormat sdf = new SimpleDateFormat(rdFormat);
String created = sdf.format(date);
MessageFormat msf = new MessageFormat(rightInfoText);
String rightInfo = msf.format(new Object[]{created});
statusPanel.setRightInfo(rightInfo); // カルテ登録日:yyyy/mm/dd
SimpleDateFormat frmt = new SimpleDateFormat(IInfoModel.DATE_WITHOUT_TIME);
Date lastDocDate = getKarte().getLastDocDate();
String pid = getKarte().getPatient().getPatientId();
if (lastDocDate != null) {
String lastDocStr = frmt.format(lastDocDate);
msf = new MessageFormat(leftInfoText1);
statusPanel.setLeftInfo(msf.format(new Object[]{pid, lastDocStr}));
} else {
msf = new MessageFormat(leftInfoText2);
statusPanel.setLeftInfo(msf.format(new Object[]{pid}));
}
//-------------------------------------------------------------
// Menu を生成する
//-------------------------------------------------------------
AbstractMenuFactory appMenu = AbstractMenuFactory.getFactory();
appMenu.setMenuSupports(getContext().getMenuSupport(), mediator);
appMenu.build(myMenuBar);
mediator.registerActions(appMenu.getActionMap());
myToolPanel = appMenu.getToolPanelProduct();
myToolPanel.add(inspector.getBasicInfoInspector().getPanel(), 0);
// adminとそれ以外
Action addUserAction = mediator.getAction(GUIConst.ACTION_ADD_USER);
boolean admin = false;
Collection<RoleModel> roles = Project.getUserModel().getRoles();
for (RoleModel model : roles) {
if (model.getRole().equals(GUIConst.ROLE_ADMIN)) {
admin = true;
break;
}
}
addUserAction.setEnabled(admin);
//s.oh^ 2014/04/16 メニュー制御
mediator.getAction(GUIConst.ACTION_EDIT_FACILITY_INFO).setEnabled(admin);
//s.oh$
//---------------------------------
// このクラス固有のToolBarを生成する
//---------------------------------
JToolBar toolBar = appMenu.getToolBar();
toolBar.addSeparator();
// テキストツールを生成する
Action action = mediator.getActions().get(GUIConst.ACTION_INSERT_TEXT);
final JToggleButton textBtn = new JToggleButton();
//textBtn.setName("textBtn");
textBtn.setAction(action);
textBtn.addItemListener((ItemEvent ie) -> {
if (ie.getStateChange()==ItemEvent.SELECTED) {
if (mediator.getActions().get(GUIConst.ACTION_INSERT_TEXT).isEnabled()) {
JPopupMenu menu = new JPopupMenu();
mediator.addTextMenu(menu);
menu.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent pme) {
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent pme) {
textBtn.setSelected(false);
}
@Override
public void popupMenuCanceled(PopupMenuEvent pme) {
textBtn.setSelected(false);
}
});
Component c = (Component)ie.getSource();
menu.show(c, 0, c.getHeight());
}
}
});
textBtn.setFocusable(false);
textBtn.setBorderPainted(false);
textBtn.setMargin(new Insets(3,3,3,3));
toolBar.add(textBtn);
// シェーマツールを生成する
action = mediator.getActions().get(GUIConst.ACTION_INSERT_SCHEMA);
final JToggleButton schemaBtn = new JToggleButton();
schemaBtn.setAction(action);
schemaBtn.addItemListener((ItemEvent ie) -> {
if (ie.getStateChange()==ItemEvent.SELECTED) {
if (mediator.getActions().get(GUIConst.ACTION_INSERT_SCHEMA).isEnabled()) {
getContext().showSchemaBox();
}
schemaBtn.setSelected(false);
}
});
schemaBtn.setFocusable(false);
schemaBtn.setBorderPainted(false);
schemaBtn.setMargin(new Insets(3,3,3,3));
toolBar.add(schemaBtn);
// スタンプツールを生成する
action = mediator.getActions().get(GUIConst.ACTION_INSERT_STAMP);
final JToggleButton stampBtn = new JToggleButton();
stampBtn.setAction(action);
stampBtn.addItemListener((ItemEvent ie) -> {
if (ie.getStateChange()==ItemEvent.SELECTED) {
if (mediator.getActions().get(GUIConst.ACTION_INSERT_STAMP).isEnabled()) {
JPopupMenu menu = new JPopupMenu();
mediator.addStampMenu(menu);
menu.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent pme) {
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent pme) {
stampBtn.setSelected(false);
}
@Override
public void popupMenuCanceled(PopupMenuEvent pme) {
stampBtn.setSelected(false);
}
});
Component c = (Component)ie.getSource();
menu.show(c, 0, c.getHeight());
}
}
});
stampBtn.setFocusable(false);
stampBtn.setBorderPainted(true);
stampBtn.setMargin(new Insets(3,3,3,3));
toolBar.add(stampBtn);
//-------------------------------------------------------------
// 保険選択ツールを生成する
// 保険の切り替え(変更)で karteEditorの applyInsurance が起動される
//-------------------------------------------------------------
action = mediator.getActions().get(GUIConst.ACTION_SELECT_INSURANCE);
final JToggleButton insBtn = new JToggleButton();
insBtn.setAction(action);
insBtn.addItemListener((ItemEvent ie) -> {
if (ie.getStateChange()==ItemEvent.SELECTED) {
if (mediator.getActions().get(GUIConst.ACTION_SELECT_INSURANCE).isEnabled()) {
JPopupMenu menu = new JPopupMenu();
PVTHealthInsuranceModel[] insurances = getHealthInsurances();
for (PVTHealthInsuranceModel hm : insurances) {
ReflectActionListener ra = new ReflectActionListener(mediator,
"applyInsurance",
new Class[]{hm.getClass()},
new Object[]{hm});
JMenuItem mi = new JMenuItem(hm.toString());
mi.addActionListener(ra);
menu.add(mi);
}
menu.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent pme) {
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent pme) {
insBtn.setSelected(false);
}
@Override
public void popupMenuCanceled(PopupMenuEvent pme) {
insBtn.setSelected(false);
}
});
Component c = (Component)ie.getSource();
menu.show(c, 0, c.getHeight());
}
}
});
insBtn.setFocusable(false);
insBtn.setBorderPainted(true);
insBtn.setMargin(new Insets(3,3,3,3));
toolBar.add(insBtn);
//s.oh^ テキストの挿入 2013/08/12
if(Project.getString(GUIConst.ACTION_SOAPANE_INSERTTEXT_DIR, "").length() > 0) {
toolBar.addSeparator();
JButton insertSOATextBtn = new JButton();
insertSOATextBtn.setAction(mediator.getActions().get("insertSOAText"));
insertSOATextBtn.setText(null);
String toolTipText = bundle.getString("toolTipText.insertSOATextBtn");
insertSOATextBtn.setToolTipText(toolTipText);
insertSOATextBtn.setMargin(new Insets(3,3,3,3));
insertSOATextBtn.setFocusable(false);
insertSOATextBtn.setBorderPainted(true);
toolBar.add(insertSOATextBtn);
}
if(Project.getString(GUIConst.ACTION_PPANE_INSERTTEXT_DIR, "").length() > 0) {
toolBar.addSeparator();
JButton insertPTextBtn = new JButton();
insertPTextBtn.setAction(mediator.getActions().get("insertPText"));
insertPTextBtn.setText(null);
String toolTipText = bundle.getString("toolTipText.insertPTextBtn");
insertPTextBtn.setToolTipText(toolTipText);
insertPTextBtn.setMargin(new Insets(3,3,3,3));
insertPTextBtn.setFocusable(false);
insertPTextBtn.setBorderPainted(true);
toolBar.add(insertPTextBtn);
}
//s.oh$
//s.oh^ 他プロセス連携(アイコン) 2014/05/09
if(Project.getBoolean(GUIConst.ACTION_OTHERPROCESS_ICON, false)) {
toolBar.addSeparator();
int num = Project.getInt("otherprocessicon.link.num", 0);
for(int i = 1; i < num+1; i++) {
final String KEY_DEF = "otherprocessicon" + String.valueOf(i) + ".link";
JButton linkBtn = new JButton();
final ChartImpl chart = this;
//linkBtn.setAction(mediator.getActions().get("otherProcessIcon" + String.valueOf(i) + "Link"));
linkBtn.addActionListener((ActionEvent e) -> {
DefaultBrowserEx.otherProcess(KEY_DEF, chart, Project.getString(KEY_DEF + ".path"), Project.getString(KEY_DEF + ".param"), null);
});
//s.oh^ 他プロセス連携(アイコン) 2014/07/15
String iconPath = Project.getString(KEY_DEF + ".icon");
if(iconPath != null) {
linkBtn.setIcon(new ImageIcon(iconPath));
}
//s.oh$
linkBtn.setText(null);
linkBtn.setToolTipText(Project.getString(KEY_DEF + ".tooltip"));
linkBtn.setMargin(new Insets(3,3,3,3));
linkBtn.setFocusable(false);
//linkBtn.setBorderPainted(true);
toolBar.add(linkBtn);
}
}
//s.oh$
// Document プラグインのタブを生成する
tabbedPane = loadDocuments();
// 全体をレイアウトする
inspector.getPanel().setPreferredSize(new Dimension(280, 620));
JPanel tmp = new JPanel(new BorderLayout());
tmp.add(myToolPanel, BorderLayout.NORTH);
tmp.add(inspector.getPanel(), BorderLayout.WEST);
tmp.add(tabbedPane, BorderLayout.CENTER);
JPanel myPanel = new JPanel();
myPanel.setOpaque(true);
myPanel.setLayout(new BorderLayout(5, 7));
myPanel.add(tmp, BorderLayout.CENTER);
myPanel.add((JPanel) statusPanel, BorderLayout.SOUTH);
frame.setContentPane(myPanel);
// Injection
textBtn.setIcon(ClientContext.getImageIconArias("icon_text_stap_menu"));
textBtn.setText(null);
String toolTipText = bundle.getString("toolTipText.textBtn");
textBtn.setToolTipText(toolTipText);
schemaBtn.setIcon(ClientContext.getImageIconArias("icon_open_schema_box"));
schemaBtn.setText(null);
toolTipText = bundle.getString("toolTipText.schemaBtn");
schemaBtn.setToolTipText(toolTipText);
stampBtn.setIcon(ClientContext.getImageIconArias("icon_stamp_menu"));
stampBtn.setText(null);
toolTipText = bundle.getString("toolTipText.stampBtn");
stampBtn.setToolTipText(toolTipText);
insBtn.setIcon(ClientContext.getImageIconArias("icon_health_insurance"));
insBtn.setText(null);
toolTipText = bundle.getString("toolTipText.insBtn");
insBtn.setToolTipText(toolTipText);
// StateMgr を生成する
stateMgr = new StateMgr();
// BlockGlass を設定する
blockGlass = new BlockGlass();
frame.setGlassPane(blockGlass);
// このチャートの Window にリスナを設定する
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// CloseBox の処理を行う
if (!blockGlass.isVisible()) {
processWindowClosing();
}
}
@Override
public void windowOpened(WindowEvent e) {
// リストへ追加する
allCharts.add(ChartImpl.this);
}
@Override
public void windowClosed(WindowEvent e) {
// リストから削除し状態変化を通知する
if (allCharts.remove(ChartImpl.this)) {
//
}
}
@Override
public void windowActivated(WindowEvent e) {
// 文書履歴へフォーカスする
getDocumentHistory().requestFocus();
}
});
// Frame の大きさをストレージからロードする
String frameX = bundle.getString("frame.x");
String frameY = bundle.getString("frame.y");
String frameWidth = bundle.getString("frame.width");
String frameHeight = bundle.getString("frame.height");
int x = Integer.parseInt(frameX);
int y = Integer.parseInt(frameY);
int width = Integer.parseInt(frameWidth);
int height = Integer.parseInt(frameHeight);
Rectangle defRect = new Rectangle(x, y, width, height);
Rectangle bounds = Project.getRectangle("chartFrame.bounds", defRect);
// フレームの表示位置を決める J2SE 5.0
boolean locByPlatform = Project.getBoolean(Project.LOCATION_BY_PLATFORM);
if (locByPlatform) {
frame.setLocationByPlatform(true);
frame.setSize(bounds.width, bounds.height);
} else {
frame.setLocationByPlatform(false);
frame.setBounds(bounds);
}
// MML 送信 Queue
if (Project.getBoolean(Project.SEND_MML)) {
mmlListener = (MmlMessageListener)getContext().getPlugin("sendMml");
}
// CLAIM 送信 Queue
// 2012-07 claimSenderIsClientかつisSendClaim()=true の時のみ必要
if (Project.claimSenderIsClient() && isSendClaim()) {
claimListener = (ClaimMessageListener)getContext().getPlugin("sendClaim");
}
getFrame().setVisible(true);
// timer 開始
statred = System.currentTimeMillis();
scheduler = Executors.newSingleThreadScheduledExecutor();
final Runnable beeper = () -> {
long time = System.currentTimeMillis() - statred;
time = time / 1000L;
statusPanel.setTimeInfo(time);
};
beeperHandle = scheduler.scheduleAtFixedRate(beeper, delay, delay, TimeUnit.SECONDS);
}
/**
* MML送信リスナを返す。
* @return MML送信リスナ
*/
@Override
public MmlMessageListener getMMLListener() {
return mmlListener;
}
/**
* CLAIM送信リスナを返す。
* @return CLAIM送信リスナ
*/
@Override
public ClaimMessageListener getCLAIMListener() {
return claimListener;
}
@Override
public boolean isSendClaim() {
// Server-ORCA, 評価で Client-ORA 等を考慮^
boolean send = true;
send = send && (!isReadOnly()); // ReadOnlyではない
send = send && Project.getBoolean(Project.SEND_CLAIM); // CLAIM送信になっている
send = send && Project.canAccessToOrca(); // ORCAにアクセス出来る
return send;
// Server-ORCA, 評価で Client-ORA 等を考慮$
}
@Override
public boolean isSendLabtest() {
boolean send = true;
send = send && (!isReadOnly());
send = send && Project.getBoolean(Project.SEND_LABTEST);
return send;
}
/**
* メニューを制御する。
*/
public void controlMenu() {
stateMgr.controlMenu();
}
/**
* ドキュメントタブを生成する。
*/
private JTabbedPane loadDocuments() {
// ドキュメントプラグインをロードする
//PluginLoader<ChartDocument> loader = PluginLoader.load(ChartDocument.class);
PluginLoader<ChartDocument> loader = PluginLoader.load(ChartDocument.class);
Iterator<ChartDocument> iterator = loader.iterator();
int index = 0;
providers = new HashMap<>();
JTabbedPane tab = new JTabbedPane();
while (iterator.hasNext()) {
try {
ChartDocument plugin = iterator.next();
//s.oh^ 2014/08/19 ID権限
if(Project.isOtherCare()) {
if(plugin instanceof DiagnosisDocument || plugin instanceof ImageBrowserProxy || plugin instanceof LaboTestBean || plugin instanceof CareMapDocument) {
continue;
}
}
//s.oh$
if (index == 0) {
plugin.setContext(this);
plugin.start();
}
tab.addTab(plugin.getTitle(), plugin.getIconInfo(this), plugin.getUI());
providers.put(String.valueOf(index), plugin);
index += 1;
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
// ゼロ番目を選択しておき changeListener を機能させる
tab.setSelectedIndex(0);
// tab に プラグインを遅延生成するためのの ChangeListener を追加する
tab.addChangeListener((ChangeListener) EventHandler.create(ChangeListener.class, this, "tabChanged", ""));
return tab;
}
/**
* ドキュメントタブにプラグインを遅延生成し追加する。
* @param e
*/
public void tabChanged(ChangeEvent e) {
// 選択されたタブ番号に対応するプラグインをテーブルから検索する
int index = tabbedPane.getSelectedIndex();
String key = String.valueOf(index);
ChartDocument plugin = (ChartDocument) providers.get(key);
if (plugin==null) {
return;
}
if (plugin.getContext() == null) {
// まだ生成されていないプラグインを生成する
plugin.setContext(ChartImpl.this);
plugin.start();
tabbedPane.setComponentAt(index, plugin.getUI());
} else {
// 既に生成済みプラグインの場合は enter() をコールする
plugin.enter();
}
}
/**
* 新規カルテを作成する。
*/
public void newKarte() {
String deptName = getPatientVisit().getDeptName();
String deptCode = getPatientVisit().getDeptCode();
String insuranceUid = getPatientVisit().getInsuranceUid();
// 新規ドキュメントのタイプ=2号カルテと可能なオプションを設定する
String docType = IInfoModel.DOCTYPE_KARTE;
Chart.NewKarteOption option;
KarteViewer base;
ChartDocument bridgeOrViewer = (ChartDocument) providers.get("0");
if (bridgeOrViewer instanceof DocumentBridgeImpl) {
// Chart画面のタブパネル
logger.fine("bridgeOrViewer instanceof DocumentBridgeImpl");
DocumentBridgeImpl bridge = (DocumentBridgeImpl) bridgeOrViewer;
base = bridge.getBaseKarte();
} else if (bridgeOrViewer instanceof KarteDocumentViewer) {
logger.fine("bridgeOrViewer instanceof KarteDocumentViewer");
KarteDocumentViewer viwer = (KarteDocumentViewer) bridgeOrViewer;
base = viwer.getBaseKarte();
} else {
return;
}
if (base != null) {
logger.fine("base != null");
if (base.getDocType().equals(IInfoModel.DOCTYPE_KARTE)) {
logger.fine("base.getDocType().equals(IInfoModel.DOCTYPE_KARTE");
option = Chart.NewKarteOption.BROWSER_COPY_NEW;
} else {
// ベースがあても2号カルテでない場合
logger.fine("base.getDocType().equals(IInfoModel.DOCTYPE_S_KARTE");
option = Chart.NewKarteOption.BROWSER_NEW;
}
} else {
// ベースのカルテがない場合
logger.fine("base == null");
option = Chart.NewKarteOption.BROWSER_NEW;
}
//
// 新規カルテ作成時に確認ダイアログを表示するかどうか
//
NewKarteParams params;
if (Project.getBoolean(Project.KARTE_SHOW_CONFIRM_AT_NEW, true)) {
// 新規カルテダイアログへパラメータを渡し、コピー新規のオプションを制御する
logger.fine("show newKarteDialog");
params = getNewKarteParams(docType, option, null, deptName, deptCode, insuranceUid);
} else {
// 保険、作成モード、配置方法を手動で設定する
params = new NewKarteParams(option);
params.setDocType(docType);
params.setDepartmentName(deptName);
params.setDepartmentCode(deptCode);
// 保険
PVTHealthInsuranceModel[] ins = getHealthInsurances();
params.setPVTHealthInsurance(ins[0]);
if (insuranceUid != null) {
for (int i = 0; i < ins.length; i++) {
if (ins[i].getGUID() != null) {
if (insuranceUid.equals(ins[i].getGUID())) {
params.setPVTHealthInsurance(ins[i]);
break;
}
}
}
}
// 作成モード
switch (option) {
case BROWSER_NEW:
params.setCreateMode(Chart.NewKarteMode.EMPTY_NEW);
break;
case BROWSER_COPY_NEW:
int cMode = Project.getInt(Project.KARTE_CREATE_MODE, 0);
if (cMode == 0) {
params.setCreateMode(Chart.NewKarteMode.EMPTY_NEW);
} else if (cMode == 1) {
params.setCreateMode(Chart.NewKarteMode.APPLY_RP);
} else if (cMode == 2) {
params.setCreateMode(Chart.NewKarteMode.ALL_COPY);
}
break;
}
// 配置方法
params.setOpenFrame(Project.getBoolean(Project.KARTE_PLACE_MODE, true));
}
// キャンセルした場合はリターンする
if (params == null) {
return;
}
logger.fine("returned newKarteDialog");
DocumentModel editModel;
KarteEditor editor;
//--------------------------------------------
// Baseになるカルテがあるかどうかでモデルの生成が異なる
//--------------------------------------------
if (params.getCreateMode() == Chart.NewKarteMode.EMPTY_NEW) {
logger.fine("empty new is selected");
editModel = getKarteModelToEdit(params);
} else {
logger.fine("copy new is selected");
editModel = getKarteModelToEdit(base.getModel(), params);
}
editor = createEditor();
editor.setModel(editModel);
editor.setEditable(true);
editor.setMode(KarteEditor.DOUBLE_MODE);
if (params.isOpenFrame()) {
EditorFrame editorFrame = new EditorFrame();
editorFrame.setChart(this);
//s.oh^ 2014/06/17 複数カルテ修正制御
editor.setEditorFrame(editorFrame);
//s.oh$
editorFrame.setKarteEditor(editor);
editorFrame.start();
} else {
editor.setContext(this);
editor.initialize();
editor.start();
this.addChartDocument(editor, params);
}
}
/**
* EmptyNew 新規カルテのモデルを生成する。
* @param params 作成パラメータセット
* @return 新規カルテのモデル
*/
@Override
public DocumentModel getKarteModelToEdit(NewKarteParams params) {
// カルテモデルを生成する
DocumentModel model = new DocumentModel();
//--------------------------
// DocInfoを設定する
//--------------------------
DocInfoModel docInfo = model.getDocInfoModel();
// docId 文書ID
docInfo.setDocId(GUIDGenerator.generate(docInfo));
// 生成目的
docInfo.setPurpose(PURPOSE_RECORD);
// DocumentType
docInfo.setDocType(params.getDocType());
//-------------------------------------------------------------------
// 2.0
// 1. UserModel に ORCAID が設定してあればそれを使用する
// 2. なければ、受付情報から deptCode,deptName,doctorId,doctorName,JMARI
// を取得している。docInfo の departmentDesc にこれらの情報をカンマで連結する。
// 3.
//-------------------------------------------------------------------
StringBuilder sb = new StringBuilder();
sb.append(getPatientVisit().getDeptName()).append(","); // 診療科名
sb.append(getPatientVisit().getDeptCode()).append(","); // 診療科コード : 受けと不一致、受信?
sb.append(Project.getUserModel().getCommonName()).append(","); // 担当医名
if (Project.getUserModel().getOrcaId()!=null) {
sb.append(Project.getUserModel().getOrcaId()).append(","); // 担当医コード: ORCA ID がある場合
} else if (getPatientVisit().getDoctorId()!=null) {
sb.append(getPatientVisit().getDoctorId()).append(","); // 担当医コード: 受付でIDがある場合
} else {
sb.append(Project.getUserModel().getUserId()).append(","); // 担当医コード: ログインユーザーID
}
sb.append(getPatientVisit().getJmariNumber()); // JMARI
docInfo.setDepartmentDesc(sb.toString()); // 上記をカンマ区切りで docInfo.departmentDesc へ設定
docInfo.setDepartment(getPatientVisit().getDeptCode()); // 診療科コード 01 内科等
//-------------------------------------------------------------------
// 2012-05 クレーム送信をJMS+MDB化するために、新たに施設名と医療資格が必要
//-------------------------------------------------------------------
docInfo.setFacilityName(Project.getUserModel().getFacilityModel().getFacilityName());
docInfo.setCreaterLisence(Project.getUserModel().getLicenseModel().getLicense());
//-----------------------------------------------------------
// 健康保険を設定する-新規カルテダイアログで選択された保険をセットしている
//-----------------------------------------------------------
PVTHealthInsuranceModel insurance = params.getPVTHealthInsurance(); // 選択された保険
docInfo.setHealthInsurance(insurance.getInsuranceClassCode()); // classCode
docInfo.setHealthInsuranceDesc(insurance.toString()); // 説明
// 受付時に選択した保険のUIDはPatientVisitModelの insuranceUidに設定されている
// これと異なる保険が選択される事もある (i.ie insuranceUid!=selectedInsurance.guid)
docInfo.setHealthInsuranceGUID(insurance.getGUID()); // UUID
// Versionを設定する
VersionModel version = new VersionModel();
version.initialize();
docInfo.setVersionNumber(version.getVersionNumber());
//---------------------------
// Document の Status を設定する
// 新規カルテの場合は none
//---------------------------
docInfo.setStatus(STATUS_NONE);
return model;
}
/**
* コピーして新規カルテを生成する場合のカルテモデルを生成する。
* @param oldModel コピー元のカルテモデル
* @param params 生成パラメータセット
* @return 新規カルテのモデル
*/
@Override
public DocumentModel getKarteModelToEdit(DocumentModel oldModel, NewKarteParams params) {
//-------------------------------------------------
// 新規モデルを作成し、表示されているモデルの内容をコピーする
//-------------------------------------------------
DocumentModel newModel = new DocumentModel();
boolean applyRp = params.getCreateMode() == Chart.NewKarteMode.APPLY_RP;
copyModel(oldModel, newModel, applyRp);
//-------------------------------------------------
// 新規カルテの DocInfo を設定する
//-------------------------------------------------
DocInfoModel docInfo = newModel.getDocInfoModel();
// 文書ID
docInfo.setDocId(GUIDGenerator.generate(docInfo));
// 生成目的
docInfo.setPurpose(PURPOSE_RECORD);
// DocumentType
docInfo.setDocType(params.getDocType());
//---------------------------
// 2.0
// 受付情報から deptCode,deptName,doctorId,doctorName,JMARI
// を取得している。docInfo の departmentDesc にこれらの情報を連結する。
//---------------------------
StringBuilder sb = new StringBuilder();
sb.append(getPatientVisit().getDeptName()).append(","); // 診療科名
sb.append(getPatientVisit().getDeptCode()).append(","); // 診療科コード : 受けと不一致、受信?
sb.append(Project.getUserModel().getCommonName()).append(","); // 担当医名
if (Project.getUserModel().getOrcaId()!=null) {
sb.append(Project.getUserModel().getOrcaId()).append(","); // 担当医コード: ORCA ID がある場合
} else if (getPatientVisit().getDoctorId()!=null) {
sb.append(getPatientVisit().getDoctorId()).append(","); // 担当医コード: 受付でIDがある場合
} else {
sb.append(Project.getUserModel().getUserId()).append(","); // 担当医コード: ログインユーザーID
}
sb.append(getPatientVisit().getJmariNumber()); // JMARI
docInfo.setDepartmentDesc(sb.toString()); // 上記をカンマ区切りで docInfo.departmentDesc へ設定
docInfo.setDepartment(getPatientVisit().getDeptCode()); // 診療科コード 01 内科等
//-------------------------------------------------------------------
// 2012-05 クレーム送信をJMS+MDB化するために、新たに施設名と医療資格が必要
//-------------------------------------------------------------------
docInfo.setFacilityName(Project.getUserModel().getFacilityModel().getFacilityName());
docInfo.setCreaterLisence(Project.getUserModel().getLicenseModel().getLicense());
//-----------------------------------------------------------
// 健康保険を設定する-新規カルテダイアログで選択された保険をセットしている
//-----------------------------------------------------------
PVTHealthInsuranceModel insurance = params.getPVTHealthInsurance();
docInfo.setHealthInsurance(insurance.getInsuranceClassCode());
docInfo.setHealthInsuranceDesc(insurance.toString());
docInfo.setHealthInsuranceGUID(insurance.getGUID());
// Versionを設定する
VersionModel version = new VersionModel();
version.initialize();
docInfo.setVersionNumber(version.getVersionNumber());
//-------------------------------------
// Document の Status を設定する
// 新規カルテの場合は none
//-------------------------------------
docInfo.setStatus(STATUS_NONE);
return newModel;
}
/**
* 修正の場合のカルテモデルを生成する。
* @param oldModel 修正対象のカルテモデル
* @return 新しい版のカルテモデル
*/
@Override
public DocumentModel getKarteModelToEdit(DocumentModel oldModel) {
// 修正対象の DocInfo を取得する
DocInfoModel oldDocInfo = oldModel.getDocInfoModel();
// 新しい版のモデルにモジュールと画像をコピーする
DocumentModel newModel = new DocumentModel();
copyModel(oldModel, newModel, false);
//-------------------------------------
// 新しい版の DocInfo を設定する
//-------------------------------------
DocInfoModel newInfo = newModel.getDocInfoModel();
// 文書ID
newInfo.setDocId(GUIDGenerator.generate(newInfo));
// 新しい版の firstConfirmDate = 元になる版の firstConfirmDate
newInfo.setFirstConfirmDate(oldDocInfo.getFirstConfirmDate());
newInfo.setConfirmDate(oldDocInfo.getConfirmDate());
newInfo.setClaimDate(oldDocInfo.getClaimDate());
// docType = old one
newInfo.setDocType(oldDocInfo.getDocType());
// purpose = old one
newInfo.setPurpose(oldDocInfo.getPurpose());
// タイトルも引き継ぐ
newInfo.setTitle(oldDocInfo.getTitle());
// 検体検査オーダー番号
newInfo.setLabtestOrderNumber(oldDocInfo.getLabtestOrderNumber());
//-------------------------------------
// 診療科を設定する
// 元になる版の情報を利用する
//-------------------------------------
newInfo.setDepartmentDesc(oldDocInfo.getDepartmentDesc());
newInfo.setDepartment(oldDocInfo.getDepartment());
//-------------------------------------------------------------------
// 2012-05 クレーム送信をJMS+MDB化するために、新たに施設名と医療資格が必要
// この情報はpersistされていないため再度設定する
//-------------------------------------------------------------------
newInfo.setFacilityName(Project.getUserModel().getFacilityModel().getFacilityName());
newInfo.setCreaterLisence(Project.getUserModel().getLicenseModel().getLicense());
//-------------------------------------
// 健康保険を設定する
// 元になる版の情報を利用する
//-------------------------------------
newInfo.setHealthInsuranceDesc(oldDocInfo.getHealthInsuranceDesc());
newInfo.setHealthInsurance(oldDocInfo.getHealthInsurance());
newInfo.setHealthInsuranceGUID(oldDocInfo.getHealthInsuranceGUID());
logger.fine(newInfo.getHealthInsuranceDesc());
logger.fine(newInfo.getHealthInsurance());
logger.fine(newInfo.getHealthInsuranceGUID());
//-------------------------------------
// 親文書IDを設定する
//-------------------------------------
newInfo.setParentId(oldDocInfo.getDocId());
newInfo.setParentIdRelation(PARENT_OLD_EDITION);
//-------------------------------------
// old PK を設定する
//-------------------------------------
newInfo.setParentPk(oldModel.getId());
//-------------------------------------
// Versionを設定する
// new = old + 1.0
//-------------------------------------
VersionModel newVersion = new VersionModel();
newVersion.setVersionNumber(oldDocInfo.getVersionNumber());
newVersion.incrementNumber(); // version number ++
newInfo.setVersionNumber(newVersion.getVersionNumber());
//-------------------------------------
// Document Status を設定する
// 元になる版の status (Final | Temporal | Modified)
//-------------------------------------
newInfo.setStatus(oldDocInfo.getStatus());
return newModel;
}
/**
* カルテエディタを生成する。
* @return カルテエディタ
*/
public KarteEditor createEditor() {
KarteEditor editor;
try {
editor = new KarteEditor();
editor.addMMLListner(mmlListener);
editor.addCLAIMListner(claimListener);
} catch (Exception e) {
logger.fine(e.getMessage());
editor = null;
}
return editor;
}
//----------------------------------
// モデルをdeepコピーする
// DocInfo の設定はない
//----------------------------------
private void copyModel(DocumentModel oldModel, DocumentModel newModel, boolean applyRp) {
if (applyRp) {
List<ModuleModel> modules = oldModel.getModules();
if (modules!=null) {
modules.stream().forEach((bean) -> {
IInfoModel model = bean.getModel();
if (model!=null && model instanceof BundleMed) {
newModel.addModule(ModelUtils.cloneModule(bean));
}
});
}
} else {
List<ModuleModel> modules = oldModel.getModules();
if (modules!=null) {
modules.stream().forEach((bean) -> {
newModel.addModule(ModelUtils.cloneModule(bean));
});
}
List<SchemaModel> schema = oldModel.getSchema();
if (schema!=null) {
schema.stream().forEach((scm) -> {
newModel.addSchema(ModelUtils.cloneSchema(scm));
});
}
List<AttachmentModel> attachment = oldModel.getAttachment();
if (attachment!=null) {
for (AttachmentModel am : attachment) {
//s.oh^ 2014/08/20 添付ファイルの別読
//newModel.addAttachment(ModelUtils.cloneAttachment(am));
DocumentDelegater ddl = new DocumentDelegater();
try {
AttachmentModel tmp = ddl.getAttachment(am.getId());
am.setBytes(tmp.getBytes());
} catch (Exception ex) {
}
newModel.addAttachment(ModelUtils.cloneAttachment(am));
am.setBytes(null);
//s.oh$
}
}
}
}
/**
* カルテ作成時にダアイログをオープンし、保険を選択させる。
*
* @param docType
* @param option
* @param f
* @param deptName
* @param deptCode
* @param insuranceUid
* @return NewKarteParams
*/
public NewKarteParams getNewKarteParams(String docType, Chart.NewKarteOption option, JFrame f, String deptName, String deptCode, String insuranceUid) {
//--------------------------------------------
// 下記は PatientVisit から取得している
// deptName
// deptCode
// insuranceUid 受付なしで患者検索からの場合は null
//--------------------------------------------
NewKarteParams params = new NewKarteParams(option);
params.setDocType(docType);
params.setDepartmentName(deptName);
params.setDepartmentCode(deptCode);
// 患者の健康保険コレクション
Collection<PVTHealthInsuranceModel> insurances = pvt.getPatientModel().getPvtHealthInsurances();
// コレクションが null の場合は自費保険を追加する
if (insurances == null || insurances.isEmpty()) {
insurances = new ArrayList<>(1);
PVTHealthInsuranceModel model = new PVTHealthInsuranceModel();
java.util.ResourceBundle clBundle = ClientContext.getClaimBundle();
model.setInsuranceClass(clBundle.getString("INSURANCE_SELF"));
model.setInsuranceClassCode(clBundle.getString("INSURANCE_SELF_CODE"));
model.setInsuranceClassCodeSys(clBundle.getString("INSURANCE_SYS"));
insurances.add(model);
}
// 保険コレクションを配列に変換し、パラメータにセットする
// ユーザがこの中の保険を選択する
PVTHealthInsuranceModel[] insModels = (PVTHealthInsuranceModel[]) insurances.toArray(new PVTHealthInsuranceModel[insurances.size()]);
params.setInsurances(insModels);
// insuranceUidがnullでない場合はそれに一致する保険を探す
// 見つかった保険をダイアログが表示された時に選択状態にする
// insuranceUid = null (受付なし)の場合は先頭(index=0)を選択する
int index = 0;
if (insuranceUid != null) {
for (int i = 0; i < insModels.length; i++) {
if (insModels[i].getGUID() != null) {
if (insModels[i].getGUID().equals(insuranceUid)) {
index = i;
break;
}
}
}
}
params.setInitialSelectedInsurance(index);
java.util.ResourceBundle bundle = ClientContext.getMyBundle(ChartImpl.class);
String titleModify = bundle.getString("title.modifyKarte");
String titleNew = bundle.getString("title.newKarte");
String text = option == Chart.NewKarteOption.BROWSER_MODIFY
? titleModify
: titleNew;
text = ClientContext.getFrameTitle(text);
// モーダルダイアログを表示する
JFrame frame = f != null ? f : getFrame();
NewKarteDialog od = new NewKarteDialog(frame, text);
od.setValue(params);
od.start();
// 戻り値をリターンする
params = (NewKarteParams) od.getValue();
return params;
}
/**
* 患者の健康保険を返す。
* @return 患者の健康保険配列
*/
@Override
public PVTHealthInsuranceModel[] getHealthInsurances() {
// 患者の健康保険
Collection<PVTHealthInsuranceModel> insurances = pvt.getPatientModel().getPvtHealthInsurances();
// 保険がない場合 自費保険を生成して追加する
if (insurances == null || insurances.isEmpty()) {
insurances = new ArrayList<>(1);
PVTHealthInsuranceModel model = new PVTHealthInsuranceModel();
java.util.ResourceBundle clBundle = ClientContext.getClaimBundle();
model.setInsuranceClass(clBundle.getString("INSURANCE_SELF"));
model.setInsuranceClassCode(clBundle.getString("INSURANCE_SELF_CODE"));
model.setInsuranceClassCodeSys(clBundle.getString("INSURANCE_SYS"));
insurances.add(model);
}
return (PVTHealthInsuranceModel[]) insurances.toArray(new PVTHealthInsuranceModel[insurances.size()]);
}
/**
* 選択された保険を特定する。
* @param uuid 選択された保険のUUID
* @return 選択された保険
*/
@Override
public PVTHealthInsuranceModel getHealthInsuranceToApply(String uuid) {
logger.log(Level.FINE, "uuid to apply = {0}", uuid);
PVTHealthInsuranceModel ret = null;
PVTHealthInsuranceModel first = null;
// 患者の健康保険
Collection<PVTHealthInsuranceModel> insurances = pvt.getPatientModel().getPvtHealthInsurances();
if (uuid!=null && insurances!=null && insurances.size()>0) {
for (PVTHealthInsuranceModel hm : insurances) {
if (first == null) {
first = hm;
}
if (uuid.equals(hm.getGUID())) {
ret = hm;
logger.log(Level.FINE, "found uuid to apply = {0}", uuid);
break;
}
}
}
if (ret != null) {
return ret;
}
else if (first!=null) {
return first;
}
return null;
}
/**
* タブにドキュメントを追加する。
* @param doc 追加するドキュメント
* @param params 追加するドキュメントの情報を保持する NewKarteParams
*/
public void addChartDocument(ChartDocument doc, NewKarteParams params) {
Runnable awt = () -> {
String title;
if (params.getPVTHealthInsurance() != null) {
title = getTabTitle(params.getDepartmentName(), params.getPVTHealthInsurance().getInsuranceClass());
} else {
title = getTabTitle(params.getDepartmentName(), null);
}
tabbedPane.addTab(title, doc.getUI());
int index = tabbedPane.getTabCount() - 1;
providers.put(String.valueOf(index), doc);
tabbedPane.setSelectedIndex(index);
};
EventQueue.invokeLater(awt);
}
/**
* タブにドキュメントを追加する。
* @param doc
* @param title タブタイトル
*/
public void addChartDocument(ChartDocument doc, String title) {
tabbedPane.addTab(title, doc.getUI());
int index = tabbedPane.getTabCount() - 1;
providers.put(String.valueOf(index), doc);
tabbedPane.setSelectedIndex(index);
}
//minagawa^ LSC Test
/**
* タブドキュメントのアイコンを変更する。
* @param icon タブに設定するアイコン
* @param c ChartDocumentの Component
*/
public void setChartDocumentIconAt(ImageIcon icon, Component c) {
int index = tabbedPane.indexOfComponent(c);
if (index>=0 && index < tabbedPane.getTabCount()) {
tabbedPane.setIconAt(index, icon);
}
}
//minagawa$
/**
* 新規カルテ用のタブタイトルを作成する
* @param dept
* @param insurance 保険名
* @return タブタイトル
*/
public String getTabTitle(String dept, String insurance) {
String[] depts = dept.split("\\s*,\\s*");
StringBuilder buf = new StringBuilder();
String tabTile = ClientContext.getMyBundle(ChartImpl.class).getString("tabTitle.newKarte");
buf.append(tabTile);
if (insurance != null) {
buf.append("(");
buf.append(depts[0]);
buf.append("・");
buf.append(insurance);
buf.append(")");
}
return buf.toString();
}
/**
* 新規文書作成で選択されたプラグインを起動する。
*
* @param pluginClass 起動するプラグインのクラス名
*/
private void invokePlugin(String pluginClass) {
try {
NChartDocument doc = (NChartDocument) Class.forName(
pluginClass).newInstance();
if (doc instanceof KarteEditor) {
String dept = getPatientVisit().getDeptName();
String deptCode = getPatientVisit().getDeptCode();
String insuranceUid = getPatientVisit().getInsuranceUid();
Chart.NewKarteOption option = Chart.NewKarteOption.BROWSER_NEW;
String docType = IInfoModel.DOCTYPE_S_KARTE;
NewKarteParams params = new NewKarteParams(option);
params.setDocType(docType);
params.setDepartmentName(dept);
params.setDepartmentCode(deptCode);
// 保険
PVTHealthInsuranceModel[] ins = getHealthInsurances();
params.setPVTHealthInsurance(ins[0]);
if (insuranceUid != null) {
for (PVTHealthInsuranceModel in : ins) {
if (in.getGUID() != null) {
if (insuranceUid.equals(in.getGUID())) {
params.setPVTHealthInsurance(in);
break;
}
}
}
}
DocumentModel editModel = getKarteModelToEdit(params);
KarteEditor editor = (KarteEditor) doc;
editor.setModel(editModel);
editor.setEditable(true);
editor.setContext(this);
editor.setMode(KarteEditor.SINGLE_MODE);
editor.initialize();
editor.start();
this.addChartDocument(editor, params);
} else {
doc.setContext(this);
doc.start();
addChartDocument(doc, doc.getTitle());
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
logger.finer(e.getMessage());
}
}
public void checkInteraction() {
CheckInteractionPanel panel = new CheckInteractionPanel();
panel.enter(this);
}
/**
* 新規文書作成で選択されたOffice文書テンプレートを開く。
* @param templatePath OpenOffice odt
*/
private void invokeOffice(final String docName, final String templatePath) {
if (!Desktop.isDesktopSupported() ||
templatePath==null ||
(!templatePath.endsWith(".odt"))) {
return;
}
SwingWorker w = new SwingWorker<String,Void>() {
@Override
protected String doInBackground() throws Exception {
DocumentTemplateFactory documentTemplateFactory = new DocumentTemplateFactory();
DocumentTemplate template = documentTemplateFactory.getTemplate(Files.newInputStream(Paths.get(templatePath)));
Map data = new HashMap();
String dateFmt = ClientContext.getMyBundle(ChartImpl.class).getString("dateFormat.openDocunent");
SimpleDateFormat sdf = new SimpleDateFormat(dateFmt);
// Entry date
Date entryDate = new Date();
data.put("entry_date", sdf.format(entryDate));
data.put("entry_date_era", MMLDate.warekiStringFromDate(entryDate));
// Patient
data.put("pt_id", getOdtString(getPatient().getPatientId()));
data.put("pt_kana", getOdtString(getPatient().getKanaName()));
data.put("pt_name", getPatient().getFullName());
data.put("g", ModelUtils.getGenderDesc(getPatient().getGender()));
Date birthday = ModelUtils.getDateAsObject(getPatient().getBirthday());
if (birthday!=null) {
data.put("pt_birth", sdf.format(birthday));
data.put("pt_birth_era", getOdtString(MMLDate.warekiStringFromDate(birthday)));
} else {
data.put("pt_birth", "");
data.put("pt_birth_era", "");
}
String age = AgeCalculater.getAge(getPatient().getBirthday(), 6);
data.put("pt_age", getOdtString(age));
data.put("pt_zip", getOdtString(getPatient().contactZipCode()));
data.put("pt_addr", getOdtString(getPatient().contactAddress()));
data.put("pt_tel", getOdtString(getPatient().getTelephone()));
// Physician
UserModel u = Project.getUserModel();
data.put("phy_hosp", getOdtString(u.getFacilityModel().getFacilityName()));
data.put("phy_zip", getOdtString(u.getFacilityModel().getZipCode()));
data.put("phy_addr", getOdtString(u.getFacilityModel().getAddress()));
data.put("phy_tel", getOdtString(u.getFacilityModel().getTelephone()));
data.put("phy_fax", getOdtString(u.getFacilityModel().getFacsimile()));
data.put("phy_name", getOdtString(u.getCommonName()));
// FileName = 文書名_患者氏名様_YYYY-MM-DD(n).odt
String pathToOpen = UserDocumentHelper.createPathToDocument(
Project.getString(Project.LOCATION_PDF), // 設定画面で指定されている dir
docName, // 文書名
".odt", // 拡張子
getPatient().getFullName(), // 患者氏名
entryDate); // 日付
Path pathObj = Paths.get(pathToOpen);
template.createDocument(data, Files.newOutputStream(pathObj));
return pathObj.toAbsolutePath().toString();
}
@Override
protected void done() {
try {
String pathToOpen = get();
if (pathToOpen!=null) {
Desktop desktop = Desktop.getDesktop();
desktop.browse(Paths.get(pathToOpen).toUri());
}
} catch (IOException ex) {
String err = ClientContext.getMyBundle(ChartImpl.class).getString("errorMessage.launchApp.openDoc");
showOfficeError(err);
} catch (InterruptedException ex) {
ex.printStackTrace(System.err);
} catch (ExecutionException ex) {
ex.printStackTrace(System.err);
String err = ClientContext.getMyBundle(ChartImpl.class).getString("errorMessage.create.openDoc");
showOfficeError(err);
}
}
};
w.execute();
}
// 差し込み作成のエラー表示
private void showOfficeError(String msg) {
Window parent = SwingUtilities.getWindowAncestor(getFrame());
String title = ClientContext.getMyBundle(ChartImpl.class).getString("title.optionPane.create.openDocument");
JOptionPane.showMessageDialog(parent, msg, ClientContext.getFrameTitle(title), JOptionPane.WARNING_MESSAGE);
}
// str == null の時 template の ${prop} ="" にする
private String getOdtString(String str) {
return str!=null ? str : "";
}
/**
* カルテ以外の文書を作成する。
*/
public void newDocument() {
// 拡張ポイント新規文書のプラグインをリストアップし、
// リストで選択させる
List<NameValuePair> documents = new ArrayList<>(3);
PluginLister<NChartDocument> lister = PluginLister.list(NChartDocument.class);
LinkedHashMap<String, String> nproviders = lister.getProviders();
if (nproviders != null) {
Iterator<String> iter = nproviders.keySet().iterator();
while (iter.hasNext()) {
String cmd = iter.next();
String clsName = nproviders.get(cmd);
NameValuePair pair = new NameValuePair(cmd, clsName);
documents.add(pair);
logger.log(Level.FINE, "{0} = {1}", new Object[]{cmd, clsName});
}
}
//---------------------------------------------------------------
// 訪問看護指示書等のローカルにある OpenOffice Template をリストアップする
//---------------------------------------------------------------
boolean hasOOD = false;
try {
DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get(ClientContext.getOdtTemplateDirectory()));
for (Path p : ds) {
if (Files.isDirectory(p)) {
continue;
}
String path = p.toAbsolutePath().toString();
if (path.toLowerCase().endsWith(".odt")) {
String name = p.getFileName().toString();
int len = name.length()-4; // .odt
name = name.substring(0, len);
documents.add(new NameValuePair(name, path));
hasOOD = true;
}
}
} catch (Exception e) {
}
if (documents.isEmpty()) {
logger.fine("No plugins");
return;
}
final JList docList = new JList(documents.toArray());
docList.setCellRenderer(new PdfOfficeIconRenderer());
java.util.ResourceBundle bundle = ClientContext.getMyBundle(ChartImpl.class);
String pdfLabelText = bundle.getString("labelText.create.pdf");
String officeLabelText = bundle.getString("labelText.insert.openDoc");
String borderTitle = bundle.getString("borderTitle.list.openDoc");
String optionSelectText = bundle.getString("optionText.select.openDoc");
String title = bundle.getString("title.optionPane.openDoc.menu");
// 凡例ラベル
JPanel pdfOffice = new JPanel();
pdfOffice.setLayout(new BoxLayout(pdfOffice,BoxLayout.Y_AXIS));
JLabel pdfLabel = new JLabel(pdfLabelText);
pdfLabel.setIcon(ClientContext.getImageIconArias("icon_pdf_small"));
pdfOffice.add(pdfLabel);
if (hasOOD) {
pdfOffice.add(Box.createVerticalStrut(5));
JLabel officeLabel = new JLabel(officeLabelText);
officeLabel.setIcon(ClientContext.getImageIconArias("icon_plain_document_small"));
pdfOffice.add(officeLabel);
}
pdfOffice.setBorder(BorderFactory.createEmptyBorder(6,6,5,5));
// List panel
JPanel listPanel = new JPanel(new BorderLayout(7, 0));
//s.oh^ 2014/05/26 差し込み文書の表示
//listPanel.add(docList, BorderLayout.CENTER);
if(documents.size() <= 20) {
listPanel.add(docList, BorderLayout.CENTER);
}else{
JScrollPane scroll = new JScrollPane(docList);
scroll.setPreferredSize(new Dimension(350, 500));
listPanel.add(scroll, BorderLayout.CENTER);
}
//s.oh$
listPanel.setBorder(BorderFactory.createEmptyBorder(6,6,5,5));
JPanel content = new JPanel(new BorderLayout());
content.add(listPanel, BorderLayout.CENTER);
content.add(pdfOffice, BorderLayout.SOUTH);
content.setBorder(BorderFactory.createTitledBorder(borderTitle));
final JButton okButton = new JButton(optionSelectText);
final JButton cancelButton = new JButton(GUIFactory.getCancelButtonText());
Object[] options = new Object[]{okButton, cancelButton};
JOptionPane jop = new JOptionPane(
content,
JOptionPane.PLAIN_MESSAGE,
JOptionPane.DEFAULT_OPTION,
null,
options,
okButton);
final JDialog dialog = jop.createDialog(getFrame(), ClientContext.getFrameTitle(title));
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
docList.requestFocusInWindow();
}
});
okButton.addActionListener((ActionEvent e) -> {
dialog.setVisible(false);
dialog.dispose();
NameValuePair pair = (NameValuePair) docList.getSelectedValue();
String test = pair.getValue();
if (test.endsWith(".odt")) {
String docName = pair.getName();
invokeOffice(docName, test);
} else {
invokePlugin(test);
}
});
okButton.setEnabled(false);
cancelButton.addActionListener((ActionEvent e) -> {
dialog.setVisible(false);
dialog.dispose();
});
docList.addListSelectionListener((ListSelectionEvent e) -> {
if (e.getValueIsAdjusting() == false) {
int index = docList.getSelectedIndex();
if (index >= 0) {
okButton.setEnabled(true);
}
}
});
dialog.setVisible(true);
}
private void saveAll() {
// listの最初のドキュメントに保存をコールしbreakする
// propertychangeを受信して次の保存へ行く
while(!dirtyList.isEmpty()) {
UnsavedDocument undoc = dirtyList.remove(0);
ChartDocument doc = (ChartDocument)providers.get(String.valueOf(undoc.getIndex()));
if (doc != null && doc.isDirty()) {
tabbedPane.setSelectedIndex(undoc.getIndex());
ListeneAndGoController ctl = new ListeneAndGoController(doc);
doc.addPropertyChangeListener(ChartDocument.CHART_DOC_DID_SAVE, ctl);
doc.save();
break;
}
}
}
// 未保存の文書が全て保存されるのを待って stopを実行するリスナ
class DirtySaveController implements PropertyChangeListener {
private final ChartDocument doc;
private final int total;
private final int index;
public DirtySaveController(ChartDocument doc, int total, int index) {
this.doc=doc;
this.total=total;
this.index=index;
}
@Override
public void propertyChange(PropertyChangeEvent pce) {
if (pce.getPropertyName().equals(AbstractChartDocument.CHART_DOC_DID_SAVE)) {
doc.removePropertyChangeListener(AbstractChartDocument.CHART_DOC_DID_SAVE, this);
if (index == (total-1)) {
// 最後なら
stop();
}
}
}
}
class ListeneAndGoController implements PropertyChangeListener {
private final ChartDocument doc;
public ListeneAndGoController(ChartDocument doc) {
this.doc=doc;
}
@Override
public void propertyChange(PropertyChangeEvent pce) {
doc.removePropertyChangeListener(AbstractChartDocument.CHART_DOC_DID_SAVE, this);
// 保存の正否 キャンセルの場合は false、saveAllがコールされないので止まる
boolean proceed = ((Boolean)pce.getNewValue());
if (proceed) {
if (!dirtyList.isEmpty()) {
saveAll();
} else {
// 空になったので stop
stop();
}
}
}
}
/**
* ドキュメントのなかにdirtyのものがあるかどうかを返す。
* @return dirtyの時true
*/
private java.util.List<UnsavedDocument> dirtyList() {
java.util.List<UnsavedDocument> ret = null;
int count = tabbedPane.getTabCount();
for (int i = 0; i < count; i++) {
ChartDocument doc = (ChartDocument)providers.get(String.valueOf(i));
if (doc != null && doc.isDirty()) {
if (ret == null) {
ret = new ArrayList<>(3);
}
ret.add(new UnsavedDocument(i, doc));
}
}
return ret;
}
/**
* CloseBox がクリックされた時の処理を行う。
*/
public void processWindowClosing() {
close();
}
/**
* チャートウインドウを閉じる。
*/
@Override
public void close() {
//masuda^ この患者のEditorFrameが開いたままなら、インスペクタを閉じられないようにする
List<Chart> editorFrames = EditorFrame.getAllEditorFrames();
if (editorFrames != null && !editorFrames.isEmpty()) {
long ptId = this.getPatient().getId();
for (Chart chart : editorFrames) {
long id = chart.getPatient().getId();
if (ptId == id) {
// よくわからないEditorFrameが残っていて、Frameがぬるぽのときがあるので
try {
// 最小化してたらFrameを再表示させる
chart.getFrame().setExtendedState(Frame.NORMAL);
java.util.ResourceBundle bundle = ClientContext.getMyBundle(ChartImpl.class);
String title = bundle.getString("title.optionPane.closeInspector");
String msg = bundle.getString("message.closeInspector");
JOptionPane.showMessageDialog(chart.getFrame(),
msg,
ClientContext.getFrameTitle(title), JOptionPane.WARNING_MESSAGE);
return;
} catch (Exception e) {
}
}
}
}
//masuda$
//--------------------------------------------
// 未保存ドキュメントがある場合はダイアログを表示し
// 保存するかどうかを確認する
//--------------------------------------------
List<UnsavedDocument> localDirtyList = dirtyList();
if (localDirtyList != null && localDirtyList.size() > 0) {
java.util.ResourceBundle bundle = ClientContext.getMyBundle(ChartImpl.class);
String saveAll = bundle.getString("optionText.save.unsaved");
String discard = bundle.getString("optionText.discard.unsaved");
String question = bundle.getString("question.unsaved");
String title = bundle.getString("title.optionPane.unsaved");
String cancelText = GUIFactory.getCancelButtonText();
Object[] message = new Object[localDirtyList.size() + 1];
message[0] = (Object) question;
int index = 1;
for (UnsavedDocument doc : localDirtyList) {
message[index++] = doc.getCheckBox();
}
int option = JOptionPane.showOptionDialog(
getFrame(),
message,
ClientContext.getFrameTitle(title),
JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
new String[]{saveAll, discard, cancelText},
saveAll);
switch (option) {
case 0:
// save
dirtyList = new ArrayList<>();
for (UnsavedDocument doc : localDirtyList) {
// 保存がcheckされているもののみ追加
if (doc.isNeedSave()) {
dirtyList.add(doc);
}
}
if (!dirtyList.isEmpty()) {
saveAll();
} else {
stop();
}
break;
case 1:
// discard
stop();
break;
case 2:
// cancel
break;
}
} else {
stop();
}
}
@Override
public void stop() {
SwingWorker worker = new SwingWorker<Integer, Void>() {
@Override
protected Integer doInBackground() throws Exception {
ChartEventHandler scl = ChartEventHandler.getInstance();
int cnt = scl.publishKarteClosedInWorkerThread(ChartImpl.this.getPatientVisit());
return cnt;
}
@Override
protected void done() {
try {
Integer cnt = get();
} catch (InterruptedException | ExecutionException e) {
logger.fine("Failed to close the karte.");
e.printStackTrace(System.err);
}
// ともかく終了させる
doStop();
}
};
worker.execute();
}
private void doStop() {
if (beeperHandle != null) {
boolean b = beeperHandle.cancel(true);
logger.log(Level.FINE, "beeperHandle.cancel = {0}", b);
}
if (scheduler != null) {
scheduler.shutdown();
logger.fine("scheduler.shutdown");
}
if (providers != null) {
for (Iterator<String> iter = providers.keySet().iterator(); iter.hasNext();) {
ChartDocument doc = providers.get(iter.next());
if (doc != null) {
doc.stop();
}
}
providers.clear();
}
mediator.dispose();
inspector.dispose();
Project.setRectangle("chartFrame.bounds", getFrame().getBounds());
getFrame().setVisible(false);
getFrame().setJMenuBar(null);
getFrame().dispose();
}
//s.oh^ 不具合修正(一括終了時のステータスクリア)
public void publishKarteClosed() {
ChartEventHandler scl = ChartEventHandler.getInstance();
if(scl != null) {
scl.publishKarteClosed(ChartImpl.this.getPatientVisit());
}
}
//s.oh$
protected abstract class ChartState {
public ChartState() {
}
public abstract void controlMenu();
}
/**
* ReadOnly ユーザの State クラス。
*/
protected final class ReadOnlyState extends ChartState {
public ReadOnlyState() {
}
/**
* 新規カルテ作成及び修正メニューを disable にする。
*/
@Override
public void controlMenu() {
mediator.getAction(GUIConst.ACTION_NEW_KARTE).setEnabled(false);
mediator.getAction(GUIConst.ACTION_MODIFY_KARTE).setEnabled(false);
//s.oh^ 2014/08/19 ID権限
mediator.getAction(GUIConst.ACTION_SHOW_STAMPBOX).setEnabled(false);
mediator.getAction(GUIConst.ACTION_SHOW_SCHEMABOX).setEnabled(false);
//s.oh$
}
}
/**
* 保険証がない場合の State クラス。
*/
protected final class NoInsuranceState extends ChartState {
public NoInsuranceState() {
}
@Override
public void controlMenu() {
mediator.getAction(GUIConst.ACTION_NEW_KARTE).setEnabled(false);
}
}
/**
* 通常の State クラス。
*/
protected final class OrdinalyState extends ChartState {
public OrdinalyState() {
}
@Override
public void controlMenu() {
mediator.getAction(GUIConst.ACTION_NEW_KARTE).setEnabled(true);
}
}
/**
* State Manager クラス。
*/
protected final class StateMgr {
private final ChartState readOnlyState = new ReadOnlyState();
private final ChartState noInsuranceState = new NoInsuranceState();
private final ChartState ordinalyState = new OrdinalyState();
private ChartState currentState;
public StateMgr() {
if (isReadOnly()) {
enterReadOnlyState();
} else {
enterOrdinalyState();
}
}
public void enterReadOnlyState() {
currentState = readOnlyState;
currentState.controlMenu();
}
public void enterNoInsuranceState() {
currentState = noInsuranceState;
currentState.controlMenu();
}
public void enterOrdinalyState() {
currentState = ordinalyState;
currentState.controlMenu();
}
public void controlMenu() {
currentState.controlMenu();
}
}
}