« 2009年8月 | トップページ | 2009年10月 »

2009年9月

2009年9月28日 (月)

dialog が開いたら特定の JTextField にフォーカス

AllergyEditor が開いたら「要因」にフォーカスする。

client/AllergyEditor.java

dialog = pane.createDialog(inspector.getContext().getFrame(), ClientContext.getFrameTitle("アレルギー登録"));

//↓  dialog が開いたら FactorFld にフォーカスを当てる
dialog.addWindowListener(new WindowAdapter(){
  @Override
  public void windowOpened(WindowEvent e) {
    view.getFactorFld().requestFocusInWindow();
  }
});
//↑

 

PhysicalEditor が開いたら「体重」にフォーカスする。

client/PhysicalEditor.java

dialog = pane.createDialog(inspector.getContext().getFrame(), ClientContext.getFrameTitle("身長体重登録"));

//↓  dialog が開いたら WeightFld にフォーカスを当てる
dialog.addWindowListener(new WindowAdapter(){
  @Override
  public void windowOpened(WindowEvent e) {
    view.getWeightFld().requestFocusInWindow();
  }
});
//↑

 

患者検索タブをクリックしたらキーワードフィールドにフォーカスする。

plugin/PatientSearchImpl.java

public void enter() {
  controlMenu();
  //↓ 入ってきたら,キーワードフィールドにフォーカス
  Runnable r = new Runnable() {
    public void run() {
      view.getKeywordFld().requestFocusInWindow();
    }
  };
  SwingUtilities.invokeLater(r);
//↑
}

【09/10/10追記】上記だけだと,起動後最初の表示の時にフォーカスが取れないことがあった。Dolphin.java の変更で対応。

client/Dolphin.java

//
// タブの切り替えで plugin.enter() をコールする
//
tabbedPane.addChangeListener(new ChangeListener() {

  public void stateChanged(ChangeEvent e) {
    int index = tabbedPane.getSelectedIndex();
    MainComponent plugin = (MainComponent) providers.get(String.valueOf(index));
    if (plugin.getContext() == null) {
      plugin.setContext(Dolphin.this);
      plugin.start();
      tabbedPane.setComponentAt(index, plugin.getUI());
//↓
//  } else {
//    plugin.enter(); // これだと,start() した最初は enter() しないことになる
//↑
    }
//↓
    plugin.enter();
//↑
    mediator.addChain(plugin);
    }
  });

 

マスター検索のとき,キーワードフィールドにフォーカスする。

order/MasterPanel.java

public void enter() {
  setItemCount(tableModel.getObjectCount());
//↓
  Runnable r = new Runnable() {
    public void run() {
      keywordField.requestFocusInWindow();
    }
  };
  SwingUtilities.invokeLater(r);
//↑
}

2009年9月21日 (月)

紹介状作成 NeoOffice マクロ

ORCAからデータを読み込んで,紹介状作成のデータとして使ってくれる NeoOffice のマクロ。

ダウンロード Letter.zip (4431.7K)

 


修正履歴

  • 住所の番地が入力されなかったのを修正。home_banti を忘れていた。(2009/9/23)
  • 診断書追加。(2009/10/25)
  • 北大病院専用予約申込書追加。(2011/09/22)

2009年9月19日 (土)

OpenDolphin-1.3.0.2 ソース公開

現時点の全ソースを公開しておくことにした。前回公開分から 09/3/25 - 09/9/19 の変更を加えたもの。バージョンは,1.3.0.2 とした。


    ※ このソースには 09/9/19 以降の変更は反映されていません。

StampHolder の隠しコマンド作成

処方スタンプを選択してシフト+コマンド+C を押すと,テキストとして処方がクリップボードにコピーされる隠しコマンドを作った。

 

client/StampHolder.java

public void enter(ActionMap map) {
 ・
 ・
  map.get(GUIConst.ACTION_PASTE).setEnabled(false);
        
  setSelected(true);
  ////    隠しコマンドセット
  addHiddenCommand();
}
    
public void exit(ActionMap map) {
  setSelected(false);
  ////    隠しコマンド除去
  removeHiddenCommand();
}
 ・
 ・
