Archive for 2月, 2008

勉強会記録(2/12)

火曜日, 2月 12th, 2008

オブジェクト指向入門 第2版 原則・コンセプト pp.467-477 (大野, 青木)

  • パートC オブジェクト指向の技法
    • 第11章契約による設計:信頼性の高いソフトウェアを構築する
      • 11.8 クラス不変表明
        • 11.8.1 定義と例
        • 11.8.2 クラス不変表明の形式と特質
        • 11.8.3 変化する不変表明
        • 11.8.4 不変表明を守らなければならないのは誰か?
        • 11.8.5 ソフトウェア工学におけるクラス不変表明規則
        • 11.8.6 不変表明と契約
      • 11.9 クラスが正しいのはいつか?
        • 11.9.1 クラスの正しさ
        • 11.9.2 生成プロシージャの役割

iDotメモ3(データファイルのロード)

金曜日, 2月 8th, 2008

iDot起動または、ツールバーの「Open」ボタンのクリックでファイルのロード処理が起動する。

idot.iDotクラス


/**
* Tries to load the state diagram from the specified file. The file
* is assumed to be in DOT format.
* After the file is loaded, a layout operation (using DOT) is attempted.
*
* @param graphFile
* @return true, if the file was loaded successfully and the laying out
* the graph using DOT completed without errors
*/

protected boolean loadFile(File graphFile) {
  boolean fileLoaded = false;
  try {
    BufferedReader br = new BufferedReader(
                new InputStreamReader(new FileInputStream(graphFile)));
    long size = graphFile.length();
    if(size > 1024*1024)
      throw new IOException(“File too big (> 1 MB): ” + graphFile);
    StringBuilder sb = new StringBuilder((int) size);
    String line;
    do {
      line = br.readLine();
      if(line != null) {
        sb.append(line).append(‘\n’);
      }
    } while(line != null);
    display.setDotFileContents(sb.toString());
    saveFile = graphFile;
    graphState = null;
    if (Config.print)
      System.out.println(“opened ” + graphFile.getName());
      display.runDOTLayout();//①
    updateTitle();
    fileLoaded = true;
  } catch ( Exception ex ) {
    JOptionPane.showMessageDialog(
      display,
      ”Sorry, an error occurred while loading the graph.\n” +
      ”(“+ ex.getLocalizedMessage() + “)”,
      ”Error Loading Graph”,
      JOptionPane.ERROR_MESSAGE);
    ex.printStackTrace();
  }
  return fileLoaded;
}

①idot.DotDisplayクラスのrunDOTLayout()メソッドをコール

idot.DotDisplayクラス

/**
* Tries to perform the layout of the current graph by executing DOT
* with the current graph content (in DOT format) as input.
* If DOT is executed succesfully, the graph is lo9aded
*/

protected void runDOTLayout() {
  Graph g = null;
  try {
    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    ProcessBuilder pb = new ProcessBuilder(dotCommand);//②
    /* If dot gives a lot of warnings the error stream
    * may get full which hangs the program –> have to empty
    * it somehow.
    * Reading it through getErrorStream() would require
    * some extra effort.
    */

    pb.redirectErrorStream(true);
    Process p = pb.start();
    OutputStream os = new BufferedOutputStream(p.getOutputStream());
    InputStream is = new BufferedInputStream(p.getInputStream());
    // pipe graph to dot
    os.write(getDotFileContents().getBytes());
//③
    // dot will only close after getting EOF
    os.close();
    // pipe output to graph layout
    g = dotReader.loadGraph(is);//④
    p.waitFor();
    if(p.exitValue() != 0) {
      System.err.println(“Process ” + dotCommand + ” exited with value ” + p.exitValue());
      throw new IOException(“DOT exit value: ” + p.exitValue());
    }
    setGraph(g);//⑤
  } catch ( Exception ex ) {
    JOptionPane.showMessageDialog(
      this,
      ”Sorry, an error occurred while running DOT.\n” +
      ”(“+ ex.getLocalizedMessage() + “)”,
      ”Error Running DOT”,
      JOptionPane.ERROR_MESSAGE);
    ex.printStackTrace();

    setCursor(Cursor.getDefaultCursor());
  }
}

//**
* Sets the graph shown on this display.
*
* @param g
*/

public void setGraph(Graph g) {
  // update graph
  m_vis.removeGroup(GRAPH_GROUP);
  m_vis.addGraph(GRAPH_GROUP, g);//⑥

  // create data description of labels, setting colors, fonts ahead of time
  Schema edgeLabelSchema = createEdgeLabelSchema();

  m_vis.removeGroup(“edgeLabels”);
  explicitHide((Graph) m_vis.getVisualGroup(GRAPH_GROUP));

  m_vis.addDecorators(“edgeLabels”, GRAPH_EDGES, null, edgeLabelSchema);//⑦

  runFilterUpdate();
  runLayout();//⑧
}

