1 package fi.jyu.mit.fxgui;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.HashMap;
8 import javax.swing.SwingConstants;
10 import javafx.application.Platform;
11 import javafx.beans.property.ListProperty;
12 import javafx.beans.property.SimpleListProperty;
13 import javafx.beans.property.SimpleStringProperty;
14 import javafx.beans.property.StringProperty;
15 import javafx.collections.FXCollections;
16 import javafx.collections.ListChangeListener;
17 import javafx.collections.ObservableList;
18 import javafx.fxml.FXML;
19 import javafx.geometry.Pos;
20 import javafx.scene.control.TableCell;
21 import javafx.scene.control.TableColumn;
22 import javafx.scene.control.TableRow;
23 import javafx.scene.control.TableView;
24 import javafx.scene.control.TextField;
25 import javafx.scene.input.KeyCode;
64 public class StringGrid<
TYPE>
extends TableView<StringGrid.GridRowItem<TYPE>> {
72 @SuppressWarnings(
"javadoc")
73 public static class GridRowItem<
TYPE> {
74 private ObservableList<String>
rowSts;
85 this.rowSts = FXCollections.observableArrayList();
115 this.rowSts.setAll(row);
119 if ( styleClasses == null )
return null;
120 return styleClasses.get(col);
124 if ( styleClasses == null ) styleClasses =
new HashMap<>();
125 styleClasses.put(col, cellClass);
129 public String
get(
int col) {
130 if ( col < 0 || col >= rowSts.size() )
return "";
131 return rowSts.get(col);
134 public void set(
int col, String
s) {
135 if ( col <0 || col >= rowSts.size() )
return;
146 public interface OnGridCell<
TYPE> {
164 public interface OnGridLiveEdit<
TYPE> {
175 String onEdit(
StringGrid<TYPE> grid,
TYPE item, String newValue,
int row,
int column, TextField textField);
179 private ListProperty<GridRowItem<TYPE>> rivitProp =
new SimpleListProperty<>();
180 private ObservableList<GridRowItem<TYPE>> tableRows = FXCollections.observableArrayList();
181 private StringProperty
rivitJono =
new SimpleStringProperty();
182 private String emptyStyleClass = null;
183 private HashMap<Integer,Pos> alignments =
new HashMap<>();
215 this.onCellValue = onCellValue;
231 this.onCellString = onCellString;
247 this.onGridEdit = onGridEdit;
255 return onGridLiveEdit;
263 this.onGridLiveEdit = onGridLiveEdit;
272 itemsProperty().bind(rivitProp);
273 rivitProp.set(tableRows);
283 String[] rows = data.split(
"\n");
284 this.getColumns().clear();
286 if ( rows.length == 0 )
return;
287 String[] headings = rows[0].split(
"\\|");
289 for (
int i=1;
i<rows.length;
i++) {
290 add(null, rows[
i].split(
"\\|"));
303 getColumns().clear();
304 for (
int i = 0;
i < headings.length;
i++) {
305 TableColumn<GridRowItem<TYPE>, String> tc =
new TableColumn<GridRowItem<TYPE>, String>(headings[
i]);
306 final int origCol =
i;
308 tc.setCellValueFactory((rivi) -> {
309 GridRowItem<TYPE> tableRow = rivi.getValue();
310 String
s =
get(rivi.getValue().getRowNr(),origCol);
311 if ( onCellString != null ) s = onCellString.onGetCell(
this, tableRow.getItem(),
s, tableRow.getRowNr(), origCol);
312 if ( onCellValue == null )
313 return new SimpleStringProperty(s.replace(
" ",
"."));
315 String val = this.onCellValue.onGetCell(
this, tableRow.getItem(),
s, tableRow.getRowNr(), origCol);
316 if ( val == null ) val =
s;
317 return new SimpleStringProperty(val.replace(
" ",
"."));
322 getColumns().add(tc);
324 tc.setCellFactory(column ->
new StringGridCell<TYPE>(origCol));
325 tc.setOnEditCommit( (
t) -> {
327 GridRowItem<TYPE> tableRow = table.getItems().
get(
t.getTablePosition().getRow());
328 String
s =
t.getNewValue();
329 if ( s == null )
return;
332 if ( s == null )
return;
333 tableRow.set(origCol, s);
347 tableRows.add(
new GridRowItem<TYPE>(items,obj, tableRows.size()));
358 add(obj,
new String[0]);
366 public void add(String...items) {
376 public void add(Collection<TYPE> objs) {
386 @SuppressWarnings(
"unchecked")
406 StringBuilder tulos =
new StringBuilder();
408 for (TableColumn<GridRowItem<TYPE>, ?> tc : getColumns() ) {
409 tulos.append(erotin + tc.getText());
413 int len = tableRows.size();
414 for (
int i=0;
i<len;
i++) {
415 GridRowItem<TYPE> rivi = findTableRow(
i);
416 if ( rivi == null )
continue;
418 for (String
s: rivi.getRow()) {
419 tulos.append(erotin +
s);
424 return tulos.toString();
434 for (TableColumn<GridRowItem<TYPE>, ?> tc : getColumns() ) {
435 if ( col == -1 || tc.getId().equals(
""+col))
436 tc.setSortable(sortable);
446 if ( col < 0 || col >= getColumns().size() )
return;
447 @SuppressWarnings(
"unchecked")
448 TableColumn<GridRowItem<TYPE>, String> tc = (TableColumn<GridRowItem<TYPE>, String>) getColumns().get(col);
449 tc.setCellValueFactory((rivi) -> {
450 int r = rivi.getValue().getRowNr();
451 String
s =
get(
r,col);
453 s = s.substring(s.length()-10, s.length());
454 return new SimpleStringProperty(s);
456 alignments.put(col, Pos.CENTER_RIGHT);
466 for (TableColumn<GridRowItem<TYPE>, ?> tc : getColumns() ) {
467 if ( col == -1 || tc.getId().equals(
""+col)) {
468 tc.setPrefWidth(width);
469 tc.setMaxWidth(width);
470 tc.setMinWidth(width);
482 Pos result = alignments.get(col);
483 if ( result == null )
return Pos.CENTER_LEFT;
494 alignments.put(col, align);
505 case SwingConstants.RIGHT:
506 setAlignment(col, Pos.CENTER_RIGHT);
508 case SwingConstants.CENTER:
509 setAlignment(col, Pos.CENTER);
512 setAlignment(col, Pos.CENTER_LEFT);
538 if ( tableRow == null )
return -1;
539 return tableRow.getRowNr();
549 int newrow = rowvisible;
550 int rowcount = getItems().size();
551 if ( rowvisible >= rowcount ) newrow = rowcount -1;
552 getFocusModel().focus(newrow);
553 getSelectionModel().select(newrow);
562 GridRowItem<TYPE> rivi = getSelectionModel().getSelectedItem();
563 return findRowNr(rivi);
571 @SuppressWarnings(
"unchecked")
572 TableColumn<GridRowItem<TYPE>, String> tc = getFocusModel().getFocusedCell().getTableColumn();
573 if ( tc == null )
return -1;
574 return Integer.parseInt(tc.getId());
584 for (GridRowItem<TYPE>
r: tableRows)
585 if (
r.getRowNr() == row )
return r;
596 public void set(String
s,
int row,
int col) {
597 GridRowItem<TYPE> rivi = findTableRow(row);
598 if ( rivi == null )
return;
610 public String
get(
int row,
int col) {
611 GridRowItem<TYPE> rivi = findTableRow(row);
612 if ( rivi == null )
return "";
613 String
s = rivi.get(col);
614 if ( onCellString == null )
return s;
615 String val = onCellString.onGetCell(
this, rivi.getItem(),
s, row, col);
616 if ( val == null ) val =
s;
617 if ( val == null ) val =
"";
628 GridRowItem<TYPE> rivi = findTableRow(row);
629 if ( rivi == null )
return;
641 GridRowItem<TYPE> rivi = findTableRow(row);
642 if ( rivi == null )
return null;
643 return rivi.getItem();
652 GridRowItem<TYPE> rivi = getSelectionModel().getSelectedItem();
653 if ( rivi == null )
return null;
654 return rivi.getItem();
665 GridRowItem<TYPE> rivi = findTableRow(row);
666 if ( rivi == null )
return;
667 rivi.setCellClass(s, col);
679 GridRowItem<TYPE> rivi = findTableRow(row);
680 if ( rivi == null )
return null;
681 return rivi.getCellClass(col);
690 public static void addStyleClasses(ObservableList<String> styles, String newClasses) {
691 if ( newClasses == null )
return;
692 for (String sc: newClasses.split(
"[, ]"))
693 if ( !sc.isEmpty() && !styles.contains(sc) )
702 return emptyStyleClass;
710 this.emptyStyleClass = emptyStyleClass;
722 final ArrayList<TableColumn<GridRowItem<TYPE>,?>> columns =
new ArrayList<>();
723 columns.addAll(getColumns());
724 getColumns().addListener(
new ListChangeListener<Object>() {
725 public boolean suspended;
728 public void onChanged(Change<?> change) {
730 if (change.wasReplaced() && !suspended) {
731 this.suspended =
true;
732 getColumns().setAll(columns);
733 this.suspended =
false;
744 protected static class StringGridCell<
TYPE>
extends TableCell<GridRowItem<TYPE>, String> {
769 @SuppressWarnings(
"unchecked")
770 TableRow<GridRowItem<TYPE>> row = getTableRow();
771 if ( row == null )
return null;
772 return row.getItem();
780 GridRowItem<TYPE> tableRow = getRowItem();
781 if ( tableRow == null )
return getItem();
783 return table.
get(tableRow.getRowNr(), origCol);
789 if ( isEmpty())
return;
793 setGraphic(textField);
794 textField.setText(getCellString());
795 Platform.runLater(() -> textField.requestFocus());
796 textField.selectAll();
803 setText(getCellString());
810 setAlignment(getTable().getAlignment(origCol));
812 super.updateItem(getCellString(), empty);
814 if (textField != null) textField.setText(getCellString());
816 setGraphic(textField);
821 addStyleClasses(getStyleClass(),getTable().getEmptyStyleClass());
825 @SuppressWarnings(
"unchecked")
826 TableRow<GridRowItem<TYPE>> row = getTableRow();
827 if ( row != null && row.getItem() != null) {
828 String styleClass = row.getItem().getCellClass(origCol);
829 addStyleClasses(getStyleClass(),styleClass);
830 setText(getCellString());
835 @SuppressWarnings(
"unchecked")
836 private
void createTextField() {
837 if ( textField != null )
return;
838 textField =
new TextField();
839 textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
840 textField.focusedProperty().addListener( (arg0, arg1,arg2) -> {
842 commitEdit(textField.getText());
845 textField.setOnAction(e -> commitEdit(textField.getText()));
846 textField.setOnKeyReleased(e -> {
847 if ( e == null )
return;
848 if ( textField == null )
return;
849 GridRowItem<TYPE> tietue = getRowItem();
850 String
s = textField.getText();
856 if ( s != null ) tietue.set(origCol, s);
858 textField.setOnKeyPressed(
t -> {
859 if (
t.getCode() == KeyCode.ENTER) {
860 commitEdit(textField.getText());
863 }
else if (
t.getCode() == KeyCode.ESCAPE) {
866 }
else if (
t.getCode() == KeyCode.TAB) {
871 if (
t.isShiftDown() )
872 table.getFocusModel().focusLeftCell();
874 table.getFocusModel().focusRightCell();
876 table.edit(getTableRow().getIndex(), table.getFocusModel().getFocusedCell().getTableColumn());