/* * $Id$ * * Copyright (c) 2004-2005 by the TeXlapse Team. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package net.sourceforge.texlipse.tableview.views; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.Vector; import net.sourceforge.texlipse.TexlipsePlugin; import net.sourceforge.texlipse.actions.TexSelections; /** * @author Esa Seuranen * * The class for holding the table's data, and all the operations that * can be done with the data. */ public class TexRowList { /** * Constant for defining up direction for function sum(int column, int row, int direction) */ public final static int SUM_UP=1; /** * Constant for defining down direction for function sum(int column, int row, int direction) */ public final static int SUM_DOWN=2; /** * Constant for defining left direction for function sum(int column, int row, int direction) */ public final static int SUM_LEFT=3; /** * Constant for defining right direction for function sum(int column, int row, int direction) */ public final static int SUM_RIGHT=4; //default number of rows upon initialization private final static int ROW_COUNT=10; private Vector rows = new Vector(ROW_COUNT); /** * Constructor */ public TexRowList(){ for (int i = 0; i < ROW_COUNT; i++) rows.add(i, new TexRow()); } // change listeners private Set changeListeners = new HashSet(); //Vector for holding TexRows public Vector getRows() { return rows; } /** * Adds row to the end of the row list * * @return the added TexRow */ public TexRow addRow() { TexRow row = new TexRow(); rows.add(rows.size(), row); Iterator iterator = changeListeners.iterator(); while (iterator.hasNext()) ((ITexRowListViewer) iterator.next()).addRow(row); return row; } /** * Inserts the given row to the given place(index) in the row list * * @param index where the row is inserted * @param row the TexRow which is inserted * @return the inserted TexRow (the same as row) */ public TexRow insertRow(int index,TexRow row) { rows.insertElementAt(row,index); Iterator iterator = changeListeners.iterator(); while (iterator.hasNext()) ((ITexRowListViewer) iterator.next()).insertRow(row); return row; } /** * Inserts new TexRow to the given place(index) in the row list * * @param index where the row is inserted * @return the inserted TexRow */ public TexRow insertRow(int index) { return insertRow(index,new TexRow()); } /** * Returns the index of given row in the row list * * @param row * @return index of the row (or -1 if the row is not in the row list) */ public int indexOf(TexRow row){ return rows.indexOf(row); } /** * Removes the given row (first occurrance) from the row list * (or does nothing, if the row is not in the row list) * * @param row to be removed */ public void removeRow(TexRow row) { rows.remove(row); // FIXME now maxrowcount becomes one less, since the row isn't cleared Iterator iterator = changeListeners.iterator(); while (iterator.hasNext()) ((ITexRowListViewer) iterator.next()).removeRow(row); } /** * Notifies the changelistener, that a row has been changed * * @param row which was changed (and should be updated in table viewer) */ public void rowChanged(TexRow row) { Iterator iterator = changeListeners.iterator(); while (iterator.hasNext()) ((ITexRowListViewer) iterator.next()).updateRow(row); } /** * Removes change listener from the given viewer * * @param viewer */ public void removeChangeListener(ITexRowListViewer viewer) { changeListeners.remove(viewer); } /** * Adds change listener to the given viewer * * @param viewer */ public void addChangeListener(ITexRowListViewer viewer) { changeListeners.add(viewer); } /* * Reads an table item from a string representing a LaTeX table row. * The items separated by '&' characters (exlcluding the combnation "\&"). * * @param source LateX table row * @param index (of the source string) from which the search for the next item * is started * @return the item as string */ private String readItemFromTexTableLine(String source,int index){ int check, end = source.indexOf("&", index); while (end > 0) { check = source.lastIndexOf("\\", end); if (check + 1 == end) end = source.indexOf("&", end + 1); else break; } if (end == -1) return source.substring(index); else return source.substring(index, end + 1); } /* * Reads an table row from a string representing the whole LaTeX table row. * The rows are separeted by string "\\", and the last line does not * need to have "\\" * * @param source LateX table * @param index (of the source string) from which the search for the next line * is started * @return the line as string */ private String readTexTableLine(String source,int index){ int end = source.indexOf("\\\\", index); if (end == -1) return source.substring(index); return source.substring(index, end + 2); } /** * Interprets the given selection as simple LaTeX table and imports * in to the given location. If the row is empty, then the import * is done to that row, otherwise a new row is created and inserted * and the import is done to that row. * * Comments (i.e. "LaTeXTableStuff %ThisPartOfTheLineIsRemoved") * are ignored, as well as "\.*line.*" parts. * * @param selection TexSelection object * @param importAt the starting row (index) for the import * */ public void importSelection(TexSelections selection,int importAt){ String line, s, item, tmps; int index = 0, index2, tmpi; int row = importAt, column; s = selection.getCompleteLines() + "\n"; //added \n so that last line comment is also removed s = s.replaceAll("%.*\n", "\n"); //remove comments s = s.replaceAll("\n\r*", " "); //remove newlines while (index < s.length()) { if (row >= rows.size()) addRow(); //check, whether the current row is empty... if not, create a new // one if (!((TexRow) rows.get(row)).empty()) insertRow(row); line = readTexTableLine(s, index); index += line.length(); line = line.trim(); while (line.startsWith("\\")) { tmpi = line.indexOf(" "); if (tmpi == -1) break; tmps = line.substring(0, tmpi); if (tmps.indexOf("line") == -1) break; line = line.substring(tmpi); } if (line.endsWith("\\\\")) line = line.substring(0, line.length() - 2); //We need this to ensure that the last empty field will be recognized (Case: &\\) if (line.endsWith("&")) line = line + " "; index2 = 0; column = 0; while ((index2 < line.length()) && (column < TexRow.COLUMNS)) { item = readItemFromTexTableLine(line, index2); index2 += item.length(); item = item.trim(); if (item.endsWith("&")) item = item.substring(0, item.length() - 1); if ("".equals(item)) item = "&"; ((TexRow) rows.get(row)).setCol(column, item); column++; } rowChanged((TexRow) rows.get(row)); row++; } } /** * Clears all data in the row list */ public void clearAll() { for (int i = 0; i < rows.size(); i++) { ((TexRow) rows.get(i)).clear(); rowChanged((TexRow) rows.get(i)); } } /** * Exports the table editor's content to clipboard * in LaTeX table format. * * @return string representing the whole table */ public String export() { String s, value = ""; boolean first; for (int i = 0; i < rows.size(); i++) { TexRow row = (TexRow) rows.get(i); int lastCol = row.lastColumn(); if (lastCol == -1) continue; first = true; boolean amp = false; for (int j = 0; j <= lastCol; j++) { s = row.getCol(j).trim(); if (s.compareTo("&") == 0){ if (first) value += s; else value += " " + s; first = false; amp = true; } else { if (first) { value += s; first = false; } else { if (!amp) value += " & " + s; else value += " " + s; amp = false; } } } value += "\\\\\n"; } return value; } /** * Returns the table editor's content in a raw, * tabulated format suitable for e.g. gnuplot. * * @return string representing the whole table */ public String exportRaw() { String s, value = ""; boolean first; for (int i = 0; i < rows.size(); i++) { TexRow row = (TexRow) rows.get(i); int lastCol = row.lastColumn(); if (lastCol == -1) continue; first = true; for (int j = 0; j <= lastCol; j++) { s = row.getCol(j).trim(); if (s.compareTo("&") == 0) value += "\t" + s; else { if (first) { value += s; first = false; } else { value += "\t" + s; } } } value += "\n"; } return value; } /** * Flips the rows and columns of the table, i.e. * 1 2 3 * 4 5 6 * becomes * 1 4 * 2 5 * 3 6 */ public void flipRowsAndColumns() { String s; boolean swap; TexRow texRow; if (rows.size() >= TexRow.COLUMNS) { TexlipsePlugin .stat("Flipping rows and columns in LaTeX Table View for more than " + Integer.toString(TexRow.COLUMNS) + " rows is not supported."); return; } for (int column = 0; column < TexRow.COLUMNS; column++) { for (int row = 0; ((row < column) && (row < rows.size())); row++) { swap = false; texRow = (TexRow) rows.get(row); if (texRow.getCol(column).length() > 0) swap = true; if ((rows.size() > column) && ((TexRow) rows.get(column)).getCol(row).length() > 0) swap = true; if (swap) { while (rows.size() <= column) addRow(); s = texRow.getCol(column); texRow.setCol(column, ((TexRow) rows.get(column)) .getCol(row)); ((TexRow) rows.get(column)).setCol(row, s); } } } for (int i = 0; i < rows.size(); i++) rowChanged((TexRow) rows.get(i)); } /** * Mirrors the columns of the table, i.e. * 1 2 3 * 4 5 6 * becomes * 3 2 1 * 6 5 4 */ public void mirrorColumns() { int i, j, last = 0; String s; TexRow row; for (i = 0; i < rows.size(); i++) { row = (TexRow) rows.get(i); for (j = last; j < TexRow.COLUMNS; j++) if (row.getCol(j).length() > 0) last = j; } for (i = 0; i < rows.size(); i++) { row = (TexRow) rows.get(i); for (j = 0; j < (int) ((last + 1) / 2); j++) { s = row.getCol(j); row.setCol(j, row.getCol(last - j)); row.setCol(last - j, s); } rowChanged(row); } } /** * Mirrors the rows of the table, i.e. * 1 2 3 * 4 5 6 * becomes * 4 5 6 * 1 2 3 */ public void mirrorRows() { int i, j, last = 0; String s; TexRow row1, row2; for (i = 0; i < rows.size(); i++) { row1 = (TexRow) rows.get(i); if (!(row1.empty())) last = i; } for (i = 0; i < ((last + 1) / 2); i++) { row1 = (TexRow) rows.get(i); row2 = (TexRow) rows.get(last - i); for (j = 0; j < TexRow.COLUMNS; j++) { s = row1.getCol(j); row1.setCol(j, row2.getCol(j)); row2.setCol(j, s); } rowChanged(row1); rowChanged(row2); } } /** * Moves given row into given location * * @param row * @param toIndex */ public void move(TexRow row, int toIndex) { int fromIndex = indexOf(row); //check parameters if ((fromIndex < 0) || (toIndex < 0) || (toIndex >= rows.size())) return; if (toIndex > fromIndex) toIndex--; removeRow(row); insertRow(toIndex, row); } /** * Sums the cells in given area, defined with top left cell * and the areas width and height * * @param column top left cell's column * @param row top left cell's row * @param width the are width (the number of cells) * @param height the are height (the number of cells) */ public double sum(int column, int row, int width, int height) { int i, j; double value = 0.0; TexRow texRow; for (i = row; (i < rows.size()) && (i < row + height); i++) { if (i < 0) continue; //just being paranoid texRow = (TexRow) rows.get(i); for (j = column; (j < TexRow.COLUMNS) && (j < column + width); j++) { if (j < 0) continue; //just being paranoid try { value += Double.parseDouble(texRow.getCol(j)); } catch (NumberFormatException nfe) { //this is expected to happen because of text strings } } } return (value); } /** * Sums the cells in given direction from the defined cell (by column and row). * The cell itself is not included into the sum * * @param column cell's column * @param row top left cell's row * @param direction one of SUM_UP, SUM_DOWN, SUM_LEFT, SUM_RIGHT */ public double sum(int column, int row, int direction){ switch(direction){ case SUM_UP: return sum(column, 0, 1, row); case SUM_DOWN: return sum(column, row + 1, 1, rows.size()-row-1); case SUM_LEFT: return sum(0, row, column, 1); case SUM_RIGHT: return sum(column+1, row, TexRow.COLUMNS-column-1, 1); } //invalid direction was given return 0.0; } /** * Duplicates the given row and insert the dublicate into the row list * (location specified by index) * * @param row * @param index */ public void copy(TexRow row, int index) { insertRow(index, new TexRow(row)); } }