package open.dolphin.client;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.datatransfer.*;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Position;
import javax.swing.tree.DefaultMutableTreeNode;
import open.dolphin.infomodel.IInfoModel;
import open.dolphin.infomodel.ModuleInfoBean;
import open.dolphin.infomodel.ModuleModel;
import open.dolphin.project.Project;
import open.dolphin.stampbox.StampTreeNode;
import open.dolphin.stampbox.TreeInfo;
/**
* KartePaneTransferHandler
* @author Minagawa,Kazushi
*/
public class PTransferHandler extends TransferHandler implements IKarteTransferHandler {
// KartePane
private final KartePane pPane;
private JTextPane source;
private boolean shouldRemove;
// Start and end position in the source text.
// We need this information when performing a MOVE
// in order to remove the dragged text from the source.
Position p0 = null, p1 = null;
public PTransferHandler(KartePane pPane) {
this.pPane = pPane;
}
@Override
public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
JTextPane tc = (JTextPane)support.getComponent();
if (tc.equals(source) &&
(tc.getCaretPosition() >= p0.getOffset()) &&
(tc.getCaretPosition() <= p1.getOffset())) {
shouldRemove = false;
return true;
}
try {
Transferable tr = support.getTransferable();
if (tr.isDataFlavorSupported(LocalStampTreeNodeTransferable.localStampTreeNodeFlavor)) {
// スタンプボックスからのスタンプをインポートする
shouldRemove = false;
StampTreeNode droppedNode = (StampTreeNode) tr.getTransferData(LocalStampTreeNodeTransferable.localStampTreeNodeFlavor);
return doStampInfoDrop(droppedNode);
} else if (tr.isDataFlavorSupported(OrderListTransferable.orderListFlavor)) {
// KartePaneからのオーダスタンプをインポートする
OrderList list = (OrderList) tr.getTransferData(OrderListTransferable.orderListFlavor);
return doStampDrop(list, support.isDrop());
} else if (tr.isDataFlavorSupported(DataFlavor.stringFlavor)) {
String str = (String) tr.getTransferData(DataFlavor.stringFlavor);
tc.replaceSelection(str);
shouldRemove = tc == source;
return true;
}
} catch (UnsupportedFlavorException | IOException ufe) {
}
return false;
}
// Create a Transferable implementation that contains the
// selected text.
@Override
protected Transferable createTransferable(JComponent c) {
source = (JTextPane) c;
int start = source.getSelectionStart();
int end = source.getSelectionEnd();
Document doc = source.getDocument();
if (start == end) {
return null;
}
try {
p0 = doc.createPosition(start);
p1 = doc.createPosition(end);
} catch (BadLocationException e) {
}
String data = source.getSelectedText();
return new StringSelection(data);
}
@Override
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
// Remove the old text if the action is a MOVE.
// However, we do not allow dropping on top of the selected text,
// so in that case do nothing.
@Override
protected void exportDone(JComponent c, Transferable data, int action) {
JTextComponent tc = (JTextComponent) c;
if (tc.isEditable() && (shouldRemove == true) && (action == MOVE)) {
if ((p0 != null) && (p1 != null)
&& (p0.getOffset() != p1.getOffset())) {
try {
tc.getDocument().remove(p0.getOffset(),
p1.getOffset() - p0.getOffset());
} catch (BadLocationException e) {
}
}
}
shouldRemove = false;
source = null;
}
@Override
public boolean canImport(TransferHandler.TransferSupport support) {
JTextPane tc = (JTextPane)support.getComponent();
boolean ok = tc.isEditable();
ok = ok && hasFlavor(support.getDataFlavors());
return ok;
}
/**
* Flavorリストのなかに受け入れられものがあるかどうかを返す。
* @param flavors
* @return
*/
protected boolean hasFlavor(DataFlavor[] flavors) {
for (DataFlavor flavor : flavors) {
// String OK
if (DataFlavor.stringFlavor.equals(flavor)) {
return true;
}
// StampTreeNode(FromStampTree) OK
if (LocalStampTreeNodeTransferable.localStampTreeNodeFlavor.equals(flavor)) {
return true;
}
// OrderStamp List OK
if (OrderListTransferable.orderListFlavor.equals(flavor)) {
return true;
}
}
return false;
}
/**
* DropされたModuleInfo(StampInfo)をインポートする。
* @param tr Transferable
* @return 成功した時 true
*/
private boolean doStampInfoDrop(StampTreeNode droppedNode) {
Chart chart = null;
ChartDocument doc = pPane.getParent();
if(doc instanceof KarteEditor) {
chart = ((KarteEditor)doc).getContext();
}
try {
// 葉の場合
if (droppedNode.isLeaf()) {
ModuleInfoBean stampInfo = (ModuleInfoBean)droppedNode.getStampInfo();
String role = stampInfo.getStampRole();
if (role.equals(IInfoModel.ROLE_P)) {
pPane.stampInfoDropped(stampInfo);
} else if (role.equals(IInfoModel.ROLE_TEXT)) {
pPane.stampInfoDropped(stampInfo);
} else if (role.equals(IInfoModel.ROLE_ORCA_SET)) {
pPane.stampInfoDropped(stampInfo);
}
// 病名も受け入れる
else if (role.equals(IInfoModel.ROLE_DIAGNOSIS)) {
// contextへ追加(エクスポートしておく)
java.util.ResourceBundle bundle = ClientContext.getMyBundle(PTransferHandler.class);
String treeName = bundle.getString("treeName.fromEditor");
String message = bundle.getString("message.dropedEditor");
if(stampInfo.getStampName().equals(treeName)) {
JOptionPane.showMessageDialog(null, message, ClientContext.getString("productString"), JOptionPane.INFORMATION_MESSAGE);
}else{
pPane.getParent().getContext().addDroppedDiagnosis(stampInfo);
showDiagnosisAddedMessage(stampInfo.getStampName());
}
}
return true;
}
// Path にふくまれているTextはSOA側へ挿入する
// カルテのテンプレートと考える
DefaultMutableTreeNode folderNode = (DefaultMutableTreeNode)droppedNode;
StampTreeNode root = (StampTreeNode)folderNode.getRoot();
TreeInfo info = (TreeInfo)root.getUserObject();
String importEntity = info.getEntity();
boolean pathTree = importEntity.contains(IInfoModel.ENTITY_PATH);
// Dropされたノードの葉を列挙する
Enumeration e = droppedNode.preorderEnumeration();
// 種類別のリストに別ける
ArrayList<ModuleInfoBean> textList = new ArrayList<>(2);
ArrayList<ModuleInfoBean> stamptList = new ArrayList<>(2);
ArrayList<ModuleInfoBean> diagList = new ArrayList<>(2);
//s.oh^ 2014/08/01 パス対応
boolean radiology = false;
if(Project.getBoolean("stamp.path.text.p")) {
while(e.hasMoreElements()) {
StampTreeNode node = (StampTreeNode)e.nextElement();
if(node.isLeaf()) {
ModuleInfoBean stampInfo = (ModuleInfoBean)node.getStampInfo();
if(stampInfo.getEntity().equals(IInfoModel.ENTITY_RADIOLOGY_ORDER)) {
radiology = true;
break;
}
}
}
e = droppedNode.preorderEnumeration();
}
//s.oh$
while (e.hasMoreElements()) {
StampTreeNode node = (StampTreeNode)e.nextElement();
if (node.isLeaf()) {
ModuleInfoBean stampInfo = (ModuleInfoBean)node.getStampInfo();
String role = stampInfo.getStampRole();
if (stampInfo.isSerialized() && (role.equals(IInfoModel.ROLE_TEXT)) ) {
// Text Stamp
//s.oh^ 2014/08/01 パス対応
//textList.add(stampInfo);
if(radiology) {
stamptList.add(stampInfo);
}else{
textList.add(stampInfo);
}
//s.oh$
}
else if (stampInfo.isSerialized() && (role.equals(IInfoModel.ROLE_P))) {
// P Stamp
stamptList.add(stampInfo);
}
else if (stampInfo.isSerialized() && (role.equals(IInfoModel.ROLE_DIAGNOSIS))) {
// 病名 Stamp
diagList.add(stampInfo);
}
}
}
// カルテのテンプレートかどうかはpathで病名があるかどうか
//s.oh^ 2013/08/12 パスの傷病名対応
//boolean hasDisease = (!diagList.isEmpty());
boolean hasDisease = true;
//s.oh$
boolean template = pathTree && hasDisease;
// まとめてデータベースからフェッチしインポートする
if (!textList.isEmpty()) {
// テンプレートの場合はSOA
if (template) {
KarteEditor ke = (KarteEditor)pPane.getParent();
ke.getSOAPane().textStampInfoDropped(textList);
} else {
pPane.textStampInfoDropped(textList);
}
}
if (!stamptList.isEmpty()) {
pPane.stampInfoDropped(stamptList);
}
// contextへエクスポートする
if (!diagList.isEmpty()) {
Chart context = pPane.getParent().getContext();
StringBuilder sb = new StringBuilder();
int index = 0;
boolean addedOther = false;
for (ModuleInfoBean b : diagList) {
context.addDroppedDiagnosis(b);
if (index==0) {
sb.append(b.getStampName());
} else {
if(!addedOther) {
sb.append(ClientContext.getMyBundle(PTransferHandler.class).getString("text.etc"));
addedOther = true;
}
}
index++;
}
// message
showDiagnosisAddedMessage(sb.toString());
}
return true;
} catch (Exception e) {
e.printStackTrace(System.err);
}
return false;
}
/**
* DropされたStamp(ModuleModel)をインポートする。
* @param tr Transferable
* @return インポートに成功した時 true
*/
private boolean doStampDrop(OrderList list, boolean drop) {
Chart chart = null;
ChartDocument doc = pPane.getParent();
if(doc instanceof KarteEditor) {
chart = ((KarteEditor)doc).getContext();
}
try {
// スタンプのリストを取得する
ModuleModel[] stamps = list.orderList;
// pPaneにスタンプを挿入する
for (int i = 0; i < stamps.length; i++) {
pPane.stamp(stamps[i]);
}
// dragggされたスタンプがあるときdroppした数を設定する
// これで同じpane内でのDnDを判定している
if (pPane.getDraggedCount() > 0 && pPane.getDrragedStamp() != null) {
if (drop) {
pPane.setDroppedCount(stamps.length);
} else {
pPane.setDraggedCount(0);
pPane.setDroppedCount(0);
pPane.setDrragedStamp(null);
}
}
return true;
} catch (Exception e) {
e.printStackTrace(System.err);
}
return false;
}
/**
* クリップボードへデータを転送する。
*/
@Override
public void exportToClipboard(JComponent comp, Clipboard clip, int action) {
super.exportToClipboard(comp, clip, action);
// cut の場合を処理する
if (action == MOVE) {
JTextPane pane = (JTextPane) comp;
if (pane.isEditable()) {
pane.replaceSelection("");
}
}
}
@Override
public JComponent getComponent() {
return pPane.getTextPane();
}
private boolean canPaste() {
if (!pPane.getTextPane().isEditable()) {
return false;
}
Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
if (t == null) {
return false;
}
return t.isDataFlavorSupported(DataFlavor.stringFlavor) ||
t.isDataFlavorSupported(OrderListTransferable.orderListFlavor) ||
t.isDataFlavorSupported(LocalStampTreeNodeTransferable.localStampTreeNodeFlavor);
}
@Override
public void enter(ActionMap map) {
if (pPane.getTextPane().isEditable()) {
map.get(GUIConst.ACTION_PASTE).setEnabled(canPaste());
map.get(GUIConst.ACTION_INSERT_TEXT).setEnabled(true);
map.get(GUIConst.ACTION_INSERT_STAMP).setEnabled(true);
}
}
@Override
public void exit(ActionMap map) {
}
private void showDiagnosisAddedMessage(String dicease) {
//s.oh^ 2013/08/12 パスの傷病名対応
//boolean show = Project.getBoolean("show.diagnosis.added.message", true);
boolean show = true;
//s.oh$
if (show) {
//s.oh^ 2013/08/12 パスの傷病名対応
//JLabel msg1 = new JLabel("下記を傷病名タブに追加しました。");
//JLabel msg2 = new JLabel(dicease);
java.util.ResourceBundle bundle = ClientContext.getMyBundle(PTransferHandler.class);
String m1 = bundle.getString("message.addedDiagnosis1");
String m2 = bundle.getString("message.addedDiagbosis2");
String cbText = bundle.getString("confirm.noShowMessage");
String paneTitle = bundle.getString("title.optionPane");
JLabel msg1 = new JLabel(m1);
JLabel msg2 = new JLabel(m2);
JLabel msg3 = new JLabel(dicease);
//s.oh$
final JCheckBox cb = new JCheckBox(cbText);
cb.setFont(new Font("Dialog", Font.PLAIN, 10));
cb.addActionListener((ActionEvent e) -> {
Project.setBoolean("show.diagnosis.added.message", !cb.isSelected());
});
JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(pPane.getParent().getUI()),
//s.oh^ 2013/08/12 パスの傷病名対応
//new Object[]{msg1,msg2,msg3,cb},
new Object[]{msg1,msg2,msg3},
//s.oh$
ClientContext.getFrameTitle(paneTitle),
JOptionPane.INFORMATION_MESSAGE,
ClientContext.getImageIconArias("icon_info"));
}
}
}