Skip to content

Commit d54cdb5

Browse files
committed
added ability to edit individual Work Items closes #28 closes #29
1 parent 4fa50bf commit d54cdb5

File tree

9 files changed

+358
-8
lines changed

9 files changed

+358
-8
lines changed

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@
6464
<artifactId>spring-boot-starter-test</artifactId>
6565
<scope>test</scope>
6666
</dependency>
67+
68+
<dependency>
69+
<groupId>no.tornado</groupId>
70+
<artifactId>tornadofx-controls</artifactId>
71+
<version>1.0.3</version>
72+
</dependency>
6773

6874
<dependency>
6975
<groupId>org.flywaydb</groupId>

src/main/java/de/doubleslash/keeptime/common/Resources.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,13 @@ public enum RESOURCE {
3939
FXML_REPORT("/layouts/report.fxml"),
4040
FXML_ABOUT("/layouts/about.fxml"),
4141
FXML_MANAGE_PROJECT("/layouts/manage-project.fxml"),
42+
FXML_MANAGE_WORK("/layouts/manage-work.fxml"),
4243

4344
// icon
4445
ICON_MAIN("/icons/icon.png"),
4546

4647
;
48+
4749
String resourceLocation;
4850

4951
private RESOURCE(final String resourceLocation) {

src/main/java/de/doubleslash/keeptime/controller/Controller.java

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,17 +184,40 @@ public void editProject(final Project projectToBeUpdated, final Project newValue
184184
model.getProjectRepository().saveAll(changedProjects);
185185
}
186186

187+
public void editWork(final Work workToBeEdited, final Work newValuedWork) {
188+
LOG.info("Changing work '{}' to '{}'.", workToBeEdited, newValuedWork);
189+
int index = model.getPastWorkItems().size() - 1;
190+
if (model.getPastWorkItems().contains(workToBeEdited)) {
191+
index = model.getPastWorkItems().indexOf(workToBeEdited);
192+
model.getPastWorkItems().remove(index);
193+
}
194+
195+
workToBeEdited.setCreationDate(newValuedWork.getCreationDate());
196+
workToBeEdited.setStartTime(newValuedWork.getStartTime());
197+
workToBeEdited.setEndTime(newValuedWork.getEndTime());
198+
workToBeEdited.setNotes(newValuedWork.getNotes());
199+
workToBeEdited.setProject(newValuedWork.getProject());
200+
201+
final LocalDate dateNow = dateProvider.dateTimeNow().toLocalDate();
202+
if (dateNow.equals(workToBeEdited.getCreationDate())) {
203+
model.getPastWorkItems().add(index, workToBeEdited);
204+
}
205+
206+
model.getWorkRepository().save(workToBeEdited);
207+
208+
}
209+
187210
/**
188211
* Changes the indexes of the originalList parameter to have a consistent order.
189212
*
190213
* @param originalList
191-
* list of all projects to adapt the indexes for
214+
* list of all projects to adapt the indexes for
192215
* @param changedProject
193-
* the project which has changed which already has the new index
216+
* the project which has changed which already has the new index
194217
* @param oldIndex
195-
* the old index of the changed project
218+
* the old index of the changed project
196219
* @param newIndex
197-
* the new index of the changed project (which the projects also already has)
220+
* the new index of the changed project (which the projects also already has)
198221
* @return all projects whose index has been adapted
199222
*/
200223
List<Project> resortProjectIndexes(final List<Project> originalList, final Project changedProject,
@@ -231,9 +254,9 @@ List<Project> resortProjectIndexes(final List<Project> originalList, final Proje
231254
* Decreases all indexes by one, after the removed index
232255
*
233256
* @param originalList
234-
* list of all projects to adapt the indexes for
257+
* list of all projects to adapt the indexes for
235258
* @param removedIndex
236-
* the index which has been removed
259+
* the index which has been removed
237260
* @return all projects whose index has been adapted
238261
*/
239262
List<Project> adaptProjectIndexesAfterRemoving(final List<Project> originalList, final int removedIndex) {
@@ -298,4 +321,5 @@ public long calcSeconds(final List<Work> workItems) {
298321

299322
return seconds;
300323
}
324+
301325
}

src/main/java/de/doubleslash/keeptime/model/Work.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ public class Work {
4545
@Lob
4646
private String notes;
4747

48-
public Work() {}
48+
public Work() {
49+
}
4950

5051
public Work(final LocalDate creationDate, final LocalDateTime startTime, final LocalDateTime endTime,
5152
final Project project, final String notes) {
@@ -89,6 +90,10 @@ public Project getProject() {
8990
return project;
9091
}
9192

93+
public void setProject(final Project project) {
94+
this.project = project;
95+
}
96+
9297
public String getNotes() {
9398
return notes;
9499
}
@@ -97,4 +102,10 @@ public void setNotes(final String notes) {
97102
this.notes = notes;
98103
}
99104

105+
@Override
106+
public String toString() {
107+
return "Work [id=" + id + ", creationDate=" + creationDate + ", startTime=" + startTime + ", endTime=" + endTime
108+
+ ", projectName=" + project.getName() + ", notes=" + notes + "]";
109+
}
110+
100111
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Copyright 2019 doubleSlash Net Business GmbH
2+
//
3+
// This file is part of KeepTime.
4+
// KeepTime is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package de.doubleslash.keeptime.view;
18+
19+
import org.slf4j.Logger;
20+
import org.slf4j.LoggerFactory;
21+
22+
import de.doubleslash.keeptime.model.Model;
23+
import de.doubleslash.keeptime.model.Project;
24+
import de.doubleslash.keeptime.model.Work;
25+
import javafx.fxml.FXML;
26+
import javafx.scene.control.ComboBox;
27+
import javafx.scene.control.DatePicker;
28+
import javafx.scene.control.ListCell;
29+
import javafx.scene.control.ListView;
30+
import javafx.scene.control.TextField;
31+
import javafx.scene.layout.GridPane;
32+
import javafx.util.Callback;
33+
import javafx.util.StringConverter;
34+
import tornadofx.control.DateTimePicker;
35+
36+
public class ManageWorkController {
37+
38+
private static final Logger LOG = LoggerFactory.getLogger(ManageWorkController.class);
39+
40+
private Model model;
41+
42+
@FXML
43+
private GridPane grid;
44+
45+
@FXML
46+
private DateTimePicker startTimePicker;
47+
48+
@FXML
49+
private DateTimePicker endTimePicker;
50+
51+
@FXML
52+
private DatePicker creationDatePicker;
53+
54+
@FXML
55+
private TextField noteTextBox;
56+
57+
@FXML
58+
private ComboBox<Project> projectComboBox;
59+
60+
public void setModel(final Model model) {
61+
this.model = model;
62+
}
63+
64+
public void initializeWith(final Work work) {
65+
LOG.info("Setting values.");
66+
startTimePicker.setDateTimeValue(work.getStartTime());
67+
startTimePicker.setFormat("yyyy-MM-dd HH:mm:ss");
68+
endTimePicker.setDateTimeValue(work.getEndTime());
69+
endTimePicker.setFormat("yyyy-MM-dd HH:mm:ss");
70+
creationDatePicker.setValue(work.getCreationDate());
71+
noteTextBox.setText(work.getNotes());
72+
projectComboBox.getItems().addAll(model.getAvailableProjects());
73+
74+
projectComboBox.setCellFactory(new Callback<ListView<Project>, ListCell<Project>>() {
75+
76+
@Override
77+
public ListCell<Project> call(final ListView<Project> l) {
78+
return new ListCell<Project>() {
79+
80+
@Override
81+
protected void updateItem(final Project item, final boolean empty) {
82+
super.updateItem(item, empty);
83+
if (item == null || empty) {
84+
setGraphic(null);
85+
} else {
86+
setText(item.getName());
87+
}
88+
}
89+
};
90+
}
91+
});
92+
93+
projectComboBox.setConverter(new StringConverter<Project>() {
94+
95+
@Override
96+
public String toString(final Project project) {
97+
if (project == null) {
98+
return null;
99+
} else {
100+
return project.getName();
101+
}
102+
}
103+
104+
@Override
105+
public Project fromString(final String string) {
106+
return null;
107+
}
108+
});
109+
110+
projectComboBox.getSelectionModel().select(work.getProject());
111+
112+
}
113+
114+
public Work getWorkFromUserInput() {
115+
116+
return new Work(creationDatePicker.getValue(), startTimePicker.getDateTimeValue(),
117+
endTimePicker.getDateTimeValue(), projectComboBox.getSelectionModel().getSelectedItem(),
118+
noteTextBox.getText());
119+
}
120+
121+
}

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

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
package de.doubleslash.keeptime.view;
1818

19+
import java.io.IOException;
1920
import java.time.LocalDate;
2021
import java.util.Comparator;
2122
import java.util.List;
23+
import java.util.Optional;
2224
import java.util.SortedSet;
2325
import java.util.TreeSet;
2426
import java.util.stream.Collectors;
@@ -30,21 +32,29 @@
3032

3133
import de.doubleslash.keeptime.common.DateFormatter;
3234
import de.doubleslash.keeptime.common.FontProvider;
35+
import de.doubleslash.keeptime.common.Resources;
36+
import de.doubleslash.keeptime.common.Resources.RESOURCE;
3337
import de.doubleslash.keeptime.controller.Controller;
38+
import de.doubleslash.keeptime.exceptions.FXMLLoaderException;
3439
import de.doubleslash.keeptime.model.Model;
3540
import de.doubleslash.keeptime.model.Project;
3641
import de.doubleslash.keeptime.model.Work;
3742
import javafx.event.ActionEvent;
3843
import javafx.event.EventHandler;
3944
import javafx.fxml.FXML;
45+
import javafx.fxml.FXMLLoader;
4046
import javafx.geometry.Insets;
4147
import javafx.geometry.Pos;
4248
import javafx.scene.Node;
4349
import javafx.scene.canvas.Canvas;
4450
import javafx.scene.control.Button;
51+
import javafx.scene.control.ButtonType;
52+
import javafx.scene.control.ContextMenu;
4553
import javafx.scene.control.DateCell;
4654
import javafx.scene.control.DatePicker;
55+
import javafx.scene.control.Dialog;
4756
import javafx.scene.control.Label;
57+
import javafx.scene.control.MenuItem;
4858
import javafx.scene.control.ScrollPane;
4959
import javafx.scene.input.Clipboard;
5060
import javafx.scene.input.ClipboardContent;
@@ -53,6 +63,7 @@
5363
import javafx.scene.layout.GridPane;
5464
import javafx.scene.layout.HBox;
5565
import javafx.scene.shape.Circle;
66+
import javafx.stage.Stage;
5667
import javafx.util.Callback;
5768

5869
public class ReportController {
@@ -93,6 +104,8 @@ public class ReportController {
93104

94105
private Controller controller;
95106

107+
private Stage stage;
108+
96109
private ColorTimeLine colorTimeLine;
97110

98111
@FXML
@@ -186,6 +199,29 @@ private void updateReport(final LocalDate dateToShow) {
186199
workedHoursLabel.setFont(FontProvider.getDefaultFont());
187200
this.gridPane.add(workedHoursLabel, 2, rowIndex);
188201

202+
final HBox clickDummy = new HBox();
203+
final ContextMenu contextMenu = new ContextMenu();
204+
final MenuItem editMenuItem = new MenuItem("edit");
205+
206+
editMenuItem.setOnAction(e -> {
207+
LOG.info("Edit work");
208+
final Dialog<Work> dialog = setupEditWorkDialog("Edit work", "Edit work ", work);
209+
210+
final Optional<Work> result = dialog.showAndWait();
211+
212+
result.ifPresent(editedWork -> {
213+
controller.editWork(work, editedWork);
214+
this.update();
215+
});
216+
});
217+
218+
contextMenu.getItems().add(editMenuItem);
219+
220+
clickDummy.setOnContextMenuRequested(
221+
event -> contextMenu.show(clickDummy, event.getScreenX(), event.getScreenY()));
222+
223+
this.gridPane.add(clickDummy, 0, rowIndex, 3, 1);
224+
189225
rowIndex++;
190226
}
191227
bProjectReport.setUserData(pr.getNotes(true));
@@ -197,6 +233,43 @@ private void updateReport(final LocalDate dateToShow) {
197233

198234
}
199235

236+
private Dialog<Work> setupEditWorkDialog(final String title, final String headerText, final Work work) {
237+
final Dialog<Work> dialog = new Dialog<>();
238+
239+
dialog.initOwner(stage);
240+
dialog.setTitle(title);
241+
dialog.setHeaderText(headerText);
242+
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
243+
244+
final GridPane grid = setUpEditWorkGridPane(work, dialog);
245+
dialog.getDialogPane().setContent(grid);
246+
247+
return dialog;
248+
}
249+
250+
private GridPane setUpEditWorkGridPane(final Work work, final Dialog<Work> dialog) {
251+
final GridPane grid;
252+
final FXMLLoader loader = new FXMLLoader(Resources.getResource(RESOURCE.FXML_MANAGE_WORK));
253+
try {
254+
grid = loader.load();
255+
} catch (final IOException e) {
256+
throw new FXMLLoaderException("Error while loading '" + Resources.RESOURCE.FXML_MANAGE_WORK + "'.", e);
257+
}
258+
final ManageWorkController manageWorkController = loader.getController();
259+
manageWorkController.setModel(model);
260+
manageWorkController.initializeWith(work);
261+
262+
dialog.setResultConverter(dialogButton -> {
263+
if (dialogButton == ButtonType.OK) {
264+
return manageWorkController.getWorkFromUserInput();
265+
}
266+
// TODO: Do you really want to return null?
267+
return null;
268+
});
269+
270+
return grid;
271+
}
272+
200273
private Button createProjectReport() {
201274
final Button bProjectReport = new Button("Copy to clipboard");
202275
final EventHandler<ActionEvent> eventListener = new EventHandler<ActionEvent>() {
@@ -248,4 +321,8 @@ public void update() {
248321
public void setController(final Controller controller) {
249322
this.controller = controller;
250323
}
324+
325+
public void setStage(final Stage stage) {
326+
this.stage = stage;
327+
}
251328
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,9 +381,10 @@ private void loadSubStages() {
381381
reportController = fxmlLoader.getController();
382382
reportController.setModel(model);
383383
reportController.setController(controller);
384+
384385
reportStage = new Stage();
385386
reportStage.initModality(Modality.APPLICATION_MODAL);
386-
387+
reportController.setStage(reportStage);
387388
final Scene reportScene = new Scene(root);
388389
reportScene.setOnKeyPressed(ke -> {
389390
if (ke.getCode() == KeyCode.ESCAPE) {

0 commit comments

Comments
 (0)