最近よく見るライブプレビューなアプリをEclipseで作ってみた・準備編

#概要
表題の通り、最近よく見るライブプレビューなアプリをEclipse+Xtextで作ってみました。
準備編は、RCPアプリケーションを構築する際のひっかけポイントを書き残しておけば、次回以降の同じ目に合わなくて済むだろう、ということで書いた次第です。
誰かの役に立てば幸いです。

#開発環境/ツール
* Eclipse Version 2019-12 (4.14.0)
[Eclipse IDE 2019-12 R Packages](https://www.eclipse.org/downloads/packages/release/2019-12/r)から導入。日本語化プラグインは導入していない

* Xtext
Eclipseを起動、メニュー`Help -> Install New Software...`を選択
Work with:は`2019-12 - http://download.eclipse.org/releases/2019-12`を選択
`Modeling`を展開すると出てくる

* Eclipse e4 Tools Developer Resources
* Eclipse Plug-in Development Environment
途中まではXtextと同じ
`General Purpose Tools`を展開すると出てくる

#画面イメージ
準備編を最後までこなしたイメージは以下の感じ。
左側にエクスプローラーのような外観、右上がエディタ領域、右下がプロパティいう構成になっている。
右下はプロパティだけだが、次のステップでプレビューを表示するウィンドウを足す予定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94018/a3362c6c-5d28-6f9f-50c5-4ce8a896b769.png)

#開発手順
基本的には、[tutorial : eclipse rcp e4 with 3.x views like project explorer, properties, etc.](https://dirksmetric.wordpress.com/2012/08/01/tutorial-eclipse-rcp-e4-with-3-x-views-like-project-explorer-properties-etc/)にある手順に従って作業を行えば、画面イメージで示したものが出来上がる。
ただし、今回の環境に合わせてアップデートが必要な箇所がある、コメント欄で逐次追加されているものも必要で全体が見えない、さら記事が英語…、などを考慮して、今回の開発環境に手順をアップデートすることにした。

##プラグインプロジェクトを作成する
File -> New -> Other -> Plug-in Development -> Plug-in Projectを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94018/6783497b-4ba4-ef07-2682-960ea722ef57.png)
以降の細かい点は以下の通り。
プロジェクトのIDはtest.rcp
Optionsのactivator...はチェックを外す
RichClientはYesを選択
contributors to the UIはチェックする
RCP3.x (minimal)を選択

Finishボタンをクリック後、PackageExplorerでtest.rcp/src/test/rcp/Application.javaなどが生成されていることを確認できればOK。

##test.rcpプラグインにapplication modelファイルを追加する
File -> New -> Eclipse 4 -> Model -> New Application Modelを選択し、ファイル名は`Application.e4xmi`とする。
ファイルの追加先はプラグインのルート直下でよい。

##test.rcpプラグインにProduct定義を追加する

plugin.xmlを開き、
<details><summary>Product定義</summary><div>

```xml
<extension id="product_test" point="org.eclipse.core.runtime.products">
  <product application="test.rcp.application" name="My Product">
    <property name="appName" value="My App"> </property>
    <property name="applicationXMI" value="test.rcp/Application.e4xmi"> </property>
  </product>
</extension>
```
</div></details>
を追記する。

##test.rcpプラグインにproduct configurationファイルを追加する
File -> New -> Plug-In Development -> Product Configurationを選択し、ファイル名は`test.rcp.product`とする。
ファイルの追加先はプラグインのルート直下でよい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94018/99fa5b94-cec7-3367-256c-58488b2f9f73.png)

##productとapplicationの関連付け
productファイルを開き、Overviewタブで、Productは`rcp.test.product_test`を選択する。
Applicationは`test.rcp.application`を選択する。


##test.rcpプラグインの依存関係を更新する
plugin.xmlを開き、Dependenciesタブをクリック
Required Plug-insのAddボタンで、`org.eclipse.rcp`と`org.eclipse.emf.common`を追加する。
なお、tutorialにはorg.eclipse.e4.rcpとあるが本環境では見当たらないので、代わりにorg.eclipse.rcpとしている。また、org.eclipse.emf.coreは本環境では含めていない（org.eclipse.emf.commonにマージされた？と推測）。

