package edu.cmu.minorthird.text.gui; import java.awt.event.ActionEvent; import java.io.File; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JTextPane; import javax.swing.KeyStroke; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.text.AttributeSet; import javax.swing.text.JTextComponent; import javax.swing.text.Keymap; import edu.cmu.minorthird.text.BasicTextBase; import edu.cmu.minorthird.text.MutableTextLabels; import edu.cmu.minorthird.text.Span; import edu.cmu.minorthird.text.SpanDifference; import edu.cmu.minorthird.text.TextLabels; import edu.cmu.minorthird.text.TextLabelsLoader; /** * Tracks what's selected in the documentList of a TextBaseViewer. * * @author William Cohen */ abstract public class ViewerTracker extends JComponent implements ListSelectionListener{ static final long serialVersionUID=20081125L; static protected boolean viewEntireDocument=true; static protected final String DUMMY_ID="***dummy id***"; // links to outside protected StatusMessage statusMsg; protected JList documentList; protected SpanPainter spanPainter; // internal state protected JTextPane editorPane; protected JScrollPane editorHolder; protected SpanDocument editedDoc; protected Span documentSpan; protected TextLabels viewLabels; protected MutableTextLabels editLabels; protected int contextWidth=0; protected File saveAsFile=null; protected JButton upButton,downButton,saveButton; protected JSlider contextWidthSlider; /** * @param viewLabels * a superset of editLabels which may include some additional * read-only information * @param editLabels * the labeling being modified (if there is one) * @param documentList * the document Span being edited is associated with the selected * entry of the documentList. * @param spanPainter * used to repaint documentList elements * @param statusMsg * a JLabel used for status messages. */ public ViewerTracker(TextLabels viewLabels,MutableTextLabels editLabels, JList documentList,SpanPainter spanPainter,StatusMessage statusMsg){ synchronized(documentList){ if(documentList.getModel().getSize()==0){ throw new IllegalArgumentException("can't edit from empty list"); } this.viewLabels=viewLabels; this.editLabels=editLabels; this.documentList=documentList; this.spanPainter=spanPainter; this.statusMsg=statusMsg; this.editorHolder=new JScrollPane(); saveButton=new JButton(new SaveLabelsAction("Save")); upButton=new JButton(new MoveDocumentCursor("Up",-1)); downButton=new JButton(new MoveDocumentCursor("Down",+1)); contextWidthSlider=new ContextWidthSlider(); } } protected Span nullSpan(){ BasicTextBase b=new BasicTextBase(); b.loadDocument(DUMMY_ID,"["+documentList.getModel().getSize()+ " spans being viewed.\n"+" Select one to make it appear here.]"); return b.documentSpanIterator().next(); } /** If set, the viewer will show the entire document a span is in. */ public void setViewEntireDocument(boolean flag){ viewEntireDocument=flag; } /** Activates the 'save' button, and indicates where to save. */ public void setSaveAs(File file){ this.saveAsFile=file; System.out.println("saveAsFile -> "+saveAsFile); saveButton.setEnabled(saveAsFile!=null); } /** change the text labels */ public void updateViewLabels(TextLabels newLabels){ this.viewLabels=newLabels; } /** * implement ListSelectionListener, so can use this to listen to the * documentList. */ @Override public void valueChanged(ListSelectionEvent e){ synchronized(documentList){ Span s=(Span)documentList.getSelectedValue(); if(s!=null) loadSpan(s); else loadSpan(nullSpan()); } } /** Declare how much context to show on either size of the span. */ protected void setContextWidth(int contextWidth){ synchronized(documentList){ this.contextWidth=contextWidth; Span s=(Span)documentList.getSelectedValue(); if(s!=null) loadSpan(s); else loadSpan(nullSpan()); } } protected void loadSpan(Span span){ documentSpan=viewEntireDocument?span.documentSpan():span; editedDoc=new SpanDocument(documentSpan,contextWidth); editorPane=new JTextPane(editedDoc); Keymap keymap=JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP); keymap.addActionForKeyStroke(KeyStroke.getKeyStroke("UP"),upButton .getAction()); keymap.addActionForKeyStroke(KeyStroke.getKeyStroke("control P"),upButton .getAction()); keymap.addActionForKeyStroke(KeyStroke.getKeyStroke("DOWN"),downButton .getAction()); keymap.addActionForKeyStroke(KeyStroke.getKeyStroke("control N"),downButton .getAction()); editorPane.setKeymap(keymap); editorHolder.getViewport().setView(editorPane); editorHolder.repaint(); statusMsg.display("editing "+documentSpan.getDocumentId()+" "+documentSpan); editorPane.requestFocus(); // any subclass-dependent processing loadSpanHook(); } /** Overload this to do something special when a new document is loaded. */ protected void loadSpanHook(){ ; } /** Useful routine */ protected void importDocumentListMarkup(String documentId){ if(!DUMMY_ID.equals(documentSpan.getDocumentId())){ // import all current markup AttributeSet[] colors=new AttributeSet[SpanDifference.MAX_STATUS+1]; colors[SpanDifference.FALSE_POS]=spanPainter.fpColor(); colors[SpanDifference.FALSE_NEG]=spanPainter.fnColor(); colors[SpanDifference.TRUE_POS]=spanPainter.tpColor(); colors[SpanDifference.UNKNOWN_POS]=spanPainter.mpColor(); for(SpanDifference.Looper i=spanPainter.differenceIterator(documentId);i .hasNext();){ Span dspan=i.next(); int status=i.getStatus(); editedDoc.highlight(dspan,colors[status]); } } } protected class SaveLabelsAction extends AbstractAction{ static final long serialVersionUID=20080314L; public SaveLabelsAction(String s){ super(s); } @Override public void actionPerformed(ActionEvent event){ try{ System.out.println("saving to file="+saveAsFile); new TextLabelsLoader().saveTypesAsOps(editLabels,saveAsFile); statusMsg.display("Saved in "+saveAsFile.getName()); }catch(Exception e){ statusMsg.display("Error: "+e); } } } protected class ContextWidthSlider extends JSlider{ static final long serialVersionUID=20080314L; public ContextWidthSlider(){ super(0,10,0); addChangeListener(new ChangeListener(){ @Override public void stateChanged(ChangeEvent e){ ContextWidthSlider slider=(ContextWidthSlider)e.getSource(); if(!slider.getValueIsAdjusting()){ int value=slider.getValue(); setContextWidth(value); } } }); } } /** Move through list of spans */ protected class MoveDocumentCursor extends AbstractAction{ static final long serialVersionUID=20080314L; private int delta; public MoveDocumentCursor(String msg,int delta){ super(msg); this.delta=delta; } @Override public void actionPerformed(ActionEvent event){ synchronized(documentList){ int currentCursor=documentList.getSelectedIndex(); // if nothing's selected, pretend it was the first thing if(currentCursor<0) currentCursor=0; int nextCursor=currentCursor+delta; if(nextCursor<documentList.getModel().getSize()&&nextCursor>=0){ documentList.setSelectedIndex(nextCursor); } } } } }