Package ij.text

Source Code of ij.text.TextPanel

package ij.text;

import java.awt.*;
import java.io.*;
import java.awt.event.*;
import java.util.*;
import java.awt.datatransfer.*;
import ij.*;
import ij.plugin.filter.Analyzer;
import ij.io.SaveDialog;
import ij.measure.ResultsTable;
import ij.util.Tools;
import ij.plugin.frame.Recorder;


/**
This is an unlimited size text panel with tab-delimited,
labeled and resizable columns. It is based on the hGrid
class at
    http://www.lynx.ch/contacts/~/thomasm/Grid/index.html.
*/
public class TextPanel extends Panel implements AdjustmentListener,
  MouseListener, MouseMotionListener, KeyListener,  ClipboardOwner,
  ActionListener, MouseWheelListener, Runnable {

  static final int DOUBLE_CLICK_THRESHOLD = 650;
  // height / width
  int iGridWidth,iGridHeight;
  int iX,iY;
  // data
  String[] sColHead;
  Vector vData;
  int[] iColWidth;
  int iColCount,iRowCount;
  int iRowHeight,iFirstRow;
  // scrolling
  Scrollbar sbHoriz,sbVert;
  int iSbWidth,iSbHeight;
  boolean bDrag;
  int iXDrag,iColDrag;
 
  boolean headings = true;
  String title = "";
  String labels;
  KeyListener keyListener;
  Cursor resizeCursor = new Cursor(Cursor.E_RESIZE_CURSOR);
    Cursor defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR);
  int selStart=-1, selEnd=-1,selOrigin=-1, selLine=-1;
  TextCanvas tc;
  PopupMenu pm;
  boolean columnsManuallyAdjusted;
  long mouseDownTime;
    String filePath;
    ResultsTable rt;
    boolean unsavedLines;

 
  /** Constructs a new TextPanel. */
  public TextPanel() {
    tc = new TextCanvas(this);
    setLayout(new BorderLayout());
    add("Center",tc);
    sbHoriz=new Scrollbar(Scrollbar.HORIZONTAL);
    sbHoriz.addAdjustmentListener(this);
    sbHoriz.setFocusable(false); // prevents scroll bar from blinking on Windows
    add("South", sbHoriz);
    sbVert=new Scrollbar(Scrollbar.VERTICAL);
    sbVert.addAdjustmentListener(this);
    sbVert.setFocusable(false);
    ImageJ ij = IJ.getInstance();
    if (ij!=null) {
      sbHoriz.addKeyListener(ij);
      sbVert.addKeyListener(ij);
    }
    add("East", sbVert);
    addPopupMenu();
  }
 
  /** Constructs a new TextPanel. */
  public TextPanel(String title) {
    this();
    if (title.equals("Results")) {
      pm.addSeparator();
      addPopupItem("Clear Results");
      addPopupItem("Summarize");
      addPopupItem("Distribution...");
      addPopupItem("Set Measurements...");
      addPopupItem("Duplicate...");
    }
  }

  void addPopupMenu() {
    pm=new PopupMenu();
    addPopupItem("Save As...");
    pm.addSeparator();
    addPopupItem("Cut");
    addPopupItem("Copy");
    addPopupItem("Clear");
    addPopupItem("Select All");
    add(pm);
  }
 
  void addPopupItem(String s) {
    MenuItem mi=new MenuItem(s);
    mi.addActionListener(this);
    pm.add(mi);
  }

  /**
  Clears this TextPanel and sets the column headings to
  those in the tab-delimited 'headings' String. Set 'headings'
  to "" to use a single column with no headings.
  */
  public synchronized void setColumnHeadings(String labels) {
    boolean sameLabels = labels.equals(this.labels);
    this.labels = labels;
    if (labels.equals("")) {
      iColCount = 1;
      sColHead=new String[1];
      sColHead[0] = "";
    } else {
      sColHead = Tools.split(labels, "\t");
          iColCount = sColHead.length;
    }
    flush();
    vData=new Vector();
    if (!(iColWidth!=null && iColWidth.length==iColCount && sameLabels && iColCount!=1)) {
      iColWidth=new int[iColCount];
      columnsManuallyAdjusted = false;
    }
    iRowCount=0;
    resetSelection();
    adjustHScroll();
    tc.repaint();
  }
 
  /** Returns the column headings as a tab-delimited string. */
  public String getColumnHeadings() {
    return labels==null?"":labels;
  }
 
  public void setFont(Font font, boolean antialiased) {
    tc.fFont = font;
    tc.iImage = null;
    tc.fMetrics = null;
    tc.antialiased = antialiased;
    iColWidth[0] = 0;
    if (isShowing()) updateDisplay();
  }
 
  /** Adds a single line to the end of this TextPanel. */
  public void appendLine(String data) {
    if (vData==null)
      setColumnHeadings("");
    char[] chars = data.toCharArray();
    vData.addElement(chars);
    iRowCount++;
    if (isShowing()) {
      if (iColCount==1 && tc.fMetrics!=null) {
        iColWidth[0] = Math.max(iColWidth[0], tc.fMetrics.charsWidth(chars,0,chars.length));
        adjustHScroll();
      }
      updateDisplay();
      unsavedLines = true;
    }
  }
 
  /** Adds one or more lines to the end of this TextPanel. */
  public void append(String data) {
    if (data==null) data="null";
    if (vData==null)
      setColumnHeadings("");
    while (true) {
      int p=data.indexOf('\n');
      if (p<0) {
        appendWithoutUpdate(data);
        break;
      }
      appendWithoutUpdate(data.substring(0,p));
      data = data.substring(p+1);
      if (data.equals(""))
        break;
    }
    if (isShowing()) {  // && !(ij.macro.Interpreter.isBatchMode()&&title.equals("Results"))
      updateDisplay();
      unsavedLines = true;
    }
  }
 
  /** Adds a single line to the end of this TextPanel without updating the display. */
  void appendWithoutUpdate(String data) {
    char[] chars = data.toCharArray();
    vData.addElement(chars);
    iRowCount++;
  }

  void updateDisplay() {
    iY=iRowHeight*(iRowCount+1);
    adjustVScroll();
    if (iColCount>1 && iRowCount<=10 && !columnsManuallyAdjusted)
      iColWidth[0] = 0; // forces column width calculation
    tc.repaint();
  }

  String getCell(int column, int row) {
    if (column<0||column>=iColCount||row<0||row>=iRowCount)
      return null;
    return new String(tc.getChars(column, row));
  }

  synchronized void adjustVScroll() {
    if(iRowHeight==0) return;
    Dimension d = tc.getSize();
    int value = iY/iRowHeight;
    int visible = d.height/iRowHeight;
    int maximum = iRowCount+1;
    if (visible<0) visible=0;
    if (visible>maximum) visible=maximum;
    if (value>(maximum-visible)) value=maximum-visible;
    sbVert.setValues(value,visible,0,maximum);
    iY=iRowHeight*value;
  }

  synchronized void adjustHScroll() {
    if(iRowHeight==0) return;
    Dimension d = tc.getSize();
    int w=0;
    for(int i=0;i<iColCount;i++)
      w+=iColWidth[i];
    iGridWidth=w;
    sbHoriz.setValues(iX,d.width,0,iGridWidth);
    iX=sbHoriz.getValue();
  }

  public void adjustmentValueChanged (AdjustmentEvent e) {
    iX=sbHoriz.getValue();
     iY=iRowHeight*sbVert.getValue();
    tc.repaint();
   }
   
  public void mousePressed (MouseEvent e) {
    int x=e.getX(), y=e.getY();
    if (e.isPopupTrigger() || e.isMetaDown())
      pm.show(e.getComponent(),x,y);
     else if (e.isShiftDown())
      extendSelection(x, y);
    else {
       select(x, y);
       handleDoubleClick();
     }
  }
 
  void handleDoubleClick() {
    if (selStart<0 || selStart!=selEnd || iColCount!=1) return;
    boolean doubleClick = System.currentTimeMillis()-mouseDownTime<=DOUBLE_CLICK_THRESHOLD;
    mouseDownTime = System.currentTimeMillis();
    if (doubleClick) {
      char[] chars = (char[])(vData.elementAt(selStart));
      String s = new String(chars);
      int index = s.indexOf(": ");
      if (index>-1 && !s.endsWith(": "))
        s = s.substring(index+2); // remove sequence number added by ListFilesRecursively
      if (s.indexOf(File.separator)!=-1 ||  s.indexOf(".")!=-1) {
        filePath = s;
        Thread thread = new Thread(this, "Open");
        thread.setPriority(thread.getPriority()-1);
        thread.start();
      }
    }
  }
 
    /** For better performance, open double-clicked files on
      separate thread instead of on event dispatch thread. */
    public void run() {
        if (filePath!=null) IJ.open(filePath);
    }

  public void mouseExited (MouseEvent e) {
    if(bDrag) {
      setCursor(defaultCursor);
      bDrag=false;
    }
  }
 
  public void mouseMoved (MouseEvent e) {
    int x=e.getX(), y=e.getY();
    if(y<=iRowHeight) {
      int xb=x;
      x=x+iX-iGridWidth;
      int i=iColCount-1;
      for(;i>=0;i--) {
        if(x>-7 && x<7) break;
        x+=iColWidth[i];       
      }
      if(i>=0) {
        if(!bDrag) {
          setCursor(resizeCursor);
          bDrag=true;
          iXDrag=xb-iColWidth[i];
          iColDrag=i;
        }
        return;
      }
    }
    if(bDrag) {
      setCursor(defaultCursor);
      bDrag=false;
    }
  }
 
  public void mouseDragged (MouseEvent e) {
    if (e.isPopupTrigger() || e.isMetaDown())
      return;
    int x=e.getX(), y=e.getY();
    if(bDrag && x<tc.getSize().width) {
      int w=x-iXDrag;
      if(w<0) w=0;
      iColWidth[iColDrag]=w;
      columnsManuallyAdjusted = true;
      adjustHScroll();
      tc.repaint();
    } else {
      extendSelection(x, y);
    }
  }

   public void mouseReleased (MouseEvent e) {}
  public void mouseClicked (MouseEvent e) {}
  public void mouseEntered (MouseEvent e) {}
 
  public void mouseWheelMoved(MouseWheelEvent event) {
    synchronized(this) {
      int rot = event.getWheelRotation();
      sbVert.setValue(sbVert.getValue()+rot);
      iY=iRowHeight*sbVert.getValue();
      tc.repaint();
    }
  }

  /** Unused keyPressed and keyTyped events will be passed to 'listener'.*/
  public void addKeyListener(KeyListener listener) {
    keyListener = listener;
  }
 
  public void keyPressed(KeyEvent e) {
    //boolean cutCopyOK = (e.isControlDown()||e.isMetaDown())
    //  && selStart!=-1 && selEnd!=-1;
    //if (cutCopyOK && e.getKeyCode()==KeyEvent.VK_C)
    //  copySelection();
    //else if (cutCopyOK && e.getKeyCode()==KeyEvent.VK_X)
    //  {if (copySelection()>0) clearSelection();}
    //else if (cutCopyOK && e.getKeyCode()==KeyEvent.VK_A)
    //  selectAll();
    //else if (keyListener!=null)
    //  keyListener.keyPressed(e);
    int key = e.getKeyCode();
    if (keyListener!=null&&key!=KeyEvent.VK_S&& key!=KeyEvent.VK_C && key!=KeyEvent.VK_X&& key!=KeyEvent.VK_A)
      keyListener.keyPressed(e);
   
  }
 
  public void keyReleased (KeyEvent e) {}
 
  public void keyTyped (KeyEvent e) {
    if (keyListener!=null)
      keyListener.keyTyped(e);
  }
 
  public void actionPerformed (ActionEvent e) {
    String cmd=e.getActionCommand();
    doCommand(cmd);
  }

   void doCommand(String cmd) {
     if (cmd==null)
       return;
    if (cmd.equals("Save As..."))
      saveAs("");
    else if (cmd.equals("Cut"))
      cutSelection();
    else if (cmd.equals("Copy"))
      copySelection();
    else if (cmd.equals("Clear"))
      clearSelection();
    else if (cmd.equals("Select All"))
      selectAll();
    else if (cmd.equals("Duplicate..."))
      duplicate();
    else if (cmd.equals("Summarize"))
      IJ.doCommand("Summarize");
    else if (cmd.equals("Distribution..."))
      IJ.doCommand("Distribution...");
    else if (cmd.equals("Clear Results"))
      IJ.doCommand("Clear Results");
    else if (cmd.equals("Set Measurements..."))
      IJ.doCommand("Set Measurements...");
     else if (cmd.equals("Set File Extension..."))
      IJ.doCommand("Input/Output...");
  }
  
   public void lostOwnership (Clipboard clip, Transferable cont) {}

  void duplicate() {
    if (rt==null) return;
    ResultsTable rt2 = (ResultsTable)rt.clone();
    String title2 = IJ.getString("Title:", "Results2");
    if (!title2.equals("")) {
      if (title2.equals("Results")) title2 = "Results2";
      rt2.show(title2);
    }
  }
 
  void select(int x,int y) {
    Dimension d = tc.getSize();
    if(iRowHeight==0 || x>d.width || y>d.height)
      return;
       int r=(y/iRowHeight)-1+iFirstRow;
       int lineWidth = iGridWidth;
    if (iColCount==1 && tc.fMetrics!=null && r>=0 && r<iRowCount) {
      char[] chars = (char[])vData.elementAt(r);
      lineWidth = Math.max(tc.fMetrics.charsWidth(chars,0,chars.length), iGridWidth);
    }
        if(r>=0 && r<iRowCount && x<lineWidth) {
      selOrigin = r;
      selStart = r;
      selEnd = r;
    } else {
      resetSelection();
      selOrigin = r;
      if (r>=iRowCount)
        selOrigin = iRowCount-1;
      //System.out.println("select: "+selOrigin);
    }
    tc.repaint();
    selLine=r;
  }

  void extendSelection(int x,int y) {
    Dimension d = tc.getSize();
    if(iRowHeight==0 || x>d.width || y>d.height)
      return;
       int r=(y/iRowHeight)-1+iFirstRow;
    //System.out.println(r+"  "+selOrigin);
       if(r>=0 && r<iRowCount) {
      if (r<selOrigin) {
        selStart = r;
        selEnd = selOrigin;
       
      } else {
        selStart = selOrigin;
        selEnd = r;
      }
    }
    tc.repaint();
    selLine=r;
  }

  /**
  Copies the current selection to the system clipboard.
  Returns the number of characters copied.
  */
  public int copySelection() {
    if (Recorder.record && title.equals("Results"))
      Recorder.record("String.copyResults");
    if (selStart==-1 || selEnd==-1)
      return copyAll();
    StringBuffer sb = new StringBuffer();
    if (Prefs.copyColumnHeaders && labels!=null && !labels.equals("") && selStart==0 && selEnd==iRowCount-1) {
      sb.append(labels);
      sb.append('\n');
    }
    for (int i=selStart; i<=selEnd; i++) {
      char[] chars = (char[])(vData.elementAt(i));
      sb.append(chars);
      if (i<selEnd || selEnd>selStart) sb.append('\n');
    }
    String s = new String(sb);
    Clipboard clip = getToolkit().getSystemClipboard();
    if (clip==null) return 0;
    StringSelection cont = new StringSelection(s);
    clip.setContents(cont,this);
    if (s.length()>0) {
      IJ.showStatus((selEnd-selStart+1)+" lines copied to clipboard");
      if (this.getParent() instanceof ImageJ)
        Analyzer.setUnsavedMeasurements(false);
    }
    return s.length();
  }
 
  int copyAll() {
    selectAll();
    int count = selEnd - selStart;
    if (count>0)
      copySelection();
    resetSelection();
    unsavedLines = false;
    return count;
  }
 
  void cutSelection() {
    if (selStart==-1 || selEnd==-1)
      selectAll();
    copySelection();
    clearSelection();
 

  /** Deletes the selected lines. */
  public void clearSelection() {
    if (selStart==-1 || selEnd==-1) {
      if (getLineCount()>0)
        IJ.error("Selection required");
      return;
    }
    if (selStart==0 && selEnd==(iRowCount-1)) {
      vData.removeAllElements();
      iRowCount = 0;
      if (rt!=null) {
        if (IJ.isResultsWindow() && IJ.getTextPanel()==this) {
          Analyzer.setUnsavedMeasurements(false);
          Analyzer.resetCounter();
        } else
          rt.reset();
      }
    } else {
      int rowCount = iRowCount;
      boolean atEnd = rowCount-selEnd<8;
      int count = selEnd-selStart+1;
      for (int i=0; i<count; i++) {
        vData.removeElementAt(selStart);
        iRowCount--;
      }
      if (rt!=null && rowCount==rt.getCounter()) {
        for (int i=0; i<count; i++)
          rt.deleteRow(selStart);
        rt.show(title);
        if (!atEnd) {
          iY = 0;
          tc.repaint();
        }
      }
    }
    selStart=-1; selEnd=-1; selOrigin=-1; selLine=-1;
    adjustVScroll();
    tc.repaint();
  }
 
  /** Deletes all the lines. */
  public void clear() {
    if (vData==null) return;
    vData.removeAllElements();
    iRowCount = 0;
    selStart=-1; selEnd=-1; selOrigin=-1; selLine=-1;
    adjustVScroll();
    tc.repaint();
  }

  /** Selects all the lines in this TextPanel. */
  public void selectAll() {
    if (selStart==0 && selEnd==iRowCount-1) {
      resetSelection();
      return;
    }
    selStart = 0;
    selEnd = iRowCount-1;
    selOrigin = 0;
    tc.repaint();
    selLine=-1;
  }

  /** Clears the selection, if any. */
  public void resetSelection() {
    selStart=-1;
    selEnd=-1;
    selOrigin=-1;
    selLine=-1;
    if (iRowCount>0)
      tc.repaint();
  }
 
  /** Writes all the text in this TextPanel to a file. */
  public void save(PrintWriter pw) {
    resetSelection();
    if (labels!=null && !labels.equals(""))
      pw.println(labels);
    for (int i=0; i<iRowCount; i++) {
      char[] chars = (char[])(vData.elementAt(i));
      pw.println(new String(chars));
    }
    unsavedLines = false;
  }

  /** Saves all the text in this TextPanel to a file. Set
    'path' to "" to display a save as dialog. Returns
    'false' if the user cancels the save as dialog.*/
  public boolean saveAs(String path) {
    boolean isResults = IJ.isResultsWindow() && IJ.getTextPanel()==this;
    if (path.equals("")) {
      IJ.wait(10);
      boolean hasHeadings = !getColumnHeadings().equals("");
      String ext = isResults||hasHeadings?Prefs.get("options.ext", ".xls"):".txt";
      SaveDialog sd = new SaveDialog("Save as Text", title, ext);
      String file = sd.getFileName();
      if (file == null) return false;
      path = sd.getDirectory() + file;
    }
    PrintWriter pw = null;
    try {
      FileOutputStream fos = new FileOutputStream(path);
      BufferedOutputStream bos = new BufferedOutputStream(fos);
      pw = new PrintWriter(bos);
    }
    catch (IOException e) {
      //IJ.write("" + e);
      return true;
    }
    save(pw);
    pw.close();
    if (isResults) {
      Analyzer.setUnsavedMeasurements(false);
      if (Recorder.record)
        Recorder.record("saveAs", "Measurements", path);
    } else {
      if (Recorder.record)
        Recorder.record("saveAs", "Text", path);
    }
    IJ.showStatus("");
    return true;
  }

  /** Returns all the text as a string. */
  public String getText() {
    StringBuffer sb = new StringBuffer();
    if (labels!=null && !labels.equals("")) {
      sb.append(labels);
      sb.append('\n');
    }
    for (int i=0; i<iRowCount; i++) {
      char[] chars = (char[])(vData.elementAt(i));
      sb.append(chars);
      sb.append('\n');
    }
    return new String(sb);
  }
 
  public void setTitle(String title) {
    this.title = title;
  }

  /** Returns the number of lines of text in this TextPanel. */
  public int getLineCount() {
    return iRowCount;
  }

  /** Returns the specified line as a string. The argument
    must be greater than or equal to zero and less than
    the value returned by getLineCount(). */
  public String getLine(int index) {
    if (index<0 || index>=iRowCount)
      throw new IllegalArgumentException("index out of range: "+index);
    return new String((char[])(vData.elementAt(index)));
  }
 
  /** Replaces the contents of the specified line, where 'index'
    must be greater than or equal to zero and less than
    the value returned by getLineCount(). */
  public void setLine(int index, String s) {
    if (index<0 || index>=iRowCount)
      throw new IllegalArgumentException("index out of range: "+index);
    if (vData!=null) {
      vData.setElementAt(s.toCharArray(), index)
      tc.repaint();
    }
  }

  /** Returns the index of the first selected line, or -1
    if there is no slection. */
  public int getSelectionStart() {
    return selStart;
  }

  /** Returns the index of the last selected line, or -1
    if there is no slection. */
  public int getSelectionEnd() {
    return selEnd;
  }
 
  /** Sets the ResultsTable associated with this TextPanel. */
  public void setResultsTable(ResultsTable rt) {
    this.rt = rt;
  }

  void flush() {
    if (vData!=null)
      vData.removeAllElements();
    vData = null;
  }

}
TOP

Related Classes of ij.text.TextPanel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.