Table: new editing and filtering

* Split buttons between the context menu and above the table.
* Moved adding/editing to above the table.
* Added filtering.
* Added shortcut to edit (double click) and to delete rows.
This commit is contained in:
Carlos Galindo 2019-09-13 00:15:27 +02:00
parent 93b7dce200
commit 7fe80b07ec
Signed by: kauron
GPG Key ID: 83E68706DEE119A3
2 changed files with 76 additions and 57 deletions

View File

@ -1,50 +1,47 @@
package es.kauron.jstudy.controller;
import es.kauron.jstudy.Main;
import es.kauron.jstudy.model.AppPrefs;
import es.kauron.jstudy.model.TestItem;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.*;
public class TableController implements Initializable {
@FXML
private TableView<TestItem> table;
@FXML
private TextField newQuestionField, newAnswerField, searchField;
@FXML
private Button addButton;
@FXML
private TableColumn<TestItem, String> answerCol, questionCol;
private FilteredList<TestItem> filtered;
private ObservableList<TestItem> data;
private Controller parent;
private File file;
StringProperty name;
final BooleanProperty saved = new SimpleBooleanProperty();
private final ObjectProperty<TestItem> editing = new SimpleObjectProperty<>(null);
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
addButton.textProperty().bind(Bindings.when(editing.isNull()).then("_Add item").otherwise("_Save item"));
// Add context menu to Table
MenuItem menuEdit = new MenuItem("_Edit");
menuEdit.setOnAction(this::onEditAction);
@ -61,16 +58,18 @@ public class TableController implements Initializable {
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
answerCol.setCellValueFactory(e -> e.getValue().answerProperty());
questionCol.setCellValueFactory(e -> e.getValue().questionProperty());
table.getSelectionModel().getSelectedIndices().addListener((ListChangeListener<? super Integer>) obs -> {
menuEdit.setDisable(obs.getList().size() != 1);
});
table.getSelectionModel().getSelectedIndices().addListener(
(ListChangeListener<? super Integer>) obs -> menuEdit.setDisable(obs.getList().size() != 1));
searchField.textProperty().addListener((obj, o, n) ->
filtered.setPredicate((item) -> item.getQuestion().contains(n) || item.getAnswer().contains(n)));
}
void setData(String name, List<TestItem> list, Controller controller, File file) {
this.name = new SimpleStringProperty(name);
this.data = FXCollections.observableArrayList(list);
this.filtered = data.filtered((item) -> true);
this.parent = controller;
table.setItems(data);
table.setItems(filtered);
this.file = file;
saved.set(file != null);
}
@ -99,41 +98,31 @@ public class TableController implements Initializable {
@FXML
protected void onAddAction(ActionEvent event) {
try {
FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/edit.fxml"));
Parent pRoot = loader.load();
((EditController) loader.getController()).setList(data, saved);
Stage stage = new Stage();
stage.setTitle("New entry");
stage.setScene(new Scene(pRoot));
stage.initModality(Modality.APPLICATION_MODAL);
stage.showAndWait();
} catch (IOException e) {
e.printStackTrace();
if (editing.get() == null) {
TestItem item = new TestItem(newQuestionField.getText().trim(), newAnswerField.getText().trim());
data.add(item);
newQuestionField.setText("");
newAnswerField.setText("");
saved.set(false);
} else {
editing.get().answerProperty().set(newAnswerField.getText().trim());
editing.get().questionProperty().set(newQuestionField.getText().trim());
editing.set(null);
newQuestionField.setText("");
newAnswerField.setText("");
}
newQuestionField.requestFocus();
}
@FXML
protected void onEditAction(ActionEvent event) {
ObservableList<Integer> list = table.getSelectionModel().getSelectedIndices();
ObservableList<TestItem> list = table.getSelectionModel().getSelectedItems();
if (list.size() != 1) return;
int index = list.get(0);
try {
FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/edit.fxml"));
Parent root = loader.load();
((EditController) loader.getController()).setList(table.getItems(), index, saved);
Stage stage = new Stage();
stage.setTitle("Editing entry...");
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
stage.showAndWait();
} catch (IOException e) {
e.printStackTrace();
}
editing.set(list.get(0));
newQuestionField.setText(list.get(0).getQuestion());
newAnswerField.setText(list.get(0).getAnswer());
saved.set(false);
newQuestionField.requestFocus();
}
@FXML
@ -151,15 +140,14 @@ public class TableController implements Initializable {
protected void onDuplicateAction(ActionEvent event) {
if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false);
for (int i : table.getSelectionModel().getSelectedIndices())
table.getItems().add(new TestItem(table.getItems().get(i)));
data.add(new TestItem(filtered.get(i)));
table.requestFocus();
}
@FXML
protected void onDeleteAction(ActionEvent event) {
if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false);
for (int i : table.getSelectionModel().getSelectedIndices())
table.getItems().remove(i);
data.removeAll(table.getSelectionModel().getSelectedItems());
table.requestFocus();
}
@ -170,6 +158,32 @@ public class TableController implements Initializable {
@FXML
protected void onTestAction(ActionEvent event) {
parent.newTest(data);
parent.newTest(filtered);
}
@FXML
protected void onTableKeyEvent(KeyEvent event) {
if (event.getCode().equals(KeyCode.DELETE)) {
onDeleteAction(null);
}
}
private final Timer timer = new Timer();
private TimerTask timerTask = null;
@FXML
protected void onTableMouseClicked(MouseEvent event) {
if (timerTask == null) {
timerTask = new TimerTask() {
@Override
public void run() {
timerTask = null;
}
};
timer.schedule(timerTask, 200);
} else {
if (timerTask.cancel())
onEditAction(null);
timerTask = null;
}
}
}

View File

@ -7,11 +7,14 @@
<children>
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<Button defaultButton="true" onAction="#onAddAction" prefWidth="105.0" text="_Add new">
<TextField fx:id="newQuestionField" promptText="Question" />
<TextField fx:id="newAnswerField" promptText="Answer" />
<Button defaultButton="true" fx:id="addButton" onAction="#onAddAction" prefWidth="105.0" text="_Add new">
<tooltip>
<Tooltip text="Add a new entry to the table" />
</tooltip>
</Button>
<TextField fx:id="searchField" promptText="Search..." />
<HBox alignment="CENTER_RIGHT" spacing="5.0" HBox.hgrow="ALWAYS" VBox.vgrow="ALWAYS">
<children>
<Button layoutX="10.0" layoutY="273.0" onAction="#onTestAction" prefWidth="105.0" text="_Test all">
@ -35,7 +38,9 @@
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</VBox.margin>
</HBox>
<TableView fx:id="table" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="400.0" HBox.hgrow="ALWAYS" VBox.vgrow="ALWAYS">
<TableView fx:id="table" onMouseClicked="#onTableMouseClicked" onKeyPressed="#onTableKeyEvent" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity"
prefHeight="200.0" prefWidth="400.0" HBox.hgrow="ALWAYS" VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="questionCol" prefWidth="75.0" text="Question" />
<TableColumn fx:id="answerCol" prefWidth="75.0" text="Answer" />