7

ある種の 3 列レイアウトの Eclipse RCP アプリケーションがあります。

ここに画像の説明を入力

エディタ領域は右端にあります。ここで、作業する を取得するIPageLayoutと、エディター領域が既に追加されています。これで問題ありません。領域 B をエディターの左側に追加し、領域 A を B の左側に追加すると、レイアウトはまさに必要なものになります。

問題は、A と B の間でサッシを移動すると、エディタ領域のサイズを変更せずにビュー A と B が変更されますが (良い;)、B とエディタ領域の間で他のサッシを移動すると、3 つのビューすべてがサイズ変更されます。レイアウト マネージャーは、A と B の幅の比率を維持するように機能しますが、それは私たちが望んでいるものではありません。ユーザーが各サッシを個別に移動できるようにし、サッシが接触する 2 つのビューだけに影響を与えるようにします。

これの根本的な原因は、 を取得したときにエディターが配置されているため、それに対して sIPageViewを配置する必要があるようです。IFolderLayout代わりに、エディターを B に対して相対的に配置できれば、サイズ変更は正しいことを行います。

だから私の質問:

  1. IPageViewビューに対してエディターを相対的に配置するように指示する方法はありますか?
  2. それを除けば、ある種のレイアウトマネージャーを書くなど、レイアウトアルゴリズムに影響を与える他の方法はありますか?
4

2 に答える 2

7

IPageLayoutEclipse3.xでのレイアウトツリーを変更する方法がわかりません。ただし、Eclipse 4.2では、アプリケーションモデルは実行時に動的に変更できます。

したがって、アプリケーションをEclipse 4に移行することを検討する場合は、このソリューションが選択肢になる可能性があります。元のアプリケーションとUIコードを可能な限り変更しないようにするために、このソリューションは

  • Eclipse 4の互換性レイヤーを最大限に活用して、Eclipse3ベースのRCPアプリケーションからアプリケーションモデルを作成します。アプリケーションモデルを作成したり、アプリケーションのUIコードを変更したりする必要はありません。
  • アプリケーションがアクティブになった後、エディタ領域のレイアウトを再配置します。これは、別のプラグインでアドオンクラスを作成することによって行われます。
  • 将来、より多くのEclipse 4機能に簡単に移行できるようにします。独自のアプリケーションモデルを構築する場合は、アドオンプラグインのフックを解除するだけです。

Eclipse3の通常のRCPMailテンプレートから始めて、問題を再現するためにパースペクティブを変更しました。これはPerspective、テストアプリケーションで使用したクラスです。

import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;

public class Perspective implements IPerspectiveFactory {

  public static final String ID = "wag.perspective";

  public void createInitialLayout(IPageLayout layout) {
    String editorArea = layout.getEditorArea();
    layout.setEditorAreaVisible(true);

    layout.addStandaloneView(AView.ID, false, IPageLayout.LEFT,
                             0.25f, editorArea);
    layout.addStandaloneView(BView.ID, false, IPageLayout.LEFT,
                             0.25f, editorArea);

    layout.getViewLayout(AView.ID).setCloseable(false);
    layout.getViewLayout(BView.ID).setCloseable(false);
  }
}

基本的に、説明したシナリオを作成します。1つのサッシが3つの部分すべてに影響し、もう1つのサッシが2つだけに影響する3列のレイアウトです。

次に、アプリケーションの移行とアプリケーションモデルの変更に進みました。

Eclipse3ベースのRCPアプリケーションをEclipse4に移行します

このプロセスに利用できるオンラインチュートリアルがあります。Eclipse 4.1:4.1とEclipse4で3.xRCPを実行し、互換性レイヤー-チュートリアルが非常に役立つことがわかりました。

org.eclipse.e4.tools.emf.liveeditor製品の依存関係にとに必要なプラグインを含めることをお勧めします。ライブエディターを使用すると、互換性レイヤーによって作成されたアプリケーションモデルを確認できます。

アプリケーションが起動しても、サッシュは同じように動作します。アプリケーションウィンドウでライブエディターを開き、モデルを確認します。

互換性レイヤーによって作成されたレイアウトツリー

PartSashContainerのプレースホルダーを含めると、AView別のが含まれていることがわかりますPartSashContainer。とそのコンテナの間でサッシAViewを移動すると、レイアウトツリーの残りの部分が更新されますが、との間でサッシを移動してBViewも、エディタはレイアウトの他の部分に影響しません。

これで、のプレースホルダーをとエディターが配置AViewされているコンテナーにドラッグできます。BViewこれにより、必要な効果が即座に作成されます。サッシュは、直接隣接するものにのみ影響します。ただし、これらの変更は、自分のランタイムワークスペースにのみ保存されます。レイアウト構造を自動的に変更するには、他に何かが必要です。

実行時のアプリケーションモデルの変更

可能であれば元のコードに触れたくなかったので、アプリケーションモデルに貢献するために別のプラグインを作成しました。

Activatorテンプレートを使用せずにプラグインプロジェクトを作成します。

クラスを追加しAddonます。[新規]->[その他]->[Eclipse4-]->[クラス]->[新しいアドオンクラス]を選択します。