////↓ 隠しコマンド
private void addHiddenCommand() {

  // Shift+command C で,処方をテキストとしてクリップボードにコピー
  InputMap im = this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
  im.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.META_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK), "copyAsText");
  this.getActionMap().put("copyAsText", new AbstractAction(){
    public void actionPerformed(ActionEvent e) {
      if (getStamp().getModel().getClass().getName().equals("open.dolphin.infomodel.BundleMed")) {
        try {
          IInfoModel model = getStamp().getModel();
          VelocityContext context = ClientContext.getVelocityContext();
          context.put("model", model);
          context.put("hints", getHints());
          context.put("stampName", getStamp().getModuleInfo().getStampName());
          String templateFile = "open.dolphin.infomodel.BundleMed-text.vm";
          StringWriter sw = new StringWriter();
          BufferedWriter bw = new BufferedWriter(sw);
          InputStream instream = ClientContext.getTemplateAsStream(templateFile);
          BufferedReader reader = new BufferedReader(new InputStreamReader(instream, "SHIFT_JIS"));
          Velocity.evaluate(context, bw, "stmpHolder", reader);
          bw.flush();
          bw.close();
          reader.close();
          // 全角数字とスペースを直す
          String text = sw.toString();
          for (int i = 0; i < MATCHIES.length; i++) {
            text = text.replace(MATCHIES[i], REPLACES[i]);
          }

          Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
          clipboard.setContents(new StringSelection(text), null);

        } catch (Exception ex) {
          ex.printStackTrace();
        }
      }
    }
  });
}