##EclipseにRun configurationを作る
test.rcpプラグイン -> plugin.xmlのLaunch Debugをクリックする。
クリック後、いろいろなエラーメッセージがConsoleに出たり、ダイアログが出てきてエラーログを見るか？などが尋ねられるが、もろもろキャンセルでOK。
EclipseメニューのRun -> DebugConfigurationを選択し、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94018/cb4a4bdc-5eb2-2b9f-a5a5-e1280d5ab361.png)
のように、Eclipse Applicationの下に、`test.rcp.product_test`がエントリされていることを確認できればOK。

##test.rcpのApplication.e4xmiに追記する
test.rcpのApplication.e4xmiを開き、XMIタブをクリックし次のコードで置き換えて保存。

<details><summary>コード</summary><div>

```xml
<?xml version="1.0" encoding="UTF-8"?>
<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:advanced="http://www.eclipse.org/ui/2010/UIModel/application/ui/advanced" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_VnmacNSzEeGBn6dQ9VPexA" elementId="test.rcp.application" bindingContexts="_VnmacdSzEeGBn6dQ9VPexA">
  <children xsi:type="basic:TrimmedWindow" xmi:id="_Vnmah9SzEeGBn6dQ9VPexA" label="My Main Window" iconURI="" width="800" height="600">
    <children xsi:type="advanced:PerspectiveStack" xmi:id="_Vnmaj9SzEeGBn6dQ9VPexA" selectedElement="_VnmakNSzEeGBn6dQ9VPexA">
      <children xsi:type="advanced:Perspective" xmi:id="_VnmakNSzEeGBn6dQ9VPexA" elementId="test.rcp.perspective" selectedElement="_VnnBgNSzEeGBn6dQ9VPexA" label="My Perspective" iconURI="">
        <tags>Perspective</tags>
        <tags>categoryTag:General</tags>
        <children xsi:type="basic:PartSashContainer" xmi:id="_VnnBgNSzEeGBn6dQ9VPexA" horizontal="true">
          <children xsi:type="basic:PartStack" xmi:id="_VnnBgdSzEeGBn6dQ9VPexA" containerData="3400">
            <tags>newtablook</tags>
            <tags>org.eclipse.e4.primaryNavigationStack</tags>
            <children xsi:type="advanced:Placeholder" xmi:id="_QR29cNS2EeGBn6dQ9VPexA" elementId="org.eclipse.ui.navigator.ProjectExplorer" ref="_sS7Q8NS1EeGBn6dQ9VPexA"/>
          </children>
          <children xsi:type="basic:PartSashContainer" xmi:id="_bTQ1YNS2EeGBn6dQ9VPexA" elementId="" containerData="10000">
            <children xsi:type="advanced:Placeholder" xmi:id="_hP-EYNS2EeGBn6dQ9VPexA" elementId="org.eclipse.ui.editorss" ref="_Hmg4kNSjEeGwXp2p959l3w"/>
            <children xsi:type="basic:PartStack" xmi:id="_qAHrYNS2EeGBn6dQ9VPexA" elementId="org.eclipse.ui.views.PropertySheetMStack" containerData="3400" selectedElement="_soNH8NS2EeGBn6dQ9VPexA">
              <tags>newtablook</tags>
              <tags>org.eclipse.e4.secondaryDataStack</tags>
              <children xsi:type="advanced:Placeholder" xmi:id="_soNH8NS2EeGBn6dQ9VPexA" elementId="org.eclipse.ui.views.PropertySheet" ref="_WqRGcNS1EeGBn6dQ9VPexA"/>
            </children>
          </children>
        </children>
      </children>
    </children>
    <sharedElements xsi:type="advanced:Area" xmi:id="_Hmg4kNSjEeGwXp2p959l3w" elementId="org.eclipse.ui.editorss">
      <children xsi:type="basic:PartStack" xmi:id="_HmhfoNSjEeGwXp2p959l3w" elementId="org.eclipse.e4.primaryDataStack">
        <tags>newtablook</tags>
        <tags>org.eclipse.e4.primaryDataStack</tags>
        <tags>EditorStack</tags>
      </children>
    </sharedElements>
    <sharedElements xsi:type="basic:Part" xmi:id="_WqRGcNS1EeGBn6dQ9VPexA" elementId="org.eclipse.ui.views.PropertySheet" contributionURI="bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.e4.compatibility.CompatibilityView" label="Properties" iconURI="platform:/plugin/org.eclipse.ui.views//icons/full/eview16/prop_ps.gif" closeable="true">
      <tags>View</tags>
      <tags>categoryTag:General</tags>
      <menus xmi:id="_HngXENSjEeGwXp2p959l3w" elementId="org.eclipse.ui.views.PropertySheet">
        <tags>ViewMenu</tags>
        <tags>menuContribution:menu</tags>
      </menus>
      <toolbar xmi:id="_Hng-INSjEeGwXp2p959l3w" elementId="org.eclipse.ui.views.PropertySheet"/>
    </sharedElements>
    <sharedElements xsi:type="basic:Part" xmi:id="_sS7Q8NS1EeGBn6dQ9VPexA" elementId="org.eclipse.ui.navigator.ProjectExplorer" contributionURI="bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.e4.compatibility.CompatibilityView" label="Project Explorer" iconURI="platform:/plugin/org.eclipse.ui.navigator.resources//icons/full/eview16/resource_persp.gif">
      <tags>View</tags>
      <tags>categoryTag:General</tags>
      <menus xmi:id="_4UXAUNSmEeG-a6zBTyJ-wg" elementId="org.eclipse.ui.navigator.ProjectExplorer">
        <tags>ViewMenu</tags>
        <tags>menuContribution:menu</tags>
      </menus>
      <menus xsi:type="menu:PopupMenu" xmi:id="_4VpZwNSmEeG-a6zBTyJ-wg" elementId="org.eclipse.ui.navigator.ProjectExplorer#PopupMenu">
        <tags>menuContribution:popup</tags>
        <tags>popup:org.eclipse.ui.navigator.ProjectExplorer#PopupMenu</tags>
      </menus>
      <toolbar xmi:id="_4UXAUdSmEeG-a6zBTyJ-wg" elementId="org.eclipse.ui.navigator.ProjectExplorer"/>
    </sharedElements>
    <trimBars xmi:id="_VOV6ANTAEeGTY-uOtVc6Mg" elementId="org.eclipse.ui.main.toolbar"/>
    <trimBars xmi:id="_VP1HwNTAEeGTY-uOtVc6Mg" elementId="org.eclipse.ui.trim.status" side="Bottom">
      <children xsi:type="menu:ToolControl" xmi:id="_VP1u0NTAEeGTY-uOtVc6Mg" elementId="org.eclipse.ui.StatusLine" contributionURI="bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.StandardTrim">
        <tags>stretch</tags>
      </children>
      <children xsi:type="menu:ToolControl" xmi:id="_VQKe8NTAEeGTY-uOtVc6Mg" elementId="org.eclipse.ui.HeapStatus" contributionURI="bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.StandardTrim"/>
      <children xsi:type="menu:ToolControl" xmi:id="_VQRMoNTAEeGTY-uOtVc6Mg" elementId="org.eclipse.ui.ProgressBar" contributionURI="bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.StandardTrim"/>
    </trimBars>
  </children>
  <bindingTables xmi:id="_VnmafNSzEeGBn6dQ9VPexA" bindingContext="_VnmacdSzEeGBn6dQ9VPexA"/>
  <rootContext xmi:id="_VnmacdSzEeGBn6dQ9VPexA" elementId="org.eclipse.ui.contexts.dialogAndWindow" name="In Dialog and Windows">
    <children xmi:id="_VnmactSzEeGBn6dQ9VPexA" elementId="org.eclipse.ui.contexts.window" name="In Windows"/>
    <children xmi:id="_Vnmac9SzEeGBn6dQ9VPexA" elementId="org.eclipse.ui.contexts.dialog" name="In Dialogs"/>
  </rootContext>
  <descriptors xmi:id="_9E9jYNS4EeGBn6dQ9VPexA" elementId="org.eclipse.ui.navigator.ProjectExplorer" label="Project Explorer" iconURI="platform:/plugin/org.eclipse.ui.navigator.resources//icons/full/eview16/resource_persp.gif" category="org.eclipse.e4.primaryNavigationStack" closeable="true" contributionURI="bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.e4.compatibility.CompatibilityView">
    <tags>View</tags>
    <tags>categoryTag:General</tags>
  </descriptors>
  <descriptors xmi:id="_W6yT4NSjEeGgKvWHVYtRxQ" elementId="org.eclipse.ui.console.ConsoleView" label="Console" iconURI="platform:/plugin/org.eclipse.ui.console//icons/full/cview16/console_view.gif" allowMultiple="true" category="org.eclipse.e4.secondaryDataStack" closeable="true" contributionURI="bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.e4.compatibility.CompatibilityView">
    <tags>View</tags>
    <tags>categoryTag:General</tags>
  </descriptors>
  <descriptors xmi:id="_W6ziANSjEeGgKvWHVYtRxQ" elementId="org.eclipse.ui.views.ProgressView" label="Progress" iconURI="platform:/plugin/org.eclipse.ui.ide//icons/full/eview16/pview.gif" category="org.eclipse.e4.secondaryDataStack" closeable="true" contributionURI="bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.e4.compatibility.CompatibilityView">
    <tags>View</tags>
    <tags>categoryTag:General</tags>
  </descriptors>
  <descriptors xmi:id="_W63zcdSjEeGgKvWHVYtRxQ" elementId="org.eclipse.ui.views.PropertySheet" label="Properties" iconURI="platform:/plugin/org.eclipse.ui.views//icons/full/eview16/prop_ps.gif" allowMultiple="true" category="org.eclipse.e4.secondaryDataStack" closeable="true" contributionURI="bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.e4.compatibility.CompatibilityView">
    <tags>View</tags>
    <tags>categoryTag:General</tags>
  </descriptors>
  <addons xmi:id="_VnmadNSzEeGBn6dQ9VPexA" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
  <addons xmi:id="_VnmaddSzEeGBn6dQ9VPexA" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
  <addons xmi:id="_VnmadtSzEeGBn6dQ9VPexA" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
  <addons xmi:id="_Vnmad9SzEeGBn6dQ9VPexA" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
  <addons xmi:id="_VnmaeNSzEeGBn6dQ9VPexA" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
  <addons xmi:id="_VnmaedSzEeGBn6dQ9VPexA" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
</application:Application>
```
</div></details>

