// 下階層用テンプレート
#topicpath
----
//ここにコンテンツを記述します。
#contents

**概要 [#z69fd4c1]
さて前回はGoogleの検索機能を呼び出したり、スペルミスを変更するダイアログだったりを作成しました。今回はその検索結果を表示するためのビューを作成していきたいと思います。プロジェクトは引き続き「nu.mine.kino.plugin.google.ui」を使用します。

**plugin.xml、MANIFEST.MFを記述する [#wc09e01d]

「META-INF/MANIFEST.MF」をマニフェストエディタで開き、[拡張]タブを選択して[追加]をクリックします。すると、拡張ポイントを選択するダイアログが開くので、「org.eclipse.ui.views」を選択し[終了]をクリックします。

#ref(view.gif)

次に、この「org.eclipse.ui.views」を右クリックして[新規]−[view]を選択します。下に要素が追加されました。右側にはidやクラス名を指定する画面が表示されているので、以下のように指定します。

|LEFT:id|LEFT:nu.mine.kino.plugin.google.ui.views.GoogleResultView|
|LEFT:name|LEFT:Google検索結果|
|LEFT:class|LEFT:nu.mine.kino.plugin.google.ui.views.GoogleResultView|
|LEFT:category|LEFT:nu.mine.kino.plugin.google|
|LEFT:icon|LEFT:icons/icon.png|



カテゴリーなども追加して結局plugin.xmlには以下のコードが追加されました。

   <extension
         point="org.eclipse.ui.views">
      <view
            category="nu.mine.kino.plugin.google"
            class="nu.mine.kino.plugin.google.ui.views.GoogleResultView"
            icon="icons/icon.png"
            id="nu.mine.kino.plugin.google.ui.views.GoogleResultView"
            name="Google検索結果"/>
      <category
            id="nu.mine.kino.plugin.google"
            name="Googleプラグイン"/>
   </extension>

**ビュークラスを追加する [#w2233d70]
先のマニフェストエディタでidやクラス名を指定しましたが、classのラベルはクリックできるようになっています。

#ref(label.gif)


これをクリックするとビューのクラスを作成するウィザードが起動します。そのまま終了をクリックすると「GoogleResultView」のソースコードが作成されます。


では、そのソースコードに色々追加していこうと思います。

**ビューの本体にテーブルビューワを配置する [#jd8459ae]
まずはビューの本体を構築していきます。ビューの構築は
 public void createPartControl(Composite parent);
をOverrideすることで行います。引数のCompositeに色々ウィジェットを配置していくわけですね。


さて今回は下記のとおりビュー全体にTableViewerを配置することにしました。ここで出てくるTableViewerとはEclipseの「問題ビュー」のようにヘッダとデータ部分を持った表形式のビューワーです。
 public void createPartControl(Composite parent) {
     // ビューワを追加。
     Composite container = new Composite(parent, SWT.NONE);
     container.setLayout(new FillLayout());
 
     viewer = new TableViewer(container, SWT.FULL_SELECTION | SWT.BORDER);
     viewer.setContentProvider(new ArrayContentProvider());
     viewer.setInput(getViewSite());
     initTable(viewer);
 
     createActions();
     initializeToolBar();
     initializeMenu();
 }

TableViewerにカラムを追加する処理は initTable(viewer); で行っています。具体的なソースは以下の通りです。

 private void initTable(final TableViewer viewer) {
     table = viewer.getTable();
     TableLayout layout = new TableLayout();
     table.setLayout(layout);
     table.setHeaderVisible(true); //ヘッダを表示する 
     table.setLinesVisible(true);  //ラインを表示する
 
     ColumnLayoutData[] columnLayouts = getColumnLayouts();
 
     for (int i = 0; i < columnLayouts.length; i++) {
         layout.addColumnData(columnLayouts[i]);
         TableColumn tc = new TableColumn(table, SWT.NONE, i);
         tc.setText(VISIBLE_FIELDS[i].getColumnHeaderText());
         tc.setImage(VISIBLE_FIELDS[i].getColumnHeaderImage());
     }
 }

ColumnLayoutDataはフィールドの幅などレイアウト情報を管理するクラスです((Eclipseでテーブルビューワを使うときはカラムの制御は[[ColumnLayoutData:http://www.eclipse.org/documentation/html/plugins/org.eclipse.platform.doc.isv/doc/reference/api/org/eclipse/jface/viewers/ColumnLayoutData.html]]でやるのがよいみたいです((とりあえずEclipseのMarkerViewなどの実装はそうなってた))。[[ColumnLayoutData:http://www.eclipse.org/documentation/html/plugins/org.eclipse.platform.doc.isv/doc/reference/api/org/eclipse/jface/viewers/ColumnLayoutData.html]]はフィールドの幅などの情報を表現するクラスです。))。

このColumnLayoutDataクラスは
 table = viewer.getTable();
 TableLayout layout = new TableLayout();
 table.setLayout(layout);
というようにTableViewerとTableLayoutが関連づけられており、TableLayoutに
 layout.addColumnData(columnLayouts[i]);
とすることでTableViewerに関連づいています。


さて
 ColumnLayoutData[] columnLayouts = getColumnLayouts();
で、各カラムのレイアウト情報を配列で取得していますが、現段階ではgetColumnLayouts();は
 private ColumnLayoutData[] getColumnLayouts() {
   return DEFAULT_COLUMN_LAYOUTS;
 }
とフィールドに定義されている配列をそのまま返すようになっています。ここはあとで「すでに前回の情報が保存されていたらその情報を復元する」という処理に変更します。たとえば前回使用していたときにフィールドの幅などを変更していたとして、その幅を次回に復元する、といったことをできるようにするわけですね。


***ColumnLayoutDataでカラムの設定をする [#ad2187b5]
ポイントは
-フィールドにあらかじめ[[ColumnLayoutData:http://www.eclipse.org/documentation/html/plugins/org.eclipse.platform.doc.isv/doc/reference/api/org/eclipse/jface/viewers/ColumnLayoutData.html]]で「初期設定」をセットしておく
-ヘッダ名やヘッダに表示するアイコンの情報、またビューワの各カラムにオブジェクトが渡されたときにオブジェクトを文字列に変換する変換処理、などを備えた自作のクラス[[IField:http://kino.mine.nu/cgi-bin/viewvc.cgi/nu.mine.kino.plugin.google.ui/source/nu/mine/kino/plugin/google/ui/views/fields/IField.java]]を作成し、それをフィールドに保持しておく
-画面表示時に、mementoを参照し、mementoから表示幅を取得してみる、取得できなかったらフィールドの「初期設定」を使う、

というところですね。わけがわからないと思うので、もっと具体的に、コーディングはこんな感じになります。

-フィールド:
 // TableLayoutと一緒になって使う。各カラムの表示幅など情報を設定する。
 private final ColumnLayoutData[] DEFAULT_COLUMN_LAYOUTS = {
         new ColumnWeightData(100), new ColumnWeightData(100),
         new ColumnWeightData(100) };
 
 private final IField[] VISIBLE_FIELDS = { new TitleField(),
            new SummaryField(), new URLField() };

-テーブルの構築:
 TableLayout layout = new TableLayout();
 table.setLayout(layout);
 table.setHeaderVisible(true);
 table.setLinesVisible(true);
 
 ColumnLayoutData[] columnLayouts = getColumnLayouts();<-後述
 
 for (int i = 0; i < columnLayouts.length; i++) {
     layout.addColumnData(columnLayouts[i]);
     TableColumn tc = new TableColumn(table, SWT.NONE, i);
     tc.setText(VISIBLE_FIELDS[i].getColumnHeaderText()); <-後述2
     tc.setImage(VISIBLE_FIELDS[i].getColumnHeaderImage()); <-後述2
     // tc.addSelectionListener(headerListener);
 }

-カラムの設定情報を、mementoかフィールドから取得するロジック(後述)
 private ColumnLayoutData[] getColumnLayouts() {
   if (memento == null) {
     return DEFAULT_COLUMN_LAYOUTS;
   }
   // ↓実際はmementoからColumnLayoutData[]を構築して返す
   return DEFAULT_COLUMN_LAYOUTS;
 }

-自前のIFieldクラスからデータを生成する(後述2)
 package nu.mine.kino.plugin.google.ui.views.fields;
 
 import org.eclipse.swt.graphics.Image;
 
 /**
  * テーブル形式のビューワのカラム情報を扱うインターフェースです。
  * 
  * @author Masatomi KINO
  * @version $Revision$
  */
 public interface IField {
   /**
    * @return The text to be displayed in the column header for this field.
    */
   String getColumnHeaderText();
 
   /**
    * @return The image to be displayed in the column header for this field or
    *     <code>null<code>.
    */
   Image getColumnHeaderImage();
 
   /**
    * @param obj
    * @return The String value of the object for this particular field to be
    *     displayed to the user.
    */
   String getValue(Object obj);
 
   /**
    * @param obj
    * @return The image value of the object for this particular field to be
    *     displayed to the user or <code>null<code>.
    */
   Image getImage(Object obj);
 }
その実装クラス
 public class TitleField implements IField {
 
   public String getColumnHeaderText() {
     return "Title";
   }
 
   public Image getColumnHeaderImage() {
     // TODO 自動生成されたメソッド・スタブ
     return null;
   }
 
   public String getValue(Object obj) {
     // TODO 自動生成されたメソッド・スタブ
     return obj.toString();
   }
 
   public Image getImage(Object obj) {
     // TODO 自動生成されたメソッド・スタブ
     return null;
   }
 }



となるような感じです。

こうすることで、
-mementoから前回の設定値などのリストアがやりやすくなる
-後に作成する、LabelProviderの実装クラスにもIFieldを渡してやることで、いやなswitch分をポリモフィズムで削除できそう
-ソートロジックなどもIFieldに実装すればポリモフィズム云々

などの効果が得られそうです。

***ソースコード [#k1062fb8]
最後にソースはこんな感じです。
//$Id$
 //作成日: 2005/05/21
 package nu.mine.kino.plugin.google.ui.views;
 
 import nu.mine.kino.plugin.google.ui.views.fields.IField;
 import nu.mine.kino.plugin.google.ui.views.fields.SummaryField;
 import nu.mine.kino.plugin.google.ui.views.fields.TitleField;
 import nu.mine.kino.plugin.google.ui.views.fields.URLField;
 
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.jface.action.IToolBarManager;
 import org.eclipse.jface.viewers.ArrayContentProvider;
 import org.eclipse.jface.viewers.ColumnLayoutData;
 import org.eclipse.jface.viewers.ColumnWeightData;
 import org.eclipse.jface.viewers.TableLayout;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.FillLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableColumn;
 import org.eclipse.ui.IMemento;
 import org.eclipse.ui.IViewSite;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.part.ViewPart;
 
 public class GoogleResultView extends ViewPart {
 
   // TableLayoutと一緒になって使う。各カラムの表示幅など情報を設定する。
   private final ColumnLayoutData[] DEFAULT_COLUMN_LAYOUTS = {
       new ColumnWeightData(200), new ColumnWeightData(200),
       new ColumnWeightData(200) };
 
   private final IField[] VISIBLE_FIELDS = { new TitleField(),
       new SummaryField(), new URLField() };
 
   private Table table;
 
   private Action doubleClickAction;
 
   private Action openBrowserAction;
 
   private IMemento memento;
 
   public void init(IViewSite site, IMemento memento) throws PartInitException {
     super.init(site, memento);
     this.memento = memento;
   }
 
   public void createPartControl(Composite parent) {
     Composite container = new Composite(parent, SWT.NONE);
     container.setLayout(new FillLayout());
 
     final TableViewer viewer = new TableViewer(container,
         SWT.FULL_SELECTION | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
 
     viewer.setContentProvider(new ArrayContentProvider());
     viewer.setInput(getViewSite());
     initTable(viewer);
 
     createActions();
     initializeToolBar();
     initializeMenu();
   }
 
   private void initTable(final TableViewer viewer) {
     table = viewer.getTable();
 
     TableLayout layout = new TableLayout();
     table.setLayout(layout);
     table.setHeaderVisible(true);
     table.setLinesVisible(true);
 
     ColumnLayoutData[] columnLayouts = getColumnLayouts();
 
     for (int i = 0; i < columnLayouts.length; i++) {
       layout.addColumnData(columnLayouts[i]);
       TableColumn tc = new TableColumn(table, SWT.NONE, i);
       tc.setText(VISIBLE_FIELDS[i].getColumnHeaderText());
       tc.setImage(VISIBLE_FIELDS[i].getColumnHeaderImage());
       // tc.addSelectionListener(headerListener);
     }
   }
 
   private ColumnLayoutData[] getColumnLayouts() {
     if (memento == null) {
       return DEFAULT_COLUMN_LAYOUTS;
     }
     // ↓実際はmementoからColumnLayoutData[]を構築して返す
     return DEFAULT_COLUMN_LAYOUTS;
   }
 
   private void createActions() {
 
     openBrowserAction = new Action("サイトにアクセスする") {
       public void run() {
       }
     };
 
     doubleClickAction = new Action("") {
       public void run() {
       }
     };
   }
 
   private void initializeToolBar() {
     IToolBarManager tbm = getViewSite().getActionBars().getToolBarManager();
   }
 
   private void initializeMenu() {
     IMenuManager manager = getViewSite().getActionBars().getMenuManager();
   }
 
   public void setFocus() {
   }
 
 }

***スクリーンショット [#ec539a86]
実際にビューを表示してみると、こんな感じです。
#ref(view.png)

次は [[検索ロジックをビューに実装>Eclipse/プラグイン開発のTIPS集/GooglePlugin/実際の検索ロジックをビューに実装]] します。




----
この記事は
#vote(おもしろかった[2],そうでもない[0])

#comment
#topicpath


SIZE(10){現在のアクセス:&counter;}

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS