/**
* @version $Id: CoronaElementDeleteOperation.java 1839 2014-04-16 02:33:51Z yukihiro-kinjyo $
*
* 2011/09/30 10:20:34
* @author kousuke-morishima
*
* Copyright 2011-2014 TIDAコンソーシアム All Rights Reserved.
*/
package com.tida_okinawa.corona.internal.ui.actions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.operations.AbstractOperation;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.PartInitException;
import com.tida_okinawa.corona.CoronaActivator;
import com.tida_okinawa.corona.internal.ui.views.model.IUIClaim;
import com.tida_okinawa.corona.internal.ui.views.model.IUIContainer;
import com.tida_okinawa.corona.internal.ui.views.model.IUIDictionary;
import com.tida_okinawa.corona.internal.ui.views.model.IUIElement;
import com.tida_okinawa.corona.internal.ui.views.model.IUILibrary;
import com.tida_okinawa.corona.internal.ui.views.model.IUIProduct;
import com.tida_okinawa.corona.internal.ui.views.model.IUIProject;
import com.tida_okinawa.corona.internal.ui.views.model.IUIWork;
import com.tida_okinawa.corona.internal.ui.views.model.impl.CoronaModel;
import com.tida_okinawa.corona.io.model.IClaimData;
import com.tida_okinawa.corona.io.model.IClaimWorkData;
import com.tida_okinawa.corona.io.model.ICoronaDics;
import com.tida_okinawa.corona.io.model.ICoronaObject;
import com.tida_okinawa.corona.io.model.ICoronaProduct;
import com.tida_okinawa.corona.io.model.ICoronaProject;
import com.tida_okinawa.corona.io.model.dic.ICoronaDic;
import com.tida_okinawa.corona.io.model.dic.IFlucDic;
import com.tida_okinawa.corona.io.model.dic.ILabelDic;
import com.tida_okinawa.corona.io.model.dic.ISynonymDic;
import com.tida_okinawa.corona.io.model.dic.IUserDic;
import com.tida_okinawa.corona.ui.UIActivator;
import com.tida_okinawa.corona.ui.ViewUtil;
import com.tida_okinawa.corona.ui.editors.AbstractDicEditor;
import com.tida_okinawa.corona.ui.editors.LabelDicEditor;
import com.tida_okinawa.corona.ui.editors.user.UserDicEditor;
/**
* @author kousuke-morishima
*/
public class CoronaElementDeleteOperation extends AbstractOperation {
private IUIElement[] deleteObjects;
/**
* @param deleteObjects
* @param label
* 名前?
*/
public CoronaElementDeleteOperation(IUIElement[] deleteObjects, String label) {
super(label);
this.deleteObjects = deleteObjects;
/* 子があるユーザ辞書の消し漏れをなくすため、子になりうるものでソートする */
Arrays.sort(deleteObjects, new Comparator<IUIElement>() {
int category(IUIElement o) {
if (o instanceof IUIProduct) {
return 10;
} else if (o instanceof IUIClaim) {
return 10;
} else if (o instanceof IUIProject) {
return 0;
} else if (o instanceof IUIDictionary) {
ICoronaDic dic = ((IUIDictionary) o).getObject();
if (dic instanceof IUserDic) {
return 25;
}
return 20;
} else {
return 99;
}
}
@Override
public int compare(IUIElement o1, IUIElement o2) {
int cat = category(o1) - category(o2);
if (cat == 0) {
/*
* 同じ辞書が複数のターゲットに登録されているとき、ひとつ消したらほかのターゲット下の辞書も確実に消さないといけない。
* 同じ辞書を一塊として処理しやすくするため、同じ辞書を指しているUIElementは連続させておく。
*/
if ((o1 instanceof IUIDictionary) && (o2 instanceof IUIDictionary)) {
ICoronaDic d1 = ((IUIDictionary) o1).getObject();
ICoronaDic d2 = ((IUIDictionary) o2).getObject();
if (d1.getId() != d2.getId()) {
return d1.getName().compareTo(d2.getName());
}
}
return 0;
}
return cat;
}
});
}
@Override
public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
monitor.beginTask(getLabel(), deleteObjects.length);
if (!monitor.isCanceled()) {
if (deleteObjects.length > 0) {
monitor.subTask(deleteObjects[0].getResource().getName());
ICoronaObject prevObject = deleteObjects[0].getObject();
for (IUIElement object : deleteObjects) {
/*
* 同じICoronaObjectを指すUIElementの削除中はキャンセルしたくないので、
* 処理対象のICoronaObjectが切り替わったタイミングでキャンセルされたか見に行く
*/
ICoronaObject curObject = object.getObject();
if ((prevObject == null) || !prevObject.equals(curObject)) {
if (monitor.isCanceled()) {
break;
}
prevObject = curObject;
monitor.subTask(object.getResource().getName());
}
delete(object);
monitor.worked(1);
}
}
}
monitor.done();
return stat;
}
private Set<IStatus> uniqueCheck = new HashSet<IStatus>();
private MultiStatus stat = new MultiStatus(UIActivator.PLUGIN_ID, 332, "", null);
private void addResult(IStatus result) {
if (uniqueCheck.add(result)) {
stat.add(result);
}
}
/**
* 削除アイテムと一緒に消えるべきアイテムのリソース
*/
List<IResource> deleteResources;
private void delete(final IUIElement uiElem) {
/*
* 削除順番
* 1.ICoronaObject
* - IResourceを消した結果、子がいなくなるような場合にアイテムが消えずに残るため、先に消す
* 2.IResource
* 3.Adapter
* - IResourceを消すとき、Adapterの情報を使用するので、後で消す。
*/
deleteResources = new ArrayList<IResource>();
/* ICoronaObject */
IStatus result = Status.OK_STATUS;
if (uiElem instanceof IUIDictionary) {
result = delete((IUIDictionary) uiElem);
} else if (uiElem instanceof IUIProject) {
result = delete((IUIProject) uiElem);
} else if (uiElem instanceof IUIProduct) {
result = delete((IUIProduct) uiElem);
} else if (uiElem instanceof IUIWork) {
result = delete((IUIWork) uiElem);
} else if (uiElem instanceof IUIClaim) {
result = delete((IUIClaim) uiElem);
}
if (!result.isOK()) {
addResult(result);
return;
}
final IStatus status = new MultiStatus(UIActivator.PLUGIN_ID, 4100, "辞書削除", null);
/* 処理後のStatusの状態を見るので、syncExec */
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
/* ProjectExplorerが更新されるため、UIスレッドで処理する */
for (IResource refRes : deleteResources) {
try {
if (refRes instanceof IProject) {
/* 閉じているとisAccessibleがfalseになるので開く */
if (!((IProject) refRes).isOpen()) {
((IProject) refRes).open(null);
}
}
if (isDeleteAvailable(refRes)) {
refRes.delete(true, new NullProgressMonitor());
}
} catch (CoreException e) {
((MultiStatus) status).add(new Status(IStatus.ERROR, UIActivator.PLUGIN_ID, refRes.getFullPath() + "の削除に失敗しました。", e));
}
}
// Adapter
/*
* ProjectExplorerの更新前に消えると困るので、こちらもUIスレッドで処理する
* IResourceの削除に失敗しても、オブジェクトの関連は消えているのでキャッシュも消す。
*/
CoronaModel.INSTANCE.remove(uiElem);
for (IResource refRes : deleteResources) {
CoronaModel.INSTANCE.remove(CoronaModel.INSTANCE.adapter(refRes, false));
}
}
});
if (!status.isOK()) {
CoronaActivator.log(status, false);
/* 削除に失敗した場合、UIアイテムがCoronaObjectのままになってしまうのでリフレッシュする */
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
ViewUtil.refreshProjectExplorer(0);
}
});
}
}
boolean isDeleteAvailable(final IResource resource) {
if (resource == null)
return false;
if (!resource.exists())
return false;
if (!resource.isAccessible())
return false;
return true;
}
/* ****************************************
* 辞書削除のときの処理
*/
/**
* 辞書と、ほかに消さなきゃいけないものがある場合はそれも消す。
*
* @param uiDic
*/
private IStatus delete(IUIDictionary uiDic) {
IUILibrary uiLib = CoronaModel.INSTANCE.getLibrary(uiDic);
final ICoronaDic dic = uiDic.getObject();
if (dic instanceof IUserDic) {
ICoronaDics dics = uiLib.getObject();
List<ICoronaDic> childDics = new ArrayList<ICoronaDic>();
childDics.addAll(AbstractDicEditor.searchChildDictionaries((IUserDic) dic, dics.getDictionarys(ILabelDic.class)));
childDics.addAll(AbstractDicEditor.searchChildDictionaries((IUserDic) dic, dics.getDictionarys(IFlucDic.class)));
childDics.addAll(AbstractDicEditor.searchChildDictionaries((IUserDic) dic, dics.getDictionarys(ISynonymDic.class)));
if (!childDics.isEmpty()) {
StringBuilder buf = new StringBuilder(128).append(dic.getName()).append("は削除できません。以下の辞書から参照されています");
for (ICoronaDic child : childDics) {
buf.append("\n").append(child.getName());
}
/* いろんなところにメッセージを配信 */
return new DicDeleteStatus(IStatus.WARNING, buf.toString(), uiDic);
}
} else if (dic instanceof ILabelDic) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
try {
/* 辞書が削除されるので、編集リスナから外す */
for (IEditorReference editorRef : LabelDicEditor.getRelatedUserDicEditor((ILabelDic) dic)) {
UserDicEditor editor = (UserDicEditor) editorRef.getEditor(false);
editor.removeRelated((ILabelDic) dic);
}
} catch (PartInitException e) {
e.printStackTrace();
}
}
});
}
/* 辞書を消す */
_delete(uiLib, uiDic);
deleteResources.add(uiDic.getResource());
return Status.OK_STATUS;
}
/**
* 指定された辞書をただ消すだけ
*
* @param lib
* @param uiDic
*/
private static void _delete(IUILibrary lib, IUIDictionary uiDic) {
if (lib instanceof IUIProject) {
ICoronaDics dics = lib.getObject();
if (dics != null) {
dics.removeDictionary(uiDic.getId());
}
} else if (lib instanceof IUIProduct) {
ICoronaDics dics = lib.getObject();
if (dics != null) {
dics.removeDictionary(uiDic.getId());
}
}
IUIContainer parent = uiDic.getParent();
if (parent != null) {
parent.modifiedChildren(); /* 子が変わったことを通知 */
}
}
/* ****************************************
* プロジェクト削除のときの処理
*/
private IStatus delete(IUIProject uiProject) {
deleteResources.add(uiProject.getResource());
return Status.OK_STATUS;
}
/* ****************************************
* ターゲット削除のときの処理
*/
/**
* ターゲットと、ほかに消さなきゃいけないものがある場合はそれも消す
*
* @param uiProduct
*/
private IStatus delete(IUIProduct uiProduct) {
IUIProject uiProject = CoronaModel.INSTANCE.getProject(uiProduct);
ICoronaProject project = uiProject.getObject();
/* ターゲット、および問合せデータを削除する */
_delete(uiProject, uiProduct);
deleteResources.add(uiProduct.getResource());
/* どのターゲットからも参照されていない問合せデータを探す */
List<IClaimData> original = project.getClaimDatas();
List<IClaimData> deleteClaims = new ArrayList<IClaimData>(original);
List<ICoronaProduct> products = project.getProducts();
for (ICoronaProduct p : products) {
deleteClaims.removeAll(p.getClaimDatas());
}
for (IClaimData claim : deleteClaims) {
IUIClaim uiClaim = CoronaModel.INSTANCE.getClaim(uiProject, claim);
_delete(uiProject, uiClaim);
deleteResources.add(uiClaim.getResource());
}
return Status.OK_STATUS;
}
/**
* 指定されたターゲットをただ消すだけ
*
* @param uiProject
* @param uiProduct
*/
private static void _delete(IUIProject uiProject, IUIProduct uiProduct) {
ICoronaProject project = uiProject.getObject();
ICoronaProduct product = uiProduct.getObject();
if ((project != null) && (product != null)) {
project.removeProduct(product);
}
uiProject.modifiedChildren();
}
/* ****************************************
* 問合せデータ
*/
private IStatus delete(IUIClaim uiClaim) {
IUIProject uiProject = CoronaModel.INSTANCE.getProject(uiClaim.getParent());
_delete(uiProject, uiClaim);
deleteResources.add(uiClaim.getResource());
return Status.OK_STATUS;
}
private static void _delete(IUIProject uiProject, IUIClaim uiClaim) {
ICoronaProject project = uiProject.getObject();
if (project != null) {
project.removeClaimData(uiClaim.getId());
}
/* 未作成なら通知しなくていいのでfalse */
IUIContainer parent = uiClaim.getParent();
if (parent != null) {
parent.modifiedChildren();
}
}
/* ****************************************
* 処理結果
*/
private IStatus delete(IUIWork uiWork) {
IUIProduct uiProduct = (IUIProduct) CoronaModel.INSTANCE.getUIContainer(IUIProduct.class, uiWork.getParent());
if (uiProduct != null) {
IClaimWorkData work = uiWork.getObject();
if (work != null) {
uiProduct.getObject().removeClaimWorkData(work);
deleteResources.add(uiWork.getResource());
IUIContainer parent = uiWork.getParent();
if (parent != null) {
parent.modifiedChildren();
}
}
}
return Status.OK_STATUS;
}
/* ****************************************
* 辞書削除結果用IStatus
*/
private static class DicDeleteStatus extends Status {
private IUIDictionary uiDic;
/**
* @param severity
* @param pluginId
* @param message
* @param targetDic
* 削除対象の辞書
*/
public DicDeleteStatus(int severity, String message, IUIDictionary targetDic) {
super(severity, UIActivator.PLUGIN_ID, message);
this.uiDic = targetDic;
}
@Override
public int hashCode() {
return uiDic.hashCode();
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (!(obj instanceof DicDeleteStatus)) {
return false;
}
DicDeleteStatus s2 = (DicDeleteStatus) obj;
if (getSeverity() != s2.getSeverity()) {
return false;
}
ICoronaDic dic = uiDic.getObject();
if (dic != null) {
return dic.equals(s2.uiDic.getObject());
}
/* 本体が取れないならfalseでいいよ */
return false;
}
}
/* ****************************************
* Undo&Redo
*/
@Override
public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
// TODO しばらくは実装しなくていいと思う
return null;
}
@Override
public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
// TODO しばらくは実装しなくていいと思う
return null;
}
}