mirror of
https://gitlab.com/kauron/jstudy
synced 2024-12-22 08:23:33 +01:00
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:
parent
93b7dce200
commit
7fe80b07ec
2 changed files with 76 additions and 57 deletions
|
@ -1,50 +1,47 @@
|
||||||
package es.kauron.jstudy.controller;
|
package es.kauron.jstudy.controller;
|
||||||
|
|
||||||
import es.kauron.jstudy.Main;
|
|
||||||
import es.kauron.jstudy.model.AppPrefs;
|
import es.kauron.jstudy.model.AppPrefs;
|
||||||
import es.kauron.jstudy.model.TestItem;
|
import es.kauron.jstudy.model.TestItem;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.*;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
|
||||||
import javafx.beans.property.StringProperty;
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.collections.transformation.FilteredList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.control.SelectionMode;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.control.TableColumn;
|
|
||||||
import javafx.scene.control.TableView;
|
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import javafx.stage.Modality;
|
|
||||||
import javafx.stage.Stage;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
|
|
||||||
public class TableController implements Initializable {
|
public class TableController implements Initializable {
|
||||||
@FXML
|
@FXML
|
||||||
private TableView<TestItem> table;
|
private TableView<TestItem> table;
|
||||||
@FXML
|
@FXML
|
||||||
|
private TextField newQuestionField, newAnswerField, searchField;
|
||||||
|
@FXML
|
||||||
|
private Button addButton;
|
||||||
|
@FXML
|
||||||
private TableColumn<TestItem, String> answerCol, questionCol;
|
private TableColumn<TestItem, String> answerCol, questionCol;
|
||||||
|
|
||||||
|
private FilteredList<TestItem> filtered;
|
||||||
private ObservableList<TestItem> data;
|
private ObservableList<TestItem> data;
|
||||||
private Controller parent;
|
private Controller parent;
|
||||||
private File file;
|
private File file;
|
||||||
StringProperty name;
|
StringProperty name;
|
||||||
final BooleanProperty saved = new SimpleBooleanProperty();
|
final BooleanProperty saved = new SimpleBooleanProperty();
|
||||||
|
private final ObjectProperty<TestItem> editing = new SimpleObjectProperty<>(null);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
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
|
// Add context menu to Table
|
||||||
MenuItem menuEdit = new MenuItem("_Edit");
|
MenuItem menuEdit = new MenuItem("_Edit");
|
||||||
menuEdit.setOnAction(this::onEditAction);
|
menuEdit.setOnAction(this::onEditAction);
|
||||||
|
@ -61,16 +58,18 @@ public class TableController implements Initializable {
|
||||||
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||||
answerCol.setCellValueFactory(e -> e.getValue().answerProperty());
|
answerCol.setCellValueFactory(e -> e.getValue().answerProperty());
|
||||||
questionCol.setCellValueFactory(e -> e.getValue().questionProperty());
|
questionCol.setCellValueFactory(e -> e.getValue().questionProperty());
|
||||||
table.getSelectionModel().getSelectedIndices().addListener((ListChangeListener<? super Integer>) obs -> {
|
table.getSelectionModel().getSelectedIndices().addListener(
|
||||||
menuEdit.setDisable(obs.getList().size() != 1);
|
(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) {
|
void setData(String name, List<TestItem> list, Controller controller, File file) {
|
||||||
this.name = new SimpleStringProperty(name);
|
this.name = new SimpleStringProperty(name);
|
||||||
this.data = FXCollections.observableArrayList(list);
|
this.data = FXCollections.observableArrayList(list);
|
||||||
|
this.filtered = data.filtered((item) -> true);
|
||||||
this.parent = controller;
|
this.parent = controller;
|
||||||
table.setItems(data);
|
table.setItems(filtered);
|
||||||
this.file = file;
|
this.file = file;
|
||||||
saved.set(file != null);
|
saved.set(file != null);
|
||||||
}
|
}
|
||||||
|
@ -99,41 +98,31 @@ public class TableController implements Initializable {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected void onAddAction(ActionEvent event) {
|
protected void onAddAction(ActionEvent event) {
|
||||||
try {
|
if (editing.get() == null) {
|
||||||
FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/edit.fxml"));
|
TestItem item = new TestItem(newQuestionField.getText().trim(), newAnswerField.getText().trim());
|
||||||
Parent pRoot = loader.load();
|
data.add(item);
|
||||||
|
newQuestionField.setText("");
|
||||||
((EditController) loader.getController()).setList(data, saved);
|
newAnswerField.setText("");
|
||||||
|
saved.set(false);
|
||||||
Stage stage = new Stage();
|
} else {
|
||||||
stage.setTitle("New entry");
|
editing.get().answerProperty().set(newAnswerField.getText().trim());
|
||||||
stage.setScene(new Scene(pRoot));
|
editing.get().questionProperty().set(newQuestionField.getText().trim());
|
||||||
stage.initModality(Modality.APPLICATION_MODAL);
|
editing.set(null);
|
||||||
stage.showAndWait();
|
newQuestionField.setText("");
|
||||||
} catch (IOException e) {
|
newAnswerField.setText("");
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
newQuestionField.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected void onEditAction(ActionEvent event) {
|
protected void onEditAction(ActionEvent event) {
|
||||||
ObservableList<Integer> list = table.getSelectionModel().getSelectedIndices();
|
ObservableList<TestItem> list = table.getSelectionModel().getSelectedItems();
|
||||||
if (list.size() != 1) return;
|
if (list.size() != 1) return;
|
||||||
int index = list.get(0);
|
editing.set(list.get(0));
|
||||||
try {
|
newQuestionField.setText(list.get(0).getQuestion());
|
||||||
FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/edit.fxml"));
|
newAnswerField.setText(list.get(0).getAnswer());
|
||||||
Parent root = loader.load();
|
saved.set(false);
|
||||||
|
newQuestionField.requestFocus();
|
||||||
((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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
|
@ -151,15 +140,14 @@ public class TableController implements Initializable {
|
||||||
protected void onDuplicateAction(ActionEvent event) {
|
protected void onDuplicateAction(ActionEvent event) {
|
||||||
if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false);
|
if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false);
|
||||||
for (int i : table.getSelectionModel().getSelectedIndices())
|
for (int i : table.getSelectionModel().getSelectedIndices())
|
||||||
table.getItems().add(new TestItem(table.getItems().get(i)));
|
data.add(new TestItem(filtered.get(i)));
|
||||||
table.requestFocus();
|
table.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected void onDeleteAction(ActionEvent event) {
|
protected void onDeleteAction(ActionEvent event) {
|
||||||
if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false);
|
if (table.getSelectionModel().getSelectedIndices().size() > 0) saved.set(false);
|
||||||
for (int i : table.getSelectionModel().getSelectedIndices())
|
data.removeAll(table.getSelectionModel().getSelectedItems());
|
||||||
table.getItems().remove(i);
|
|
||||||
table.requestFocus();
|
table.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +158,32 @@ public class TableController implements Initializable {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected void onTestAction(ActionEvent event) {
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,14 @@
|
||||||
<children>
|
<children>
|
||||||
<HBox alignment="CENTER_LEFT" spacing="5.0">
|
<HBox alignment="CENTER_LEFT" spacing="5.0">
|
||||||
<children>
|
<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>
|
||||||
<Tooltip text="Add a new entry to the table" />
|
<Tooltip text="Add a new entry to the table" />
|
||||||
</tooltip>
|
</tooltip>
|
||||||
</Button>
|
</Button>
|
||||||
|
<TextField fx:id="searchField" promptText="Search..." />
|
||||||
<HBox alignment="CENTER_RIGHT" spacing="5.0" HBox.hgrow="ALWAYS" VBox.vgrow="ALWAYS">
|
<HBox alignment="CENTER_RIGHT" spacing="5.0" HBox.hgrow="ALWAYS" VBox.vgrow="ALWAYS">
|
||||||
<children>
|
<children>
|
||||||
<Button layoutX="10.0" layoutY="273.0" onAction="#onTestAction" prefWidth="105.0" text="_Test all">
|
<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" />
|
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||||
</VBox.margin>
|
</VBox.margin>
|
||||||
</HBox>
|
</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>
|
<columns>
|
||||||
<TableColumn fx:id="questionCol" prefWidth="75.0" text="Question" />
|
<TableColumn fx:id="questionCol" prefWidth="75.0" text="Question" />
|
||||||
<TableColumn fx:id="answerCol" prefWidth="75.0" text="Answer" />
|
<TableColumn fx:id="answerCol" prefWidth="75.0" text="Answer" />
|
||||||
|
|
Loading…
Reference in a new issue