/**
* @version $Id: TermDetailsPage.java 1839 2014-04-16 02:33:51Z yukihiro-kinjyo $
*
* 2011/08/31 14:19:34
* @author kousuke-morishima
*
* Copyright 2011-2014 TIDAコンソーシアム All Rights Reserved.
*/
package com.tida_okinawa.corona.ui.editors.pattern;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.IFormPart;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.widgets.Section;
import com.tida_okinawa.corona.correction.collocation.CorrectionStringList;
import com.tida_okinawa.corona.correction.erratum.Erratum;
import com.tida_okinawa.corona.correction.morphem.SyntaxStructure;
import com.tida_okinawa.corona.correction.parsing.model.Pattern;
import com.tida_okinawa.corona.correction.parsing.model.PatternContainer;
import com.tida_okinawa.corona.correction.parsing.model.QuantifierType;
import com.tida_okinawa.corona.correction.parsing.model.SearchScopeType;
import com.tida_okinawa.corona.correction.parsing.model.Sequence;
import com.tida_okinawa.corona.correction.parsing.model.Term;
import com.tida_okinawa.corona.internal.ui.component.CompositeUtil;
import com.tida_okinawa.corona.internal.ui.views.model.IUIDictionary;
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.ICoronaProduct;
import com.tida_okinawa.corona.io.model.ICoronaProject;
import com.tida_okinawa.corona.io.model.MorphemeElement;
import com.tida_okinawa.corona.io.model.dic.ICoronaDic;
import com.tida_okinawa.corona.io.model.dic.ILabel;
import com.tida_okinawa.corona.io.model.dic.ILabelDic;
import com.tida_okinawa.corona.io.model.dic.ITerm;
import com.tida_okinawa.corona.io.model.dic.IUserDic;
import com.tida_okinawa.corona.io.model.dic.TermClass;
import com.tida_okinawa.corona.io.model.dic.TermPart;
import com.tida_okinawa.corona.ui.editors.DicEditorInput;
/**
* @author kousuke-morishima
*/
public class TermDetailsPage extends PatternDetailsPage {
/**
* @param editor
* 辞書情報
*/
public TermDetailsPage(FormEditor editor) {
super(editor);
}
Text wordText;
private Button wordButton;
private Combo partCombo;
private Combo classCombo;
private Combo quantCombo;
Text labelText;
private Button labelButton;
private Label quantLabel;
private Button morphemeButton;
private static class TermLabelProvider extends 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 static 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();
}
};
@Override
public void createContents(Composite parent) {
parent.setLayout(new FillLayout());
Section section = createSection(parent, "単語の設定", DESCRIPTION_TERM);
Composite client = kit.createComposite(section);
client.setLayout(new GridLayout(4, false));
client.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
Label wordLabel = kit.createLabel(client, "単語 : ");
wordText = kit.createText(client, ""); //$NON-NLS-1$
wordText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
wordText.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
Listener[] ls = wordText.getListeners(SWT.Modify);
for (Listener l : ls) {
wordText.removeListener(SWT.Modify, l);
}
wordText.setText(Erratum.convertZenkakuString(wordText.getText()));
for (Listener l : ls) {
wordText.addListener(SWT.Modify, l);
}
}
});
wordButton = kit.createButton(client, " ... ", SWT.PUSH); //$NON-NLS-1$
wordButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
/*
* 登録済み単語の選択ダイアログを開く
* ユーザ辞書(固有辞書、分野辞書、一般辞書)、Jumanからインポートした一般辞書を表示する
*/
/** #1385 単語選択ダイアログを表示の高速化のためにカスタマイズ */
TermElementListSelectionDialog d = new TermElementListSelectionDialog(editor.getSite().getShell(), new TermLabelProvider());
d.setTitle("単語選択");
d.setMessage("指定する単語を選択してください。");
d.setDicList(createDialogInput(IUserDic.class));
d.setConvertZenkaku(true);
d.setImeMode(SWT.NATIVE);
d.setMultipleSelection(false);
d.open();
if (d.getReturnCode() == Dialog.OK) {
Object result = d.getFirstResult();
wordText.setText(((ITerm) result).getValue());
}
}
});
/**
* @author s.takuro
* #187 構文パターン自動生成(形態素化)
*/
final Composite p = parent;
morphemeButton = kit.createButton(client, Messages.TermDetailsPage_buttonMorpheme, SWT.PUSH);
morphemeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
boolean result;
if ("".equals(wordText.getText())) { //$NON-NLS-1$
MessageBox messageError = new MessageBox(p.getShell(), SWT.ICON_ERROR);
messageError.setText(Messages.TermDetailsPage_messageErrorTitle);
messageError.setMessage(Messages.TermDetailsPage_messageErrorNotTerm);
messageError.open();
return;
} else {
/* 対象のパターンを形態素化 */
result = morphemePattern(wordText.getText());
if (result != true) {
MessageBox messageError = new MessageBox(p.getShell(), SWT.ICON_ERROR);
messageError.setText(Messages.TermDetailsPage_messageErrorTitle);
messageError.setMessage(Messages.TermDetailsPage_messageErrorMorpheme);
messageError.open();
return;
}
}
}
});
Label partLabel = kit.createLabel(client, "品詞 : ");
partCombo = CompositeUtil.createCombo(client, new String[] {});
partCombo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
TermPart[] parts = TermPart.values();
for (TermPart part : parts) {
partCombo.add(part.getName());
}
partCombo.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
/* 選択されたアイテムによって、品詞詳細の内容を変える */
updateWordClassItems();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
});
Label classLabel = kit.createLabel(client, "品詞詳細 : ");
classCombo = CompositeUtil.createCombo(client, new String[] {});
classCombo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
Label labelLabel = kit.createLabel(client, "ラベル : ");
labelText = kit.createText(client, "", SWT.BORDER); //$NON-NLS-1$
labelText.setEnabled(false);
labelText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
labelButton = kit.createButton(client, " ... ", SWT.PUSH); //$NON-NLS-1$
final ITreeContentProvider lConPro = new PrivateLabelDicContentProvider();
final LabelProvider lLPro = new PrivateLabelDicLabelProvider();
labelButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
List<ICoronaDic> input = createDialogInput(ILabelDic.class);
InternalElementTreeSelectionDialog d = new InternalElementTreeSelectionDialog(editor.getSite().getShell(), lLPro, lConPro);
d.setTitle("ラベル選択");
d.setMessage("指定するラベルを選択してください。");
d.setEmptyListMessage("ラベル辞書が登録されていません。");
d.setValidator(new Class<?>[] { ILabel.class });
d.setInput(input);
d.setAllowMultiple(false);
d.open();
if (d.getReturnCode() == Dialog.OK) {
Object result = d.getFirstResult();
if (result != null) {
labelText.setText(((ILabel) result).getName());
} else {
labelText.setText(""); //$NON-NLS-1$
}
}
}
});
CompositeUtil.createBtn(client, SWT.PUSH, "クリア", new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
labelText.setText(""); //$NON-NLS-1$
}
});
/* 数量子 */
quantLabel = kit.createLabel(client, "数量子 : ");
quantCombo = CompositeUtil.createCombo(client, new String[] {});
quantCombo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
QuantifierType[] quants = QuantifierType.values();
for (QuantifierType quant : quants) {
quantCombo.add(quant.getName());
}
final IInformationControl info = getInformationControl(editor.getSite().getShell(), false, new Point(500, 200));
setHover(info, wordLabel,
"単語は形態素で分節された用語を言います。「動詞」、「助動詞」、「形容詞」は原形を入力してください。原形は「形態素・係り受け結果」から参照することができます。\n 例) 表記='でしょう' 原形='だろう'の場合、'だろう'と入力してください。\n");
setHover(info, partLabel, "品詞は「形態素・係り受け結果」から参照することができます。");
setHover(info, classLabel, "品詞の詳細分類は「形態素・係り受け結果」から参照することができます。");
setHover(info, labelLabel, "ラベルはユーザ用語辞書でラベル付与した単語にマッチします。");
setHover(info, quantLabel,
"数量子は「ミス(を)した」、「ミス(は)した」、「ミス()した」のように1単語の差異を簡略化する機能です。この場合(を)と(は)は「助詞」なので品詞を「助詞」にして数量子を「0..1」にします。 数量子は、「連続」パターンの子の場合にのみ使用できます。");
setDirtyCheckListenerTo(wordText, SWT.Modify);
setDirtyCheckListenerTo(partCombo, SWT.Selection);
setDirtyCheckListenerTo(classCombo, SWT.Selection);
setDirtyCheckListenerTo(labelText, SWT.Modify);
setDirtyCheckListenerTo(quantCombo, SWT.Selection);
section.setClient(client);
}
List<ICoronaDic> createDialogInput(Class<? extends ICoronaDic> clazz) {
List<ICoronaDic> input = new ArrayList<ICoronaDic>();
IUIDictionary uiDic = ((DicEditorInput) editor.getEditorInput()).getUIDictionary();
if (uiDic != null) {
ICoronaDics parentObject = CoronaModel.INSTANCE.getLibrary(uiDic).getObject();
if (parentObject instanceof ICoronaProject) {
/* 共通辞書のパターン辞書を開いている */
input.addAll(parentObject.getDictionarys(clazz));
} else if (parentObject instanceof ICoronaProduct) {
/* ターゲット下のパターン辞書を開いている */
ICoronaProject coronaProject = CoronaModel.INSTANCE.getProject(uiDic).getObject();
input.addAll(coronaProject.getDictionarys(clazz));
input.addAll(parentObject.getDictionarys(clazz));
} else {
throw new IllegalStateException("プロジェクトデータを取得できませんでした");
}
} else {
input.addAll(IoActivator.getService().getDictionarys(clazz));
}
return input;
}
@Override
protected void doSave() {
commit();
}
@Override
protected void commit() {
/* 誤記補正(文字の全角化)もやる */
term.setWord(Erratum.convertZenkakuString(wordText.getText()));
TermPart part = TermPart.valueOfName(partCombo.getText());
term.setPart(part);
TermClass termClass = TermClass.valueOf(classCombo.getText(), part);
term.setWordClass(termClass);
term.setLabel(labelText.getText());
QuantifierType quant = QuantifierType.valueOfName(quantCombo.getText());
term.setQuant(quant);
}
@Override
public void setFocus() {
wordText.setFocus();
}
private Term term;
@Override
protected void selectionChanged(IFormPart part, Object selectedObject) {
term = (Term) selectedObject;
wordText.setText(term.getWord());
TermPart termPart = term.getPart();
if (term.getPart() == null) {
termPart = TermPart.NONE;
}
partCombo.setText(termPart.getName());
/* SelectionChangedイベントが起きないから、強制的に内容を変更させる */
updateWordClassItems();
TermClass wordClass = term.getWordClass();
if (wordClass == null) {
wordClass = TermClass.NONE;
}
classCombo.setText(wordClass.getName());
String label = term.getLabel();
if (label == null) {
label = ""; //$NON-NLS-1$
}
labelText.setText(label);
QuantifierType termQuant = term.getQuant();
if (term.getQuant() == null) {
termQuant = QuantifierType.QUANT_NONE;
}
quantCombo.setText(termQuant.getName());
/* Sequenceの子である時だけ、このオブジェクトを表示する */
PatternContainer p = term.getParent();
if (p instanceof Sequence) {
quantCombo.setVisible(true);
quantLabel.setVisible(true);
} else {
quantCombo.setVisible(false);
quantLabel.setVisible(false);
}
}
void updateWordClassItems() {
classCombo.removeAll();
TermPart part = TermPart.valueOfName(partCombo.getText());
if (part == null)
part = TermPart.NONE;
List<TermClass> classes = TermClass.values(part.getIntValue());
if (classes != null) {
for (TermClass tClass : classes) {
classCombo.add(tClass.getName());
}
}
}
/**
* @author s.takuro
* #187 構文パターン自動生成(形態素化)
*/
final char NL_CODE = '\n';
/**
* Treeで選択中のパターンを形態素化
*
* @param text
* 形態素化する文字列
* @return 処理結果
*/
public boolean morphemePattern(String text) {
/* 形態素化の結果を取得 */
boolean result = false;
List<String> input = new ArrayList<String>(1);
List<SyntaxStructure> ssList = new ArrayList<SyntaxStructure>(100);
input.add(text);
CorrectionStringList correctionList = new CorrectionStringList();
try {
String jumanResult = correctionList.exec(input).get(0);
String[] jumanResults = jumanResult.split(",");
for (int i = 0; i < jumanResults.length; i++) {
/* 環境依存文字を含む結果を除去 */
String[] jumanElement = jumanResults[i].split(" ");
if (jumanElement[0].indexOf("?") == -1) {
/* 形態素化 */
SyntaxStructure ss = new SyntaxStructure(jumanResults[i]);
if (ss.size() != 0) {
ssList.add(ss);
}
}
}
} catch (InvocationTargetException e) {
e.printStackTrace();
return result;
} catch (InterruptedException e) {
e.printStackTrace();
return result;
}
if (ssList.size() > 0) {
result = morphemeElements(ssList, term);
}
return result;
}
/**
* 選択中の項目を形態素化した要素に置き換える
*
* @param ssList
* 形態素リスト
* @param pattern
* 登録先パターン
* @return true:成功、false:失敗
*/
private boolean morphemeElements(List<SyntaxStructure> ssList, Pattern pattern) {
if (pattern == null || pattern.getParent() == null) {
return false;
}
PatternContainer parent = pattern.getParent();
/* 元の位置を保持するために挿入位置を取得 */
int index = parent.getChildren().indexOf(pattern);
/* 親と削除対象の要素の関連を除去 */
parent.removeChild(pattern);
pattern.setParent(null);
/* 単語が2つより少ない場合はSequence下に作成しない。また、Sequence下にSequenceは作成不可 */
if (ssList.size() < 2 || parent instanceof Sequence) {
createTerm(ssList, parent, index);
} else {
PatternContainer sequence = new Sequence(parent);
/* "一文"に設定 */
((Sequence) sequence).setScope(SearchScopeType.SEARCH_SENTENCE);
createTerm(ssList, sequence, -1);
/* 親と追加対象の要素を紐づけ */
parent.addChild(index, sequence);
}
return true;
}
/**
* 単語の生成
*
* @param ssList
* 形態素リスト
* @param parent
* 親パターン
* @param index
* 単語を生成する位置(-1の場合は設定しない)
*/
@SuppressWarnings("static-method")
private void createTerm(List<SyntaxStructure> ssList, PatternContainer parent, int index) {
for (SyntaxStructure ss : ssList) {
Term term = new Term(parent);
MorphemeElement morphemeElement = ss.getMorphemeElemsnts().get(0);
term.setWord(morphemeElement.getGenkei());
term.setPart(TermPart.valueOfName(morphemeElement.getHinshi()));
term.setWordClass(TermClass.valueOfName(morphemeElement.getHinshiSaibunrui()));
if (index != -1) {
parent.addChild(index++, term);
} else {
parent.addChild(term);
}
}
}
}