##test.rcpプラグインの依存関係を更新する
plugin.xmlを開き、Dependenciesタブをクリック
Required Plug-insのAddボタンで、ProjectExplorerの追加に必要な`org.eclipse.ui.views`、`org.eclipse.ui.navigator`と`org.eclipse.ui.navigator.resources`を追加する

##ApplicationWorkbenchAdvisor.javaにProjectExplorerの初期化コードを追加する
initializeメソッドと追加メソッドを以下のようにする。
initializeメソッドと追加メソッドで、ProjectExplorerに表示するフォルダ開閉アイコンの登録をしている。
なお、tutorialと異なるのは、アイコンの拡張子がgifではなくpngである点（昔、gifのライセンスの話があってわざわざ変えた？）。
getDefaultPageInputメソッドは、デフォルトで表示するパスを指定している。
<details><summary>ProjectExplorerの初期化コード</summary><div>

```java
@Override
public void initialize(IWorkbenchConfigurer configurer) {
    super.initialize(configurer);
    ...
    // inserted: register workbench adapters
    IDE.registerAdapters();
 
    // inserted: register images for rendering explorer view
    final String ICONS_PATH = "icons/full/";
    final String PATH_OBJECT = ICONS_PATH + "obj16/";
    Bundle ideBundle = Platform.getBundle(IDEWorkbenchPlugin.IDE_WORKBENCH);
    declareWorkbenchImage(configurer, ideBundle,
        IDE.SharedImages.IMG_OBJ_PROJECT, PATH_OBJECT + "prj_obj.png", true);
    declareWorkbenchImage(configurer, ideBundle,
        IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT + "cprj_obj.png", true);
}

private void declareWorkbenchImage(IWorkbenchConfigurer configurer_p,
        Bundle ideBundle, String symbolicName, String path, boolean shared) {
    URL url = ideBundle.getEntry(path);
    ImageDescriptor desc = ImageDescriptor.createFromURL(url);
    configurer_p.declareImage(symbolicName, desc, shared);
}

@Override
public IAdaptable getDefaultPageInput() {
    return ResourcesPlugin.getWorkspace().getRoot();
}
```
</div></details>

