/** * @version $Id: SynonymDicEditor.java 1840 2014-04-16 05:38:34Z yukihiro-kinjyo $ * * 2011/10/05 18:33:52 * @author kousuke-morishima * * Copyright 2011-2014 TIDAコンソーシアム All Rights Reserved. */ package com.tida_okinawa.corona.ui.editors; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.dialogs.ISelectionStatusValidator; import org.eclipse.ui.internal.OverlayIcon; import com.tida_okinawa.corona.internal.ui.component.ElementListSelectionDialog1; import com.tida_okinawa.corona.internal.ui.views.model.IUILibrary; import com.tida_okinawa.corona.internal.ui.views.model.impl.CoronaModel; import com.tida_okinawa.corona.io.IoActivator; import com.tida_okinawa.corona.io.model.ICoronaDics; import com.tida_okinawa.corona.io.model.dic.ICoronaDic; import com.tida_okinawa.corona.io.model.dic.IDepend; import com.tida_okinawa.corona.io.model.dic.IDependDic; import com.tida_okinawa.corona.io.model.dic.IDicFactory; import com.tida_okinawa.corona.io.model.dic.IDicItem; import com.tida_okinawa.corona.io.model.dic.ITerm; import com.tida_okinawa.corona.io.model.dic.IUserDic; import com.tida_okinawa.corona.ui.Icons; import com.tida_okinawa.corona.ui.UIActivator; /** * 同義語辞書エディターオブジェクト * * @author kousuke-morishima */ public class SynonymDicEditor extends MasterServantEditor2 { public static final String EDITOR_ID = "com.tida_okinawa.corona.ui.editor.synonymdic"; //$NON-NLS-1$ /** * 同義語辞書エディターオブジェクトの初期化 */ public SynonymDicEditor() { super(new int[] { 1, 1 }); } private IDependDic dependDic; private DicEditorDisposer disposer; @Override protected void update() { dependDic.update(); registeredMasterItems = null; } @Override protected boolean validDictionary(ICoronaDic dic) { if (dic instanceof IDependDic) { dependDic = (IDependDic) dic; return true; } return false; } @Override public void init(IEditorSite site, IEditorInput input) throws PartInitException { super.init(site, input); setPartName(input.getName()); List<ICoronaDic> dics = new ArrayList<ICoronaDic>(1); dics.add(dependDic); disposer = new DicEditorDisposer(this, dics); getSite().getPage().addPartListener(disposer); } @Override public void dispose() { super.dispose(); if (isLocalFile()) { /* エラーのデータは保存されないので、閉じたらマーカーは消さなきゃいけない */ IResource res = uiDic.getResource(); try { if (res.exists()) { res.deleteMarkers(IMarker.PROBLEM, false, IResource.DEPTH_ZERO); } } catch (CoreException e) { e.printStackTrace(); } } getSite().getPage().removePartListener(disposer); } /* **************************************** * 保存 */ @Override public void doSave(IProgressMonitor monitor) { /* エラーアイテムを保存しない */ Map<IDepend, Integer> errorItemMap = new TreeMap<IDepend, Integer>(new Comparator<IDepend>() { @Override public int compare(IDepend o1, IDepend o2) { /* putした順に追加する */ if (o1.equals(o2)) { return 0; } return 1; } }); List<IDicItem> currentItems = dependDic.getItems(); // Memo 今は、SynonymDicが持っているitemsをそのままもらっているのでこれでOK int i = 0; for (IDicItem item : currentItems) { if (isError((IDepend) item)) { // 直接消しているので、ICoronaDicの削除フラグは立たない */ errorItemMap.put((IDepend) item, i--); } i++; } for (Entry<IDepend, Integer> e : errorItemMap.entrySet()) { currentItems.remove((int) e.getValue()); } dependDic.commit(monitor); /* Memo 削除フラグを立てていないので、またこっそり戻す */ if (errorItemMap.size() > 0) { StringBuilder message = new StringBuilder(30 + (15 * errorItemMap.size())); message.append(Messages.SynonymDicEditor_messageSaveFail); int cnt = 0; for (Entry<IDepend, Integer> e : errorItemMap.entrySet()) { currentItems.add(cnt + e.getValue(), e.getKey()); if ((cnt % 5) == 0) { message.append("\n"); //$NON-NLS-1$ } message.append(e.getKey().getMain().getValue()).append(", "); //$NON-NLS-1$ cnt++; } MessageDialog.openWarning(getSite().getShell(), Messages.SynonymDicEditor_unsavedItem, message.toString()); dependDic.setDirty(true); } dirtyChanged(); getMasterViewer().update(errorItemMap.keySet().toArray(), null); } boolean isError(IDepend depend) { boolean ret = depend.getSub().isEmpty(); return ret; } @Override public boolean isDirty() { return dependDic.isDirty(); } @Override public void doSaveAs() { } @Override public boolean isSaveAsAllowed() { return false; } /* **************************************** * Override */ @Override protected Control createMasterArea(Composite parent) { Control c = super.createMasterArea(parent); getMasterViewer().setSorter(sorter); return c; } @Override protected Control createServantArea(Composite parent) { Control c = super.createServantArea(parent); getServantViewer().setSorter(sorter); return c; } private ViewerSorter sorter = new ViewerSorter() { @Override public int compare(Viewer viewer, Object e1, Object e2) { ITerm t1 = null; ITerm t2 = null; if (e1 instanceof IDepend) { t1 = ((IDepend) e1).getMain(); t2 = ((IDepend) e2).getMain(); } else if (e1 instanceof ITerm) { t1 = (ITerm) e1; t2 = (ITerm) e2; } else { return 0; } return t1.getValue().compareTo(t2.getValue()); } }; private Set<ITerm> registeredMasterItems; /** * 従属語、親アイテム */ Map<ITerm, IDepend> registeredSubItems; @Override protected Object getMasterInput() { /* 登録済みの代表語と従属語のリストを作成 */ List<IDicItem> items = dependDic.getItems(); if (registeredMasterItems == null) { Comparator<ITerm> comparator = new Comparator<ITerm>() { @Override public int compare(ITerm o1, ITerm o2) { return o1.getKeyword().compareTo(o2.getKeyword()); } }; registeredMasterItems = new TreeSet<ITerm>(comparator); registeredSubItems = new TreeMap<ITerm, IDepend>(comparator); looper = new LoopDetector<ITerm>(); for (Iterator<IDicItem> itr = items.iterator(); itr.hasNext();) { IDepend item = (IDepend) itr.next(); ITerm masterTerm = item.getMain(); if (masterTerm != null) { registeredMasterItems.add(masterTerm); looper.add(masterTerm); List<ITerm> subs = item.getSub(); for (Iterator<ITerm> itr2 = subs.iterator(); itr2.hasNext();) { ITerm subTerm = itr2.next(); if (subTerm != null) { registeredSubItems.put(subTerm, item); looper.add(masterTerm, subTerm); } else { itr2.remove(); /* nullアイテムは除去 */ } } } else { itr.remove(); /* nullアイテムは除去 */ } } } return items; } ILabelProvider masterLabelProvider = new LabelProvider() { @Override public String getText(Object element) { if (element instanceof IDepend) { ITerm term = ((IDepend) element).getMain(); return servantLabelProvider.getText(term); } return super.getText(element); } @SuppressWarnings("restriction") @Override public Image getImage(Object element) { if (element instanceof IDepend) { if (isError((IDepend) element)) { // error item ImageDescriptor base = Icons.INSTANCE.getDescriptor(Icons.IMG_PATTERN_RECORD); ImageDescriptor overlay = Icons.INSTANCE.getDescriptor(Icons.IMG_OVR_ERROR); return new OverlayIcon(base, overlay, new Point(16, 16)).createImage(); } } return super.getImage(element); } }; @Override protected ILabelProvider getMasterLabelProvider() { return masterLabelProvider; } @Override protected IStructuredContentProvider getServantContentProvider() { return new IStructuredContentProvider() { private final Object[] EMPTY_ARRAY = new Object[0]; @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public void dispose() { } @Override public Object[] getElements(Object input) { if (input instanceof IDepend) { return ((IDepend) input).getSub().toArray(); } return EMPTY_ARRAY; } }; } @Override protected ILabelProvider getServantLabelProvider() { return servantLabelProvider; } LabelProvider servantLabelProvider = new LabelProvider() { @Override public String getText(Object element) { if (element instanceof ITerm) { ITerm term = (ITerm) element; return getString(50, ":", term.getValue(), term.getTermPart().getName(), term.getTermClass().getName()); //$NON-NLS-1$ } return super.getText(element); } private final String getString(int initCapa, String sepa, Object... args) { StringBuilder buf = new StringBuilder(initCapa); for (Object arg : args) { buf.append(sepa).append(arg); } buf.delete(0, sepa.length()); return buf.toString(); } }; private static final IDicFactory factory = IoActivator.getDicFactory(); LoopDetector<ITerm> looper = new LoopDetector<ITerm>(); @Override protected void addButtonSelected(String masterOrServant) { /* 表示アイテムを親辞書から取得 */ List<IUserDic> parentDics = getParentDics(); List<IDicItem> viewItems = new ArrayList<IDicItem>(); for (IUserDic udic : parentDics) { viewItems.addAll(udic.getItems()); } final ElementListSelectionDialog1 d = new ElementListSelectionDialog1(getSite().getShell(), new LabelProvider() { @Override public String getText(Object element) { StringBuilder base = new StringBuilder(50).append(servantLabelProvider.getText(element)); if (registeredSubItems.containsKey(element)) { base.append(" -> ").append(masterLabelProvider.getText(registeredSubItems.get(element))); //$NON-NLS-1$ } return base.toString(); } }); d.setConvertZenkaku(true); d.setMultipleSelection(true); d.setImeMode(SWT.NATIVE); if (MASTER.equals(masterOrServant)) { /* 単語を選択してもらう */ d.setTitle(Messages.SynonymDicEditor_titleSelectMainTerm); d.setMessage(Messages.SynonymDicEditor_messageSelectMainTerm); /* 登録済み単語を消す */ viewItems.removeAll(registeredMasterItems); d.setElements(viewItems.toArray()); if (d.open() == Dialog.OK) { IDepend addedItem = null; for (Object r : d.getResult()) { /* 辞書に */ addedItem = factory.createSynonym((ITerm) r); dependDic.addItem(addedItem); /* キャッシュに */ if (addedItem.getMain() != null) { registeredMasterItems.add(addedItem.getMain()); } looper.add(addedItem.getMain()); } getMasterViewer().refresh(); if (addedItem != null) { getMasterViewer().setSelection(new StructuredSelection(addedItem)); } dirtyChanged(); } } else { List<IDepend> elements = getSelectedMasterItems(); if (elements.size() == 1) { final IDepend parent = elements.get(0); /* 登録済み単語と親を消す */ // viewItems.removeAll(registeredSubItems); viewItems.remove(parent.getMain()); d.setElements(viewItems.toArray()); d.setTitle(Messages.SynonymDicEditor_titleSelectDependentTerm); d.setMessage(Messages.SynonymDicEditor_messageSelectDependentTerm); d.setValidator(new ISelectionStatusValidator() { @Override public IStatus validate(Object[] selection) { /* 代表語と従属語でループしないか確認する */ StringBuilder message = new StringBuilder(); for (Object select : selection) { if (select instanceof ITerm) { ITerm t = (ITerm) select; if (!looper.check(parent.getMain(), t)) { message.append(", ").append(t.getValue()); //$NON-NLS-1$ } } } if (message.length() > 0) { return new Status(IStatus.ERROR, UIActivator.PLUGIN_ID, message.substring(2) + Messages.SynonymDicEditor_messageCycle); } for (Object select : selection) { if (select instanceof ITerm) { ITerm t = (ITerm) select; IDepend parent = registeredSubItems.get(t); if (parent != null) { message.append(", ").append(t.getValue()); //$NON-NLS-1$ } } } if (message.length() > 0) { return new Status(IStatus.ERROR, UIActivator.PLUGIN_ID, message.substring(2) + Messages.SynonymDicEditor_messageRegistered); } return Status.OK_STATUS; } }); if (d.open() == Dialog.OK) { ITerm addedChild = null; for (Object r : d.getResult()) { addedChild = (ITerm) r; parent.addSub(addedChild); registeredSubItems.put(addedChild, parent); looper.add(parent.getMain(), addedChild); } getMasterViewer().update(parent, null); getServantViewer().refresh(); if (addedChild != null) { getServantViewer().setSelection(new StructuredSelection(addedChild)); } dirtyChanged(); } } else { /* マスターが選択されていないか、複数選択されているので、なにもしない */ } } } @Override protected void removeButtonSelected(String masterOrServant) { /* 選択されているアイテムを全部消す */ if (MASTER.equals(masterOrServant)) { List<IDepend> depends = getSelectedMasterItems(); if (!depends.isEmpty()) { for (IDepend depend : depends) { /* 辞書から */ dependDic.removeItem(depend); /* キャッシュから */ if (depend.getMain() != null) { registeredMasterItems.remove(depend.getMain()); for (ITerm sub : depend.getSub()) { registeredSubItems.remove(sub); } } /* ループ検出から */ for (ITerm sub : depend.getSub()) { looper.remove(sub); } looper.remove(depend.getMain()); } setNewSelection(getMasterViewer()); dirtyChanged(); } } else { /* マスターで選択されているアイテムが1つのときだけ処理する */ List<IDepend> masterItems = getSelectedMasterItems(); if (masterItems.size() == 1) { IDepend master = masterItems.get(0); /* サブで選択されているアイテムすべてを削除する */ TableViewer v = getServantViewer(); IStructuredSelection selection = (IStructuredSelection) v.getSelection(); List<?> elements = selection.toList(); if (!elements.isEmpty()) { for (Object element : elements) { if (element instanceof ITerm) { ITerm term = (ITerm) element; master.removeSub(term); registeredSubItems.remove(term); looper.remove(term); } } setNewSelection(v); dirtyChanged(); } } getMasterViewer().refresh(); } } /** * @return 選択されているアイテムをすべて返す。 */ protected List<IDepend> getSelectedMasterItems() { TableViewer v = getMasterViewer(); int itemNum = v.getTable().getItemCount(); List<IDepend> ret = new ArrayList<IDepend>(itemNum); IStructuredSelection selection = (IStructuredSelection) v.getSelection(); for (Object o : selection.toArray()) { ret.add((IDepend) o); } return ret; } /* **************************************** * 親辞書 */ private List<IUserDic> parentDics; private List<IUserDic> getParentDics() { if (parentDics == null) { parentDics = new ArrayList<IUserDic>(); if (isLocalFile()) { /* ローカルファイルの場合、同じLibraryが保持しているはず */ IUILibrary lib = CoronaModel.INSTANCE.getLibrary(uiDic); ICoronaDics dics = lib.getObject(); if (dics == null) { parentDics = new ArrayList<IUserDic>(0); } else { parentDics = searchParentDictionaries(dependDic, dics.getDictionarys(IUserDic.class)); } } else { /* 全辞書走査 */ parentDics = searchParentDictionaries(dependDic, IoActivator.getService().getDictionarys(IUserDic.class)); } } return parentDics; } }