2012年8月17日金曜日

Eclipse 4 アプリケーションの作成 (4) CSSテーマ

E4 では、CSSを使ってアプリケーションの外観を柔軟に設定できます。 今回は、アプリケーションに CSS テーマを適用する方法を試してみることにします。 ただ残念なことに、今回UIとして使用した、Nebula Gallery Widget も vlcj も、この方法で簡単にスタイルを設定することができませんでした。 そのため、この方法の利点をあまり実感できないサンプルとなってしまいました。

簡単なスタイルシートの作成
com.itrane.myvideo プラグインの css フォルダに、以下の2つの CSS ファイルを作成します。 2つの違いは背景色だけです。
blue.css:
Gallery {
    background-color: #5b99d6;
}
.MPart {
  background-color: #5b99d6;
}
.MPart Label {
  color: #ffffff;
  font: 'arial' 11px;
  font-weight: bold;
}

red.css:
Gallery {
    background-color: #cc7665;
}
.MPart {
  background-color: #cc7665;
}
.MPart Label {
  color: #ffffff;
  font: 'arial' 11px;
  font-weight: bold;
}

テーマの定義
plugin.xml を開いて、拡張ページで、org.eclipse.e4.ui.css.swt.theme 拡張ポイントを追加して、上記の2つの CSS に対応するテーマ(テーマ青とテーマ赤)を登録します。 この拡張ポイントを使うには、依存関係ページで、必須プラグインとして org.eclipse.e4.ui.css.swt.theme を追加しておく必要があります。修正した plugin.xml は次のようになります:
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
   <extension
         id="product"
         point="org.eclipse.core.runtime.products">
      <product
            name="com.itrane.myvideo"
            application="org.eclipse.e4.ui.workbench.swt.E4Application">
         <property
               name="appName"
               value="com.itrane.myvideo">
         </property>
         <property
               name="applicationXMI"
               value="com.itrane.myvideo/Application.e4xmi">
         </property>
         <property
               name="cssTheme"
               value="blue.theme">
         </property>
      </product>
   </extension>
   <extension
         point="org.eclipse.e4.ui.css.swt.theme">
      <theme
            basestylesheeturi="css/blue.css"
            id="blue.theme"
            label="テーマ青">
      </theme>
      <theme
            basestylesheeturi="css/red.css"
            id="red.theme"
            label="テーマ赤">
      </theme>
   </extension>
</plugin>

テーマ変更のためのコマンド、ハンドラ、メニューの追加
Application.e4xmi を開いて、パラメータを持つコマンドを追加します:
コマンド:(Id:command.switchTheme、Name:switchTheme)
パラメータ:(Id:commandparameter.themeId、Name:themeId)

このコマンドに対応するハンドラを追加します:
ハンドラ:(Command:switchTheme - command.switchTheme)

ハンドラの "Class URI" をクリックして、com.itrane.myvideo.handlers パッケージに SwitchThemeHandler クラスを作成します:
public class SwitchThemeHandler {
    @Execute
    public void execute(
            @Named("commandparameter.themeId") String themeId, 
            IThemeEngine engine,
            EPartService service) {
        MPart galleryPart = (MPart)service.findPart("com.itrane.myvideo.GalleryPart");
        MPart videoPart = (MPart)service.findPart("com.itrane.myvideo.VideoPart");
        if (galleryPart!=null && videoPart!=null) {
            if (galleryPart.getObject() instanceof GalleryView &&
                videoPart.getObject() instanceof VideoView) {
                engine.setTheme(themeId,true);
                GalleryView galleryView = (GalleryView)galleryPart.getObject();
                VideoView videoView = (VideoView)videoPart.getObject();
                galleryView.setGroupTitleBackgroud();
                videoView.setCanvasBackground();
            }
        }
    }
}