追加Model Fragment:[新規]->[その他]-[Eclipse4-]->[モデル]->[新しいモデルフラグメント]を選択します。作成したfragment.e4xmiファイルを開き、を追加しModel Fragmentます。Element Idには、put org.eclipse.e4.legacy.ide.application(これはレガシーアプリケーションの標準IDです)とFeaturenameを入力しaddonsます。にを追加AddonModel Fragmentます。IDを入力Class URIし、アドオンクラスに設定します。

次に、拡張ポイントにを追加fragment.e4xmiします。org.eclipse.e4.workbench.model

<extension
  id="id1"
  point="org.eclipse.e4.workbench.model">
  <fragment
    uri="fragment.e4xmi">
  </fragment>
</extension>

アプリケーション製品の依存関係にコントリビューションプラグインを追加します。アプリケーションを起動し、ライブエディターでモデルを見ると、モデルにAddonリストされていることがわかります。

これで、を実装できますAddon。これは私のAddonクラスのコードです:

package wag.contribution.addons;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;

import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.MElementContainer;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;

public class LayoutSorter {

  @Inject private IEventBroker broker;

  private EventHandler handler;

  // The part IDs we are interested in, sorted in the sequence they should be
  // shown
  private static List<String> PART_IDS = Arrays.asList(new String[] {
              "wag.aView", "wag.bView", "org.eclipse.ui.editorss" });

  // Listen to the e4 core service's event broker to find the magical time
  // when the application is created and try to sort the layout.
  @PostConstruct
  void hookListeners(final MApplication application,
                     final EModelService service) {

    if (handler == null) {
      handler = new EventHandler() {
        // Try to sort the layout. Unsubscribe from event broker if
        // successful.
        @Override
        public void handleEvent(Event event) {
          try {
            sort(application, service);
            // sort did finish: stop listening to the broker.
            broker.unsubscribe(handler);
          } catch (Exception e) {
            // Something went wrong, the application model was not ready yet.
            // Keep on listening.
          }
        }
      };

      // Subscribe "ServiceEvent.MODIFIED" to grab the application.STARTED
      // event. Does anybody know how to do this in a better way?
      broker.subscribe("org/osgi/framework/ServiceEvent/MODIFIED",
                       handler);
    }
  }

  private void sort(MApplication application, EModelService service) {

    // find all placeholders
    List<MPlaceholder> placeholders = service.findElements(application,
              null, MPlaceholder.class, null);

    // only keep the ones we are interested in
    for (int i = placeholders.size() - 1; i > -1; i--) {
      if (!PART_IDS.contains(placeholders.get(i).getElementId())) {
        placeholders.remove(i);
      }
    }

    // find the parents of the placeholders
    List<MElementContainer<MUIElement>> parents = new ArrayList<>(
             placeholders.size());
    for (MPlaceholder placeholder : placeholders) {
      parents.add(placeholder.getParent());
    }

    // find the parent that is "deepest down" in the tree
    MElementContainer<MUIElement> targetParent = null;
    for (MElementContainer<MUIElement> parent : parents) {
      for (MUIElement child : parent.getChildren()) {
        if (parents.contains(child)) {
          continue;
        }
        targetParent = parent;
      }
    }

    // move all parts to the target parent
    if (targetParent != null) {
      for (int i = 0; i < placeholders.size(); i++) {
        if (targetParent != placeholders.get(i).getParent()) {
          service.move(placeholders.get(i), targetParent, i);
        }
      }
    }
  }

  @PreDestroy
  void unhookListeners() {
    if (handler != null) {
      // in case it wasn't unhooked earlier
      broker.unsubscribe(handler);
    }
  }
}

(上記のコードは、この特定の問題にのみ本当に適しているため、ちょっとしたハックであることに注意してください。)

再起動後、アプリケーションは希望どおりに動作するはずです。アプリケーションモデルを見て、変更を確認してください。

注意すべき点の1つは、.metadata\.plugins\org.eclipse.e4.workbench\workbench.xmi保存がオンになっている場合、ローカルの変更はファイルのランタイムワークスペースに保存されるため、このファイルをテストするために変更されていないモデルを再作成するには、削除する必要があります。

于 2012-08-17T16:46:12.663 に答える
2

あなたが望むものを正確に達成することは可能だとは思いません(したがって、質問への答えは1.いいえ、2.いいえになります)。しかし、IMO が非常にうまく動作する 3 番目の選択肢があります。

Eclipse で試す場合: 左側に viewA、右側に Editor から始めます。次に、viewB を viewA の右側にドラッグすると、説明した (間違った) セットアップが得られます。しかし、それをエディターの左側にドラッグすると、別の構成が得られ、右側のサッシをドラッグすると思いどおりに動作します。左のサッシをドラッグすると、viewA と Editor のサイズが変更され、viewB が移動します。

これを達成するためのコードは次のようになります。

IFolderLayout areaA = layout.createFolder("A", IPageLayout.LEFT, 0.33f, editorArea);
IFolderLayout areaB = layout.createFolder("B", IPageLayout.LEFT, 0.5f, editorArea);
于 2012-08-14T15:24:47.010 に答える