/*
* Copyright (C) 2013-2015, VistaTEC or third-party contributors as indicated
* by the @author tags or express copyright attribution statements applied by
* the authors. All third-party contributions are distributed under license by
* VistaTEC.
*
* This file is part of Ocelot.
*
* Ocelot 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 3 of the License, or
* (at your option) any later version.
*
* Ocelot 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 program. If not, write to:
*
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301
* USA
*
* Also, see the full LGPL text here: <http://www.gnu.org/copyleft/lesser.html>
*/
package com.vistatec.ocelot.segment.view;
import static com.vistatec.ocelot.SegmentViewColumn.Original;
import static com.vistatec.ocelot.SegmentViewColumn.SegNum;
import static com.vistatec.ocelot.SegmentViewColumn.Source;
import static com.vistatec.ocelot.SegmentViewColumn.Target;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.print.PrinterException;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;
import javax.print.PrintService;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableRowSorter;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import com.vistatec.ocelot.ContextMenu;
import com.vistatec.ocelot.OcelotApp;
import com.vistatec.ocelot.SegmentViewColumn;
import com.vistatec.ocelot.TextContextMenu;
import com.vistatec.ocelot.config.ConfigTransferService.TransferException;
import com.vistatec.ocelot.config.LqiConfigService;
import com.vistatec.ocelot.events.HighlightEvent;
import com.vistatec.ocelot.events.ItsSelectionEvent;
import com.vistatec.ocelot.events.LQIModificationEvent;
import com.vistatec.ocelot.events.LQISelectionEvent;
import com.vistatec.ocelot.events.OcelotEditingEvent;
import com.vistatec.ocelot.events.OpenFileEvent;
import com.vistatec.ocelot.events.RefreshSegmentView;
import com.vistatec.ocelot.events.ReplaceDoneEvent;
import com.vistatec.ocelot.events.ReplaceEvent;
import com.vistatec.ocelot.events.SegmentEditEvent;
import com.vistatec.ocelot.events.SegmentNoteUpdatedEvent;
import com.vistatec.ocelot.events.SegmentSelectionEvent;
import com.vistatec.ocelot.events.SegmentTargetEnterEvent;
import com.vistatec.ocelot.events.SegmentTargetExitEvent;
import com.vistatec.ocelot.events.SegmentTargetResetEvent;
import com.vistatec.ocelot.events.SegmentTargetUpdateEvent;
import com.vistatec.ocelot.events.SegmentTargetUpdateFromMatchEvent;
import com.vistatec.ocelot.events.api.OcelotEventQueue;
import com.vistatec.ocelot.events.api.OcelotEventQueueListener;
import com.vistatec.ocelot.findrep.FindResult;
import com.vistatec.ocelot.its.model.ITSMetadata;
import com.vistatec.ocelot.lqi.model.LQIGrid;
import com.vistatec.ocelot.rules.DataCategoryFlag;
import com.vistatec.ocelot.rules.DataCategoryFlagRenderer;
import com.vistatec.ocelot.rules.NullITSMetadata;
import com.vistatec.ocelot.rules.RuleConfiguration;
import com.vistatec.ocelot.rules.RuleListener;
import com.vistatec.ocelot.rules.SegmentSelector;
import com.vistatec.ocelot.rules.StateQualifier;
import com.vistatec.ocelot.segment.model.BaseSegmentVariant;
import com.vistatec.ocelot.segment.model.HighlightData;
import com.vistatec.ocelot.segment.model.OcelotSegment;
import com.vistatec.ocelot.segment.model.SegmentVariant;
import com.vistatec.ocelot.segment.model.TextAtom;
import com.vistatec.ocelot.segment.model.okapi.FragmentVariant;
import com.vistatec.ocelot.segment.model.okapi.Note;
import com.vistatec.ocelot.segment.model.okapi.Notes;
import com.vistatec.ocelot.xliff.XLIFFDocument;
import net.sf.okapi.common.LocaleId;
/**
* Table view containing the source and target segments extracted from the
* opened file. Indicates attached LTS metadata as flags.
*/
public class SegmentView extends JScrollPane implements RuleListener,
OcelotEventQueueListener {
private static final long serialVersionUID = 1L;
private static Logger LOG = LoggerFactory.getLogger(SegmentView.class);
private static final String TAG_VALIDATION_ERROR_MESSAGE = "This segment's tags are in an "
+ "inconsistent state and can't be saved. Do you want to discard your work, or keep editing?";
private static final String TAG_VALIDATION_ERROR_TITLE = "Tag Error";
private static final String TAG_VALIDATION_BUTTON_CONTINUE = "Continue";
private static final String TAG_VALIDATION_BUTTON_DISCARD = "Discard";
protected SegmentTableModel segmentTableModel;
protected SegmentViewTable sourceTargetTable;
private TableColumnModel tableColumnModel;
protected TableRowSorter<SegmentTableModel> sort;
private boolean enabledTargetDiff = true;
private OcelotApp ocelotApp;
protected RuleConfiguration ruleConfig;
private final OcelotEventQueue eventQueue;
private boolean targetChangedFromMatch;
private LQIGrid lqiGrid;
private XLIFFDocument xliff;
private boolean isSourceBidi = false;
private boolean isTargetBidi = false;
private int editingRow = -1;
private List<Integer> highlightedSegments;
private BaseSegmentVariant currHLVariant;
/**
* Table implementation that recalculates row heights when doLayout() is
* called. To try to minimize redraw time, we avoid recalculating the whole
* table unless recalculateAllRowHeights() has been called since the last
* call to doLayout().
*/
class SegmentViewTable extends JTable {
private static final long serialVersionUID = 1L;
private boolean requireFullRecalc = false;
SegmentViewTable(AbstractTableModel model) {
super(model);
}
@Override
public void doLayout() {
long start = System.currentTimeMillis();
// The call to super will trigger any necessary recalculation of
// margin sizes. We do this first to avoid rendering and then
// immediately re-rendering with the updated column sizes (which
// produces a noticeable UI flicker.)
super.doLayout();
int updatedRowCount = 0;
for (int row = 0; row < getRowCount(); row++) {
if (requireFullRecalc || editingRow == row) {
updateRowHeight(row, getIntercellSpacing().height);
updatedRowCount++;
}
}
requireFullRecalc = false;
LOG.trace("doLayout() took {} ms for {} rows", (System.currentTimeMillis() - start), updatedRowCount);
}
// Dirty the whole layout
public void recalculateAllRowHeights() {
this.requireFullRecalc = true;
}
@Override
public void columnMoved(TableColumnModelEvent e) {
// Unilaterally cancel editing here; see SegmentEditor.stopCellEditing()
if (isEditing()) {
getCellEditor().cancelCellEditing();
}
super.columnMoved(e);
}
@Override
public void columnMarginChanged(ChangeEvent e) {
// Unilaterally cancel editing here; see SegmentEditor.stopCellEditing()
if (isEditing()) {
getCellEditor().cancelCellEditing();
}
super.columnMarginChanged(e);
}
@Override
public boolean print(PrintMode printMode, MessageFormat headerFormat, MessageFormat footerFormat,
boolean showPrintDialog, PrintRequestAttributeSet attr, boolean interactive, PrintService service)
throws PrinterException, HeadlessException {
// Unilaterally cancel editing here; see SegmentEditor.stopCellEditing()
if (isEditing()) {
getCellEditor().cancelCellEditing();
}
return super.print(printMode, headerFormat, footerFormat, showPrintDialog, attr, interactive, service);
}
}
@Inject
public SegmentView(OcelotEventQueue eventQueue,
SegmentTableModel segmentTableModel, RuleConfiguration ruleConfig,
OcelotApp ocelotApp, LqiConfigService lqiService) throws IOException, InstantiationException,
InstantiationException, IllegalAccessException, TransferException {
this.eventQueue = eventQueue;
this.segmentTableModel = segmentTableModel;
this.ruleConfig = ruleConfig;
this.ruleConfig.addRuleListener(this);
this.lqiGrid = lqiService.readLQIConfig();
this.ocelotApp = ocelotApp;
UIManager.put("Table.focusCellHighlightBorder",
BorderFactory.createLineBorder(Color.BLUE, 2));
initializeTable();
eventQueue.registerListener(this);
this.highlightedSegments = new ArrayList<Integer>();
}
@Subscribe
public void openFile(OpenFileEvent e) {
isSourceBidi = LocaleId.isBidirectional(e.getDocument().getSrcLocale());
isTargetBidi = LocaleId.isBidirectional(e.getDocument().getTgtLocale());
xliff = e.getDocument();
}
@Subscribe
public void highlightStrings(HighlightEvent e) {
clearHighlightedSegments();
List<FindResult> highlightResults = e.getHighlightDataList();
if (highlightResults != null) {
FindResult hr = null;
int currSegmentIdx = -1;
for (int i = 0; i < highlightResults.size(); i++) {
hr = highlightResults.get(i);
if (hr.getSegmentIndex() < segmentTableModel.getRowCount()) {
OcelotSegment segment = segmentTableModel.getSegment(hr
.getSegmentIndex());
BaseSegmentVariant variant = null;
if (hr.isTargetScope()) {
variant = (BaseSegmentVariant) segment.getTarget();
} else {
variant = (BaseSegmentVariant) segment.getSource();
}
if (variant != null) {
HighlightData hlData = new HighlightData(
hr.getAtomIndex(), new int[] {
hr.getStringStartIndex(),
hr.getStringEndIndex() });
variant.addHighlightData(hlData);
if (i == e.getCurrResultIndex()) {
variant.setCurrentHighlightedIndex(variant
.getHighlightDataList().indexOf(hlData));
currHLVariant = variant;
currSegmentIdx = hr.getSegmentIndex();
}
highlightedSegments.add(hr.getSegmentIndex());
updateTableRow(hr.getSegmentIndex());
}
}
}
sourceTargetTable.scrollRectToVisible(sourceTargetTable
.getCellRect(currSegmentIdx, 0, false));
}
}
private void clearHighlightedSegments() {
if (!highlightedSegments.isEmpty()) {
OcelotSegment hlSegment = null;
for (int segIndex : highlightedSegments) {
if (segIndex < segmentTableModel.getRowCount()) {
hlSegment = segmentTableModel.getSegment(segIndex);
((BaseSegmentVariant) hlSegment.getSource())
.clearHighlightedText();
if (hlSegment.getTarget() != null) {
((BaseSegmentVariant) hlSegment.getTarget())
.clearHighlightedText();
}
updateTableRow(segIndex);
}
}
highlightedSegments.clear();
}
}
@Subscribe
public void replace(ReplaceEvent e) {
if (e.getAction() == ReplaceEvent.REPLACE && currHLVariant != null) {
replaceTarget(e.getNewString(), e.getSegmentIndex());
} else if (e.getAction() == ReplaceEvent.REPLACE_ALL) {
OcelotSegment segment = null;
int replacedOccNum = 0;
for (int segIdx = 0; segIdx < segmentTableModel.getRowCount(); segIdx++) {
segment = segmentTableModel.getSegment(segIdx);
replacedOccNum += replaceAllTarget(
(BaseSegmentVariant) segment.getTarget(),
e.getNewString(), segIdx);
}
eventQueue.post(new ReplaceDoneEvent(replacedOccNum));
}
}
private int replaceAllTarget(BaseSegmentVariant target, String newString,
int segIdx) {
SegmentVariant updatedTarget = target.createCopy();
int replacedOccNum = 0;
if(target.getHighlightDataList() != null){
for(HighlightData hd: target.getHighlightDataList()){
int startOffset = 0;
for (int i = 0; i < hd.getAtomIndex(); i++) {
startOffset += target.getAtoms().get(i).getLength();
}
startOffset += hd.getHighlightIndices()[0];
int oldStringLength = hd.getHighlightIndices()[1]
- hd.getHighlightIndices()[0];
updatedTarget.modifyChars(startOffset, oldStringLength,
newString);
replacedOccNum++;
}
target.clearHighlightedText();
eventQueue.post(new SegmentTargetUpdateEvent(xliff,
segmentTableModel.getSegment(segIdx),
updatedTarget));
updateTableRow(segIdx);
}
return replacedOccNum;
}
private void replaceTarget(String newString, int segmentIndex) {
SegmentVariant updatedTarget = currHLVariant.createCopy();
if (currHLVariant.getHighlightDataList() != null
&& currHLVariant.getCurrentHighlightedIndex() > -1
&& currHLVariant.getCurrentHighlightedIndex() < currHLVariant
.getHighlightDataList().size()) {
if(updatedTarget instanceof FragmentVariant){
replaceTargetTextXliff20((FragmentVariant)updatedTarget, newString);
} else {
replaceTargetTextXliff12((BaseSegmentVariant)updatedTarget, newString);
}
eventQueue.post(new SegmentTargetUpdateEvent(xliff,
segmentTableModel.getSegment(segmentIndex),
updatedTarget));
updateTableRow(segmentIndex);
}
}
private void replaceTargetTextXliff12(BaseSegmentVariant target, String replaceString) {
HighlightData hd = currHLVariant.getHighlightDataList().get(
currHLVariant.getCurrentHighlightedIndex());
int startOffset = 0;
for (int i = 0; i < hd.getAtomIndex(); i++) {
startOffset += currHLVariant.getAtoms().get(i).getLength();
}
startOffset += hd.getHighlightIndices()[0];
int oldStringLength = hd.getHighlightIndices()[1]
- hd.getHighlightIndices()[0];
target.modifyChars(startOffset, oldStringLength,
replaceString);
currHLVariant.replaced(replaceString);
target.setHighlightDataList(currHLVariant.getHighlightDataList());
}
private void replaceTargetTextXliff20(FragmentVariant target, String replaceString ) {
HighlightData hd = currHLVariant.getHighlightDataList().get(
currHLVariant.getCurrentHighlightedIndex());
if(target.getAtoms() != null && hd.getAtomIndex()<target.getAtoms().size()){
if(target.getAtoms().get(hd.getAtomIndex()) instanceof TextAtom ) {
TextAtom txtAtom = (TextAtom)target.getAtoms().get(hd.getAtomIndex());
String newText = txtAtom.getData().substring(0, hd.getHighlightIndices()[0]) +
replaceString + txtAtom.getData().substring(hd.getHighlightIndices()[1]);
TextAtom newTextAtom = new TextAtom(newText);
target.getAtoms().set(hd.getAtomIndex(), newTextAtom);
}
}
target.setHighlightDataList(currHLVariant.getHighlightDataList());
target.setCurrentHighlightedIndex(currHLVariant.getCurrentHighlightedIndex());
target.replaced(replaceString);
}
public final void initializeTable() {
sourceTargetTable = new SegmentViewTable(segmentTableModel);
sourceTargetTable.getTableHeader().setReorderingAllowed(false);
ListSelectionListener selectSegmentHandler = new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent lse) {
selectedSegment();
}
};
ListSelectionModel tableSelectionModel = sourceTargetTable
.getSelectionModel();
tableSelectionModel
.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
tableSelectionModel.addListSelectionListener(selectSegmentHandler);
sourceTargetTable.setDefaultRenderer(Integer.class,
new IntegerRenderer());
sourceTargetTable.setDefaultRenderer(ITSMetadata.class,
new ITSMetadataRenderer());
sourceTargetTable.setDefaultRenderer(SegmentVariant.class,
new SegmentTextRenderer());
sourceTargetTable.setDefaultRenderer(String.class,
new NotesCellRenderer());
// Install our custom edit behavior: hitting 'enter' anywhere inside the
// row will open the target cell for editing. Double-clicking will also
// work, but this is handled separately (see
// SegmentEditor.isCellEditable()).
InputMap inputMap = sourceTargetTable
.getInputMap(JComponent.WHEN_FOCUSED);
ActionMap actionMap = sourceTargetTable.getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
"myStartEditing");
final Action startEditAction = actionMap.get("startEditing");
actionMap.put("myStartEditing", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
sourceTargetTable.changeSelection(
sourceTargetTable.getSelectedRow(),
segmentTableModel.getSegmentTargetColumnIndex(), false,
false);
startEditAction.actionPerformed(e);
// Ensure the editor is focused. XXX It's wrapped in a
// scrollpane, so we need
// to drill down to get the SegmentTextCell instance.
JScrollPane scrollPane = (JScrollPane) sourceTargetTable
.getEditorComponent();
if (scrollPane != null) {
scrollPane.getViewport().getView().requestFocus();
}
}
});
tableColumnModel = sourceTargetTable.getColumnModel();
configureColumns();
tableColumnModel.getSelectionModel().addListSelectionListener(
selectSegmentHandler);
tableColumnModel.addColumnModelListener(new TableColumnModelListener() {
@Override
public void columnAdded(TableColumnModelEvent tcme) {
// Set the preferred column width when we add a column back
// (eg, when we're changing column setup)
int index = tcme.getToIndex();
configureColumn(segmentTableModel.getColumn(index), index);
}
@Override
public void columnRemoved(TableColumnModelEvent tcme) {
}
@Override
public void columnMoved(TableColumnModelEvent tcme) {
}
@Override
public void columnMarginChanged(ChangeEvent ce) {
sourceTargetTable.recalculateAllRowHeights();
}
@Override
public void columnSelectionChanged(ListSelectionEvent lse) {
}
});
addFilters();
sourceTargetTable.addMouseListener(new SegmentPopupMenuListener());
setViewportView(sourceTargetTable);
addEditingListeners(sourceTargetTable);
}
private void configureColumns() {
for (SegmentViewColumn col : SegmentViewColumn.values()) {
configureColumn(col, segmentTableModel.getIndexForColumn(col));
}
}
private void configureColumn(SegmentViewColumn col, int index) {
if (!segmentTableModel.isColumnEnabled(col)) {
return;
}
switch (col) {
case SegNum:
tableColumnModel.getColumn(index).setMinWidth(20);
tableColumnModel.getColumn(index).setPreferredWidth(25);
tableColumnModel.getColumn(index).setMaxWidth(50);
break;
case Source:
final TableColumn sourceCol = tableColumnModel.getColumn(index);
sourceCol.setCellEditor(new ReadOnlySegmentEditor());
sourceCol.setCellRenderer(new SegmentTextFontRenderer(
sourceTargetTable.getFont()));
break;
case Target:
final TableColumn targetCol = tableColumnModel.getColumn(index);
targetCol.setCellRenderer(new SegmentTextFontRenderer(
sourceTargetTable.getFont()));
targetCol.setCellEditor(new SegmentEditor(sourceTargetTable
.getFont()));
break;
case Original:
final TableColumn targetOriginalCol = tableColumnModel
.getColumn(index);
targetOriginalCol.setCellRenderer(new SegmentTextFontRenderer(
sourceTargetTable.getFont()));
break;
case EditDistance:
tableColumnModel.getColumn(index).setMinWidth(25);
tableColumnModel.getColumn(index).setPreferredWidth(25);
tableColumnModel.getColumn(index).setMaxWidth(40);
break;
case Notes:
tableColumnModel.getColumn(index).setCellEditor(
new NotesCellEditor());
break;
case Flag1:
case Flag2:
case Flag3:
case Flag4:
case Flag5:
tableColumnModel.getColumn(index).setMinWidth(15);
tableColumnModel.getColumn(index).setPreferredWidth(20);
tableColumnModel.getColumn(index).setMaxWidth(20);
break;
default:
break;
}
}
private void addEditingListeners(Component component) {
final FocusListener focusListener = new FocusListener() {
@Override
public void focusLost(FocusEvent e) {
eventQueue.post(new OcelotEditingEvent(
OcelotEditingEvent.Type.STOP_EDITING));
}
@Override
public void focusGained(FocusEvent e) {
eventQueue.post(new OcelotEditingEvent(
OcelotEditingEvent.Type.START_EDITING));
}
};
final ContainerListener containerListener = new ContainerListener() {
@Override
public void componentRemoved(ContainerEvent e) {
}
@Override
public void componentAdded(ContainerEvent e) {
addListenersToComponents(e.getChild(), focusListener, this);
}
};
addListenersToComponents(component, focusListener, containerListener);
}
private void addListenersToComponents(Component component,
FocusListener focusListener, ContainerListener containerListener) {
if (component instanceof JTextComponent) {
component.addFocusListener(focusListener);
} else if (component instanceof Container) {
Container container = (Container) component;
container.addContainerListener(containerListener);
if (container.getComponentCount() > 0) {
for (int i = 0; i < container.getComponentCount(); i++) {
addListenersToComponents(container.getComponent(i),
focusListener, containerListener);
}
}
}
}
public SegmentTableModel getTableModel() {
return segmentTableModel;
}
public void clearTable() {
sourceTargetTable.clearSelection();
sourceTargetTable.setRowSorter(null);
setViewportView(null);
}
public void reloadTable() {
clearTable();
setViewportView(sourceTargetTable);
addFilters();
segmentTableModel.fireTableDataChanged();
final TableColumn currColumn = tableColumnModel
.getColumn(segmentTableModel.getSegmentNumColumnIndex());
Font font = sourceTargetTable.getFont();
if (currColumn.getCellRenderer() != null
&& currColumn.getCellRenderer() instanceof SegmentTextFontRenderer) {
font = ((SegmentTextFontRenderer) currColumn.getCellRenderer())
.getFont();
}
// Adjust the segment number column width
currColumn.setPreferredWidth(this.getFontMetrics(font).stringWidth(
" " + segmentTableModel.getRowCount()));
sourceTargetTable.recalculateAllRowHeights();
}
private void updateTableRow(int row) {
segmentTableModel.fireTableRowsUpdated(row, row);
updateRowHeight(row, sourceTargetTable.getIntercellSpacing().height);
}
public void requestFocusTable() {
sourceTargetTable.requestFocus();
}
public void addFilters() {
sort = new TableRowSorter<SegmentTableModel>(segmentTableModel);
sourceTargetTable.setRowSorter(sort);
sort.setRowFilter(new RowFilter<SegmentTableModel, Integer>() {
private SegmentSelector selector = new SegmentSelector(ruleConfig);
@Override
public boolean include(
RowFilter.Entry<? extends SegmentTableModel, ? extends Integer> entry) {
return selector.matches(entry.getModel().getSegment(
entry.getIdentifier()));
}
});
}
private void updateRowHeight(int row, int intercellHeight) {
if (row == editingRow) {
adjustEditorInitialSize(row);
return;
}
int modelRow = sort.convertRowIndexToModel(row);
FontMetrics font = sourceTargetTable.getFontMetrics(sourceTargetTable
.getFont());
int rowHeight = font.getHeight();
rowHeight = getColumnHeight(SegNum, row, "1", rowHeight,
sourceTargetTable.getFont());
OcelotSegment segment = segmentTableModel.getSegment(modelRow);
Font sourceFont = getFontForColumn(Source);
rowHeight = getColumnHeight(Source, row, segment.getSource()
.getDisplayText(), rowHeight, sourceFont);
Font targetFont = getFontForColumn(Target);
rowHeight = getColumnHeight(Target, row, segment.getTarget()
.getDisplayText(), rowHeight, targetFont);
rowHeight = getColumnHeight(Original, row,
getOriginalTargetText(modelRow), rowHeight, targetFont);
sourceTargetTable.setRowHeight(row, rowHeight + intercellHeight);
}
private void adjustEditorInitialSize(int row) {
final FontMetrics defFontMetrics = sourceTargetTable
.getFontMetrics(sourceTargetTable.getFont());
final int defFontHeight = defFontMetrics.getHeight();
final FontMetrics sourceFontMetrics = sourceTargetTable
.getFontMetrics(((SegmentTextFontRenderer) sourceTargetTable
.getColumnModel()
.getColumn(
segmentTableModel.getSegmentSourceColumnIndex())
.getCellRenderer()).getFont());
final int sourceFontHeight = sourceFontMetrics.getHeight();
final FontMetrics targetFontMetrics = sourceTargetTable
.getFontMetrics(((SegmentTextFontRenderer) sourceTargetTable
.getColumnModel()
.getColumn(
segmentTableModel.getSegmentTargetColumnIndex())
.getCellRenderer()).getFont());
final int targetFontHeight = targetFontMetrics.getHeight();
int height = Math.max(defFontHeight, sourceFontHeight);
height = Math.max(height, targetFontHeight);
sourceTargetTable.setRowHeight(row, height * 10);
}
private Font getFontForColumn(SegmentViewColumn col) {
return ((SegmentTextFontRenderer) tableColumnModel.getColumn(
col.ordinal()).getCellRenderer()).getFont();
}
// TODO: move elsewhere
private String getOriginalTargetText(int modelRow) {
if (enabledTargetDiff) {
List<String> textDiff = segmentTableModel.getSegment(modelRow)
.getTargetDiff();
StringBuilder displayText = new StringBuilder();
for (int i = 0; i < textDiff.size(); i += 2) {
displayText.append(textDiff.get(i));
}
return displayText.toString();
} else {
return segmentTableModel.getSegment(modelRow).getOriginalTarget()
.getDisplayText();
}
}
private int getColumnHeight(SegmentViewColumn colData, int viewRow,
String text, int previousHeight, Font font) {
if (!segmentTableModel.isColumnEnabled(colData)) {
return previousHeight;
}
SegmentTextCell segmentCell = SegmentTextCell.createDummyCell();
segmentCell.setBorder(UIManager
.getBorder("Table.focusCellHighlightBorder"));
segmentCell.setFont(font);
int col = segmentTableModel.getIndexForColumn(colData);
int width = sourceTargetTable.getColumnModel().getColumn(col)
.getWidth();
segmentCell.setText(text);
// Need to set width to force text area to calculate a pref height
segmentCell.setSize(new Dimension(width, sourceTargetTable
.getRowHeight(viewRow)));
return Math.max(previousHeight, segmentCell.getPreferredSize().height);
}
public OcelotSegment getSelectedSegment() {
OcelotSegment selectedSeg = null;
if (sourceTargetTable.getSelectedRow() >= 0) {
selectedSeg = segmentTableModel
.getSegment(sort.convertRowIndexToModel(sourceTargetTable
.getSelectedRow()));
}
return selectedSeg;
}
public void selectedSegment() {
OcelotSegment seg = getSelectedSegment();
if (seg != null) {
int colIndex = sourceTargetTable.getSelectedColumn();
SegmentViewColumn col = segmentTableModel.getColumn(colIndex);
if (col != null && col.isFlagColumn()) {
ITSMetadata its = ruleConfig.getTopDataCategory(seg,
col.getFlagIndex());
if (its != null) {
eventQueue.post(new ItsSelectionEvent(its));
}
}
}
postSegmentSelection(seg);
}
public boolean getEnabledTargetDiff() {
return enabledTargetDiff;
}
public void setEnabledTargetDiff(boolean enabled) {
this.enabledTargetDiff = enabled;
reloadTable();
}
@Subscribe
public void updateSegmentView(RefreshSegmentView event) {
try {
synchronized (segmentTableModel) {
if (segmentTableModel.getRowCount() > 0) {
segmentTableModel.fireTableRowsUpdated(
event.getSegmentNumber() - 1,
event.getSegmentNumber() - 1);
} else {
segmentTableModel.fireTableDataChanged();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Font getSourceFont() {
Font font = null;
if (sourceTargetTable != null) {
font = ((SegmentTextFontRenderer) sourceTargetTable
.getColumnModel()
.getColumn(segmentTableModel.getSegmentSourceColumnIndex())
.getCellRenderer()).getFont();
}
return font;
}
public Font getTargetFont() {
Font font = null;
if (sourceTargetTable != null) {
font = ((SegmentTextFontRenderer) sourceTargetTable
.getColumnModel()
.getColumn(segmentTableModel.getSegmentTargetColumnIndex())
.getCellRenderer()).getFont();
}
return font;
}
public void setSourceFont(final Font font) {
if (sourceTargetTable != null) {
sourceTargetTable.recalculateAllRowHeights();
((SegmentTextFontRenderer) sourceTargetTable.getColumnModel()
.getColumn(segmentTableModel.getSegmentSourceColumnIndex())
.getCellRenderer()).setFont(font);
sourceTargetTable.revalidate();
sourceTargetTable.repaint();
segmentTableModel.fireTableDataChanged();
}
}
public void setTargetFont(final Font font) {
if (sourceTargetTable != null) {
sourceTargetTable.recalculateAllRowHeights();
((SegmentTextFontRenderer) sourceTargetTable.getColumnModel()
.getColumn(segmentTableModel.getSegmentTargetColumnIndex())
.getCellRenderer()).setFont(font);
((SegmentTextFontRenderer) sourceTargetTable
.getColumnModel()
.getColumn(
segmentTableModel
.getSegmentTargetOriginalColumnIndex())
.getCellRenderer()).setFont(font);
((SegmentEditor) sourceTargetTable.getColumnModel()
.getColumn(segmentTableModel.getSegmentTargetColumnIndex())
.getCellEditor()).setFont(font);
segmentTableModel.fireTableDataChanged();
}
}
@Subscribe
public void notifyModifiedLQI(LQIModificationEvent event) {
int selectedRow = sourceTargetTable.getSelectedRow();
updateTableRow(selectedRow);
sourceTargetTable.setRowSelectionInterval(selectedRow, selectedRow);
eventQueue.post(new LQISelectionEvent(event.getLQI()));
postSegmentSelection(event.getSegment());
requestFocusTable();
}
@Subscribe
public void notifySegmentTargetReset(SegmentTargetResetEvent event) {
segmentTableModel.fireTableDataChanged();
sourceTargetTable.recalculateAllRowHeights();
}
@Subscribe
public synchronized void handleTargetUpdatedFromMatch(
SegmentTargetUpdateFromMatchEvent event) {
// int selRow = sourceTargetTable.getSelectedRow();
// // segmentTableModel.fireTableRowsUpdated(selRow, selRow);
// // updateRowHeights();
// updateTableRow(selRow);
// sourceTargetTable.requestFocusInWindow();
targetChangedFromMatch = true;
}
@Subscribe
public synchronized void handleTargetUpdatedFromMatch(SegmentEditEvent event) {
if (targetChangedFromMatch) {
int selRow = sourceTargetTable.getSelectedRow();
// segmentTableModel.fireTableRowsUpdated(selRow, selRow);
// updateRowHeights();
updateTableRow(selRow);
sourceTargetTable.requestFocusInWindow();
targetChangedFromMatch = false;
}
}
@Subscribe
public void notifySegmentEdit(SegmentEditEvent event) {
int selRow = sourceTargetTable.getSelectedRow();
updateTableRow(selRow);
sourceTargetTable.requestFocusInWindow();
}
@Override
public void enabledRule(String ruleLabel, boolean enabled) {
reloadTable();
}
@Override
public void setFilterMode(RuleConfiguration.FilterMode mode) {
reloadTable();
}
@Override
public void setStateQualifierMode(RuleConfiguration.StateQualifierMode mode) {
reloadTable();
}
private void postSegmentSelection(OcelotSegment seg) {
if (seg != null) {
eventQueue.post(new SegmentSelectionEvent(xliff, seg));
}
}
/**
* TableCellRenderer for source/target text in the SegmentTableView.
*/
public class SegmentTextRenderer implements TableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable jtable, Object o,
boolean isSelected, boolean hasFocus, int row, int col) {
SegmentTextCell renderTextPane = SegmentTextCell.createCell();
if (segmentTableModel.getRowCount() > row) {
OcelotSegment seg = segmentTableModel.getSegment(sort
.convertRowIndexToModel(row));
SegmentVariant v = null;
if (segmentTableModel.getSegmentSourceColumnIndex() == col) {
v = seg.getSource();
renderTextPane.setBidi(isSourceBidi);
} else if (segmentTableModel.getSegmentTargetColumnIndex() == col) {
v = seg.getTarget();
renderTextPane.setBidi(isTargetBidi);
} else if (segmentTableModel
.getSegmentTargetOriginalColumnIndex() == col) {
renderTextPane.setBidi(isTargetBidi);
if (!enabledTargetDiff) {
v = seg.getOriginalTarget();
}
}
if (v != null) {
renderTextPane.setVariant(row, v, false);
} else {
renderTextPane.setTargetDiff(seg.getTargetDiff());
}
Color background = isSelected ? seg.isEditable() ? jtable
.getSelectionBackground() : Color.LIGHT_GRAY : jtable
.getBackground();
Color foreground = seg.isEditable() ? isSelected ? jtable
.getSelectionForeground() : jtable.getForeground()
: Color.GRAY;
renderTextPane.setBackground(background);
renderTextPane.setForeground(foreground);
renderTextPane.setBorder(hasFocus ? UIManager
.getBorder("Table.focusCellHighlightBorder") : jtable
.getBorder());
}
return renderTextPane;
}
}
public class SegmentTextFontRenderer extends SegmentTextRenderer {
private Font font;
public SegmentTextFontRenderer(final Font font) {
this.font = font;
}
@Override
public Component getTableCellRendererComponent(JTable jtable, Object o,
boolean isSelected, boolean hasFocus, int row, int col) {
Component component = super.getTableCellRendererComponent(jtable,
o, isSelected, hasFocus, row, col);
component.setFont(font);
return component;
}
public Font getFont() {
return font;
}
public void setFont(final Font font) {
this.font = font;
}
}
static class ITSMetadataRenderer extends DataCategoryFlagRenderer {
private static final long serialVersionUID = 1L;
public ITSMetadataRenderer() {
super();
}
@Override
public Component getTableCellRendererComponent(JTable jtable,
Object obj, boolean isSelected, boolean hasFocus, int row,
int col) {
ITSMetadata its = (obj != null) ? ((ITSMetadata) obj)
: NullITSMetadata.getInstance();
DataCategoryFlag flag = its.getFlag();
flag = (flag != null) ? flag : DataCategoryFlag.getDefault();
return super.getTableCellRendererComponent(jtable, flag,
isSelected, hasFocus, row, col);
}
}
public class IntegerRenderer extends JLabel implements TableCellRenderer {
private static final long serialVersionUID = 1L;
private final Color enrichedColor = new Color(5, 169, 71);
private final Color sentToFremeColor = Color.red;
public IntegerRenderer() {
setOpaque(true);
}
private Color getSegmentColor(OcelotSegment seg) {
StateQualifier sq = seg.getStateQualifier();
if (sq != null) {
Color sqColor = ruleConfig.getStateQualifierColor(sq);
if (sqColor == null) {
LOG.debug("No UI color for state-qualifier '{}'", sq);
}
return sqColor;
}
return null;
}
@Override
public Component getTableCellRendererComponent(JTable jtable,
Object obj, boolean isSelected, boolean hasFocus, int row,
int col) {
Integer segNum = (Integer) obj;
OcelotSegment seg = segmentTableModel.getSegment(sort
.convertRowIndexToModel(row));
Color background = getSegmentColor(seg);
background = background != null ? background : isSelected ? seg
.isEditable() ? jtable.getSelectionBackground()
: Color.LIGHT_GRAY : jtable.getBackground();
Color foreground = seg.isEditable() ? isSelected ? jtable
.getSelectionForeground() : jtable.getForeground()
: Color.GRAY;
if (seg.getSource() instanceof BaseSegmentVariant
&& ((BaseSegmentVariant) seg.getSource()).isEnriched()
&& (((BaseSegmentVariant) seg.getTarget()).isEnriched()
|| seg.getTarget().getDisplayText() == null || seg
.getTarget().getDisplayText().isEmpty())) {
foreground = enrichedColor;
} else if (seg.getSource() instanceof BaseSegmentVariant
&& ((BaseSegmentVariant) seg.getSource()).isSentToFreme()
&& (((BaseSegmentVariant) seg.getTarget()).isSentToFreme())) {
foreground = sentToFremeColor;
}
setHorizontalAlignment(JLabel.LEFT);
setVerticalAlignment(JLabel.TOP);
setBackground(background);
setForeground(foreground);
setBorder(hasFocus ? UIManager
.getBorder("Table.focusCellHighlightBorder") : jtable
.getBorder());
if (segNum != null) {
setText(segNum.toString());
}
return this;
}
}
public class ReadOnlySegmentEditor extends AbstractCellEditor implements
TableCellEditor {
private static final long serialVersionUID = -591391978033697647L;
private SegmentTextCell editorComponent;
@Override
public Object getCellEditorValue() {
return editorComponent.getVariant();
}
@Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
OcelotSegment seg = segmentTableModel.getSegment(sort
.convertRowIndexToModel(row));
editorComponent = SegmentTextCell.createCell(row, seg.getSource()
.createCopy(), false, isSourceBidi);
editorComponent.setBackground(table.getSelectionBackground());
editorComponent.setSelectionColor(Color.BLUE);
editorComponent.setSelectedTextColor(Color.WHITE);
editorComponent.setEditable(false);
editorComponent.getCaret().setVisible(true);
editorComponent.addMouseListener(new TextPopupMenuListener());
editorComponent.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "finish");
editorComponent.getActionMap().put("finish", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
ToolTipManager.sharedInstance().registerComponent(editorComponent);
return editorComponent;
}
@Override
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
// Override normal behavior and only allow double-click to edit
// the
// cell
return ((MouseEvent) anEvent).getClickCount() >= 2;
}
if (anEvent instanceof ActionEvent) {
return true;
}
return false;
}
@Override
public void removeCellEditorListener(CellEditorListener l) {
super.removeCellEditorListener(l);
ToolTipManager.sharedInstance().unregisterComponent(editorComponent);
}
}
public class SegmentEditor extends AbstractCellEditor implements
TableCellEditor {
private static final long serialVersionUID = 1L;
protected SegmentTextCell editorComponent;
protected SegmentCellEditorListener editListener;
private Font font;
public SegmentEditor(final Font font) {
editListener = new SegmentCellEditorListener();
addCellEditorListener(editListener);
this.font = font;
}
@Override
public Component getTableCellEditorComponent(JTable jtable,
Object value, boolean isSelected, int row, int col) {
OcelotSegment seg = segmentTableModel.getSegment(sort
.convertRowIndexToModel(row));
if (col == segmentTableModel.getSegmentSourceColumnIndex()) {
editorComponent = SegmentTextCell.createCell(row, seg.getSource()
.createCopy(), false, isSourceBidi);
editorComponent.setEditable(false);
} else if (col == segmentTableModel.getSegmentTargetColumnIndex()) {
editListener
.setBeginEdit(seg, seg.getTarget().getDisplayText());
editorComponent = SegmentTextCell.createCell(row, seg.getTarget()
.createCopy(), false, isTargetBidi);
editorComponent.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "finish");
editorComponent.getActionMap().put("finish",
new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
if (stopCellEditing()) {
fireEditingStopped();
eventQueue.post(new OcelotEditingEvent(OcelotEditingEvent.Type.STOP_EDITING));
}
}
});
editingRow = row;
editorComponent.setFont(font);
editorComponent.prepareEditingUI();
ToolTipManager.sharedInstance().registerComponent(editorComponent);
}
eventQueue.post(new OcelotEditingEvent(
OcelotEditingEvent.Type.START_EDITING));
return new JScrollPane(editorComponent);
}
public void setFont(final Font font) {
this.font = font;
}
@Override
public Object getCellEditorValue() {
return editorComponent.getVariant();
}
@Override
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
// Override normal behavior and only allow double-click to edit
// the
// cell
return ((MouseEvent) anEvent).getClickCount() >= 2;
}
if (anEvent instanceof ActionEvent) {
// I could further restrict this to "startEditing" event,
// but I don't think it's necessary
return true;
}
return false;
}
@Override
public boolean stopCellEditing() {
if (!editorComponent.canStopEditing()) {
// It seems that it's not good to make a blocking call here, as
// e.g. window resize events can make us enter this method
// multiple times and we get multiple dialogs. However there
// seems to be no other way to prompt the user before committing
// or cancelling changes, so instead we work around by
// overriding JTable methods that might call this method to
// first unilaterally cancel editing. See:
// columnMoved(), columnMarginChanged(), print()
int response = JOptionPane.showOptionDialog(SegmentView.this, TAG_VALIDATION_ERROR_MESSAGE,
TAG_VALIDATION_ERROR_TITLE, JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null,
new String[] { TAG_VALIDATION_BUTTON_CONTINUE, TAG_VALIDATION_BUTTON_DISCARD },
TAG_VALIDATION_BUTTON_CONTINUE);
if (response == 1) {
cancelCellEditing();
}
return false;
}
return super.stopCellEditing();
}
@Override
public void removeCellEditorListener(CellEditorListener l) {
// This appears to be the only way for the TableCellEditor to find
// out that editing has ended in the case of the user invoking the
// "cancel" action (by e.g. pressing Esc): JTable.removeEditor() is
// called directly in BasicTableUI.Actions.actionPerformed(). Thus
// we do cleanup here.
super.removeCellEditorListener(l);
editorComponent.closeEditingUI();
ToolTipManager.sharedInstance().unregisterComponent(editorComponent);
}
}
public class SegmentCellEditorListener implements CellEditorListener {
private OcelotSegment seg;
public void setBeginEdit(OcelotSegment seg, String codedText) {
this.seg = seg;
eventQueue.post(new SegmentTargetEnterEvent(xliff, seg));
}
@Override
public void editingStopped(ChangeEvent ce) {
SegmentVariant updatedTarget = ((SegmentEditor) ce.getSource()).editorComponent
.getVariant();
int row = sourceTargetTable.getSelectedRow();
eventQueue.post(new SegmentTargetExitEvent(xliff, seg));
eventQueue.post(new SegmentTargetUpdateEvent(xliff, seg,
updatedTarget));
postSegmentSelection(seg);
editingRow = -1;
updateTableRow(row);
// Restore row selection
sourceTargetTable.setRowSelectionInterval(row, row);
}
@Override
public void editingCanceled(ChangeEvent ce) {
// Cancel not supported.
}
}
public class NotesCellRenderer implements TableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
JTextArea txtArea = new JTextArea();
if (value != null && value instanceof Notes) {
Note ocelotNote = ((Notes) value).getOcelotNote();
if (ocelotNote != null) {
txtArea.setText(ocelotNote.getContent());
}
}
if (isSelected) {
txtArea.setBackground(table.getSelectionBackground());
} else {
txtArea.setBackground(table.getBackground());
}
txtArea.setWrapStyleWord(true);
txtArea.setLineWrap(true);
JScrollPane pane = new JScrollPane(txtArea);
pane.setBorder(BorderFactory.createEmptyBorder());
pane.setSize(new Dimension(table.getColumnModel().getColumn(column)
.getWidth(), table.getRowHeight(row)));
pane.setBorder(hasFocus ? UIManager
.getBorder("Table.focusCellHighlightBorder") : table
.getBorder());
return pane;
}
}
public class NotesCellEditor extends AbstractCellEditor implements
TableCellEditor {
private static final long serialVersionUID = 1L;
private JTextArea txtArea;
private NotesCellEditorListener listener;
public NotesCellEditor() {
listener = new NotesCellEditorListener();
addCellEditorListener(listener);
}
@Override
public Object getCellEditorValue() {
return txtArea.getText();
}
@Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
OcelotSegment seg = segmentTableModel.getSegment(sort
.convertRowIndexToModel(row));
listener.beginEditSegment(seg);
txtArea = new JTextArea();
if (value != null && value instanceof Notes) {
Note ocelotNote = ((Notes) value).getOcelotNote();
if (ocelotNote != null) {
txtArea.setText(ocelotNote.getContent());
}
}
if (isSelected) {
txtArea.setBackground(table.getSelectionBackground());
} else {
txtArea.setBackground(table.getBackground());
}
txtArea.setWrapStyleWord(true);
txtArea.setLineWrap(true);
txtArea.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
stopCellEditing();
}
}
});
JScrollPane scrollPane = new JScrollPane(txtArea);
scrollPane.setPreferredSize(new Dimension(table.getColumnModel()
.getColumn(column).getWidth(), table.getRowHeight(row)));
scrollPane.setBorder(BorderFactory.createEmptyBorder());
eventQueue.post(new OcelotEditingEvent(
OcelotEditingEvent.Type.START_EDITING));
return scrollPane;
}
@Override
public boolean isCellEditable(EventObject e) {
return e instanceof MouseEvent
&& ((MouseEvent) e).getButton() == MouseEvent.BUTTON1
&& ((MouseEvent) e).getClickCount() >= 2;
}
@Override
public boolean stopCellEditing() {
eventQueue.post(new OcelotEditingEvent(
OcelotEditingEvent.Type.STOP_EDITING));
return super.stopCellEditing();
}
}
public class NotesCellEditorListener implements CellEditorListener {
private OcelotSegment seg;
public void beginEditSegment(OcelotSegment seg) {
this.seg = seg;
}
@Override
public void editingStopped(ChangeEvent ce) {
int row = sourceTargetTable.getSelectedRow();
String noteContent = ((NotesCellEditor) ce.getSource()).txtArea
.getText();
eventQueue
.post(new SegmentNoteUpdatedEvent(xliff, seg, noteContent));
updateTableRow(row);
// Restore row selection
sourceTargetTable.setRowSelectionInterval(row, row);
// SegmentVariant updatedTarget = ((SegmentEditor)
// ce.getSource()).editorComponent
// .getVariant();
// int row = sourceTargetTable.getSelectedRow();
// eventQueue.post(new SegmentTargetExitEvent(seg));
// eventQueue.post(new SegmentTargetUpdateEvent(seg,
// updatedTarget));
// postSegmentSelection(seg);
// updateTableRow(row);
// // Restore row selection
// sourceTargetTable.setRowSelectionInterval(row, row);
}
@Override
public void editingCanceled(ChangeEvent ce) {
// Cancel not supported.
}
}
public class TextPopupMenuListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
if (e.isPopupTrigger()) {
displayTextPopupMenu(e);
}
}
@Override
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) {
displayTextPopupMenu(e);
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
displayTextPopupMenu(e);
}
}
private void displayTextPopupMenu(MouseEvent e) {
SegmentTextCell sourceCell = (SegmentTextCell) e.getSource();
if (sourceCell.getSelectedText() != null) {
try {
Rectangle markRect = sourceCell.modelToView(sourceCell
.getCaret().getMark());
Rectangle dotRect = sourceCell.modelToView(sourceCell
.getCaret().getDot());
Rectangle rect = markRect.union(dotRect);
if (rect.contains(e.getPoint())) {
TextContextMenu ctxMenu = new TextContextMenu(
eventQueue, sourceCell.getSelectedText());
ctxMenu.show(e.getComponent(), e.getX(), e.getY());
}
} catch (BadLocationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
public class SegmentPopupMenuListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) {
displayContextMenu(e);
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
displayContextMenu(e);
}
}
public void displayContextMenu(MouseEvent e) {
OcelotSegment seg = null;
BaseSegmentVariant variant = null;
int r = sourceTargetTable.rowAtPoint(e.getPoint());
if (r >= 0 && r < sourceTargetTable.getRowCount()) {
sourceTargetTable.setRowSelectionInterval(r, r);
seg = segmentTableModel.getSegment(r);
}
int c = sourceTargetTable.columnAtPoint(e.getPoint());
boolean target = false;
if (c == segmentTableModel.getIndexForColumn(Source)) {
variant = (BaseSegmentVariant) seg.getSource();
} else if (c == segmentTableModel.getIndexForColumn(Target)) {
variant = (BaseSegmentVariant) seg.getTarget();
target = true;
}
if (seg != null) {
ContextMenu menu = new ContextMenu(xliff, seg, variant, null,
eventQueue, lqiGrid);
List<JMenuItem> pluginsItems = ocelotApp
.getSegmentContexPluginMenues(seg, variant, target);
if (pluginsItems != null) {
for (JMenuItem item : pluginsItems) {
menu.add(item);
}
}
menu.show(e.getComponent(), e.getX(), e.getY());
}
}
}
public JTable getTable() {
return sourceTargetTable;
}
}