« 2009年1月 | トップページ | 2009年3月 »

2009年2月

2009年2月27日 (金)

カルテ保存後ウインドウを閉じる

カルテを別ウインドウで編集してセーブした後,エディタフレームは不要なので,セーブ後に閉じるようにする。

client/KarteEditor.java の編集

private void save2(final SaveParams params) throws DolphinException {
 ・
 ・
    // 文書履歴の更新を通知する
    //
    chart.getDocumentHistory().getDocumentHistory();
////↓セーブしたら,frame を閉じるようにする
    if (getContext() instanceof EditorFrame) chart.getFrame().dispose();
////↑

2009年2月23日 (月)

動的 startNumRow

オリジナルでは TableModel の startNumRow を多めに設定してある。そのため,table を使う画面では,最初からスクロールバーが出ており,知らないうちにちょっとスクロールして,先頭の方の項目が隠れてしまったりする。startNumRow を少なめに設定するとスクロールバーは消えるが,今度は renderer が getRowCount データのある範囲しかレンダリングしてくれず,実用上は問題がないものの見た目がかっこわるい。そこで,動的に startNumRow を調節して,いつも画面全体にレンダリングして,しかもスクロールバーがでないようにした。

 

table/ObjectReflectTableModel.java の編集

//// 組込先の JTable とその親の viewport
private boolean table = false; //親テーブルのセットの有無
private javax.swing.JComponent view; // 親テーブルの viewport
private int rowHeight; // 親テーブルの行の高さ
 ・
 ・
////↓ 動的 startNumRow のため,組み込み先の table をセットする
    public void setTable(javax.swing.JTable t) {
        if (t != null) {
            rowHeight = t.getRowHeight();
            view = (JComponent) t.getParent();
            if ((rowHeight != 0) & (view != null)) table = true;
        } else table = false;
    }
////↑
 ・
 ・
  public int getRowCount() {
////↓   動的 startNumRows のため,組み込み先のテーブルがセットされていたらその親に startNumRows を合わせる
    if (table) startNumRows = view.getHeight() / rowHeight;
////↑
    return (objectList != null && objectList.size() > startNumRows) ? objectList.size()
                : startNumRows;
  }

table/ObjectTableModel.java の編集

////↓   動的 startNumRow 調整のためのコード
    private int rowHeight;
    private JComponent view;
    private boolean table;

    public void setTable(javax.swing.JTable t) {
        if (t != null) {
            rowHeight = t.getRowHeight();
            view = (JComponent) t.getParent();
            if ((rowHeight != 0) & (view != null)) table = true;
            } else table = false;
        }

    public int getRowCount() { //オリジナルの getRowCount はコメントアウト
        // 動的 startNumRows のため,組み込み先のテーブルがセットされていたらその親に startNumRows を合わせる
        if (table) {
            startNumRows = view.getHeight() / rowHeight;
        }
        int size = getObjectCount();
        return size < startNumRows ? startNumRows : size;
    }
////↑
あとは,上記の TableModel を組み込んだ画面を表示するクラスで,画面初期化部分(initComponent(), initialize()等)の最後に TableModel に対して組み込まれた JTable を教える1行を加える。
////↓   動的 startNumRows 調節のための設定
  tableModel.setTable(diagTable);
////↑
組み込むところ
  • DiagnosisDocument.java
  • DocumentHistory.java
  • AllergyInspecter.java
  • PhysicalInspecter.java
    plugin
  • PatientSearchImpl.java
  • WatingListImpl.java
  • LaboTestImporter.java
  • AppointTablePanel.java
  • OrderHistoryPanel.java

2009年2月21日 (土)

1年前のカルテが出なくなった

OpenDolphin 使用開始から1年を過ぎて,1年前のカルテがでなくなった。
DocumentHistory.java のバグだったので修正した。ついでに,extractionObjects をきれいに並べて,DocumentHistoryView.java の extractionCombo とデータを合わせた。

 

client/DocumentHistory.java の修正

/**
 * 抽出期間を変更し再検索する。
 */
public void periodChanged(int state) {
    if (state == ItemEvent.SELECTED) {
        ////バグ見つけちゃった int index = contentCombo.getSelectedIndex();
        int index = extractionCombo.getSelectedIndex();
 ・
 ・
private void initComponent() {
 ・
 ・
    // ToDO
    //// きれいに並べた。DocumentHistoryView の extractionCombo も同じく並べた
    extractionObjects = new NameValuePair[7];
    extractionObjects[0] = new NameValuePair("1ヶ月", "-1");
    extractionObjects[1] = new NameValuePair("3ヶ月", "-3");
    extractionObjects[2] = new NameValuePair("半年", "-6");
    extractionObjects[3] = new NameValuePair("1年", "-12");
    extractionObjects[4] = new NameValuePair("2年", "-24");
    extractionObjects[5] = new NameValuePair("3年", "-36");
    extractionObjects[6] = new NameValuePair("全て", "-60");

2009年2月18日 (水)

カレンダー表示

Calendar
  • 文字をセンタリングした
  • 矢印アイコンを小さくした
  • ポップアップカレンダーが尻切れになる場合があるのを修正
  • ポップアップカレンダーのデフォルト表示月を最終受診日のある月にした
  • ポップアップカレンダーのボタン制御がされてなかったのを修正

client/PatientInspector.java の編集

private void initComponents() {
 ・
 ・
  basicInfoInspector.getPanel().setPreferredSize(new Dimension(prefW2, 40));
  basicInfoInspector.getPanel().setMaximumSize(new Dimension(prefW2, 40));
  basicInfoInspector.getPanel().setMinimumSize(new Dimension(prefW2, 40));
  //memoInspector.getPanel().setPreferredSize(new Dimension(prefW, 70));
  allergyInspector.getPanel().setPreferredSize(new Dimension(prefW, 100));
  ////docHistory.getPanel().setPreferredSize(new Dimension(prefW, 280));
  physicalInspector.getPanel().setPreferredSize(new Dimension(prefW, 110));
  //int prefH = patientVisitInspector.getPanel().getPreferredSize().height;
  //patientVisitInspector.getPanel().setPreferredSize(new Dimension(prefW, prefH));
////↓   サイズ微調整
  docHistory.getPanel().setPreferredSize(new Dimension(prefW, 350));
  patientVisitInspector.getPanel().setPreferredSize(new Dimension(prefW, 180));
  patientVisitInspector.getPanel().setMinimumSize(new Dimension(prefW, 180));
  patientVisitInspector.getPanel().setMaximumSize(new Dimension(prefW, 180));
  memoInspector.getPanel().setPreferredSize(new Dimension(prefW, 70));
  memoInspector.getPanel().setPreferredSize(new Dimension(prefW, 70));
////↑

client/CalendarCardPanel.java の編集

////↓
private JPanel cmdPanel;
private JPanel dummyPanel;
public CalendarCardPanel(HashMap colorTable) {
  this(colorTable, 0);
}

//public CalendarCardPanel(HashMap colorTable) {
public CalendarCardPanel(HashMap colorTable, int month) {
  current = month;
////↑
  this.colorTable = colorTable;
  calendarListener = new CalendarListener(this);
 ・
 ・
  cardPanel.setLayout(cardLayout);
  cardPanel.add(lc, name);
////↓
  //backBtn.setMargin(new Insets(2,2,2,2));
  //stopBtn.setMargin(new Insets(2,2,2,2));
  //forwardBtn.setMargin(new Insets(2,2,2,2));
  backBtn.setPreferredSize(new Dimension(15,15));
  stopBtn.setPreferredSize(new Dimension(15,15));
  forwardBtn.setPreferredSize(new Dimension(15,15));
  backBtn.setBorderPainted(false);
  stopBtn.setBorderPainted(false);
  forwardBtn.setBorderPainted(false);
  backBtn.setContentAreaFilled(false);
  stopBtn.setContentAreaFilled(false);
  forwardBtn.setContentAreaFilled(false);
////↑
 ・
 ・
  //JPanel cmdPanel = createCommnadPanel();
////↓
  cmdPanel = createCommnadPanel();
  cmdPanel.setBackground(ClientContext.getColor("color.calendar.title.back"));
  cmdPanel.setOpaque(true);
  dummyPanel = new JPanel();
  dummyPanel.setPreferredSize(cmdPanel.getPreferredSize());
  dummyPanel.setBackground(ClientContext.getColor("color.calendar.title.back"));
  dummyPanel.setOpaque(true);
  lc.getTitlePanel().add(cmdPanel, BorderLayout.EAST);
  lc.getTitlePanel().add(dummyPanel, BorderLayout.WEST);
  //cardPanel.setPreferredSize(new Dimension(193,153)); //h=45+18×n

  this.setLayout(new BorderLayout(0,0));
  //this.add(cmdPanel, BorderLayout.WEST);
  this.add(cardPanel, BorderLayout.CENTER);
  //this.add(cmdPanel, BorderLayout.NORTH);
  //this.add(cmdPanel, BorderLayout.EAST);
////↑
  controlNavigation();
 ・
 ・
public void setCalendarRange(int[] range) {
  this.range = range;
////追加
  controlNavigation();
}
 ・
 ・
private void controlNavigation() {
  if (range != null) {
////変更
    if (current == range[0]) {
      backBtn.setEnabled(false);
      forwardBtn.setEnabled(true);
      //if (backBtn.isEnabled()) {
      //    backBtn.setEnabled(false);
      //}
      } else if (current == range[1]) {
        backBtn.setEnabled(true);
        forwardBtn.setEnabled(false);
        //if (forwardBtn.isEnabled()) {
        //    forwardBtn.setEnabled(false);
        //}
      } else {
        backBtn.setEnabled(true);
        forwardBtn.setEnabled(true);
        //if (! backBtn.isEnabled()) {
        //    backBtn.setEnabled(true);
        //}
        //if (! forwardBtn.isEnabled()) {
        //    forwardBtn.setEnabled(true);
        //}
 ・
 ・
  private void showCalendar() {
 ・
 ・
    lc.getTableModel().setMarkDates(markList);
        }
////↓
    lc.getTitlePanel().add(cmdPanel, BorderLayout.EAST);
    lc.getTitlePanel().add(dummyPanel, BorderLayout.WEST);
    // popup メニューに表示されているときは,カレンダーの大きさに合わせて大きさを変える
    int n = lc.getTableModel().getRowCount();
    cardPanel.setPreferredSize(new Dimension(193,18*n+45));
    Container con = this.getParent();
    if (con instanceof JPopupMenu) ((JPopupMenu) con).pack();
////↑
    cardLayout.show(cardPanel, key);
  }

////↓   復活
  private JPanel createCommnadPanel() {
    JPanel cmd = new JPanel(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER,0,0));
    cmd.add(backBtn);
    cmd.add(stopBtn);
    cmd.add(forwardBtn);
    return cmd;
  }

client/LiteCalendarPanel.java の編集

////↓
private JPanel titlePanel = new JPanel();
public JPanel getTitlePanel() {
  return titlePanel;
}
////↑
public LiteCalendarPanel(int n, boolean addTitle) {
 ・
 ・
  // Replace DefaultRender
  DateRenderer dateRenderer = new DateRenderer();
////↓ dateRenderer.setHorizontalAlignment(SwingConstants.RIGHT);
  dateRenderer.setHorizontalAlignment(SwingConstants.CENTER);
  table.setShowHorizontalLines(true);
  table.setShowVerticalLines(false);
  table.setGridColor(new Color(250,250,250));
  table.setRowSelectionAllowed(false);
  //header
  table.getTableHeader().setDefaultRenderer(new CalendarHeaderRenderer());
  table.getTableHeader().setResizingAllowed(false);
  table.getTableHeader().setReorderingAllowed(false);
////↑
 ・
 ・
  // レイアウトする
  this.setLayout(new BorderLayout(0,0));
  if (addTitle) {
////↓
  titlePanel.setBackground(titleBack);
  titlePanel.setLayout(new BorderLayout(0,0));
  titlePanel.add(titleLabel, BorderLayout.CENTER);

  this.add(titlePanel, BorderLayout.NORTH);
  //this.add(getTitleLabel(), BorderLayout.NORTH);
////↑
}
 ・
 ・
protected class DateRenderer extends DefaultTableCellRenderer {
 ・
 ・
  public DateRenderer() {
    super();
    this.setOpaque(true);
////  this.setHorizontalAlignment(SwingConstants.RIGHT);
    this.setHorizontalAlignment(SwingConstants.CENTER);
 ・

client/CalendarHeaderRenderer.java の作成

package open.dolphin.client;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;

public class CalendarHeaderRenderer extends DefaultTableCellRenderer {

    private Border border;

    public CalendarHeaderRenderer() {
        this.setHorizontalAlignment(SwingConstants.CENTER);
        border = UIManager.getBorder("TableHeader.cellBorder");
    }
    @Override
    public Component getTableCellRendererComponent(JTable t, Object v, boolean isSelected, boolean hasFocus, int row, int col) {
        super.getTableCellRendererComponent(t, v, isSelected, hasFocus, row, col);

        setBorder(border);

        switch (col) {
            case 0:
                setForeground(Color.red);
                break;
            case 6:
                setForeground(Color.blue);
                break;
            default:
                setForeground(Color.black);
        }
        return this;
    }
}

plugin/CaremapDocument/…/SimpleCalendarPanel.java の編集

public final class SimpleCalendarPanel extends JPanel implements DragGestureListener, DropTargetListener, DragSourceListener {
 ・
 ・
//// private int horizontalAlignment = SwingConstants.RIGHT;
  private int horizontalAlignment = SwingConstants.CENTER;
private JTable createCalendarTable(GregorianCalendar gc) {
 ・
 ・
  tbl.setDefaultRenderer(java.lang.Object.class, dateRenderer);
////↓
  tbl.getTableHeader().setDefaultRenderer(new CalendarHeaderRenderer());
////↑

2009年2月11日 (水)

JBoss の server.log

診療終了後に何気なく JBoss の server.log を確認したところ,肥大化してものすごいことになっているのに気付いた。ログレベルを下げておいた。

 

/usr/local/jboss/server/default/conf/log4j.xml

<!-- Limit JBoss categories -->
<category name="org.jboss">
  <priority value="INFO"/>
</category>

<!-- Limit Hibernate categories -->
<category name="org.hibernate">
  <priority value="INFO"/>
</category>

2009年2月 2日 (月)

疑い病名の入力インターフェース

スタンプ箱から病名をカルテに入力する時に,ALT キーを押しながらドロップすると「疑い病名」で入力されるようにする。TransferHandler を登録した後に,DropTarget として設定して,ドラッグしてきた病名が diagTable 上に来たときに,ALT キーが押されているかどうかを検出して action として保存し,action の値で動作を変えるしくみ。

 

client/DiagnosisDocument.java の編集

////↓
  // 病名修飾語リスト
  private static String[] DIAGNOSIS_PREP = {"右","左","両"};
  private static String[] DIAGNOSIS_PREP_CODE = {"2056","2049","2057"};
  private static String[] DIAGNOSIS_POST = {"の急性増悪","の二次感染","の再発","の術後","の治療後"};
  private static String[] DIAGNOSIS_POST_CODE = {"8061","8069","8065","8048","8075"};
  // 最終受診日=今日受診している場合は今日,していないばあいは最後の受診日
  private int lastVisit_year;
  private int lastVisit_month;
  private int lastVisit_day;
  // Stamp から drop を受け取る場合のアクション
  private int action; // 通常は MOVE で,ALT が押されていたら COPY になる
////↑
 ・
 ・
private JPanel createDignosisPanel() {
 ・
 ・
  //
  // TransferHandler を設定する
  //
  diagTable.setTransferHandler(new DiagnosisTransferHandler(this));
  diagTable.setDragEnabled(true);
        
////↓ insertStamp() でALT キーで疑い病名に変換する機能をつけるため,action を記録する
  // ALT 押した場合が COPY になり,押してないと MOVE
  DropTarget dt = new DropTarget(diagTable, new DropTargetAdapter() {

    @Override
    public void dragEnter(DropTargetDragEvent dtde) {
      action = dtde.getDropAction();
    }

    @Override
      public void dropActionChanged(DropTargetDragEvent dtde) {
        action = dtde.getDropAction();
    }

    public void drop(DropTargetDropEvent dtde) {
      diagTable.getTransferHandler().importData(diagTable, dtde.getTransferable());
      dtde.dropComplete(true); // これをしないとドラッグしてきたアイコンが逃げる
    }
  });
  dt.setActive(true);
////↑
  // Layout
 ・
 ・
 ・
private void insertStamp(StampModel sm, int row) {

  if (sm != null) {
    RegisteredDiagnosisModel module = (RegisteredDiagnosisModel) BeanUtils.xmlDecode(sm.getStampBytes());

    // 今日の日付を疾患開始日として設定する
////↓ 疾患開始日を lastVisit に設定
    //GregorianCalendar gc = new GregorianCalendar();
    GregorianCalendar gc = new GregorianCalendar(lastVisit_year, lastVisit_month, lastVisit_day);
////↑
    String today = MMLDate.getDate(gc);
    module.setStartDate(today);

////↓ デフォルトのカテゴリーをセットする
    module.setCategory(open.dolphin.infomodel.IInfoModel.DEFAULT_DIAGNOSIS_CATEGORY);
    module.setCategoryDesc(open.dolphin.infomodel.IInfoModel.DEFAULT_DIAGNOSIS_CATEGORY_DESC);
    module.setCategoryCodeSys(open.dolphin.infomodel.IInfoModel.DEFAULT_DIAGNOSIS_CATEGORY_CODESYS);
    // diagnosis に「疑い」が入っていたら,疑いにセットする
    String diag = module.getDiagnosis();
    if (diag.endsWith("の疑い")) {
      String diagCode = module.getDiagnosisCode();
      module.setDiagnosis(diag.replace("の疑い", ""));
      module.setDiagnosisCode(diagCode.replace(".8002", ""));
      module.setCategory("suspectedDiagnosis");
      module.setCategoryDesc("疑い病名");
      module.setCategoryCodeSys("MML0015");
    }
    // ALT キーが押されていたら,疑いにセットする
    if (action == java.awt.dnd.DnDConstants.ACTION_COPY) {
      module.setCategory("suspectedDiagnosis");
      module.setCategoryDesc("疑い病名");
      module.setCategoryCodeSys("MML0015");
    }
////↑
 ・
 ・

スタンプ箱順番入替のインターフェース

スタンプ箱の項目を入れ替えるとき,フォルダの上にドロップするとフォルダの中に入ってしまい,どうしてもフォルダの前後に項目を移動することができない。そこで,フォルダの上にドロップしたときは,フォルダの中ではなく,そのフォルダの前に置くようにする。フォルダの中に入れたいときは,ALT キーを押すか,フォルダを展開して,その中の希望の場所にドロップすることにする。

 

client/StampTreeTransferHandler.java の編集

public class StampTreeTransferHandler extends TransferHandler {
 ・
 ・
  // KartePaneからDropされるテキストFlavor

  private DataFlavor stringFlavor = DataFlavor.stringFlavor;
     
////↓ ALT キーの状態を保存
  public boolean altPressed;
  public void setAltState(boolean a) {
    altPressed = a;
  }
////↑
 ・
 ・
@Override
public boolean importData(JComponent c, Transferable tr) {

  if (canImport(c, tr.getTransferDataFlavors())) {
 ・
 ・
    // newChild is ancestor のケース
    if (newParent != dropNode) {

      // Drag元のStampTreeとDropされるTreeが同じかどうかを判定する
      // shouldRemove = (sourceTree == target) ? true : false;
      // Tree内のDnDはLocalTransferable(参照)の故、挿入時点で元のスタンプを
      // 常に削除する。DnD後の削除は行わない。
      // shouldRemove = false;

////↓drop 位置が Leaf か, ALT が押されていなかったら前に挿入する
      // if (selected.isLeaf()) {
      if (selected.isLeaf() | !altPressed) {
////↑
        //
        // Drop位置のノードが葉の場合、その前に挿入する
 ・
 ・

 

client/StampTree.java の編集

public StampTree(TreeModel model) {
 ・
 ・
  this.putClientProperty("JTree.lineStyle", "Angled"); // 水平及び垂直線を使用する
  this.setEditable(false); // ノード名を編集不可にする
  this.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); // Single Selection// にする
  
  this.setRootVisible(true);
  //this.addMouseMotionListener(new MouseDragDetecter()); // オリジナルの listener はコメントアウト
////↓ 選択状態じゃなくてもドラッグ開始するための drag listener
  this.addMouseMotionListener(new MouseMotionAdapter() {
    @Override
    public void mouseDragged (MouseEvent e) {
      getTransferHandler().exportAsDrag((JComponent) e.getSource(), e, TransferHandler.COPY);
    }
  });
  // JTree のデフォルトの DropTarget をオーバーライドする
    DropTarget dt = new DropTarget(this, new DropTargetAdapter() {
      StampTree st;
      StampTreeTransferHandler sttf;
      TreePath initRow;

      @Override
      public void dragEnter(DropTargetDragEvent dtde) {
        // drag 開始時の path を記録しておく
        st = (StampTree) dtde.getDropTargetContext().getComponent();
        sttf = (StampTreeTransferHandler) st.getTransferHandler();
        initRow = st.getSelectionPath();
      }
      @Override
      public void dragExit(DropTargetEvent dte) {
        // drop 領域から出たら,開始時の path に戻しておく
        st.setSelectionPath(initRow);
      }
      @Override
       public void dragOver(DropTargetDragEvent dtde) {
        // drop しようとしている部分を選択状態にする
        st.setSelectionPath(st.getClosestPathForLocation(dtde.getLocation().x, dtde.getLocation().y));
      }
      public void drop(DropTargetDropEvent dtde) {
        // action= (ALT 押した場合が COPY) (押してないと MOVE)
        boolean alt = (dtde.getDropAction() == DnDConstants.ACTION_COPY)? true: false;
        sttf.setAltState(alt); // ALT の状態をセットしてから importData を呼ぶ
        st.getTransferHandler().importData(st, dtde.getTransferable());
        dtde.dropComplete(true); // これをしないとドラッグしてきたアイコンが逃げる
      }
    });
    dt.setActive(true);
////↑
 ・
 ・

« 2009年1月 | トップページ | 2009年3月 »