②別プロセスを起動するためProcessBuilderオブジェクトを作成。String配列のdotCommandは{“bin\dot”,”-Tdot”}となっている。
③読み込んだファイルのデータを、別プロセスのアウトプットストリームに書き込む。
この別プロセスでは、nodeの位置決めとedgeの曲線を計算しているようだ。
④idot.util.DotFileReaderクラスのloadGraphメソッドをコールして、prefuse.data.Graphオブジェクトにデータを読み込む。
⑤setGraph()メソッドをコール
⑥prefuse.VisualizationオブジェクトにGraphオブジェクトをGRAPH_GROUPという名前で登録する。
GraphオブジェクトをVisualizationに登録すると自動的にprefuse.visual.VisualGraphオブジェクトが作られる。
VisualGraphオブジェクトは、Graphオブジェクトが持つデータの他、可視化(表示)のために必要な情報(座標、色、サイズなど)を持っている。
⑦edgeのラベル用にDecoratorを登録。Decoratorを登録すると既存のvisual data group(この場合は、GRAPH_EDGESという名前のグループ)に新たなコントロールを追加することができるようになるようだ。具体的には、edgeラベルの表示に使われる。
⑧レイアウトを実行する。レイアウト処理は、idot.DotLayoutクラスに実装されている。

iDotメモ2へ

勉強会記録(2/5)

火曜日, 2月 5th, 2008

オブジェクト指向入門 第2版 原則・コンセプト pp.446-456 (大野, 青木)

  • パートC オブジェクト指向の技法
    • 第11章契約による設計:信頼性の高いソフトウェアを構築する
      • 11.6 ソフトウェア信頼性のための契約
        • 11.6.3 表明は入力検査メカニズムにあらず
        • 11.6.4 表明は制御構造にあらず
        • 11.6.5 エラー、欠陥、その他、モゾモゾ這い回るやつ
      • 11.7 表明を用いた作業
        • 11.7.1 スタッククラス
        • 11.7.2 命令的であることと適用的であること
        • 11.7.3 空(empty)の構造に関する知見

iDotメモ2(idot.DotDisplayクラス)

金曜日, 2月 1st, 2008

idot.DotDisplayクラス

DotDisplayクラスはprefuseグラフィックライブラリのprefuse.Displayクラスを継承している。
prefuse.Displayクラスはprefuse.Visualizationクラスのコンテンツを表示する役割がある。
DotDisplayクラスのコンストラクタはiDotクラスのコンストラクタからコールされる。
DotDisplayクラスのコンストラクタを見てみる。

/**
* Creates a new DotDisplay initialized with the given graph
*
* @param graph
* the graph to load to the display
*/

public DotDisplay(Graph graph) {//①
  this(graph, new Visualization());
}

/**
* Creates a new DotDisplay initialized the given graph and visualization
*
* @param graph
* the graph to load to the display
* @param visualization
* the visualization that will be used provide the visual
* counterparts for the objects in the graph
*/

