This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository jtimer. See http://git.chorem.org/jtimer.git commit 3ef0e1f57c2e76ffbf275f2d6af3f207dbf0936d Author: Eric Chatellier <chatellier@codelutin.com> Date: Wed Feb 24 13:39:33 2016 +0100 fixes #1319: Add a way to create a tree structure from a template --- src/main/java/org/chorem/jtimer/JTimer.java | 13 +-- src/main/java/org/chorem/jtimer/JTimerConfig.java | 19 ++++ .../org/chorem/jtimer/data/TimerDataManager.java | 40 +++++++- .../java/org/chorem/jtimer/ui/NewTaskPanel.java | 104 +++++++++++++++++++++ .../org/chorem/jtimer/resources/JTimer.properties | 1 + .../chorem/jtimer/resources/JTimer_fr.properties | 1 + .../java/org/chorem/jtimer/JTimerFactoryTest.java | 15 +++ .../org/chorem/jtimer/data/CommonVetoableTest.java | 2 +- .../chorem/jtimer/data/TimerDataManagerTest.java | 4 +- src/test/resources/jtimertest.properties | 11 +-- 10 files changed, 193 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/chorem/jtimer/JTimer.java b/src/main/java/org/chorem/jtimer/JTimer.java index f48a532..a5ba0b5 100644 --- a/src/main/java/org/chorem/jtimer/JTimer.java +++ b/src/main/java/org/chorem/jtimer/JTimer.java @@ -67,6 +67,7 @@ import org.chorem.jtimer.data.TimerCore; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; import org.chorem.jtimer.ui.HelpFrame; +import org.chorem.jtimer.ui.NewTaskPanel; import org.chorem.jtimer.ui.StatusBar; import org.chorem.jtimer.ui.TimerTaskEditor; import org.chorem.jtimer.ui.alert.AlertEditor; @@ -628,11 +629,11 @@ public class JTimer extends SingleFrameApplication implements TimerTask selectedTask = projectsAndTasksTable.getSelectedElements() .get(0); - String taskName = JOptionPane.showInputDialog(getMainFrame(), - resourceMap.getString("input.newTaskMessage", selectedTask - .getName()), resourceMap - .getString("input.newTaskTitle"), - JOptionPane.QUESTION_MESSAGE); + NewTaskPanel newTaskPanel = new NewTaskPanel(this, selectedTask); + JOptionPane.showMessageDialog(getMainFrame(), newTaskPanel, resourceMap + .getString("input.newTaskTitle"), JOptionPane.QUESTION_MESSAGE); + String taskName = newTaskPanel.getTaskName(); + String taskTemplate = newTaskPanel.getTaskTemplate(); if (taskName != null) { @@ -645,7 +646,7 @@ public class JTimer extends SingleFrameApplication implements t.setCreationDate(new Date()); try { - core.getData().addTask(selectedTask, t); + core.getData().addTask(selectedTask, t, taskTemplate); } catch (DataViolationException e) { displayErrorMessage(e.getExceptionKey()); } diff --git a/src/main/java/org/chorem/jtimer/JTimerConfig.java b/src/main/java/org/chorem/jtimer/JTimerConfig.java index 2812aa8..5817394 100644 --- a/src/main/java/org/chorem/jtimer/JTimerConfig.java +++ b/src/main/java/org/chorem/jtimer/JTimerConfig.java @@ -22,8 +22,12 @@ package org.chorem.jtimer; +import java.util.List; +import java.util.Map; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.json.simple.JSONValue; import org.nuiton.config.ApplicationConfig; import org.nuiton.config.ArgumentsParserException; @@ -141,6 +145,20 @@ public class JTimerConfig { } /** + * Get task template from configuration. + * + * @return task template as map + */ + public Map<String, List<?>> getTaskTemplates() { + String value = appConfig.getOption(JTimerOption.UI_TASK_TEMPLATES.key); + Map<String, List<?>> result = null; + if (value != null) { + result = (Map<String, List<?>>)JSONValue.parse(value); + } + return result; + } + + /** * Get close to systray option. * * @return close to systray @@ -187,6 +205,7 @@ public class JTimerConfig { UI_IDLE_TIME("jtimer.ui.idletime", "300"), UI_SHOW_CLOSED("jtimer.ui.showclosed", "false"), UI_CLOSE_TO_SYSTRAY("jtimer.ui.closetosystray", "true"), + UI_TASK_TEMPLATES("jtimer.ui.task.templates", null), UI_REPORT_FIRSTDAYOFWEEK("jtimer.ui.report.firstdayofweek", "0"); protected String key; diff --git a/src/main/java/org/chorem/jtimer/data/TimerDataManager.java b/src/main/java/org/chorem/jtimer/data/TimerDataManager.java index 014d1da..28a645f 100644 --- a/src/main/java/org/chorem/jtimer/data/TimerDataManager.java +++ b/src/main/java/org/chorem/jtimer/data/TimerDataManager.java @@ -34,9 +34,11 @@ import java.util.Map.Entry; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.chorem.jtimer.JTimer; import org.chorem.jtimer.entities.TimerAlert; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; +import org.json.simple.JSONObject; /** * Gere les donnees. Des objets peuvent s'enregistrer pour etre notifies des @@ -138,8 +140,9 @@ public class TimerDataManager { * * @param parent parent task * @param task task to add + * @param taskTemplate task template to apply for subtasks */ - public void addTask(TimerTask parent, TimerTask task) { + public void addTask(TimerTask parent, TimerTask task, String taskTemplate) { // fire vetoable event for (VetoableDataEventListener vetoableDataEventListener : vetoableDataEventListeners) { @@ -152,6 +155,41 @@ public class TimerDataManager { for (DataEventListener dataEventListener : dataEventListeners) { dataEventListener.addTask(task); } + + if (taskTemplate != null) { + List<?> subTasks = JTimer.config.getTaskTemplates().get(taskTemplate); + createSubTasks(subTasks, task); + } + } + + /** + * Recursive method to apply tempate to current task. + * + * @param subTasks template to apply + * @param task current subtask + */ + protected void createSubTasks(List<?> subTasks, TimerTask task) { + for (JSONObject subTask : (List<JSONObject>)subTasks) { + String name = (String)subTask.get("name"); + if (name != null) { + TimerTask newTask = new TimerTask(name); + + // Fix creation date + newTask.setCreationDate(new Date()); + + task.addTask(newTask); + + // send notification + for (DataEventListener dataEventListener : dataEventListeners) { + dataEventListener.addTask(newTask); + } + + List<?> newSubTasks = (List<?>)subTask.get("tasks"); + if (newSubTasks != null) { + createSubTasks(newSubTasks, newTask); + } + } + } } /** diff --git a/src/main/java/org/chorem/jtimer/ui/NewTaskPanel.java b/src/main/java/org/chorem/jtimer/ui/NewTaskPanel.java new file mode 100644 index 0000000..1e33b27 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/ui/NewTaskPanel.java @@ -0,0 +1,104 @@ +/* + * #%L + * jTimer + * %% + * Copyright (C) 2016 CodeLutin, Chatellier Eric + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ +package org.chorem.jtimer.ui; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.List; +import java.util.Map; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import org.chorem.jtimer.JTimer; +import org.chorem.jtimer.entities.TimerTask; +import org.jdesktop.application.Application; +import org.jdesktop.application.ResourceMap; + +/** + * New task panel used to ask for: + * <ul> + * <li>Task name</li> + * <li>Task template (if available)</li> + * </ul> + * + * @author Eric Chatellier + */ +public class NewTaskPanel extends JPanel { + + /** serialVersionUID. */ + private static final long serialVersionUID = -6725150779251233404L; + + protected JTextField newTaskField; + protected JComboBox<String> newTaskTemplateBox; + + public NewTaskPanel(Application app, TimerTask selectedTask) { + super(new GridBagLayout()); + + ResourceMap resourceMap = app.getContext().getResourceMap(); + + // task name + JLabel newTaskLabel = new JLabel(resourceMap.getString("input.newTaskMessage", selectedTask.getName())); + this.add(newTaskLabel, new GridBagConstraints(0, 0, 1, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, + new Insets(1, 1, 1, 1), 0, 0)); + newTaskField = new JTextField(); + this.add(newTaskField, new GridBagConstraints(0, 1, 1, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, + new Insets(1, 1, 1, 1), 0, 0)); + + // Task template + Map<String, List<?>> templates = JTimer.config.getTaskTemplates(); + + + newTaskTemplateBox = new JComboBox<>(); + if (templates != null && !templates.isEmpty()) { + + // model + DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>(templates.keySet().toArray(new String[0])); + model.insertElementAt(null, 0); // empty option + newTaskTemplateBox.setModel(model); + newTaskTemplateBox.setSelectedItem(null); // empty option + + JLabel newTaskTemplateLabel = new JLabel(resourceMap.getString("input.newTaskTemplate")); + this.add(newTaskTemplateLabel, new GridBagConstraints(0, 2, 1, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, + new Insets(1, 1, 1, 1), 0, 0)); + + this.add(newTaskTemplateBox, new GridBagConstraints(0, 3, 1, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, + new Insets(1, 1, 1, 1), 0, 0)); + } + } + + public String getTaskName() { + return newTaskField.getText(); + } + + public String getTaskTemplate() { + return (String)newTaskTemplateBox.getSelectedItem(); + } +} diff --git a/src/main/resources/org/chorem/jtimer/resources/JTimer.properties b/src/main/resources/org/chorem/jtimer/resources/JTimer.properties index 1490cda..82298fe 100644 --- a/src/main/resources/org/chorem/jtimer/resources/JTimer.properties +++ b/src/main/resources/org/chorem/jtimer/resources/JTimer.properties @@ -164,6 +164,7 @@ input.deleteProjectTitle=Confirm input.deleteProjectMessage=Do you want to delete project "%s" ? input.newTaskTitle=New task input.newTaskMessage=Task name to create for "%s" : +input.newTaskTemplate=Task template to use : input.editTaskTitle=Edit task input.editTaskMessage=New task name : input.deleteTaskTitle=Confirm diff --git a/src/main/resources/org/chorem/jtimer/resources/JTimer_fr.properties b/src/main/resources/org/chorem/jtimer/resources/JTimer_fr.properties index be9d292..efc0e16 100644 --- a/src/main/resources/org/chorem/jtimer/resources/JTimer_fr.properties +++ b/src/main/resources/org/chorem/jtimer/resources/JTimer_fr.properties @@ -129,6 +129,7 @@ input.deleteProjectTitle=Confirmation input.deleteProjectMessage=Voulez-vous supprimer le projet "%s" ? input.newTaskTitle=Nouvelle t\u00E2che input.newTaskMessage=Nom de la t\u00E2che \u00E0 cr\u00E9er pour "%s" : +input.newTaskTemplate=Template \u00E0 utiliser : input.editTaskTitle=\u00C9dition de la t\u00E2che input.editTaskMessage=Nouveau nom de la t\u00E2che : input.deleteTaskTitle=Confirmation diff --git a/src/test/java/org/chorem/jtimer/JTimerFactoryTest.java b/src/test/java/org/chorem/jtimer/JTimerFactoryTest.java index 5d83e4c..2b4eaa1 100644 --- a/src/test/java/org/chorem/jtimer/JTimerFactoryTest.java +++ b/src/test/java/org/chorem/jtimer/JTimerFactoryTest.java @@ -22,6 +22,9 @@ package org.chorem.jtimer; +import java.util.List; +import java.util.Map; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.jtimer.io.GTimerIncrementalSaver; @@ -64,6 +67,18 @@ public class JTimerFactoryTest extends AbstractJTimerTest { } /** + * Test json parsing of config property. + */ + @Test + public void testJsonTaskTemplates() { + Map<String, List<?>> templates = JTimer.config.getTaskTemplates(); + List<?> p1Tpl = (List<?>)templates.get("projet1"); + Assert.assertNotNull(p1Tpl); + + Assert.assertEquals(p1Tpl.size(), 5); + } + + /** * Test que le saver de fichier s'est bien initialise. */ @Test diff --git a/src/test/java/org/chorem/jtimer/data/CommonVetoableTest.java b/src/test/java/org/chorem/jtimer/data/CommonVetoableTest.java index 2b84606..43fa1c7 100644 --- a/src/test/java/org/chorem/jtimer/data/CommonVetoableTest.java +++ b/src/test/java/org/chorem/jtimer/data/CommonVetoableTest.java @@ -84,7 +84,7 @@ public class CommonVetoableTest extends AbstractJTimerTest { // add a new task TimerTask newTask = new TimerTask("Debug"); newTask.setCreationDate(new Date()); - dataManager.addTask(task1, newTask); + dataManager.addTask(task1, newTask, null); } /** diff --git a/src/test/java/org/chorem/jtimer/data/TimerDataManagerTest.java b/src/test/java/org/chorem/jtimer/data/TimerDataManagerTest.java index 171bcdf..a4ce723 100644 --- a/src/test/java/org/chorem/jtimer/data/TimerDataManagerTest.java +++ b/src/test/java/org/chorem/jtimer/data/TimerDataManagerTest.java @@ -172,7 +172,7 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // add a new task TimerTask newTask = new TimerTask("new task"); newTask.setCreationDate(new Date()); - dataManager.addTask(task1, newTask); + dataManager.addTask(task1, newTask, null); core.exit(); // second reload @@ -466,7 +466,7 @@ public class TimerDataManagerTest extends AbstractJTimerTest { TimerTask tTreeTests = new TimerTask("Tree tests"); tTreeTests.setCreationDate(new Date()); tTreeTests.setTime(new Date(), Long.valueOf(200000)); - dataManager.addTask(task1, tTreeTests); + dataManager.addTask(task1, tTreeTests, null); Assert.assertEquals(task1.getSubTasks().size(), 3); Assert.assertEquals(TimerTaskHelper.getAllTotalTime(task1), 55035000 + 200000); diff --git a/src/test/resources/jtimertest.properties b/src/test/resources/jtimertest.properties index 8de67e5..e8ceafb 100644 --- a/src/test/resources/jtimertest.properties +++ b/src/test/resources/jtimertest.properties @@ -2,7 +2,7 @@ # #%L # jTimer # %% -# Copyright (C) 2007 - 2011 CodeLutin, Chatellier Eric +# Copyright (C) 2007 - 2016 CodeLutin, Chatellier Eric # %% # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as @@ -19,12 +19,6 @@ # <http://www.gnu.org/licenses/gpl-3.0.html>. # #L% ### -# Service class -jtimer.service.class=org.chorem.jtimer.ws.xmlrpc.ChoremXMLRPCClient -# Service resource to use for previous class -jtimer.service.resource=JTimer -# Service endpoint to use for previous class -jtimer.service.endpoint=http://localhost:8080 # Idle time (integer in seconds) jtimer.ui.idletime=299 @@ -35,3 +29,6 @@ jtimer.io.saver.class=org.chorem.jtimer.io.GTimerIncrementalSaver jtimer.io.saver.directory=${user.home}/testngdata # Save delay jtimer.io.saver.autosavedelay=199 + +# Task templates as json +jtimer.ui.task.templates={"projet1":[{"name":"dev", "tasks":[{"name":"E1"},{"name":"E2"}]},{"name":"ano", "tasks":[{"name":"A1"}]},{"name":"admin", "tasks":[{"name":"database", "tasks":[{"name":"sub database task1"},{"name":"sub database task2"}]}]},{"name":"meetings"},{"name":"releases"}]} -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.