##ApplicationWorkbenchWindowAdvisor.javaのウィンドウサイズを変更するコードを削除
デフォルトではウィンドウサイズが400*300になってしまうので、preWindowOpenメソッドを以下のようにコードをコメントアウトする。
これにより、Application.e4xmiで指定したウィンドウサイズ800*600が上書きされなくなる。
<details><summary>preWindowOpenメソッド</summary><div>

```Java
    @Override
    public void preWindowOpen() {
//        IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
//        configurer.setInitialSize(new Point(400, 300));
//        configurer.setShowCoolBar(false);
//        configurer.setShowStatusLine(false);
//        configurer.setTitle("Hello RCP"); //$NON-NLS-1$
    }
```
</div></details>

##起動時のウィンドウ構成を初期状態に戻すオプションを追加する
Run -> DebugConfigurationを選択し、
さらに、Eclipse Applicationの下の`test.rcp.product_test`を選択。
Argumentタブをクリック。
Program Arguments内のテキストの末尾に、`-clearPersistedState`を追加しておく。
コメント欄でのやり取りに記載されているもの。


##必要なプラグインを追加して、起動する
DebugConfigurationにて、Plug-insタブをクリック。
Launch withはall～ではなく、below～を選択する。
右にあるDeselect Allボタンをクリックして、すべてのプラグインのチェックを外す。
Workspace内のtest.rcpだけにチェックを入れ、Add Required Plug-insボタンをクリック。
画面はいろいろなプラグインにもチェックが入っているのは、無視してほしい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94018/1f52380a-d9d8-7cf5-0e9a-102040ee746c.png)