private void removeHiddenCommand() {

  // Shift+command C
  InputMap im = this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
  im.remove(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.META_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
}

resources/template/open.dolphin.infomodel.BundleMed-text.java

##-------------------------------------
##         RP Template    
##-------------------------------------
#foreach ($item in $model.getClaimItem())
#if (!$item.getCode().matches("0085[0-9]{5}") && !$item.getCode().matches("001000[0-9]{3}") && !$item.getCode().matches("810000001"))
${item.getName()}	$!{item.getNumber()} $!{item.getUnit()} 
#else
${item.getName()} 
#end
#end
${model.getAdminDisplayString()}

2009年9月17日 (木)

jconsole による解析

jconsole というツールが jdk に標準で入っている。ヒープメモリやスレッドの状態を教えてくれるツールである。試しに,ある日の OpenDolphin の様子を,jconsole で見てみた。なお jconsole を使うには起動時にオプション -Dcom.sun.management.jmxremote を付けて起動し,その後 jconsole を立ち上げて接続する。

 

Photo

    当院は患者さんの数が少ないので参考にはならないが,ヒープメモリはピーク時 40M をわずかに超えるくらいで推移しているようだ。なお,ヒープメモリは -Xms128m -Xmx256m としていた。

Eden_space

    Eden 領域

Survivor_space

    Survivor 領域

Tenured_gen

    Tenured Gen

Photo_2

    非ヒープ領域

Photo_3

    ライブスレッドが 27個。

 

当面メモリ不足と言うことはなさそう。

SendClaimImpl.java の BufferedOutputStream

close() して,null を入れるとメモリの節約になるような記事を見つけたので,close() してみた。意味があるのかどうか不明。

 

plugin/SendClaimImpl.java

public void run() {
 ・
 ・
  // Gets io stream
  writer = new BufferedOutputStream(new DataOutputStream(socket.getOutputStream()));
  reader = new BufferedInputStream(new DataInputStream(socket.getInputStream()));

  // Writes UTF8 data
  writer.write(instance.getBytes(enc));
  writer.write(EOT);
  writer.flush();

  // Reads result
  int c = reader.read();
  if (c == ACK) {
      log("CLAIM ACK", claimEvent);
  } else if (c == NAK) {
      warnLog("CLAIM NAK", claimEvent);
  }
  socket.close();

////↓ 解放した方がいい?
  writer.close(); writer = null;
  reader.close(); reader = null;
////↑
 ・
 ・

2009年9月15日 (火)

ScheduledExecutorService の使い回し

jconsole というツールが jdk に標準で入っている。ヒープメモリやスレッドの状態を教えてくれるツールであるが,そんなものがあることを初めて知った。jconsole で見ていたら,靴ボタンを押して受付患者チェックをすると,ライブスレッドがどんどん増えていくことに気がついた。試しに靴ボタンを連打してみたら,えらいことになった。普通そんなことはしないので問題ないのかもしれないが,気持ち悪いのでScheduledExecutorService は使い回すことにした。これで,靴ボタンを連打しても大丈夫。

 

plugin/WatingListImpl.java

////↓
private DocumentPeeker peeker;
private ScheduledExecutorService schedule;
private static final Color SHOSHIN_COLOR = new Color(180,220,240); //青っぽい色
private static final Color KARTE_EMPTY_COLOR = new Color(250,200,160); //茶色っぽい色
private static final Color DIAGNOSIS_EMPTY_COLOR = new Color(243,255,15); //黄色
////↑

/** 
 * Creates new WatingList 
 */
public WatingListImpl() {
  setName(NAME);
  ////↓   使い回すオブジェクト
  peeker  = new DocumentPeeker();
  schedule = Executors.newSingleThreadScheduledExecutor();
  ////↑
}
 ・
 ・
 public void restartCheckTimer() {
 ・
 ・
  ////↓   schedule は,コンストラクタで作って使い回すことにする
  // ScheduledExecutorService schedule = Executors.newSingleThreadScheduledExecutor();
  timerHandler = schedule.scheduleWithFixedDelay(pvtChecker, 0, checkInterval, TimeUnit.SECONDS);
}
 ・
 ・
public void checkFullPvt() {
  if (timerHandler != null) {
    ////↓ 定期チェック中ならチェックしない
    if (timerHandler.getDelay(TimeUnit.SECONDS) <= 1) {
      logger.info("regular pvtChecker in process");
      return;
    }
    ////↑
    timerHandler.cancel(false);
  }
 ・
 ・
  ////↓   schedule は,コンストラクタで作って使い回すことにする
  // ScheduledExecutorService schedule = Executors.newSingleThreadScheduledExecutor();
  timerHandler = schedule.scheduleWithFixedDelay(pvtChecker, checkInterval, checkInterval, TimeUnit.SECONDS);
}

2009年9月14日 (月)

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

以前 Exception が出て直していたのだが,頻度は減っていたもののやっぱり時々同じ Exception が出る。根本的に何かおかしいと思ってよく考えてみると,2つの問題点が分かった。編集終了後の EditorFrame を閉じるのは思ったより大変なことだった。

  1. まず,EditorFrame で KarteEditor が作られているのに,KarteEditor の方から EditorFrame.close() を呼んだらだめだろう。KarteEditor から EditorFrame.close() を呼んだら,戻ってきたら自分が既に消えていた,という事態になりうる。【2009/10/18追記】PropertyChangeListener の使い方を勉強して,KarteEditor で save が完了したら EditorFrame に PropertyChange を知らせて対処するように書き換えた。
  2. ChartMediator の調整も必要。ChartMediator は ChartImpl と EditorFrame で各々インスタンスが作られるが,KeyboardFocusManager にリスナが付くので,EditorFrame の Component をクリックした場合でも,ChartImpl と EditorFrame の両方の ChartMediator にイベントが行く仕様になっている。つまり,クリックされた Component は,ChartImpl からと,EditorFrame から,連続して2回 enter や exit を受け取る。
    オリジナルの状態だと ChartImpl と EditorFrame の両方の実体があるので問題ないが,今回のように EditorFrame を先に閉じてしまうと,EditorFrame を閉じる際に発生したイベントが ChartImpl に伝わって,ChartImpl 側の ChartMediator から,もう無いはずの EditorFrame の Component に対して exit(getActions()) が送られて Exception が出る。
    この過程でかかった微妙な時間により,それを受ける EditorFrame の実体がまだ残っていれば Exception は出ず,解放されてしまっていれば Null Pointer Exception が出る。Exception が毎回ではなく,たまに出ていたのはそういうわけだったようだ。

というわけで,EditorFrame.close() は EditorFrame 側で呼ぶように書き直し,ChartMediator は自分の component からのイベントのみ処理するようにした。

 

client/KarteEditor.java

SINGLE_MODE も使う場合は,save1 も同様に変更
private void save2(final SaveParams params) throws DolphinException {
  ・
  ・
      //
      // 文書履歴の更新を通知する
      //
      chart.getDocumentHistory().getDocumentHistory();
      ////↓セーブしたら,frame を閉じるようにする ← これはダメ
      // if (getContext() instanceof EditorFrame) chart.close();
      ////↑
      //// PropertyChangeListener で対応
      boundSupport.firePropertyChange(KarteEditor.SAVE_DONE, false, true);
    
    } else {
        // errMsg を処理する
        // エラーを表示する
        JFrame parent = chart.getFrame();
        String title = ClientContext.getString("karte.task.saveTitle");
        JOptionPane.showMessageDialog(parent,
          errMsg,
          ClientContext.getFrameTitle(title),
          JOptionPane.WARNING_MESSAGE);
      }
    }
  };
  // EditorFrame に save 後閉じる処理を入れたので,ここの Thread が終わらないうちに
  // EditorFrame が閉じてしまわないように,chart が EditorFrame の時は,仕事が終わるまで待ってもらう。
  // if (chart instanceof EditorFrame) task.executeInForeground();
  // else task.execute();  // PropertyChangeListener で対応
