package gsingh.learnkirtan.ui.shabadeditor.tableeditor;
import gsingh.learnkirtan.FileManager;
import gsingh.learnkirtan.note.Note;
import gsingh.learnkirtan.note.Note.Length;
import gsingh.learnkirtan.parser.Parser;
import gsingh.learnkirtan.shabad.Shabad;
import gsingh.learnkirtan.shabad.ShabadMetaData;
import gsingh.learnkirtan.shabad.ShabadNotes;
import gsingh.learnkirtan.ui.WindowTitleManager;
import gsingh.learnkirtan.ui.action.ActionFactory;
import gsingh.learnkirtan.ui.shabadeditor.SwingShabadEditor;
import gsingh.learnkirtan.ui.shabadeditor.tableeditor.EditUndoManager.UndoEventListener;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
@SuppressWarnings("serial")
public class TableShabadEditor extends SwingShabadEditor implements
UndoEventListener {
private ShabadTable table;
private UndoTableModel model;
private EditUndoManager undoManager = new EditUndoManager();;
private ShabadMetaData metaData;
private WindowTitleManager titleManager;
private boolean metaModified = false;
private boolean repeating = false;
private int numRows = 32;
private int numCols = 16;
private JTable rowTable = new JTable(numRows, 1);
public TableShabadEditor(final WindowTitleManager titleManager,
FileManager fileManager) {
this.titleManager = titleManager;
undoManager.addUndoEventListener(this);
table = new ShabadTable(numRows, numCols, titleManager,
new ActionFactory(this, fileManager));
model = (UndoTableModel) table.getModel();
model.addUndoableEditListener(undoManager);
table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
rowTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
rowTable.setPreferredScrollableViewportSize(new Dimension(30, 0));
rowTable.getColumnModel().getColumn(0).setPreferredWidth(30);
rowTable.setRowHeight(20);
rowTable.setEnabled(false);
DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
centerRenderer.setHorizontalAlignment(SwingConstants.CENTER);
rowTable.getColumnModel().getColumn(0).setCellRenderer(centerRenderer);
setRowLabels();
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setRowHeaderView(rowTable);
setLayout(new GridLayout());
add(scrollPane);
model.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent event) {
modified = true;
titleManager.setDocumentModifiedTitle();
}
});
metaData = new ShabadMetaData("", "", "", "", "");
}
private void setRowLabels() {
for (int i = 0; i < numRows; i++) {
rowTable.setValueAt(i + 1, i, 0);
}
}
public void setRepeating(boolean bool) {
repeating = bool;
}
public boolean getRepeating() {
return repeating;
}
public Action getUndoAction() {
return undoManager.getUndoAction();
}
public Action getRedoAction() {
return undoManager.getRedoAction();
}
public Action getCutAction() {
return table.new CutAction();
}
public Action getCopyAction() {
return table.new CopyAction();
}
public Action getPasteAction() {
return table.new PasteAction();
}
@Override
public Shabad getShabad() {
Shabad shabad = new Shabad(getNotesString(), getWords());
shabad.setMetaData(metaData);
return shabad;
}
@Override
public void setShabad(Shabad shabad) {
metaData = shabad.getMetaData();
setNotes(shabad.getNotes());
setWords(shabad.getWords());
}
private void setNotes(ShabadNotes notes) {
int numRows = model.getRowCount();
if (numRows < 2 * notes.size() / numCols) {
numRows = 2 * notes.size() / numCols;
this.numRows = numRows;
model.setRowCount(numRows);
}
int index = 0;
for (int i = 1; i < numRows; i += 2) {
for (int j = 0; j < numCols; j++) {
if (index < notes.size()) {
Note note = notes.get(index);
if (note == null) {
table.setValueAt(null, i, j);
} else if (note.getLength() == Length.LONG) {
table.setValueAt(note.getNoteText(), i, j);
if (j == 15) {
j = 0;
i += 2;
} else {
j++;
}
table.setValueAt("-", i, j);
} else if (note.getLength() == Length.HALF) {
Note note2 = notes.get(++index);
table.setValueAt(
note.getNoteText() + "-" + note2.getNoteText(),
i, j);
} else {
table.setValueAt(note.getNoteText(), i, j);
}
index++;
} else {
table.setValueAt(null, i, j);
}
}
}
}
@Override
public ShabadNotes getNotes() {
Parser parser = new Parser();
return parser.parse(getNotesString());
}
private String getNotesString() {
int firstCol, firstRow;
int colCount, rowCount;
if (repeating) {
firstCol = table.getSelectedColumn();
firstRow = table.getSelectedRow();
colCount = table.getSelectedColumnCount();
rowCount = table.getSelectedRowCount();
} else {
firstCol = 0;
firstRow = 0;
colCount = numCols;
rowCount = model.getRowCount();
}
// Only start on shabad rows, not wording rows
if (firstRow % 2 == 0) {
firstRow++;
}
StringBuilder sb = new StringBuilder();
for (int i = firstRow; i < firstRow + rowCount; i += 2) {
for (int j = firstCol; j < firstCol + colCount; j++) {
sb.append(model.getValueAt(i, j)).append(" ");
}
}
return sb.toString();
}
public List<String> getWords() {
List<String> l = new ArrayList<String>();
int numRows = model.getRowCount();
for (int i = 0; i < numRows; i += 2) {
for (int j = 0; j < numCols; j++) {
l.add((String) model.getValueAt(i, j));
}
}
return l;
}
public boolean isValidShabad() {
return table.isValidShabad();
}
public void setWords(List<String> words) {
int numRows = model.getRowCount();
if (numRows < 2 * words.size() / numCols) {
numRows = 2 * words.size() / numCols;
this.numRows = numRows;
model.setRowCount(numRows);
}
for (int i = 0; i < numRows; i += 2) {
for (int j = 0; j < numCols; j++) {
int index = i / 2 * numCols + j;
String word;
if (index >= words.size())
word = "null";
else
word = words.get(index);
if (word != null && !word.equalsIgnoreCase("null")) {
table.setValueAt(word, i, j);
} else {
table.setValueAt(null, i, j);
}
}
}
}
private Action emptyAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
}
};
private void setUndoActions() {
if (undoManager.canRedo()) {
table.getActionMap().put("redo", getRedoAction());
} else {
table.getActionMap().put("redo", emptyAction);
}
if (undoManager.canUndo()) {
table.getActionMap().put("undo", getUndoAction());
} else {
table.getActionMap().put("undo", emptyAction);
}
}
@Override
public void setEditable(boolean bool) {
setEditable(bool);
}
@Override
public void reset() {
modified = false;
metaModified = false;
undoManager.discardAllEdits();
}
/**
* Inserts a pair of rows into the table
*
* @param row
* the row to insert the pair above
*/
public void addRowAbove(int row) {
numRows += 2;
DefaultTableModel rowModel = (DefaultTableModel) rowTable.getModel();
rowModel.insertRow(row, new Object[] {});
rowModel.insertRow(row, new Object[] {});
if (row % 2 == 0) {
model.insertRow(row, new Object[] {});
model.insertRow(row, new Object[] {});
} else {
model.insertRow(row - 1, new Object[] {});
model.insertRow(row - 1, new Object[] {});
}
setRowLabels();
}
public void addRowBelow(int row) {
// TODO
}
/**
* Deletes the specified row from the table. Also deletes the other row in
* the pair
*
* @param row
* the row number of the row to delete
*/
public void deleteRow(int row) {
numRows -= 2;
DefaultTableModel rowModel = (DefaultTableModel) rowTable.getModel();
rowModel.removeRow(row);
rowModel.removeRow(row);
model.removeRow(row);
if (row % 2 == 0) {
model.removeRow(row);
} else {
model.removeRow(row - 1);
}
setRowLabels();
}
@Override
public void setEnabled(boolean bool) {
table.setEnabled(bool);
}
public int getSelectedRow() {
return table.getSelectedRow();
}
@Override
public ShabadMetaData getMetaData() {
return metaData;
}
@Override
public void setMetaData(ShabadMetaData metaData) {
if (!this.metaData.equals(metaData)) {
modified = true;
metaModified = true;
titleManager.setDocumentModifiedTitle();
}
this.metaData = metaData;
}
@Override
public void undoEventOccurred() {
if (!undoManager.canUndo() && !metaModified) {
titleManager.setDocumentUnmodifiedTitle();
modified = false;
metaModified = false;
} else {
titleManager.setDocumentModifiedTitle();
}
setUndoActions();
}
}