Validate Plug-insボタンをクリックして、エラーが出ないことを確認して、Debugボタンをクリック。
冒頭で示したウィンドウが現れればOK。

#成果物
以上の作業で生成されたものを[GitHub](https://github.com/tfLabs/live1.git)に登録した。
ほぼ素の状態なので、別のアプリを構築したい場合のベースに使えるかも。

#振り返り
## E4のみでの開発は断念
本音では、E4だけをつかってすべてを定義したかったのだが、今回は断念した。
ネックになったのは、ProjectExplorerをE4環境で**簡単に**用意すること。
既存のものを作り直すのはなんとかの再発明だし、試してみたらエラーが解決できない。
結構な時間を使ってググったが、解決につながるいい情報が見つけられなかった。
Eclipse初心者には技術的にも時間的にも厳しいだろうと、ここで諦めた。
誰かご存じの方はいないだろうか…。

## clearPersistedStateオプション
デフォルト（オプションを指定しない）では、ユーザ操作によるウィンドウサイズやレイアウト変更などを記憶して、次回起動時にも同じレイアウトで表示してくれる。
指定すると、レイアウトは初期状態で表示される。
開発中はオプションを指定し、リリース後は指定を外す、という方針で当面はいいはず。
ユーザがいじりすぎてしまった場合に備えて、レイアウトを初期状態に戻せる機能をメニューなどに追加することを、以降のステップで検討してみる。