public DotDisplay(Graph graph, Visualization visualization) {//②
  super();
  setHighQuality(true);//③
  setVisualization(visualization);//④

  // initialize renderers ⑤
  MultilineTextItemRenderer nodeRenderer = new MultilineTextItemRenderer(
                         MultilineTextItemRenderer.CENTER);
  TransitionRenderer edgeRenderer = new TransitionRenderer();
  DefaultRendererFactory rf = new DefaultRendererFactory(nodeRenderer,edgeRenderer);
  rf.add(“INGROUP(‘edgeLabels’)”, new LabelRenderer() {//⑥
    public void render(Graphics2D g, VisualItem item) {

      // make sure edge labels are at correct positions before rendering them
      if (item.canGet(“lp2”, double[].class)) {
        double[] xy = (double[]) item.get(“lp2”);
        if (xy != null) {
          item.setX(xy[0]);
          item.setY(xy[1]);
          super.render(g, item);
        }
      }
    }
  });

  // hide invisible nodes and edges
  rf.add(“style=’invis'”, new NullRenderer());
  m_vis.setRendererFactory(rf);

  // initialize display ⑦
  setBackground(Color.WHITE);
  addControlListeners();//⑧
  addLayouts();//⑨
  setGraph(graph);//⑩
}

iDotクラスのコンストラクタからDotDisplayのコンストラクタ①がコールされる。
コンストラクタ①はコンストラクタ②をコールする。
③レンダリングの品質に関する設定で、falseにすると表示が粗くなる。
④purefuse.Visualizationオブジェクトを設定している。
Visualizationはprefuseグラフィックライブラリの中でも重要なクラスのようだ。
⑤からはレンダラーファクトリ作成処理である。idot.util.MultilineTextItemRendererはノードのレンダラーで、複数行に渡るテキストと枠線を描くクラス。idot.util.TransitionRendererは、ノードとノードをつなぐ線(=edge)を描くクラス。
⑥さらにedgeラベル用のレンダラーをDefaultRendererFactoryに追加している。
DefaultRendererFactory#add(String predicate, Renderer r)のpredicateは、
rのレンダリング対象とするVisualItemを決めるための条件である。
ここでは、’edgeLabels’グループに属するVisualItemという条件。
⑦DefaultRendererFactoryを④で設定したVisualizationに設定する。
⑧コントロールリスナーを追加する
⑨レイアウトを追加する
⑩Graphオブジェクトを設定する。

次に⑧のコントロールリスナー登録メソッド(addControlListeners())を見てみる。
このメソッドでは、VisualizationへのActionListの登録とDotDisplayへのControlの登録をしている。

/**
* Adds the needed control listeners and action lists to the display.
*/

private void addControlListeners() {
  // update takes care of colors and font sizes
  ActionList update = new ActionList(m_vis);
  ColorAction color = new ColorAction(GRAPH_GROUP, VisualItem.STROKECOLOR) {//①
    @Override
    public int getColor(VisualItem item) {
      // honor the value of the color attribute
      if (item.canGetInt(“color”)) {
        return item.getInt(“color”);
      }
    return super.getColor(item);
    }
  };
  // base color is black
  color.setDefaultColor(ColorLib.rgb(0, 0, 0));
  update.add(color);

  // text is always black
  color = new ColorAction(GRAPH_GROUP, VisualItem.TEXTCOLOR);//②
  color.setDefaultColor(ColorLib.gray(0));
  update.add(color);

  // arrow heads are filled with color from the attribute, and nodes with white
  color = new ColorAction(GRAPH_GROUP, VisualItem.FILLCOLOR) {//③
    @Override
    public int getColor(VisualItem item) {
      // honor the value of the color attribute
      if (item instanceof EdgeItem && item.canGetInt(“color”)) {
        return item.getInt(“color”);
      } else if (item instanceof NodeItem
            && item.getString(“shape”).equalsIgnoreCase(“point”)) {
        return item.getStrokeColor();
      }
      return super.getColor(item);
    }
  };

  color.add(“ingroup(‘” + GRAPH_EDGES + “‘)”, ColorLib.gray(0));
  color.setDefaultColor(ColorLib.gray(255));
  update.add(color);

  // hilighted nodes and edges are drawn with doubled lines
  // StrokeAction stroke = new StrokeAction(GRAPH_GROUP);
  // stroke.add(“_highlight”, StrokeLib.getStroke(2));
  // update.add(stroke);

  update.add(new FontAction() {//④
    public Font getFont(VisualItem item) {
      String fontname = currFont.getFamily();
      int fontsize = currFont.getSize();
      if (item.canGetString(“fontname”)) {
        fontname = item.getString(“fontname”);
      }
      if (item.canGetInt(“fontsize”)) {
        fontsize = item.getInt(“fontsize”);
      }
      return FontLib.getFont(fontname, fontsize);
      // return currFont;
    }//
  });

  ShapeDecoder sd = new ShapeDecoder(“shape”);//⑤
  update.add(sd);
  StrokeAction sa = new StrokeAction(GRAPH_GROUP, new BasicStroke());//⑥
  sa.add(“style=’bold'”, new BasicStroke(2));
  // this is alternative to using a NullRenderer, although this is not completely invisible
  // sa.add(“style=’invis'”, new BasicStroke(0));

  update.add(sa);
  update.add(new RepaintAction());
  m_vis.putAction(“update”, update);//⑦
  addControlListener(new ZoomControl());//⑧
  addControlListener(new PanControl());
  addControlListener(new InvertedWheelZoomControl());
  addControlListener(new FocusControl(0));
  Controller c = new Controller();
  controller = c;
  addControlListener(c);
}

①線の色の設定。
itemのcolorフィールドに設定があればその設定値を、なければ黒。
②テキストの色(=黒)の設定。
③矢印のヘッドとノードの内部の色の設定。
itemのcolorフィールドに設定があればその設定値を、なければ矢印のヘッドは黒、ノードの内部は白。
④フォントの設定。
⑤ノードの形の設定。VisualItemのデータフィールド”shape”の値で形が決定することを設定している。
⑥線の太さの設定
⑦これまでの設定を”update”という名前を付けてVisualizationに登録する。
⑧からはコントロールの登録
ZoomControl:ビューア画面上のマウス右ボタンドラッグで拡大縮小
PanControl:背景のマウス左ボタンドラッグで全体が移動
InvertedWheelZoomControl:マウスホイールの回転で拡大縮小
FocusControl:ノードやエッジ(矢印)へのカーソルのフォーカスイベントで起動するコントローラ
Controller:専用コントローラ。DotDisplayのインナークラスで定義
Controllerクラスでは、イベント発生時の処理をしている。主な機能は次のとおり。

  • nodeのダブルクリックで子ノードを表示する
  • nodeまたはedgeのドラッグ

iDotメモ1へ  iDotメモ3へ