/* This file is part of the Joshua Machine Translation System.
*
* Joshua is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package joshua.ui.alignment;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
import joshua.corpus.Corpus;
import joshua.corpus.alignment.Alignments;
/**
* Presents a visual display of an alignment grid for one aligned
* sentence.
*
* @author Lane Schwartz
*/
public class GridPanel extends JPanel {
/** Logger for this class. */
private static final Logger logger =
Logger.getLogger(GridPanel.class.getName());
/** Source side of an aligned parallel corpus. */
private final Corpus sourceCorpus;
/** Target side of an aligned parallel corpus. */
private final Corpus targetCorpus;
/** Alignment data for an aligned parallel corpus. */
private final Alignments alignments;
private Dimension preferredSize;
private int numSentences;
private int sentenceNumber;
private int numSourceWords;
private int numTargetWords;
/**
* Represents the breadth and height of a cell when displayed
* on screen.
*/
private int screenScaleFactor = 25;
/**
* Represents the breadth and height of a cell when printed.
*/
private int printerScaleFactor = 25;
// private final PrefixTree prefixTree;
/**
* Constructs a panel to display an aligned sentence pair.
*
* @param sourceCorpus Source corpus
* @param targetCorpus Target corpus
* @param alignments Sentence alignments for the parallel corpus
* @param sentenceNumber Index of the sentence to display (0-based index)
*/
public GridPanel(Corpus sourceCorpus, Corpus targetCorpus, Alignments alignments, int sentenceNumber) {
this.sourceCorpus = sourceCorpus;
this.targetCorpus = targetCorpus;
this.alignments = alignments;
this.numSentences = alignments.size();
// this.prefixTree = prefixTree;
// prefixTree.setPrintStream(System.out);
this.setSentenceNumber(sentenceNumber);
}
/**
* Sets the aligned sentence to be displayed by this
* component.
*
* @param sentenceNumber Index of the sentence to display
*/
public void setSentenceNumber(int sentenceNumber) {
this.sentenceNumber = sentenceNumber;
this.numSourceWords =
sourceCorpus.getSentenceEndPosition(sentenceNumber) -
sourceCorpus.getSentencePosition(sentenceNumber);
this.numTargetWords =
targetCorpus.getSentenceEndPosition(sentenceNumber) -
targetCorpus.getSentencePosition(sentenceNumber);
int preferredWidth = numTargetWords*screenScaleFactor;
int preferredHeight = numSourceWords*screenScaleFactor;
preferredSize = new Dimension(preferredWidth, preferredHeight);
String[] sourceWords = this.getSourceWords();
int[] sourceIDs = new int[sourceWords.length];
for (int i=0, n=sourceIDs.length; i<n; i++) {
sourceIDs[i] = sourceCorpus.getVocabulary().getID(sourceWords[i]);
}
// prefixTree.add(sourceIDs);
}
/* See Javadoc for javax.swing.JComponent#getPreferredSize */
@Override
public Dimension getPreferredSize() {
return preferredSize;
}
/* See Javadoc for javax.swing.JComponent#getMinimumSize */
@Override
public Dimension getMinimumSize() {
return preferredSize;
}
public int getScreenScaleFactor() {
return this.screenScaleFactor;
}
public int getPrinterScaleFactor() {
return this.printerScaleFactor;
}
/* See Javadoc for javax.swing.JComponent#paintComponent(Graphics) */
@Override
protected void paintComponent(Graphics graphics) {
paintSomething(graphics, screenScaleFactor);
}
/* See Javadoc for javax.swing.JComponent#printComponent(Graphics) */
@Override
protected void printComponent(Graphics graphics) {
this.paintSomething(graphics, printerScaleFactor);
}
protected void paintSomething(Graphics graphics, int scaleFactor) {
// Dimension d = preferredSize;
int sentenceNumber = this.sentenceNumber;
int width = numTargetWords*scaleFactor;
int height = numSourceWords*scaleFactor;
Graphics2D g = (Graphics2D) graphics;
// {
// g.setColor(Color.GREEN);
// g.fillRect(0, 0, this.getWidth(), this.getHeight());
// }
g.setBackground(Color.WHITE);
g.setColor(Color.WHITE);
//
g.fillRect(0, 0, width, height);
if (sentenceNumber < numSentences) {
g.setColor(Color.BLACK);
int widthStep = scaleFactor; //d.width / numTargetWords;
int heightStep = scaleFactor; //d.height / numSourceWords;
if (logger.isLoggable(Level.FINER)) {
// logger.finer("widthStep = " + numTargetWords + "/" + d.width + " = "+ widthStep);
// logger.finer("heightStep = " + numSourceWords + "/" + d.height + " = "+ heightStep);
logger.finer("widthStep = " + numTargetWords + "/" + width + " = "+ widthStep);
logger.finer("heightStep = " + numSourceWords + "/" + height + " = "+ heightStep);
}
int minX = 0;
int minY = 0;
// Draw vertical grid lines
// for (int x=minX, maxX=d.width, maxY=d.height; x<=maxX; x+=widthStep) {
for (int x=minX, maxX=width, maxY=height; x<=maxX; x+=widthStep) {
g.drawLine(x, minY, x, maxY);
}
// Draw horizontal grid lines
// for (int y=minY, maxX=d.width, maxY=d.height; y<=maxY; y+=heightStep) {
for (int y=minY, maxX=width, maxY=height; y<=maxY; y+=heightStep) {
g.drawLine(minX, y, maxX, y);
}
int sourceSentenceStart = sourceCorpus.getSentencePosition(sentenceNumber);
int targetSentenceStart = targetCorpus.getSentencePosition(sentenceNumber);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Source sentence " + sentenceNumber + " starts at " + sourceSentenceStart);
logger.fine("Target sentence " + sentenceNumber + " starts at " + targetSentenceStart);
}
// Draw aligned points
for (int sourceSentenceIndex=0, sourceCorpusIndex=sourceSentenceStart+sourceSentenceIndex; sourceSentenceIndex<numSourceWords; sourceSentenceIndex++, sourceCorpusIndex++) {
int y = sourceSentenceIndex * heightStep;
int[] targetPoints = alignments.getAlignedTargetIndices(sourceCorpusIndex);
if (targetPoints != null) {
for (int targetCorpusIndex : targetPoints) {
if (logger.isLoggable(Level.FINER)) logger.finer("Alignment point in corpus at " + sourceCorpusIndex + "-" + targetCorpusIndex);
int targetSentenceIndex = targetCorpusIndex - targetSentenceStart;
int x = targetSentenceIndex * widthStep;
g.fillRect(x, y, widthStep, heightStep);
if (logger.isLoggable(Level.FINEST)) logger.finest("Filling rectangle for " + sourceSentenceIndex + "-" + targetSentenceIndex);
}
}
}
}
}
public String[] getSourceWords() {
int sentenceNumber = this.sentenceNumber;
if (logger.isLoggable(Level.FINE)) logger.fine("Getting source words for sentence " + sentenceNumber);
String[] words = new String[numSourceWords];
int sentenceStart = sourceCorpus.getSentencePosition(sentenceNumber);
for (int sourceIndex=0; sourceIndex<numSourceWords; sourceIndex++) {
int token = sourceCorpus.getWordID(sentenceStart + sourceIndex);
words[sourceIndex] = sourceCorpus.getVocabulary().getTerminal(token);
}
return words;
}
public String[] getTargetWords() {
int sentenceNumber = this.sentenceNumber;
if (logger.isLoggable(Level.FINE)) logger.fine("Getting target words for sentence " + sentenceNumber);
String[] words = new String[numTargetWords];
int sentenceStart = targetCorpus.getSentencePosition(sentenceNumber);
for (int targetIndex=0; targetIndex<numTargetWords; targetIndex++) {
int token = targetCorpus.getWordID(sentenceStart + targetIndex);
words[targetIndex] = targetCorpus.getVocabulary().getTerminal(token);
}
return words;
}
int getSentenceNumber() {
return sentenceNumber;
}
int getNumSentences() {
return numSentences;
}
}