Skip to content

Commit 6711ac8

Browse files
committed
#178: add dialog to import multiple projects at once. change project created to use "taskName - project" instead of other way around
1 parent c2034f0 commit 6711ac8

File tree

2 files changed

+77
-37
lines changed

2 files changed

+77
-37
lines changed

src/main/java/de/doubleslash/keeptime/view/MapExternalProjectsController.java

Lines changed: 76 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,20 @@
2727
import javafx.beans.property.SimpleObjectProperty;
2828
import javafx.beans.property.SimpleStringProperty;
2929
import javafx.collections.FXCollections;
30+
import javafx.collections.ListChangeListener;
3031
import javafx.collections.ObservableList;
3132
import javafx.collections.transformation.FilteredList;
3233
import javafx.fxml.FXML;
3334
import javafx.scene.control.*;
3435
import javafx.scene.layout.VBox;
35-
import javafx.scene.paint.Color;
3636
import javafx.stage.Stage;
3737
import org.slf4j.Logger;
3838
import org.slf4j.LoggerFactory;
3939
import org.springframework.stereotype.Component;
4040

4141
import java.time.LocalDate;
4242
import java.util.List;
43+
import java.util.Optional;
4344

4445
@Component
4546
public class MapExternalProjectsController {
@@ -61,9 +62,6 @@ public class MapExternalProjectsController {
6162
@FXML
6263
private Button cancelButton;
6364

64-
@FXML
65-
private ComboBox<HeimatTask> addNewProjectComboBox;
66-
6765
@FXML
6866
private Button addNewProjectButton;
6967

@@ -165,7 +163,52 @@ protected void updateItem(HeimatTask item, boolean empty) {
165163

166164
mappingTableView.getColumns().addAll(keepTimeColumn, externalColumn);
167165

168-
addNewProjectComboBox.setCellFactory(param -> new ListCell<>() {
166+
addNewProjectButton.setOnAction(e -> {
167+
final List<HeimatTask> unmappedHeimatTasks = externalProjects.stream().filter(ht -> {
168+
final boolean alreadyMapped = value.stream()
169+
.anyMatch(mapping -> mapping.getHeimatTask() != null
170+
&& mapping.getHeimatTask().id() == ht.id());
171+
return !alreadyMapped;
172+
}).toList();
173+
List<HeimatTask> selectedItems = showMultiSelectDialog(externalProjectsObservableList, unmappedHeimatTasks);
174+
for (HeimatTask toBeCreatedHeimatTask : selectedItems) {
175+
final int sortIndex = model.getAvailableProjects().size();
176+
final Project project = controller.addNewProject(
177+
new Project(toBeCreatedHeimatTask.name() + " - " + toBeCreatedHeimatTask.taskHolderName(),
178+
toBeCreatedHeimatTask.bookingHint(), ColorHelper.randomColor(), true, sortIndex));
179+
newProjectMappings.add(new HeimatController.ProjectMapping(project, toBeCreatedHeimatTask));
180+
}
181+
});
182+
183+
saveButton.setOnAction(ae -> {
184+
heimatController.updateMappings(newProjectMappings);
185+
thisStage.close();
186+
});
187+
188+
cancelButton.setOnAction(ae -> thisStage.close());
189+
190+
List<String> warnings = existingAndInvalidMappings.invalidMappingsAsString();
191+
if (!warnings.isEmpty()) {
192+
Platform.runLater(() -> showInvalidMappingsDialog(warnings));
193+
}
194+
}
195+
196+
private List<HeimatTask> showMultiSelectDialog(final ObservableList<HeimatTask> externalProjectsObservableList,
197+
List<HeimatTask> unmappedHeimatTasks) {
198+
Dialog<List<HeimatTask>> dialog = new Dialog<>();
199+
dialog.setTitle("Import HEIMAT projects");
200+
dialog.setHeaderText("You can select mutliple items");
201+
dialog.initOwner(this.thisStage);
202+
dialog.setWidth(600);
203+
dialog.setHeight(500);
204+
205+
// Buttons
206+
ButtonType okButtonType = new ButtonType("OK", ButtonBar.ButtonData.OK_DONE);
207+
ButtonType cancelButtonType = new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
208+
dialog.getDialogPane().getButtonTypes().addAll(okButtonType, cancelButtonType);
209+
210+
ListView<HeimatTask> listView = new ListView<>();
211+
listView.setCellFactory(param -> new ListCell<>() {
169212
@Override
170213
protected void updateItem(HeimatTask item, boolean empty) {
171214
super.updateItem(item, empty);
@@ -178,41 +221,40 @@ protected void updateItem(HeimatTask item, boolean empty) {
178221
}
179222
}
180223
});
181-
addNewProjectComboBox.setButtonCell(new ListCell<>() {
182-
@Override
183-
protected void updateItem(HeimatTask item, boolean empty) {
184-
super.updateItem(item, empty);
185-
if (empty || item == null) {
186-
setText(null);
187-
} else {
188-
setText(item.taskHolderName() + " - " + item.name());
189-
}
224+
listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
225+
listView.setItems(externalProjectsObservableList);
226+
227+
Button selectAllUnmappedButton = new Button("Select All Unmapped");
228+
selectAllUnmappedButton.setOnAction(e -> {
229+
listView.getSelectionModel().clearSelection();
230+
for (HeimatTask ht : unmappedHeimatTasks) {
231+
listView.getSelectionModel().select(ht);
190232
}
233+
listView.requestFocus();
191234
});
192-
addNewProjectButton.disableProperty()
193-
.bind(addNewProjectComboBox.getSelectionModel().selectedItemProperty().isNull());
194-
addNewProjectButton.setOnAction(ae -> {
195-
final HeimatTask task = addNewProjectComboBox.getValue();
196-
final int sortIndex = model.getAvailableProjects().size();
197-
final Project project = controller.addNewProject(
198-
new Project(task.taskHolderName() + " - " + task.name(), task.bookingHint(), ColorHelper.randomColor(), true,
199-
sortIndex));
200-
newProjectMappings.add(new HeimatController.ProjectMapping(project, task));
201-
addNewProjectComboBox.getSelectionModel().clearSelection();
202-
});
203-
addNewProjectComboBox.setItems(externalProjectsObservableList);
204235

205-
saveButton.setOnAction(ae -> {
206-
heimatController.updateMappings(newProjectMappings);
207-
thisStage.close();
236+
VBox content = new VBox(10, selectAllUnmappedButton, listView);
237+
dialog.getDialogPane().setContent(content);
238+
final List<HeimatTask> emptyList = List.of();
239+
// Handle result when OK is clicked
240+
dialog.setResultConverter(dialogButton -> {
241+
if (dialogButton == okButtonType) {
242+
return listView.getSelectionModel().getSelectedItems().stream().toList();
243+
}
244+
return emptyList; // Cancel was clicked
208245
});
209246

210-
cancelButton.setOnAction(ae -> thisStage.close());
247+
Button okButton = (Button) dialog.getDialogPane().lookupButton(okButtonType);
248+
okButton.setText("Import (0)"); // Initial state
211249

212-
List<String> warnings = existingAndInvalidMappings.invalidMappingsAsString();
213-
if (!warnings.isEmpty()) {
214-
Platform.runLater(() -> showInvalidMappingsDialog(warnings));
215-
}
250+
// Listen for selection changes and update button text
251+
listView.getSelectionModel().getSelectedItems().addListener((ListChangeListener<HeimatTask>) change -> {
252+
int selectedCount = listView.getSelectionModel().getSelectedItems().size();
253+
okButton.setText("Import (" + selectedCount + ")");
254+
});
255+
256+
Optional<List<HeimatTask>> result = dialog.showAndWait();
257+
return result.orElse(emptyList);
216258
}
217259

218260
private void showInvalidMappingsDialog(final List<String> warnings) {

src/main/resources/layouts/externalProjectMapping.fxml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22

33
<?import javafx.scene.control.Button?>
4-
<?import javafx.scene.control.ComboBox?>
54
<?import javafx.scene.control.DatePicker?>
65
<?import javafx.scene.control.TableView?>
76
<?import javafx.scene.layout.AnchorPane?>
@@ -18,8 +17,7 @@
1817
</HBox>
1918
<HBox layoutX="5.0" layoutY="564.0" spacing="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.topAnchor="5.0">
2019
<children>
21-
<ComboBox fx:id="addNewProjectComboBox" prefHeight="25.0" prefWidth="210.0" />
22-
<Button fx:id="addNewProjectButton" mnemonicParsing="false" text="Import project" />
20+
<Button fx:id="addNewProjectButton" mnemonicParsing="false" text="Import project(s)" />
2321
</children>
2422
</HBox>
2523
<DatePicker fx:id="tasksForDateDatePicker" layoutX="371.0" layoutY="16.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="5.0" />

0 commit comments

Comments
 (0)