////↑
  task.execute();
}

helper/DBTask.java

////↓
/**
 * non thread version of execute
 * Thread を使わないで,Task が終了するまで待って欲しいとき用
 * @return
 */
public T executeInForeground() {
  T ret = null;
  try {
    ret = doInBackground();
    succeeded(ret);
  } catch (Exception ex) {
    System.out.println(ex);
  }
  return ret;
}
////↑

client/EditorFrame.java

public void close() {
        
  if (mode == EditorMode.EDITOR) {

    if (editor.isDirty()) {
  ・
  ・
       switch (option) {
                    
        case 0:
          editor.save();
          //// editor が Dirty でなければ(セーブ完了していれば),EditorFrame を閉じる
          //// if (!editor.isDirty()) stop(); // PropertyChangeListener で対応
          break;

        case 1:
          stop();
          break;
  ・
  ・

client/ChartMediator.java

class FocusPropertyChangeListener implements PropertyChangeListener {

  public void propertyChange(PropertyChangeEvent e) {
    String prop = e.getPropertyName();
    logger.debug("focusManager propertyChange :" + prop);
    if ("focusOwner".equals(prop)) {

    // 自分の component からの propertyChange だけ処理するようにする
    Window w = ((KeyboardFocusManager) e.getSource()).getActiveWindow();
    if ((w != null) && (w == chart.getFrame())) {
      Component comp = (Component) e.getNewValue();
      if (comp instanceof JTextPane) {
        Object obj = ((JTextPane) comp).getClientProperty("kartePane");
        if (obj != null && obj instanceof KartePane) {
          setCurKarteComposit((KarteComposite) obj);
        }
      } else if (comp instanceof KarteComposite) {
        setCurKarteComposit((KarteComposite) comp);
      }
    }
  }
}

2009年9月12日 (土)

マスタ検索画面の結果リストの文字色

マスタ検索の検索結果が表示される Table は,文字が Label で表示されるため,JTable の Selected Color が適用されず,選択しても文字色が黒のままになってしまう。黒のままでも実用上問題はないのだが,他の Table のように,選択すると Selected Color になるように変更した。

 

client/MasterRenderer.java

//↓ 選択された状態の時は,色を変えたいので,パラメーターとして,色を持ってくることにした
// 呼び元で,isSelected の状態に合わせて色を指定して呼び出す

// public void setColor(JLabel label, String startDate, String endDate) {
public void setColor(JLabel label, String startDate, String endDate, Color c) {

  switch (useState(startDate, endDate)) {

  case 0:
    label.setEnabled(false);
    //label.setForeground(beforStartColor);
    ////label.setForeground(Color.BLACK);
    label.setForeground(c);
    break;

    case 1:
      label.setEnabled(true);
      //label.setForeground(inUseColor);
      ////label.setForeground(Color.BLACK);
      label.setForeground(c);
      break;

    case 2:
      label.setEnabled(false);
      //label.setForeground(afterEndColor);
      ////label.setForeground(Color.BLACK);
      label.setForeground(c);
      break;
  }
}

public void setColor(JLabel label, String endDate, Color c) {

  //setColor(label, null, endDate);
  setColor(label, null, endDate, c);
}
あとは,呼び出し元で,setColor に色をセットする
  • order/DiagnosisMaster.java
  • order/InjectionMedicineMaster.java
  • order/MedicalSuppliesMaster.java
  • order/ToolMaterialMaster.java
  • order/TreatmentMaster.java
public Component getTableCellRendererComponent(
    JTable table,
    Object value,
    boolean isSelected,
    boolean isFocused,
    int row, int col) {
  Component c = super.getTableCellRendererComponent(
 ・
 ・
  if (value != null && value instanceof DiseaseEntry) {

    DiseaseEntry entry = (DiseaseEntry) value;

    String disUseDate = entry.getDisUseDate();

    ////  setColor(label, disUseDate); // isSelected に合わせて色を変える
    if (isSelected) setColor(label, disUseDate, table.getSelectionForeground());
    else setColor(label, disUseDate, table.getForeground());
 ・
 ・

2009年9月11日 (金)

にせモーダル

SchemaEditor を改造した時,オリジナルは JDialog だったが,それを JFrame + setAlwaysOnTop にして,にせモーダルにした。そのため SchemaEditor は一見モーダルなようで,実は後ろのウインドウを操作することができる。後ろのウインドウを閉じてしまうこともできるので危険なのだが,知ってて使えば他のカルテの画像を見ながらシェーマを書くこともできて便利。知ってて自分だけ使うのならこの方がいい。というわけで,StampEditorDialog もにせモーダル化した。

 

client/StampEditorDialog.java

 ・
 ・
////private JDialog dialog; にせモーダル化
private JFrame dialog;
 ・
 ・
private void initialize() {
        
  // カルテに展開するかスタンプボックスに保存するかで
  // モーダル属性及びボタンのアイコンとツールチップを変える
  if (toKarte) {
////↓ にせモーダル化 dialog = new JDialog((Frame) null, true);
    dialog = new JFrame();
    dialog.setAlwaysOnTop(true);
////↑
    okButton = new JButton(createImageIcon(OK_ICON_KARTE));
    okButton.setToolTipText("カルテに展開します");
  } else {
////↓ここは使われてないようだ dialog = new JDialog((Frame) null, false);
    dialog = new JFrame();
////↑
    okButton = new JButton(createImageIcon(OK_ICON_STAMPBOX));
    okButton.setToolTipText("スタンプボックスに保存します");
  }
 ・
 ・

2009年9月10日 (木)

処方箋にコメント挿入

処方箋にコメントを入れられたら便利ではないかというご指摘を戴いた。確かに,たまに処方箋に手書きでコメントを入れたりすることもあったので,コメント(810000001)が挿入できるようにしてみた。基本的には「処置・検査スタンプにコメント」と同じ変更を MedicineTablePanel.java に行っただけ。ユーザ登録コメント検索の追加(^8 を検索するようにする)も必要。

 

order/MedicineTablePanel.java

public MedicineTablePanel(StampModelEditor parent) {
 ・
 ・
  medTableModel = new ObjectReflectTableModel(COLUMN_NAMES, ROWS, METHOD_NAMES, null) {
            
    // 数量と回数のみ編集可能
    @Override
    public boolean isCellEditable(int row, int col) {
    ////↓ コメントが付けられるようにする
    if (col == 1) { // 診療内容カラム
      // col=0 がコメントコード(810000001)なら,この cell を編集可能とする
      String code = (String) this.getValueAt(row, 0);
      if (code != null) return code.equals("810000001")? true : false;
    }
    ////↑
    return (col == ONEDAY_COLUMN || col == BUNDLE_COLUMN) ? true : false;
  }
 ・
 ・
  MasterItem mItem = (MasterItem) getObject(row);
                
  if ( col == ONEDAY_COLUMN && mItem != null) {
    mItem.setNumber((String) o);
    stateMgr.checkState();
  } else if ( col == BUNDLE_COLUMN && mItem != null) {
    mItem.setBundleNumber((String) o);
    stateMgr.checkState();
  }
  ////↓ MasterItem に診療内容(入力したコメント)を設定する
  if (col == 1 && mItem != null) {
    mItem.setName((String) o);
    stateMgr.checkState();
  }
  ////↑
 ・
 ・

  // 回数カラム
  JTextField tf2 = new JTextField();
  tf2.addFocusListener(AutoRomanListener.getInstance());
  TableColumn column2 = medTable.getColumnModel().getColumn(BUNDLE_COLUMN);
  DefaultCellEditor dce2 = new DefaultCellEditor2(tf2);
  dce2.setClickCountToStart(ccts);
  column2.setCellEditor(dce2);
        
  ////↓   診療内容カラム(column number = 1)にセルエディタを設定する
  JTextField tf3 = new JTextField();
  tf3.addFocusListener(AutoRomanListener.getInstance());
  column = medTable.getColumnModel().getColumn(1);
  DefaultCellEditor dce3 = new DefaultCellEditor2(tf3);
  dce3.setClickCountToStart(ccts);
  column.setCellEditor(dce3);
  ////↑
 ・
 ・
 ・
public void propertyChange(PropertyChangeEvent e) {
 ・
 ・
  ////↓ ユーザ登録領域なら,投与量の初期値 を "." にセットする
  //if (item.getCode().substring(0,6).equals("001000")) {
  if (item.getCode().substring(0,6).equals("001000") || item.getCode().startsWith("8")) {
    item.setNumber(".");
  }
  ////↑
 ・
 ・

2009年9月 9日 (水)

シェーマボックスの多重起動禁止

オリジナルではシェーマボックスを多重起動できるが,当院の診療ではシェーマボックスを頻用するため,画面が重なったシェーマボックスだらけになってしまいがちだった。そこで,多重起動しないように改変していたのだが,一度シェーマボックスを閉じると二度と起動しないようになってしまっていたので直した。

 

client/Dolphin.java

/**
 * シェーマボックスを表示する。
 */
//// 多重起動しないようにする
public void showSchemaBox() {
  //System.out.println("---------------imageBox=" + imageBox);
  if (imageBox == null) {
    imageBox = new ImageBox();
    imageBox.setContext(this);
    imageBox.start();
  } else imageBox.enter();
}

client/ImageBox.java

////↓ 多重起動しないための入り口
@Override
public void enter() {
  if (frame != null) {
    frame.setVisible(true);
  }
}
////↑

public void stop() {
//// 多重起動しないようにするので,window を close しても,window は残しておいて,見えなくするだけにする
////        if (tabbedPane != null) {
////            int cnt = tabbedPane.getTabCount();
////            for (int i = 0; i < cnt; i++) {
////                ImagePalette ip = (ImagePalette) tabbedPane.getComponentAt(i);
////                if (ip != null) {
////                    ip.dispose();
////                }
////            }
////        }
  frame.setVisible(false);
////        frame.dispose();
}

2009年9月 8日 (火)

Snow Leopard へのアップグレード

開発用マシンを Snow Leopard へのアップグレードしてみた。いつも情報を下さる先生から,Snow Leopard は Java 1.6 なので,1.5 を入れないと動かないというご報告を頂いた。Snow Leopard で JDK 1.5 環境を維持する方法は以下の通り。これで Snow Leopard 時代も Java 1.5 で生きていくことができる。
  1. アップグレード前に Java 1.5 の本体 /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0 を,どこか別の場所にコピーして保存しておく。(今後もずっと 1.5.0 を使い続けるつもりなので,大切に保存しておく)
  2. Snow Leopard へアップグレード。これは時間がかかるけど問題なし。
  3. アップグレード後に /System/Library/Frameworks/JavaVM.framework/Versions/ をのぞいてみると,1.5.0 の実体は消去され,CurrentJDK へのリンクになっている。CurrentJDK は 1.6 へのリンクになっている。
  4. リンクになっている 1.5.0 の名前を変えて,保存しておいた 1.5.0 の実体を書き戻す。
  5. CurrentJDK を 1.5 へのリンクに書き換える。
    drwxr-xr-x  13 root  wheel  442  9  2 17:03 ./
    drwxr-xr-x  12 root  wheel  408  9  2 15:26 ../
    lrwxr-xr-x   1 root  wheel    5  9  2 14:59 1.3@ -> 1.3.1
    drwxr-xr-x   3 root  wheel  102  7 21 08:35 1.3.1/
    lrwxr-xr-x   1 root  wheel    5  9  2 16:35 1.5@ -> 1.5.0
    drwxr-xr-x  10 root  wheel  340  9  2 16:57 1.5.0/
    lrwxr-xr-x   1 root  wheel   10  9  2 14:59 1.5.0.orig@ -> CurrentJDK
    lrwxr-xr-x   1 root  wheel    5  9  2 14:59 1.6@ -> 1.6.0
    drwxr-xr-x   8 root  wheel  272  9  2 15:26 1.6.0/
    drwxr-xr-x   9 root  wheel  306  9  2 15:26 A/
    lrwxr-xr-x   1 root  wheel    1  9  2 15:00 Current@ -> A
    lrwxr-xr-x   1 root  wheel    3  9  2 17:03 CurrentJDK@ -> 1.5
    lrwxr-xr-x   1 root  wheel    3  9  2 14:59 CurrentJDK.orig@ -> 1.6
    
さらに,/Applications/NetBeans/NetBeans 6.7.1/Contents/Resources/NetBeans/etc/netbeans.conf を編集して,NetBeans のデフォルト環境を JDK1.5 にする必要がある。
    # Default location of JDK, can be overridden by using --jdkhome <dir>:
    #netbeans_jdkhome="/path/to/jdk"
    netbeans_jdkhome="/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Home"
    
さらに,Quaqua が Snow Leopard を無視するので,Leopard として設定する必要がある。client/Dolphin.javainitialize に以下を加える。
    System.setProperty("Quaqua.design","leopard");
    

2009年9月 4日 (金)

ソースの UTF-8 化

オリジナルの OpenDolphin はソースの日本語が SJIS だが,何となく UTF-8 の方が今風でかっこいいのではないかと思って,NetBeans を 6.7.1 にバージョンアップした機会に UTF に変換してみた。

  1. MultiTextConverter を使うと一気に変換できる。
    • 改行コード LF
    • 文字コード UTF 8
    • BOM有りのチェックボックスは外す
    • Shift JIS 機種依存文字のマッピング:Mac OS
  2. いくつか変換できないソースがあるので,それは mi で手動で変換。
  3. NetBeans で,全部のプロジェクトについて「プロジェクトプロパティー」→「ソース」→「エンコーディング」を UTF-8 に設定。
  4. 「コンパイル」→「追加のコンパイラオプション」の -encoding SJIS を削除

2009年9月 2日 (水)

インスペクタを閉じる前にエディタをチェック

OpenDolphin をカスタマイズされている先生を web で見つけてしまった(Masuda Naika Clinic 様)。カスタマイズ内容で私も欲しい機能があったので,使わせていただきました。ありがとうございます。

オリジナルでは,カルテを閉じる時,エディタを開きっぱなしでインスペクタを閉じることができる。気をつけてはいても,インスペクタを閉じてから画面に開きっぱなしのエディタを発見して,がっかりすることがあった。Masuda 先生の変更を加えると,エディタが開いている状態でインスペクタを閉じようとすると注意してくれるようになる。エディタをドックに格納しっぱなしで忘れていても,ドックから出てきて注意してくれる。

 

client/ChartImpl.java

/**
 * チャートウインドウを閉じる。
 */
public void close() {

  // この患者のEditorFrameが開いたままなら、インスペクタを閉じられないようにする masuda
  java.util.List editorFrames = EditorFrame.getAllEditorFrames();
  if (editorFrames.size() != 0) {
    String patientId = this.getKarte().getPatient().getPatientId();
    for (Chart chart : editorFrames) {
      String id = chart.getKarte().getPatient().getPatientId();
      if (patientId.equals(id)) {
        chart.getFrame().setExtendedState(java.awt.Frame.NORMAL);
        JOptionPane.showMessageDialog(chart.getFrame(), 
          "インスペクタを閉じる前にカルテエディタを閉じてください。",
          "OpenDolphin", JOptionPane.WARNING_MESSAGE);
        return;
      }
    }
  }
  // masuda

  //
  // 未保存ドキュメントがある場合はダイアログを表示し
  // 保存するかどうかを確認する
  //
 ・
 ・

2009年9月 1日 (火)

カタカナ名での患者検索

カタカナ名で患者検索をする時,フルネームでの検索ができなかった。姓名の間にスペースが入ると,カナではないと判断されてしまうためだった。「ヤマダ タロウ」等とフルネームで検索できるように修正した。姓名の間のスペースは全角でも半角でも通るようにした。

 

util/StringTool.java に追加

public static boolean isSpace(char c) {
    Character test = new Character(c);
    return (test.equals(' ') || test.equals(' '))? true : false;
}

dto/PatientSearchSpec.java

public void setName(String name) {
//// 名前に全角スペースが入っていた場合,半角に変換してセットする
  //this.name = name;
  this.name = name.replace(' ', ' ');
}

plugin/PatientSearchImpl.java

private boolean isKana(String text) {
//// スペースが入っていてもカタカナと判断するようにする
  boolean maybe = true;
  if (text != null) {
  for (int i = 0; i < text.length(); i++) {
    char c = text.charAt(i);
    //// if (!StringTool.isKatakana(c)) {
    if (!StringTool.isKatakana(c) && !StringTool.isSpace(c)) {
      maybe = false;
      break;
  ・
  ・

« 2009年8月 | トップページ | 2009年10月 »