@Execute アノテーションが付加された execute メソッドが実行されるときに、パラメータIdが "commandparameter.themeId" であるパラメータの値が themId にセットされます。 依存性注入により、IThemeEngine と EPartService もセットされます。 渡された themeId を使って、IThemeEngine#setTheme メソッドにより、指定テーマに変更します。 上述したように、Nebula Widget と vlcj プレーヤーは、CSSの適用だけでは、完全にスタイルを制御できません。 よって、パートサービス (EPartService) を使って、要素IDから、ギャラリーパートと、ビデオパートを検索し、MPart#getObject で、リンクされているビューを取得します。 最終的にそれらのビューのメソッドを呼び出して、ギャラリーのグループタイトルとプレーヤーキャンバスの背景色を変更します。 ここでは、パートサービスの使い方を見るため、かなり分かりにくいコードになってしまいましたが、イベントブローカーを使えばもっとすっきりしたコードになります。これについてはまた後で説明します。

ギャラリービューに、ハンドラから呼ばれる、setGroupTitleBackgroud() メソッドを追加します:
    public void setGroupTitleBackgroud() {
        fGalleryGroupRenderer.setTitleBackground(
                createTitleBackground(fComposite.getBackground()));
    }
    
    private Color createTitleBackground(Color color) {
        int r = color.getRed()   < 10 ? 0 : color.getRed() - 10;
        int g = color.getGreen() < 10 ? 0 : color.getGreen() - 10;
        int b = color.getBlue()  < 10 ? 0 : color.getBlue() - 10;
        Display display = Display.getCurrent();
        return new Color(display, new RGB(r,g,b));
    }
ギャラリーのグループタイトルは CSS で設定された背景色よりも若干暗めの色を設定しています。
また、テーマ変更時だけでなく、アプリケーションの起動時にも、初期テーマの背景色がグループタイトルに反映されるように、ギャラリービューの createGallery メソッドを以下のように修正します:
    private void createGallery(Composite composite) {
        // ...

        // グループレンダラーの作成
        fGalleryGroupRenderer = new DefaultGalleryGroupRenderer();
        fGalleryGroupRenderer.setMaxImageWidth(60);
        fGalleryGroupRenderer.setMinMargin(0);
        fGalleryGroupRenderer.setTitleForeground(
                ResourceManager.getColor(SWT.COLOR_WHITE));
        setGroupTitleBackgroud();
        // ...
    }

同じく、ビデオビューに setCanvasBackground() メソッドを追加します:
    public void setCanvasBackground() {
        fVideoViewer.setCanvasBackground();
    }

さらに、VideoViewer に 以下のメソッドを追加します:
    public void setCanvasBackground() {
        Color color = this.getBackground();
        java.awt.Color jcolor = new java.awt.Color(color.getRed(),
                color.getGreen(), color.getBlue());
        fVideoCanvas.setBackground(jcolor);
    }

こちらも起動時に反映されるように、VideoViewer の createPlayer メソッドを以下のように修正します:
    private void createPlayer(Composite composite) {
        // ...

        setCanvasBackground();
    }
テーマ変更のためのメニューを追加します:
メインメニューに Menu 要素(Label: テーマ)を追加して、子要素として、2つの HandledMenuItem 要素を追加して、それぞれにパラメータを追加します。
1つ目の HandledMenuItem:(Label: テーマ赤, Command:switchTheme - command.switchTheme)
 パラメータ:(Name:commandparameter.themeId, Value:red.theme)
2つ目の HandledMenuItem:(Label: テーマ青, Command:switchTheme - command.switchTheme)
 パラメータ:(Name:commandparameter.themeId, Value:blue.theme)

上記のメニューを選択すると、テーマ変更コマンドに対応するハンドラが実行され、ハンドラの execute メソッドにパラメータの値(red.theme または blue.theme) が渡されます。そして、それぞれのテーマId に対応する CSS(red.css または blue.css) が適用されます。アプリケーションを実行すると、最初のテーマのテーマ青が適用されます:

メニューから、テーマ > テーマ赤を選択して、テーマを変更します:

次回は、ビデオのトップディレクトリを変更、保存するために、E4 プリファレンスを使用します。

0 件のコメント: