Skip to content
Snippets Groups Projects
Commit 05e03cc7 authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

Fixes and cleanup, ready to merge into master.

parent 4e59e520
No related branches found
No related tags found
No related merge requests found
Showing
with 90 additions and 44 deletions
......@@ -125,6 +125,6 @@ public class TodoModel implements Iterable<AbstractTodoList> {
* @return a function that gets the todo items of a todo list in the corresponding sort order
*/
public Function<TodoList, Collection<TodoItem>> getSortedTodoItemsProvider() {
return getSortedTodoItemsProvider(getSettings().getTodoItemSortOrder());
return getSortedTodoItemsProvider(getSettings().getTodoItemsSortOrder());
}
}
package todolist.core;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
......@@ -9,6 +8,11 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* A class for managing settings,
* i.e. properties that control behavior of other classes.
* Changes to settings can be listened to and vetoed by throwing an exception.
*/
public class TodoSettings {
private Collection<TodoSettingsListener> todoSettingsListeners = new ArrayList<>();
......@@ -23,7 +27,7 @@ public class TodoSettings {
private Map<String, Object> oldValues = null;
private void fireSettingChanged(String property, Object oldValue, Object newValue) {
private void handleSettingChanged(String property, Object oldValue, Object newValue) {
if (Objects.equals(oldValue, newValue)) {
return;
}
......@@ -48,21 +52,28 @@ public class TodoSettings {
}
}
/**
* Call to indicate that new values will be used, and
* old values can be forgotten.
*/
public void applyChanges() {
oldValues = null;
}
private void cancelChange(String property) {
Object oldValue = oldValues.get(property);
var oldValue = oldValues.get(property);
var setterName = "set" + Character.toUpperCase(property.charAt(0)) + property.substring(1);
try {
Method setter = getClass().getMethod("set" + Character.toUpperCase(property.charAt(0)) + property.substring(1),
oldValue.getClass());
var setter = getClass().getMethod(setterName, oldValue.getClass());
setter.invoke(this, oldValue);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
// ignore
}
}
/**
* Call to rollback changes to old values.
*/
public void cancelChanges() {
try {
for (String property : oldValues.keySet()) {
......@@ -75,21 +86,30 @@ public class TodoSettings {
//
/**
* Enum for possible values of sort order for items.
*/
public enum TodoItemsSortOrder {
NONE, UNCHECKED_CHECKED, CHECKED_UNCHECKED
}
private TodoItemsSortOrder todoItemSortOrder = TodoItemsSortOrder.UNCHECKED_CHECKED;
private TodoItemsSortOrder todoItemsSortOrder = TodoItemsSortOrder.NONE;
public TodoItemsSortOrder getTodoItemSortOrder() {
return todoItemSortOrder;
public TodoItemsSortOrder getTodoItemsSortOrder() {
return todoItemsSortOrder;
}
public final static String TODO_ITEM_SORT_ORDER_SETTING = "todoItemSortOrder";
// settings name must correspond to setter name!
public static final String TODO_ITEM_SORT_ORDER_SETTING = "todoItemsSortOrder";
public void setTodoItemSortOrder(TodoItemsSortOrder todoItemSortOrder) {
Object oldValue = this.todoItemSortOrder;
this.todoItemSortOrder = todoItemSortOrder;
fireSettingChanged(TODO_ITEM_SORT_ORDER_SETTING, oldValue, todoItemSortOrder);
/**
* Sets the todoItemsSortOrder property, and notifies listeners.
*
* @param todoItemSortOrder the new todoItemSortOrder value
*/
public void setTodoItemsSortOrder(TodoItemsSortOrder todoItemSortOrder) {
Object oldValue = this.todoItemsSortOrder;
this.todoItemsSortOrder = todoItemSortOrder;
handleSettingChanged(TODO_ITEM_SORT_ORDER_SETTING, oldValue, todoItemSortOrder);
}
}
......@@ -2,6 +2,17 @@ package todolist.core;
import java.util.Collection;
/**
* Listener for changes to TodoSettings.
*/
public interface TodoSettingsListener {
/**
* Called when settings are changed.
* Changes may be vetoed by throwing an exception.
*
* @param settings the TodoSettings that changed
* @param changedProperties the properties (names) that changed
*/
public void todoSettingsChanged(TodoSettings settings, Collection<String> changedProperties);
}
\ No newline at end of file
......@@ -29,7 +29,7 @@ class TodoSettingsDeserializer extends JsonDeserializer<TodoSettings> {
if (todoItemsSortOrderNode instanceof TextNode) {
try {
TodoItemsSortOrder sortOrder = TodoItemsSortOrder.valueOf(todoItemsSortOrderNode.asText());
settings.setTodoItemSortOrder(sortOrder);
settings.setTodoItemsSortOrder(sortOrder);
} catch (IllegalArgumentException iae) {
// ignore unknown sort order constant
}
......
......@@ -9,7 +9,7 @@ import todolist.core.TodoSettings;
class TodoSettingsSerializer extends JsonSerializer<TodoSettings> {
/*
* format: { "todoItemSortOrder": "..." }
* format: { "todoItemsSortOrder": "..." }
*/
@Override
......@@ -17,7 +17,7 @@ class TodoSettingsSerializer extends JsonSerializer<TodoSettings> {
SerializerProvider serializerProvider)
throws IOException {
jsonGen.writeStartObject();
jsonGen.writeStringField(TodoSettings.TODO_ITEM_SORT_ORDER_SETTING, settings.getTodoItemSortOrder().name());
jsonGen.writeStringField(TodoSettings.TODO_ITEM_SORT_ORDER_SETTING, settings.getTodoItemsSortOrder().name());
jsonGen.writeEndObject();
}
}
......@@ -78,7 +78,7 @@ public class TodoModelTest {
List<TodoItem> allAddedItems = new ArrayList<>(todoList.getTodoItems());
Collection<TodoItem> expectedOrder = Stream.of(sortedTodoItemIndices).map(allAddedItems::get).collect(Collectors.toList());
TodoListTest.checkItems(TodoModel.getSortedTodoItemsProvider(sortOrder).apply(todoList), expectedOrder.toArray(new TodoItem[expectedOrder.size()]));
todoModel.getSettings().setTodoItemSortOrder(sortOrder);
todoModel.getSettings().setTodoItemsSortOrder(sortOrder);
TodoListTest.checkItems(todoModel.getSortedTodoItemsProvider().apply(todoList), expectedOrder.toArray(new TodoItem[expectedOrder.size()]));
}
......
......@@ -19,32 +19,32 @@ public class TodoSettingsTest {
@BeforeEach
public void setup() {
todoSettings = new TodoSettings();
todoSettings.setTodoItemSortOrder(TodoItemsSortOrder.NONE);
todoSettings.setTodoItemsSortOrder(TodoItemsSortOrder.NONE);
todoSettings.applyChanges();
}
@Test
public void testSetTodoItemsSortOrder_changesProperty() {
todoSettings.setTodoItemSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
assertEquals(TodoItemsSortOrder.CHECKED_UNCHECKED, todoSettings.getTodoItemSortOrder());
todoSettings.setTodoItemsSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
assertEquals(TodoItemsSortOrder.CHECKED_UNCHECKED, todoSettings.getTodoItemsSortOrder());
}
private static Collection<String> TODO_ITEMS_SORT_ORDER_SINGLETON_COLLECTION = Collections.singleton("todoItemSortOrder");
private static Collection<String> TODO_ITEMS_SORT_ORDER_SINGLETON_COLLECTION = Collections.singleton(TodoSettings.TODO_ITEM_SORT_ORDER_SETTING);
@Test
public void testSetTodoItemsSortOrder_todoSettingsChangedCalledWhenPropertyChanged() {
TodoSettingsListener todoSettingsListener = mock(TodoSettingsListener.class);
todoSettings.addTodoSettingsListener(todoSettingsListener);
todoSettings.setTodoItemSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
assertEquals(TodoItemsSortOrder.CHECKED_UNCHECKED, todoSettings.getTodoItemSortOrder());
todoSettings.setTodoItemsSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
assertEquals(TodoItemsSortOrder.CHECKED_UNCHECKED, todoSettings.getTodoItemsSortOrder());
// listener called when property changed
verify(todoSettingsListener, times(1)).todoSettingsChanged(todoSettings, TODO_ITEMS_SORT_ORDER_SINGLETON_COLLECTION);
todoSettings.setTodoItemSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
assertEquals(TodoItemsSortOrder.CHECKED_UNCHECKED, todoSettings.getTodoItemSortOrder());
todoSettings.setTodoItemsSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
assertEquals(TodoItemsSortOrder.CHECKED_UNCHECKED, todoSettings.getTodoItemsSortOrder());
// listener not called when property didn't change
verify(todoSettingsListener, times(1)).todoSettingsChanged(todoSettings, TODO_ITEMS_SORT_ORDER_SINGLETON_COLLECTION);
todoSettings.setTodoItemSortOrder(TodoItemsSortOrder.UNCHECKED_CHECKED);
assertEquals(TodoItemsSortOrder.UNCHECKED_CHECKED, todoSettings.getTodoItemSortOrder());
todoSettings.setTodoItemsSortOrder(TodoItemsSortOrder.UNCHECKED_CHECKED);
assertEquals(TodoItemsSortOrder.UNCHECKED_CHECKED, todoSettings.getTodoItemsSortOrder());
// listener called another time when property changed
verify(todoSettingsListener, times(2)).todoSettingsChanged(todoSettings, TODO_ITEMS_SORT_ORDER_SINGLETON_COLLECTION);
}
......@@ -53,7 +53,7 @@ public class TodoSettingsTest {
public void testSetTodoItemsSortOrder_todoSettingsChangedNotCalledWhenPropertyNotChanged() {
TodoSettingsListener todoSettingsListener = mock(TodoSettingsListener.class);
todoSettings.addTodoSettingsListener(todoSettingsListener);
todoSettings.setTodoItemSortOrder(TodoItemsSortOrder.NONE);
todoSettings.setTodoItemsSortOrder(TodoItemsSortOrder.NONE);
verifyNoInteractions(todoSettingsListener);
}
......@@ -61,22 +61,22 @@ public class TodoSettingsTest {
public void testSetTodoItemsSortOrder_applyChanges() {
TodoSettingsListener todoSettingsListener = mock(TodoSettingsListener.class);
todoSettings.addTodoSettingsListener(todoSettingsListener);
todoSettings.setTodoItemSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
todoSettings.setTodoItemsSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
// listener called when property changed
verify(todoSettingsListener, times(1)).todoSettingsChanged(todoSettings, TODO_ITEMS_SORT_ORDER_SINGLETON_COLLECTION);
todoSettings.applyChanges();
// apply changes not canceled
assertEquals(TodoItemsSortOrder.CHECKED_UNCHECKED, todoSettings.getTodoItemSortOrder());
assertEquals(TodoItemsSortOrder.CHECKED_UNCHECKED, todoSettings.getTodoItemsSortOrder());
}
@Test
public void testSetTodoItemsSortOrder_cancelChanges() {
TodoSettingsListener todoSettingsListener = mock(TodoSettingsListener.class);
todoSettings.addTodoSettingsListener(todoSettingsListener);
todoSettings.setTodoItemSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
todoSettings.setTodoItemsSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
todoSettings.cancelChanges();
// property change(s) rolled back
assertEquals(TodoItemsSortOrder.NONE, todoSettings.getTodoItemSortOrder());
assertEquals(TodoItemsSortOrder.NONE, todoSettings.getTodoItemsSortOrder());
}
@Test
......@@ -84,9 +84,9 @@ public class TodoSettingsTest {
TodoSettingsListener todoSettingsListener = mock(TodoSettingsListener.class);
doThrow(IllegalStateException.class).when(todoSettingsListener).todoSettingsChanged(todoSettings, TODO_ITEMS_SORT_ORDER_SINGLETON_COLLECTION);
todoSettings.addTodoSettingsListener(todoSettingsListener);
todoSettings.setTodoItemSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
todoSettings.setTodoItemsSortOrder(TodoItemsSortOrder.CHECKED_UNCHECKED);
// property change rolled back
assertEquals(TodoItemsSortOrder.NONE, todoSettings.getTodoItemSortOrder());
assertEquals(TodoItemsSortOrder.NONE, todoSettings.getTodoItemsSortOrder());
verify(todoSettingsListener, times(2)).todoSettingsChanged(todoSettings, TODO_ITEMS_SORT_ORDER_SINGLETON_COLLECTION);
}
}
......@@ -132,12 +132,12 @@ public class TodoModuleTest {
@Test
public void testTodoSettings() {
TodoSettings settings = new TodoSettings();
settings.setTodoItemSortOrder(TodoItemsSortOrder.UNCHECKED_CHECKED);
settings.setTodoItemsSortOrder(TodoItemsSortOrder.UNCHECKED_CHECKED);
try {
String json = mapper.writeValueAsString(settings);
assertEquals(defaultTodoSettings.replaceAll("\\s+", ""), mapper.writeValueAsString(settings));
TodoSettings settings2 = mapper.readValue(json, TodoSettings.class);
assertEquals(settings.getTodoItemSortOrder(), settings2.getTodoItemSortOrder());
assertEquals(settings.getTodoItemsSortOrder(), settings2.getTodoItemsSortOrder());
} catch (JsonProcessingException e) {
fail(e.getMessage());
}
......
......@@ -8,6 +8,9 @@ import javafx.scene.input.TransferMode;
import todolist.core.TodoItem;
import todolist.core.TodoList;
/**
* Handles dragging of ListCells in a ListView of TodoItems in a TodoList.
*/
public class TodoItemListCellDragHandler {
private TodoList todoList;
......
......@@ -15,8 +15,8 @@ import todolist.core.AbstractTodoList;
import todolist.core.TodoList;
import todolist.core.TodoModel;
import todolist.core.TodoSettings;
import todolist.core.TodoSettingsListener;
import todolist.core.TodoSettings.TodoItemsSortOrder;
import todolist.core.TodoSettingsListener;
import todolist.ui.util.SceneTarget;
/**
......@@ -40,6 +40,12 @@ public class TodoModelController implements TodoSettingsListener {
@FXML
TodoListController todoListViewController;
/**
* Sets the TodoModelAccess for this controller,
* so data can come from different sources.
*
* @param todoModelAccess the new TodoModelAccess to use
*/
public void setTodoModelAccess(TodoModelAccess todoModelAccess) {
this.todoModelAccess = todoModelAccess;
updateTodoItemsProvider();
......@@ -47,6 +53,7 @@ public class TodoModelController implements TodoSettingsListener {
todoModelAccess.getTodoSettings().addTodoSettingsListener(this);
}
@Override
public void todoSettingsChanged(TodoSettings settings, Collection<String> changedProperties) {
if (changedProperties.contains(TodoSettings.TODO_ITEM_SORT_ORDER_SETTING)) {
updateTodoItemsProvider();
......@@ -54,7 +61,7 @@ public class TodoModelController implements TodoSettingsListener {
}
private void updateTodoItemsProvider() {
TodoItemsSortOrder sortOrder = this.todoModelAccess.getTodoSettings().getTodoItemSortOrder();
TodoItemsSortOrder sortOrder = this.todoModelAccess.getTodoSettings().getTodoItemsSortOrder();
todoListViewController.setTodoItemsProvider(TodoModel.getSortedTodoItemsProvider(sortOrder));
}
......
......@@ -7,6 +7,9 @@ import todolist.core.TodoSettings;
import todolist.core.TodoSettings.TodoItemsSortOrder;
import todolist.ui.util.SceneTarget;
/**
* Controller for editing TodoSettings.
*/
public class TodoSettingsController {
private TodoSettings todoSettings = new TodoSettings();
......@@ -30,7 +33,7 @@ public class TodoSettingsController {
void initialize() {
todoItemsSortOrderSelector.setOnAction(actionEvent -> {
int ordinal = todoItemsSortOrderSelector.getSelectionModel().getSelectedIndex();
getTodoSettings().setTodoItemSortOrder(TodoItemsSortOrder.values()[ordinal]);
getTodoSettings().setTodoItemsSortOrder(TodoItemsSortOrder.values()[ordinal]);
});
updateView();
}
......@@ -40,7 +43,7 @@ public class TodoSettingsController {
}
private void updateView() {
TodoItemsSortOrder sortOrder = getTodoSettings().getTodoItemSortOrder();
TodoItemsSortOrder sortOrder = getTodoSettings().getTodoItemsSortOrder();
todoItemsSortOrderSelector.getSelectionModel().select(sortOrder.ordinal());
}
}
\ No newline at end of file
......@@ -6,6 +6,9 @@ import javafx.scene.Scene;
import javafx.scene.control.Control;
import javafx.stage.Stage;
/**
* Helper class for buttons that transition to a specific scene.
*/
public class SceneTarget {
private Scene scene;
......
......@@ -44,8 +44,7 @@ public class TodoSettingsResource {
/**
* Replaces the TodoSettings.
*
* @param todoSettings the todoSettings to set
* @return true if it was added, false if it replaced
* @param todoSettings the new TodoSettings to use
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment