IPageLayout
Eclipse3.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
ます。にを追加Addon
しModel 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
保存がオンになっている場合、ローカルの変更はファイルのランタイムワークスペースに保存されるため、このファイルをテストするために変更されていないモデルを再作成するには、削除する必要があります。