package jav.gui.token.display;
import jav.correctionBackend.Candidate;
import jav.correctionBackend.Token;
import jav.gui.events.MessageCenter;
import jav.gui.events.tokenNavigation.TokenNavigationEvent;
import jav.gui.events.tokenNavigation.TokenNavigationType;
import jav.gui.main.AbstractTokenVisualization;
import jav.gui.main.MainController;
import jav.gui.token.behaviour.TokenVisualizationMode;
import jav.gui.token.edit.ComboBoxEntry;
import jav.gui.token.edit.ComboBoxEntryType;
import jav.gui.token.edit.MyEditCustomComboBox;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.*;
import java.util.Iterator;
import java.util.LinkedHashSet;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
*Copyright (c) 2012, IMPACT working group at the Centrum für Informations- und Sprachverarbeitung, University of Munich.
*All rights reserved.
*Redistribution and use in source and binary forms, with or without
*modification, are permitted provided that the following conditions are met:
*Redistributions of source code must retain the above copyright
*notice, this list of conditions and the following disclaimer.
*Redistributions in binary form must reproduce the above copyright
*notice, this list of conditions and the following disclaimer in the
*documentation and/or other materials provided with the distribution.
*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
*IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
*TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
*PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
*HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
*SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
*LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
*OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This file is part of the ocr-postcorrection tool developed
* by the IMPACT working group at the Centrum für Informations- und Sprachverarbeitung, University of Munich.
* For further information and contacts visit http://ocr.cis.uni-muenchen.de/
*
* @author thorsten (thorsten.vobl@googlemail.com)
*
* abstract class for building visual representations of tokens
* all methods that are independent from implementation are here, all abstract methods
* have to be implemented
*
*/
public abstract class TokenVisualization extends AbstractTokenVisualization {
int tokenID;
Token temptoken = null;
boolean isEditing = false;
TokenTextLabel tokenTextLabel;
MyEditCustomComboBox box;
TokenVisualizationMode tvm = null;
boolean hasImage;
TokenVisualization instance = this;
boolean isSelected;
boolean isMultiSelected;
KeyListenerImpl keyListener = new KeyListenerImpl();
String delete = java.util.ResourceBundle.getBundle("jav/gui/token/display/Bundle").getString("delete");
String setcorrect = java.util.ResourceBundle.getBundle("jav/gui/token/display/Bundle").getString("setcorr");
String merger = java.util.ResourceBundle.getBundle("jav/gui/token/display/Bundle").getString("mergeR");
String focusInMain = java.util.ResourceBundle.getBundle("jav/gui/token/display/Bundle").getString("jumpto");
FocusListener fl;
public void setFontSize(int fontSize) {
Font f = tokenTextLabel.getFont();
float nS = (float) fontSize;
Font deriveFont = f.deriveFont(nS);
tokenTextLabel.setFont(deriveFont);
}
public Point getCentroid() {
if (this.isSpace()) {
return new Point(this.getX(), this.getY());
} else {
return new Point((this.getX() + (this.getWidth() / 2)), (this.getY() + (this.getHeight() / 2)));
}
}
public abstract void calculateSizeNormMode();
public abstract void calculateSizeEditMode();
public boolean isNewline() {
if (tokenTextLabel.getText().equals("¶")) {
return true;
} else {
return false;
}
}
public boolean isSpace() {
if (tokenTextLabel.getText().equals(" ")) {
return true;
} else {
return false;
}
}
public boolean hasImage() {
return hasImage;
}
public void setTokenID( int i ) {
this.tokenID = i;
}
public int getTokenID() {
return this.tokenID;
}
public void zoomFont(int newSize) {
if (!tokenTextLabel.isSpace()) {
Font f = tokenTextLabel.getFont();
float nS = (float) newSize;
Font deriveFont = f.deriveFont(nS);
tokenTextLabel.setFont(deriveFont);
tokenTextLabel.revalidate();
if (this.hasImage) {
this.calculateSizeNormMode();
this.revalidate();
}
}
}
public void setMode(TokenVisualizationMode n) {
this.tvm = n;
this.tokenTextLabel.setForeground(tvm.getUnselectedColor());
this.addMouseListener(tvm.getMouseListener());
this.addKeyListener(tvm.getKeyListener());
tvm.setTokenVisualizationStyle(this);
this.calculateSizeNormMode();
this.revalidate();
}
public void setMode(TokenVisualizationMode n, Token t) {
this.tvm = n;
this.tokenTextLabel.setForeground(tvm.getUnselectedColor());
this.addMouseListener(tvm.getMouseListener());
this.addKeyListener(tvm.getKeyListener());
tvm.setTokenVisualizationStyle(this, t);
this.calculateSizeNormMode();
this.revalidate();
}
public void deactivate() {
if (tvm != null) {
this.removeMouseListener(tvm.getMouseListener());
this.removeKeyListener(keyListener);
this.setBackground(Color.lightGray);
}
}
public void activate() {
if (tvm != null) {
this.addMouseListener(tvm.getMouseListener());
this.addKeyListener(keyListener);
this.setBackground(Color.white);
}
}
public void setSelected(boolean b) {
this.isSelected = b;
this.grabFocus();
tvm.setTokenVisualizationStyle(this);
}
public void setMultiSelected(boolean b) {
this.isMultiSelected = b;
if (!this.isSpace()) {
tvm.setTokenVisualizationStyle(this);
}
}
public boolean isSelected() {
return this.isSelected;
}
public boolean isMultiSelected() {
return this.isMultiSelected;
}
public TokenTextLabel getTokenTextLabel() {
return this.tokenTextLabel;
}
public String getTokenTextLabelText() {
return tokenTextLabel.getText();
}
public void update( String newtext ) {
tokenTextLabel.setText( newtext );
tvm.setTokenVisualizationStyle(instance);
this.calculateSizeNormMode();
this.revalidate();
}
public void update( String newtext, boolean corrected ) {
tokenTextLabel.setText( newtext );
this.setCorrected(corrected);
this.calculateSizeNormMode();
this.revalidate();
}
public void setCorrected( boolean b ) {
tvm.setCorrected(instance, b);
}
public void startTokenEditing() {
this.isEditing = true;
LinkedHashSet<ComboBoxEntry> cands = new LinkedHashSet<>();
temptoken = MainController.findInstance().getDocument().getTokenByID( tokenID );
cands.add(new ComboBoxEntry(this.getTokenTextLabelText(), ComboBoxEntryType.NORMAL));
Iterator<Candidate> iterator = MainController.findInstance().getDocument().candidateIterator( tokenID );
int maxcands = 5;
while (iterator.hasNext() && maxcands > 1) {
maxcands--;
cands.add(new ComboBoxEntry(iterator.next().getSuggestion(), ComboBoxEntryType.NORMAL));
}
cands.add(new ComboBoxEntry(setcorrect, ComboBoxEntryType.SETCORRECTED));
cands.add(new ComboBoxEntry(delete, ComboBoxEntryType.DELETE));
cands.add(new ComboBoxEntry(merger, ComboBoxEntryType.MERGE));
if(tvm.getClass().getSimpleName().equals("TokenVisualizationConcordanceMode")) {
cands.add(new ComboBoxEntry(focusInMain, ComboBoxEntryType.FOCUS_IN_MAIN));
}
JButton submitButton = new JButton("↵");
submitButton.setFocusable(false);
submitButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
endTokenEditing(box.getEditor().getItem().toString());
}
});
box = new MyEditCustomComboBox(cands, tokenTextLabel.getFont(), new Dimension(tokenTextLabel.getPreferredSize().width,tokenTextLabel.getPreferredSize().height), temptoken.getNumberOfCandidates(), submitButton);
box.setWide(true);
((JPanel) box.getEditor().getEditorComponent()).getComponent(0).addKeyListener(keyListener);
// box.getEditor().getEditorComponent().addKeyListener(keyListener);
fl = new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
if (e.getComponent().getParent().getParent().getClass().getName().equals("jav.gui.token.edit.MyEditCustomComboBox")) {
JComboBox b = (JComboBox) e.getComponent().getParent().getParent();
if( !b.isPopupVisible()) {
b.showPopup();
b.setPopupVisible(true);
b.getEditor().selectAll();
}
}
}
@Override
public void focusLost(FocusEvent e) {
abortTokenEditing();
}
};
((JPanel) box.getEditor().getEditorComponent()).getComponent(0).addFocusListener(fl);
// box.getEditor().getEditorComponent().addFocusListener(fl);
// BoundsPopupMenuListener lis = new BoundsPopupMenuListener( false , true ) {
// @Override
// public void popupMenuCanceled(PopupMenuEvent e) {
// abortTokenEditing();
// }
// };
// box.addPopupMenuListener( lis );
// box.addPopupMenuListener(new PopupMenuListener() {
//
// @Override
// public void popupMenuWillBecomeVisible(PopupMenuEvent pme) {
// JComboBox comboBox = (JComboBox) pme.getSource();
// if (comboBox.getItemCount() == 0) return;
// Object child = comboBox.getAccessibleContext().getAccessibleChild(0);
// }
//
// @Override
// public void popupMenuWillBecomeInvisible(PopupMenuEvent pme) {
// }
//
// @Override
// public void popupMenuCanceled(PopupMenuEvent pme) {
//// abortTokenEditing();
// }
// });
this.remove(tokenTextLabel);
this.add(box);
this.calculateSizeEditMode();
this.repaint();
this.revalidate();
((JTextField)((JPanel) box.getEditor().getEditorComponent()).getComponent(0)).grabFocus();
}
/*
* correct Token with String in editor Textfield
*/
public void endTokenEditing(String editString) {
// TODO check implementation
// boolean b = Pattern.matches("([^ ]+ [^ ]+)*", editString);
// if (b) {
if( editString.contains(" ")) {
MainController.findInstance().splitToken( this.tokenID, editString);
// MainController.findInstance().addToLog(MainController.findInstance().getLastFocusedTCName() + " # split # " + temptoken.getWOCR() + " # " + retval);
} else {
//if (!editString.equals(tokenTextLabel.getText())) {
MainController.findInstance().correctTokenByString( this.tokenID, editString);
// MainController.findInstance().addToLog(MainController.findInstance().getLastFocusedTCName() + " # correct # " + temptoken.getWOCR() + " # " + editString);
// } else {
// abortTokenEditing();
// }
}
// if (editString.contains(" ") && !editString.startsWith(" ") && !editString.endsWith(" ")) {
//// if (editString.matches("\\p{Alnum}.*\\W+.*\\p{Alnum}*")) {
// int retval = this.token.handleSplit(editString);
// MainController.findInstance().addToLog(MainController.findInstance().getLastFocusedTCName()+" # split # "+this.token.getWOCR()+" # "+retval);
// MessageCenter.getInstance().fireTokenStatusEvent(new TokenStatusEvent(this.token, TokenStatusType.SPLIT, retval));
// } else if (editString.contains(" ") && (editString.startsWith(" ") || editString.endsWith(" "))) {
// abortTokenEditing();
// } else {
// MainController.findInstance().correctTokenByString(token, editorf.getText());
// MainController.findInstance().addToLog(MainController.findInstance().getLastFocusedTCName()+ " # correct # "+token.getWOCR()+" # "+editorf.getText());
// }
// this.remove(editorf);
box.getEditor().getEditorComponent().removeFocusListener(fl);
this.remove(box);
this.add(tokenTextLabel);
this.calculateSizeNormMode();
this.repaint();
this.revalidate();
this.grabFocus();
this.isEditing = false;
}
/*
* abort editing, keep original string
*/
public void abortTokenEditing() {
box.getEditor().getEditorComponent().removeFocusListener(fl);
this.remove(box);
this.add(tokenTextLabel);
this.calculateSizeNormMode();
this.repaint();
this.revalidate();
this.grabFocus();
this.isEditing = false;
}
public void processEdit(ComboBoxEntry cbe) {
if (cbe.getType() == ComboBoxEntryType.NORMAL) {
endTokenEditing(box.getEditor().getItem().toString());
} else if (cbe.getType() == ComboBoxEntryType.MERGE) {
abortTokenEditing();
MainController.findInstance().mergeRightward( tokenID );
MainController.findInstance().addToLog(MainController.findInstance().getLastFocusedTCName() + " # merge # " + " # " + temptoken.getWOCR() + " # " + temptoken.getWOCR());
} else if (cbe.getType() == ComboBoxEntryType.SETCORRECTED) {
abortTokenEditing();
if( !temptoken.isCorrected()) {
MainController.findInstance().setCorrected( tokenID, true );
}
instance.revalidate();
MainController.findInstance().addToLog(MainController.findInstance().getLastFocusedTCName() + " # set as corrected # " + temptoken.getWOCR());
// if delete, check if prev and next token are spaces, if the case delete one of them to not produce sequent spaces
} else if (cbe.getType() == ComboBoxEntryType.DELETE) {
abortTokenEditing();
MainController.findInstance().deleteToken( tokenID );
} else if(cbe.getType() == ComboBoxEntryType.FOCUS_IN_MAIN) {
abortTokenEditing();
MessageCenter.getInstance().fireTokenNavigationEvent(new TokenNavigationEvent(this, tokenID, TokenNavigationType.FOCUS_IN_MAIN));
}
}
public boolean isEditing() {
return this.isEditing;
}
private class KeyListenerImpl implements KeyListener {
public KeyListenerImpl() {
}
@Override
public void keyTyped(KeyEvent ke) {
}
@Override
public void keyPressed(KeyEvent ke) {
if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
ComboBoxEntry cbe = (ComboBoxEntry) box.getSelectedItem();
processEdit(cbe);
} else if (ke.getKeyCode() == KeyEvent.VK_ESCAPE) {
abortTokenEditing();
}
}
@Override
public void keyReleased(KeyEvent ke) {
}
}
}