2009年6月6日土曜日

GraphicalEditorのファイルを削除、名前変更された時

AIR GEARではGEFのGraphicalEditorを使っています。
GraphicalEditorに限らずですが、FileEditorを自作している時は、Editorで表示しているファイルが削除された時、名前を変更された時のイベントを拾って整合性を合わせてあげる必要があります。

ファイルを削除された時。→ EditorをCloseする必要がある。
ファイルの名前が変わった時。→ Editorの名前をファイル名にしているのであれば、変更する必要がある。

これらのイベントの取得は、IResourceChangeListenerを使ってリソースの変更のタイミングを取得するのですが、このリスナーを追加する場所は Workspaceです。
ResourcesPlugin.getWorkspace().addResourceChangeListener(new MyResourceChangeLisnter());

ということで、自分のEditor以外でのリソース変更のタイミングも飛んでくるようになります。
ここで! AIR GEARで不具合が発生していました(涙)

GraphicalEditorではAdobeAIRのMXMLファイルの内容を表示しているのですが、MXMLファイルを編集するのは、その他のEditor(TextEditorとかXMLEditorとか)もアリ。
その他のEditorで変更された場合、表示中のGraphicalEditorの表示も最新にする必要があるので、このResourceChangeLisnterで受け取ったタイミングで、どのファイルが変更されたか?を確認せずに「ファイルの内容を読込みしてGUIを生成し直す」という処理を入れちゃってた。

元のソース
public void resourceChanged(final IResourceChangeEvent event) {
if (event.getType() == IResourceChangeEvent.POST_CHANGE) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
IFile file = ((IFileEditorInput) input).getFile();
if (!file.exists()) {
// ファイル名が変更されていたら、EditorをCloseする
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
page.closeEditor(VisualMXMLEditor.this, false);
} else {
if (!getPartName().equals(file.getName())) {
//ファイル名が変わっていたらEditorPartの名前も変更する
setPartName(file.getName());
}
// GraphicalEditorをファイルの情報から読込み直し
refreshGraphicalEditor();
}
}
});
}
}
view raw gistfile1.java hosted with ❤ by GitHub


どのファイルのリソースが修正されたか? は IResourceChangeEventのgetDelta()に含まれているようです。

ということで、修正後のソース。
public void resourceChanged(final IResourceChangeEvent event) {
if (event.getType() == IResourceChangeEvent.POST_CHANGE) {
IResourceDelta rootDelta = event.getDelta();
final IEditorInput input = getEditorInput();
IFile file = ((IFileEditorInput) input).getFile();
IPath filePath = file.getFullPath();
IResourceDelta targetDelta = rootDelta.findMember(filePath);
if (targetDelta != null) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
IFile file = ((IFileEditorInput) input).getFile();
if (!file.exists()) {
// ファイル名が変更されていたら、EditorをCloseする
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
page.closeEditor(VisualMXMLEditor.this, false);
} else {
if (!getPartName().equals(file.getName())) {
//ファイル名が変わっていたらEditorPartの名前も変更する
setPartName(file.getName());
}
// GraphicalEditorをファイルの情報から読込み直し
refreshGraphicalViewer();
}
}
});
}
}
}
view raw gistfile1.java hosted with ❤ by GitHub


ですが、このままではファイル名が変更された時には、Editorが終了してしまう様子。
ファイル名の変更=ファイルの移動としてちゃんとチェックをしてあげないとダメみたい。

で、再度変更ソース。
public void resourceChanged(final IResourceChangeEvent event) {
if (event.getType() != IResourceChangeEvent.POST_CHANGE
|| !(getEditorInput() instanceof IFileEditorInput)) {
return;
}
IResourceDelta rootDelta = event.getDelta();
IFile file = ((IFileEditorInput) getEditorInput()).getFile();
IPath filePath = file.getFullPath();
IResourceDelta delta = rootDelta.findMember(filePath);
if (delta == null) {
return;
}
Runnable changeRunnable = null;
if (delta.getKind() == IResourceDelta.REMOVED) {
if ((IResourceDelta.MOVED_TO & delta.getFlags()) != 0) {
IPath path = delta.getMovedToPath();
final IFile newFile = delta.getResource().getWorkspace().getRoot().getFile(path);
if (newFile != null) {
changeRunnable = new Runnable() {
public void run() {
setInput(new FileEditorInput(newFile));
setPartName(getEditorInput().getName());
}
};
}
} else {
changeRunnable = new Runnable() {
public void run() {
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
page.closeEditor(VisualMXMLEditor.this, false);
}
};
}
} else if (delta.getKind() == IResourceDelta.CHANGED) {
changeRunnable = new Runnable() {
public void run() {
refreshGraphicalViewer();
}
};
}
if (changeRunnable != null) {
getSite().getShell().getDisplay().asyncExec(changeRunnable);
}
}
view raw gistfile1.java hosted with ❤ by GitHub


これで何となく動いているようだ。
ファイルをフォルダ移動した時、Eclipse本体のWindowタイトルに表示されるファイルパスが移動先のものにならない...というのを除いて。
んー まぁそこは...今度みます。。
• • •