This is an automated email from the git hooks/post-receive script. New commit to branch sync-timebundle in repository jtimer. See https://gitlab.nuiton.org/chorem/jtimer.git commit ad7916980ef9c2ce5a654ce4ab644de3f59ddc91 Author: Eric Chatellier <chatellier@codelutin.com> Date: Tue Mar 7 11:52:59 2017 +0100 Add new version of timebundle plugin --- pom.xml | 7 +- src/main/java/org/chorem/jtimer/JTimer.java | 106 ++++----- src/main/java/org/chorem/jtimer/JTimerFactory.java | 35 --- .../{data/TimerCore.java => JTimerService.java} | 76 +++--- .../org/chorem/jtimer/data/TimerDataManager.java | 8 +- .../java/org/chorem/jtimer/entities/TimerTask.java | 25 +- .../jtimer/plugin/timebundle/TimeBundleHelper.java | 136 ----------- .../jtimer/plugin/timebundle/TimeBundleSaver.java | 219 ------------------ .../plugin/timebundle/TimeBundleSynchronizer.java | 171 -------------- .../plugin/timebundle/TimeBundleVetoable.java | 56 ----- .../plugin/timebundle/TimerSyncCellRenderer.java | 46 ---- .../jtimer/plugin/timebundle/TimerSyncEditor.java | 245 -------------------- .../plugin/timebundle/TimerSyncTableModel.java | 203 ---------------- .../java/org/chorem/jtimer/plugins/Plugin.java | 30 +++ .../jtimer/plugins/timebundle/Constants.java | 27 +++ .../plugins/timebundle/LocalSynchronizer.java | 30 +++ .../plugins/timebundle/RemoteSynchronizer.java | 257 +++++++++++++++++++++ .../jtimer/plugins/timebundle/SyncIOSaver.java | 211 +++++++++++++++++ .../chorem/jtimer/plugins/timebundle/SyncView.java | 207 +++++++++++++++++ .../jtimer/plugins/timebundle/Synchronizer.java | 27 +++ .../plugins/timebundle/TimeBundlePlugin.java | 131 +++++++++++ .../plugins/timebundle/data/RemoteProject.java | 27 +++ .../jtimer/plugins/timebundle/data/RemoteTask.java | 85 +++++++ .../timebundle/model/RemoteTaskTreeModel.java | 121 ++++++++++ .../timebundle/model/RemoveTaskCellRenderer.java | 42 ++++ .../java/org/chorem/jtimer/ui/NewTaskView.java | 10 +- .../java/org/chorem/jtimer/ui/TimerTaskEditor.java | 14 +- .../java/org/chorem/jtimer/ui/TimerUIManager.java | 50 ++++ .../chorem/jtimer/ui/UserInterfaceListener.java | 37 +++ .../org/chorem/jtimer/ui/report/ReportView.java | 24 +- .../org/chorem/jtimer/ui/tasks/IdleDialog.java | 20 +- .../chorem/jtimer/ui/tasks/RefreshTreeTask.java | 10 +- .../org/chorem/jtimer/ui/tasks/RunTaskJob.java | 2 +- .../jtimer/ui/tree/CheckBoxTreeCellComponent.java | 28 ++- .../jtimer/ui/tree/CheckBoxTreeCellEditor.java | 22 +- .../jtimer/ui/tree/CheckBoxTreeCellRenderer.java | 13 +- .../org/chorem/jtimer/ui/tree/TaskTreeModel.java | 31 +-- .../jtimer/ui/treetable/ProjectsAndTasksModel.java | 8 +- .../ProjectsAndTasksRunningCellRenderer.java | 8 +- .../jtimer/ui/treetable/ProjectsAndTasksTable.java | 14 +- .../services/org.chorem.jtimer.plugins.Plugin | 1 + src/main/resources/log4j2.xml | 2 +- .../ui/report/resources/ReportView.properties | 1 - .../ui/report/resources/ReportView_fr.properties | 1 - .../java/org/chorem/jtimer/AbstractJTimerTest.java | 2 - .../org/chorem/jtimer/data/CommonVetoableTest.java | 49 ++-- .../chorem/jtimer/data/TimerDataManagerTest.java | 199 ++++++++-------- .../plugin/timebundle/TimeBundleHelperTest.java | 87 ------- .../plugin/timebundle/TimeBundleSaverTest.java | 66 ------ src/test/resources/testsync/41.task.sync | 8 - 50 files changed, 1622 insertions(+), 1613 deletions(-) diff --git a/pom.xml b/pom.xml index 08467bd..77060af 100644 --- a/pom.xml +++ b/pom.xml @@ -197,6 +197,11 @@ <version>2.8.0</version> </dependency> <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20160810</version> + </dependency> + <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.5</version> @@ -216,7 +221,7 @@ <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> - <version>6.10</version> + <version>6.11</version> <scope>test</scope> <exclusions> <exclusion> diff --git a/src/main/java/org/chorem/jtimer/JTimer.java b/src/main/java/org/chorem/jtimer/JTimer.java index f711d12..96ec4b8 100644 --- a/src/main/java/org/chorem/jtimer/JTimer.java +++ b/src/main/java/org/chorem/jtimer/JTimer.java @@ -23,15 +23,12 @@ package org.chorem.jtimer; import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.jtimer.data.DataViolationException; -import org.chorem.jtimer.data.TimerCore; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; -import org.chorem.jtimer.plugin.timebundle.TimerSyncEditor; import org.chorem.jtimer.system.SystemInfo; import org.chorem.jtimer.system.SystemInfoFactory; import org.chorem.jtimer.ui.HelpFrame; @@ -106,8 +103,8 @@ public class JTimer extends SingleFrameApplication implements /** log. */ private static Log log = LogFactory.getLog(JTimer.class); - /** Timer core controller. */ - protected TimerCore core; + /** Timer service controller. */ + protected JTimerService service; /** Tree structure. */ protected ProjectsAndTasksTable projectsAndTasksTable; @@ -195,14 +192,14 @@ public class JTimer extends SingleFrameApplication implements // fix start in iconified mode ctxt.getSessionStorage().putProperty(JFrame.class, new WindowProperty2()); - // init timercore - core = new TimerCore(); + // init timerservice + service = new JTimerService(); // Systray mgr systrayManager = new SystrayManager(this); - core.getData().addDataEventListener(systrayManager); + service.getData().addDataEventListener(systrayManager); - IdleDialog.init(this, core); + IdleDialog.init(this, service); } /** @@ -255,6 +252,9 @@ public class JTimer extends SingleFrameApplication implements // set Menu Bar getMainFrame().setJMenuBar(createMenuBar()); + // post UI init + service.getUi().initUI(this); + // show main panel components show(createMainComponent()); @@ -281,9 +281,9 @@ public class JTimer extends SingleFrameApplication implements panel.add(scrollPaneProjectTreeTable, BorderLayout.CENTER); // status bar bottom - StatusBar sb = new StatusBar(this, core.getData()); + StatusBar sb = new StatusBar(this, service.getData()); // status bar ui will be notified from events - core.getData().addDataEventListener(sb); + service.getData().addDataEventListener(sb); panel.add(sb, BorderLayout.SOUTH); // taille par defaut au premier lancement de l'application @@ -300,7 +300,7 @@ public class JTimer extends SingleFrameApplication implements */ protected ProjectsAndTasksTable createTreeTable() { - projectsAndTasksTable = new ProjectsAndTasksTable(this, core); + projectsAndTasksTable = new ProjectsAndTasksTable(this, service); // name used in properties files projectsAndTasksTable.setName("projectslist"); @@ -366,9 +366,6 @@ public class JTimer extends SingleFrameApplication implements String[] projectMenuActionNames = {"newProject", "editProject", "closeProject", "deleteProject", "---", "quit"}; - if (JTimerFactory.getSynchronizer() != null) { - projectMenuActionNames = ArrayUtils.add(projectMenuActionNames, 2, "editSync"); - } menuBar.add(createMenu("projectMenu", projectMenuActionNames)); String[] taskMenuActionNames = {"newTask", "editTask", "closeTask", @@ -376,16 +373,13 @@ public class JTimer extends SingleFrameApplication implements "addAnnotation", "editAlert", "increment1Task", "increment5Task", "increment30Task", "decrement1Task", "decrement5Task", "decrement30Task", "setToZero", "mergeTasks"}; - if (JTimerFactory.getSynchronizer() != null) { - taskMenuActionNames = ArrayUtils.add(taskMenuActionNames, 2, "editSync"); - } menuBar.add(createMenu("taskMenu", taskMenuActionNames)); String[] reportMenuActionNames = {"makeReport"}; menuBar.add(createMenu("reportMenu", reportMenuActionNames)); - JMenu optionmMenu = createOptionMenu(); - menuBar.add(optionmMenu); + JMenu optionMenu = createOptionMenu(); + menuBar.add(optionMenu); String[] helpMenuActionNames = {"about"}; menuBar.add(createMenu("helpMenu", helpMenuActionNames)); @@ -488,8 +482,8 @@ public class JTimer extends SingleFrameApplication implements @Override protected void ready() { - // init core, load list, synchronization, etc... - boolean init = core.init(); + // init service, load list, synchronization, etc... + boolean init = service.init(); if (init) { // schedule tree refresh at midnight @@ -520,7 +514,7 @@ public class JTimer extends SingleFrameApplication implements @Override protected void shutdown() { log.debug("Shutdown called"); - core.exit(); + service.exit(); // save context // super, sauve le context des fenetres, etc... @@ -533,7 +527,7 @@ public class JTimer extends SingleFrameApplication implements protected void scheduleTreeRefresh() { // task used to refresh tree - java.util.TimerTask refreshTreeTask = new RefreshTreeTask(core); + java.util.TimerTask refreshTreeTask = new RefreshTreeTask(service); Timer timer = new Timer(); @@ -595,7 +589,7 @@ public class JTimer extends SingleFrameApplication implements p.setCreationDate(new Date()); try { - core.getData().addProject(p); + service.getData().addProject(p); } catch (DataViolationException e) { displayErrorMessage(e.getExceptionKey()); } @@ -623,7 +617,7 @@ public class JTimer extends SingleFrameApplication implements newProjectName = newProjectName.trim(); try { - core.getData().editProject(project, newProjectName); + service.getData().editProject(project, newProjectName); } catch (DataViolationException e) { displayErrorMessage(e.getExceptionKey()); } @@ -641,7 +635,7 @@ public class JTimer extends SingleFrameApplication implements // select task to add new task TimerTask selectedTask = projectsAndTasksTable.getSelectedElements().get(0); - NewTaskView newTaskPanel = new NewTaskView(this, core, selectedTask); + NewTaskView newTaskPanel = new NewTaskView(this, service, selectedTask); show(newTaskPanel); } @@ -664,23 +658,11 @@ public class JTimer extends SingleFrameApplication implements TimerTask task = projectsAndTasksTable.getSelectedTasks().get(0); - TimerTaskEditor editor = new TimerTaskEditor(this, task, core); + TimerTaskEditor editor = new TimerTaskEditor(this, task, service); show(editor); } /** - * Update task. - * Enabled when a task is selected - */ - @Action(enabledProperty = "selectedSingleElement") - public void editSync() { - TimerTask task = projectsAndTasksTable.getSelectedElements().get(0); - - TimerSyncEditor updater = new TimerSyncEditor(this, core, task); - show(updater); - } - - /** * Start selected task in tree. * * If it not already been running @@ -695,8 +677,8 @@ public class JTimer extends SingleFrameApplication implements // can't be null TimerTask task = projectsAndTasksTable.getSelectedTasks().get(0); - RunTaskJob jobToRun = new RunTaskJob(this, task, core.getData()); - core.getData().startTask(task); + RunTaskJob jobToRun = new RunTaskJob(this, task, service.getData()); + service.getData().startTask(task); return jobToRun; } @@ -707,11 +689,11 @@ public class JTimer extends SingleFrameApplication implements * @param taskPath task path to start (from root to task) */ public void startTask(String taskPath) { - TimerTask task = core.getData().getTaskForPath(taskPath); + TimerTask task = service.getData().getTaskForPath(taskPath); if (task != null) { - RunTaskJob jobToRun = new RunTaskJob(this, task, core.getData()); + RunTaskJob jobToRun = new RunTaskJob(this, task, service.getData()); getContext().getTaskService().execute(jobToRun); - core.getData().startTask(task); + service.getData().startTask(task); } else { if (log.isWarnEnabled()) { log.warn("Can't find task '" + taskPath + "'"); @@ -777,7 +759,7 @@ public class JTimer extends SingleFrameApplication implements // test if task is already running if (rtt != null) { rtt.wantToStop(); - core.getData().stopTask(task); + service.getData().stopTask(task); // re-enable/disable buttons setSelectedSingleRunningTask(false); @@ -805,7 +787,7 @@ public class JTimer extends SingleFrameApplication implements public void closeProject() { TimerProject project = projectsAndTasksTable.getSelectedProjects().get(0); - core.getData().changeProjectCloseState(project); + service.getData().changeProjectCloseState(project); } /** @@ -815,7 +797,7 @@ public class JTimer extends SingleFrameApplication implements public void closeTask() { TimerTask task = projectsAndTasksTable.getSelectedTasks().get(0); - core.getData().changeTaskCloseState(task); + service.getData().changeTaskCloseState(task); } /** @@ -843,7 +825,7 @@ public class JTimer extends SingleFrameApplication implements if (confirm == JOptionPane.YES_OPTION) { // approved for (TimerProject project : projects) { try { - core.getData().deleteProject(project); + service.getData().deleteProject(project); } catch (DataViolationException e) { displayErrorMessage(e.getExceptionKey()); } @@ -878,7 +860,7 @@ public class JTimer extends SingleFrameApplication implements for (TimerTask task : tasks) { try { stopTask(task); - core.getData().deleteTask(task); + service.getData().deleteTask(task); } catch (DataViolationException e) { displayErrorMessage(e.getExceptionKey()); } @@ -1035,11 +1017,11 @@ public class JTimer extends SingleFrameApplication implements try { // check if + negative increment still positive if (newTodayTime > 0) { - core.getData().changeTaskTime(selectedTask, now, + service.getData().changeTaskTime(selectedTask, now, newTodayTime); } else { // force to 0 - core.getData().changeTaskTime(selectedTask, now, 0L); + service.getData().changeTaskTime(selectedTask, now, 0L); } } catch (DataViolationException e) { displayErrorMessage(e.getExceptionKey()); @@ -1069,7 +1051,7 @@ public class JTimer extends SingleFrameApplication implements resourceMap.getString("input.mergeTaskTitle"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (confirm == JOptionPane.YES_OPTION) { try { - core.getData().mergeTasks(destinationTask, otherTasks); + service.getData().mergeTasks(destinationTask, otherTasks); } catch (DataViolationException e) { displayErrorMessage(e.getExceptionKey()); } @@ -1096,7 +1078,7 @@ public class JTimer extends SingleFrameApplication implements annotation = annotation.trim(); try { - core.getData().addAnnotation(selectedTask, new Date(), + service.getData().addAnnotation(selectedTask, new Date(), annotation); } catch (DataViolationException e) { displayErrorMessage(e.getExceptionKey()); @@ -1113,7 +1095,7 @@ public class JTimer extends SingleFrameApplication implements TimerTask selectedTask = projectsAndTasksTable.getSelectedTasks() .get(0); - AlertEditor alertEditor = new AlertEditor(this, core.getData(), + AlertEditor alertEditor = new AlertEditor(this, service.getData(), selectedTask); show(alertEditor); } @@ -1123,7 +1105,7 @@ public class JTimer extends SingleFrameApplication implements */ @Action public void makeReport() { - ReportView view = new ReportView(this, core); + ReportView view = new ReportView(this, service); show(view); } @@ -1334,6 +1316,10 @@ public class JTimer extends SingleFrameApplication implements firePropertyChange("selectedProjects", oldValue, selectedProjects); } + public List<TimerProject> getSelectedProject() { + return projectsAndTasksTable.getSelectedProjects(); + } + /** * Is selected task property. * @@ -1498,9 +1484,6 @@ public class JTimer extends SingleFrameApplication implements if (isSelectedSingleProject()) { actionNames = new String[]{"newTask", "---", "newProject", "editProject", "closeProject", "deleteProject"}; - if (JTimerFactory.getSynchronizer() != null) { - actionNames = ArrayUtils.add(actionNames, 4, "editSync"); - } } if (isSelectedSingleTask()) { @@ -1509,9 +1492,6 @@ public class JTimer extends SingleFrameApplication implements "---", "addAnnotation", "editAlert", "increment1Task", "increment5Task", "increment30Task", "decrement1Task", "decrement5Task", "decrement30Task", "setToZero"}; - if (JTimerFactory.getSynchronizer() != null) { - actionNames = ArrayUtils.add(actionNames, 4, "editSync"); - } } if (isSelectedMultiplesTasks()) { @@ -1522,6 +1502,8 @@ public class JTimer extends SingleFrameApplication implements if (actionNames != null) { addActionToMenu(menu, actionNames); + service.getUi().initTreePopupMenu(menu); + menu.show(e.getComponent(), e.getX(), e.getY()); } } diff --git a/src/main/java/org/chorem/jtimer/JTimerFactory.java b/src/main/java/org/chorem/jtimer/JTimerFactory.java index dc2953e..6fc72ac 100644 --- a/src/main/java/org/chorem/jtimer/JTimerFactory.java +++ b/src/main/java/org/chorem/jtimer/JTimerFactory.java @@ -25,7 +25,6 @@ package org.chorem.jtimer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.jtimer.io.Saver; -import org.chorem.jtimer.plugin.timebundle.TimeBundleSynchronizer; /** * JTimer config class. @@ -44,9 +43,6 @@ public class JTimerFactory { /** Saver */ protected static Saver saver; - /** Synchronizer */ - protected static TimeBundleSynchronizer synchronizer; - /** * Constructeur. */ @@ -93,35 +89,4 @@ public class JTimerFactory { return saver; } - /** - * Get synchronizer manager - */ - public static TimeBundleSynchronizer getSynchronizer() { - if (synchronizer == null) { - - Class<?> synchronizerClass = JTimer.config.getIOSynchronizerClass(); - - if (synchronizerClass != null) { - // log - if (log.isInfoEnabled()) { - log.info("Using synchronizer class : " + synchronizerClass); - } - - try { - // get instance - synchronizer = (TimeBundleSynchronizer) synchronizerClass.newInstance(); - - } catch (InstantiationException e) { - if (log.isErrorEnabled()) { - log.error("Can't instanciate class : " + synchronizerClass, e); - } - } catch (IllegalAccessException e) { - if (log.isErrorEnabled()) { - log.error("Can't access class : " + synchronizerClass, e); - } - } - } - } - return synchronizer; - } } diff --git a/src/main/java/org/chorem/jtimer/data/TimerCore.java b/src/main/java/org/chorem/jtimer/JTimerService.java similarity index 75% rename from src/main/java/org/chorem/jtimer/data/TimerCore.java rename to src/main/java/org/chorem/jtimer/JTimerService.java index ae4a4cc..342fb92 100644 --- a/src/main/java/org/chorem/jtimer/data/TimerCore.java +++ b/src/main/java/org/chorem/jtimer/JTimerService.java @@ -2,7 +2,7 @@ * #%L * jTimer * %% - * Copyright (C) 2007 - 2016 CodeLutin + * Copyright (C) 2007 - 2017 CodeLutin * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as @@ -20,19 +20,19 @@ * #L% */ -package org.chorem.jtimer.data; +package org.chorem.jtimer; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.chorem.jtimer.JTimer; -import org.chorem.jtimer.JTimerFactory; +import org.chorem.jtimer.data.CommonVetoable; +import org.chorem.jtimer.data.TimerDataManager; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.io.DataLockingException; import org.chorem.jtimer.io.Saver; -import org.chorem.jtimer.plugin.timebundle.TimeBundleSaver; -import org.chorem.jtimer.plugin.timebundle.TimeBundleSynchronizer; -import org.chorem.jtimer.plugin.timebundle.TimeBundleVetoable; +import org.chorem.jtimer.plugins.Plugin; +import org.chorem.jtimer.ui.TimerUIManager; import java.io.File; import java.io.IOException; @@ -40,9 +40,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.ServiceLoader; /** - * TimerCore + * JTimerService * * @author chatellier * @version $Revision$ @@ -50,24 +51,27 @@ import java.util.List; * Last update : $Date$ * By : $Author$ */ -public class TimerCore { +public class JTimerService { /** log. */ - private static Log log = LogFactory.getLog(TimerCore.class); + private static Log log = LogFactory.getLog(JTimerService.class); - /** Timer data. */ + /** Data Manager. */ protected TimerDataManager data; + /** UI Manager. */ + protected TimerUIManager ui; + /** saver io controller. */ protected Saver saver; - /** sync */ - protected TimeBundleSynchronizer synchronizer; + /** Plugin activated by configuration. */ + protected List<Plugin> activePlugins = new ArrayList<>(); /** * Constructor. */ - public TimerCore() { + public JTimerService() { // migrate if necessary try { @@ -78,8 +82,9 @@ public class TimerCore { } } - // init data + // init managers data = new TimerDataManager(); + ui = new TimerUIManager(); // add commmon vetoable CommonVetoable commonVetoable = new CommonVetoable(data); @@ -92,15 +97,21 @@ public class TimerCore { data.addDataEventListener(saver); } - //init sync - synchronizer = JTimerFactory.getSynchronizer(); - if (synchronizer != null) { - TimeBundleSaver saver = new TimeBundleSaver(); - data.addVetoableDataEventListener(new TimeBundleVetoable()); - data.addDataEventListener(saver); - data.addDataEventListener(synchronizer); - synchronizer.setSaver(saver); - } + ServiceLoader<Plugin> load = ServiceLoader.load(Plugin.class); + load.forEach(plugin -> { + // extract package name + String pluginPackage = plugin.getClass().getPackage().getName(); + pluginPackage = StringUtils.remove(pluginPackage, Plugin.class.getPackage().getName() + "."); + String pluginName = StringUtils.substringBefore(pluginPackage, "."); + + // loading + if (log.isInfoEnabled()) { + log.info("Loading plugin : " + pluginName); + } + activePlugins.add(plugin); + }); + + activePlugins.forEach(p -> p.register(this)); } /** @@ -149,7 +160,7 @@ public class TimerCore { // log if (log.isInfoEnabled()) { - log.info("Init core"); + log.info("Init service"); } try { @@ -169,18 +180,27 @@ public class TimerCore { } /** - * Get data. + * Get data manager. * - * @return timer data + * @return data manager */ public TimerDataManager getData() { return data; } /** + * Get UI manager. + * + * @return ui manager + */ + public TimerUIManager getUi() { + return ui; + } + + /** * Load project list from. */ - protected void load() { + public void load() { // log if (log.isInfoEnabled()) { diff --git a/src/main/java/org/chorem/jtimer/data/TimerDataManager.java b/src/main/java/org/chorem/jtimer/data/TimerDataManager.java index 79013d5..96ffd3c 100644 --- a/src/main/java/org/chorem/jtimer/data/TimerDataManager.java +++ b/src/main/java/org/chorem/jtimer/data/TimerDataManager.java @@ -2,7 +2,7 @@ * #%L * jTimer * %% - * Copyright (C) 2007 - 2016 CodeLutin + * Copyright (C) 2007 - 2017 CodeLutin * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as @@ -99,8 +99,7 @@ public class TimerDataManager { * * @param listener listener */ - public void addVetoableDataEventListener( - VetoableDataEventListener listener) { + public void addVetoableDataEventListener(VetoableDataEventListener listener) { vetoableDataEventListeners.add(listener); } @@ -109,8 +108,7 @@ public class TimerDataManager { * * @param listener listener */ - public void removeVetoableDataEventListener( - VetoableDataEventListener listener) { + public void removeVetoableDataEventListener(VetoableDataEventListener listener) { vetoableDataEventListeners.remove(listener); } diff --git a/src/main/java/org/chorem/jtimer/entities/TimerTask.java b/src/main/java/org/chorem/jtimer/entities/TimerTask.java index 19175ea..c761188 100644 --- a/src/main/java/org/chorem/jtimer/entities/TimerTask.java +++ b/src/main/java/org/chorem/jtimer/entities/TimerTask.java @@ -2,7 +2,7 @@ * #%L * jTimer * %% - * Copyright (C) 2007 - 2016 CodeLutin + * Copyright (C) 2007 - 2017 CodeLutin * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as @@ -27,7 +27,9 @@ import org.chorem.jtimer.utils.DailySortedMap; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import java.util.UUID; @@ -88,10 +90,8 @@ public class TimerTask implements Cloneable, */ protected List<TimerAlert> alerts; - /** - * Synchronization Info - */ - protected List<TimerSync> syncs; + /** Meta info for plugins. */ + protected Map<String, Object> meta = new HashMap<>(); /** * Constructor. @@ -102,7 +102,6 @@ public class TimerTask implements Cloneable, allDaysAnnotations = new TreeMap<>(); subTasks = new ArrayList<>(); alerts = new ArrayList<>(); - syncs = new ArrayList<>(); // wrong value to detect bug number = -1; } @@ -321,16 +320,8 @@ public class TimerTask implements Cloneable, this.alerts = alerts; } - public void addSync(TimerSync sync) { - syncs.add(sync); - } - - public List<TimerSync> getSyncs() { - return syncs; - } - - public void setSyncs(List<TimerSync> syncs) { - this.syncs = syncs; + public Map<String, Object> getMeta() { + return meta; } @Override @@ -375,7 +366,7 @@ public class TimerTask implements Cloneable, task.allDaysTimes = new DailySortedMap<>(allDaysTimes); task.allDaysAnnotations = new TreeMap<>(allDaysAnnotations); task.subTasks = new ArrayList<>(subTasks); - task.syncs = new ArrayList<>(syncs); + task.meta = new HashMap<>(meta); } catch (CloneNotSupportedException e) { throw new RuntimeException("Can't clone", e); } diff --git a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleHelper.java b/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleHelper.java deleted file mode 100644 index b8baaaf..0000000 --- a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleHelper.java +++ /dev/null @@ -1,136 +0,0 @@ -/*- - * #%L - * jTimer - * %% - * Copyright (C) 2016 CodeLutin, Charlène Servantie - * %% - * 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.plugin.timebundle; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import org.apache.commons.lang3.time.DateFormatUtils; -import org.apache.commons.lang3.time.DateUtils; -import org.chorem.jtimer.entities.TimerSync; -import org.chorem.jtimer.entities.TimerTask; -import org.chorem.jtimer.entities.TimerTaskHelper; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.SortedMap; - -/** - * Helper for time bundle. - */ -public class TimeBundleHelper { - - protected static final String DATE_MIDNIGHT_PATTERN = "yyyy-MM-dd'T'00:00:00XXX"; - - /** - * Returns all the subtasks of a task (including the subtaks of subtasks). - * - * @param task - * @return a List<TimerTask> - */ - public static List<TimerTask> getAllSubTasks(TimerTask task) { - List<TimerTask> subTasksList = new ArrayList<>(); - if (task.getSubTasks() != null) { - for (TimerTask subTask : task.getSubTasks()) { - subTasksList.add(subTask); - subTasksList.addAll(getAllSubTasks(subTask)); - } - } - return subTasksList; - } - - /** - * makes a JSONObject corresponding to one sync with all the times since lastSync. - * - * @param task - * @param sync - * @return - */ - public static JsonObject taskToJsonObject(TimerTask task, TimerSync sync) { - JsonObject resultingObject = new JsonObject(); - JsonArray periodArray = new JsonArray(); - Date startDate = sync.getLastSync(); - Date endDate = DateUtils.ceiling(new Date(), Calendar.DAY_OF_MONTH); - String startPeriodString = DateFormatUtils.format(startDate, DATE_MIDNIGHT_PATTERN); - String endPeriodString = DateFormatUtils.format(endDate, DATE_MIDNIGHT_PATTERN); - - //get the times of the task - periodArray.addAll(getTimesAsJsonArray(task, startDate, endDate, sync.isWithAnnotations())); - //if there are subtasks, get the times of the subtasks that have no syncInfo - if (!task.getSubTasks().isEmpty()) { - for (TimerTask subtask : getAllSubTasks(task)) { - if (subtask.getSyncs().isEmpty()) { - periodArray.addAll(getTimesAsJsonArray(subtask, startDate, endDate, sync.isWithAnnotations())); - } - } - } - resultingObject.addProperty("URL", sync.getUrl()); - resultingObject.addProperty("startDate", startPeriodString); - resultingObject.addProperty("endDate", endPeriodString); - resultingObject.add("periods", periodArray); - - return resultingObject; - - } - - /*** - * Returns a JsonArray of all the times of a task, according to format - * the id is made of the date of the time and the id of the task (as in the number given - * by jTimer) - * id, startdate, duration, info (if annotations is true) - * - * @param task - * @param startDate - * @param endDate - * @param withAnnotations - * @return a JsonArray of the periods - */ - public static JsonArray getTimesAsJsonArray(TimerTask task, Date startDate, Date endDate, boolean withAnnotations) { - JsonArray periodArray = new JsonArray(); - SortedMap<Date, Long> dates = task.getAllDaysAndTimes().subMap(startDate, endDate); - for (SortedMap.Entry<Date, Long> entry : dates.entrySet()) { - //adding id, startDate and duration - String dateString = DateFormatUtils.format(entry.getKey(), DATE_MIDNIGHT_PATTERN); - //as jtimer has time entries only for a day, the id of the times will be the date in yyyy-mm-dd format - String idString = DateFormatUtils.format(entry.getKey(), "yyyy-MM-dd"); - JsonObject periodElement = new JsonObject(); - periodElement.addProperty("id", idString + "_" + task.getNumber()); - periodElement.addProperty("startDate", dateString); - //TimerTaskHelper.getTotalTime(task, entry.getKey()) to get the total time of the task and all the subtasks - //entry.getValue() to get only the time of the task divided by 1000 (jtimer stores milliseconds) - periodElement.addProperty("duration", entry.getValue() / 1000); - if (withAnnotations && !(TimerTaskHelper.getAnnotation(task, entry.getKey()).isEmpty())) { - StringBuilder annotationBuilder = new StringBuilder(); - for (String s : TimerTaskHelper.getAnnotation(task, entry.getKey())) { - annotationBuilder.append(s); - annotationBuilder.append(","); - } - periodElement.addProperty("info", annotationBuilder.toString()); - } - periodArray.add(periodElement); - } - return periodArray; - - } - -} diff --git a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleSaver.java b/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleSaver.java deleted file mode 100644 index f2f0fa4..0000000 --- a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleSaver.java +++ /dev/null @@ -1,219 +0,0 @@ -/*- - * #%L - * jTimer - * %% - * Copyright (C) 2016 CodeLutin, Charlène Servantie - * %% - * 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.plugin.timebundle; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.chorem.jtimer.JTimer; -import org.chorem.jtimer.data.DataEventListener; -import org.chorem.jtimer.entities.TimerProject; -import org.chorem.jtimer.entities.TimerSync; -import org.chorem.jtimer.entities.TimerTask; -import org.chorem.jtimer.io.BackupUtils; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.Writer; -import java.util.Collection; -import java.util.List; - -/** - * Saver to handle sync related info. - */ -public class TimeBundleSaver implements DataEventListener { - - private static Log log = LogFactory.getLog(TimeBundleSaver.class); - - protected static final String JTIMER_SYNC_DIRECTORY = "timebundle"; - - protected static final String JTIMER_PROJECT_EXTENSION = ".project.sync"; - - protected static final String JTIMER_TASK_EXTENSION = ".task.sync"; - - protected File syncDataDirectory; - - public TimeBundleSaver() { - syncDataDirectory = new File(JTimer.config.getHomeDirectory(), JTIMER_SYNC_DIRECTORY); - syncDataDirectory.mkdirs(); - } - - @Override - public void dataLoaded(Collection<TimerProject> projects) { - projects.forEach(this::addProjectSync); - } - - @Override - public void modifyProject(TimerProject project) { - saveProjectSync(project); - } - - @Override - public void modifyTask(TimerTask task) { - saveTaskSync(task); - } - - @Override - public void addProject(TimerProject project) { - saveProjectSync(project); - } - - @Override - public void addTask(TimerTask task) { - saveTaskSync(task); - } - - @Override - public void deleteProject(TimerProject project) { - int projectNumber = project.getNumber(); - File projectSyncFile = new File(syncDataDirectory, projectNumber + JTIMER_PROJECT_EXTENSION); - if (projectSyncFile.exists()) { - projectSyncFile.delete(); - if (log.isDebugEnabled()) { - log.debug("Synchronization file deleted for " + project.getName()); - } - } - } - - @Override - public void deleteTask(TimerTask task) { - int taskNumber = task.getNumber(); - File taskSyncFile = new File(syncDataDirectory, taskNumber + JTIMER_TASK_EXTENSION); - if (taskSyncFile.exists()) { - taskSyncFile.delete(); - if (log.isDebugEnabled()) { - log.debug("Synchronization file deleted for " + task.getName()); - } - } - } - - protected void addProjectSync(TimerProject timerProject) { - int projectNumber = timerProject.getNumber(); - File projectSyncFile = new File(syncDataDirectory, projectNumber + JTIMER_PROJECT_EXTENSION); - parseFileSync(timerProject, projectSyncFile); - timerProject.getSubTasks().forEach(this::addTaskSync); - } - - protected void addTaskSync(TimerTask timerTask) { - int taskNumber = timerTask.getNumber(); - File taskSyncFile = new File(syncDataDirectory, taskNumber + JTIMER_TASK_EXTENSION); - parseFileSync(timerTask, taskSyncFile); - timerTask.getSubTasks().forEach(this::addTaskSync); - } - - protected void parseFileSync(TimerTask projectOrTask, File syncFile) { - if (syncFile.exists()) { - if (log.isDebugEnabled()) { - log.debug("Add sync for project " + projectOrTask.getName()); - } - - try (Reader parseIn = new BufferedReader(new FileReader(syncFile))) { - JsonParser parser = new JsonParser(); - Gson gson = new Gson(); - JsonElement element = parser.parse(parseIn); - JsonArray infoArray = (JsonArray) element; - for (JsonElement obj : infoArray) { - JsonObject res = (JsonObject) obj; - TimerSync sync = gson.fromJson(res, TimerSync.class); - projectOrTask.addSync(sync); - } - } catch (IOException ex) { - if (log.isErrorEnabled()) { - log.error("Can't parse sync file", ex); - } - } - } else if (log.isTraceEnabled()) { - log.trace("Sync not found for " + projectOrTask.getName()); - } - } - - protected void saveProjectSync(TimerProject timerProject) { - int projectNumber = timerProject.getNumber(); - File projectSyncFile = new File(syncDataDirectory, projectNumber + JTIMER_PROJECT_EXTENSION); - saveFileSync(timerProject, projectSyncFile); - } - - protected void saveTaskSync(TimerTask timerTask) { - int taskNumber = timerTask.getNumber(); - File taskSyncFile = new File(syncDataDirectory, taskNumber + JTIMER_TASK_EXTENSION); - saveFileSync(timerTask, taskSyncFile); - } - - protected void saveFileSync(TimerTask task, File taskSyncFile) { - - if (task.getSyncs() == null || task.getSyncs().isEmpty()) { - taskSyncFile.delete(); - - } else { - File backupfile = null; - - try (Writer out = new OutputStreamWriter(new FileOutputStream(taskSyncFile), "ISO-8859-1")) { - - // first make backup - backupfile = BackupUtils.makeBackupFile(taskSyncFile); - - //make a json object for the syncInfo - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - out.write(gson.toJson(task.getSyncs())); - - out.close(); - BackupUtils.deleteBackupFile(backupfile); - if (log.isDebugEnabled()) { - log.debug("Saving sync on task : " + task.getName()); - } - } catch (IOException e) { - if (log.isErrorEnabled()) { - log.debug("Can't save task synchronization information", e); - } - - // can be null if backup throws the exception - if (backupfile != null) { - BackupUtils.restoreBackupFile(backupfile); - } - } - } - } - - @Override - public void postMergeTasks(TimerTask destinationTask, List<TimerTask> otherTasks) { - otherTasks.forEach(task -> { - task.getSyncs().forEach(sync -> { - boolean urlExists = destinationTask.getSyncs().stream() - .anyMatch(timerSync -> timerSync.getUrl().equals(sync.getUrl())); - if (!urlExists) { - destinationTask.getSyncs().add(sync); - } - }); - }); - modifyTask(destinationTask); - } -} diff --git a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleSynchronizer.java b/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleSynchronizer.java deleted file mode 100644 index e42f59c..0000000 --- a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleSynchronizer.java +++ /dev/null @@ -1,171 +0,0 @@ -/*- - * #%L - * jTimer - * %% - * Copyright (C) 2016 CodeLutin, Charlène Servantie - * %% - * 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.plugin.timebundle; - -import com.google.gson.JsonObject; -import org.apache.commons.lang3.time.DateUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.chorem.jtimer.data.DataEventListener; -import org.chorem.jtimer.entities.TimerProject; -import org.chorem.jtimer.entities.TimerSync; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Collection; -import java.util.Date; -import java.util.Timer; -import java.util.TimerTask; - -/** - * Synchronizer background task. - */ -public class TimeBundleSynchronizer extends TimerTask implements DataEventListener { - - /** log */ - private static Log log = LogFactory.getLog(TimeBundleSynchronizer.class); - - /** timer to schedule syncs */ - protected Timer timer; - - protected Collection<TimerProject> projects; - - protected TimeBundleSaver saver; - - /** - * TimeBundleSynchronizer constructor - */ - public TimeBundleSynchronizer() { - log.info("Starting synchronizer"); - timer = new Timer(); - } - - @Override - public void dataLoaded(Collection<TimerProject> projects) { - this.projects = projects; - timer.schedule(this, 0, 60 * 60 * 1000); - } - - @Override - public void run() { - projects.forEach(this::synchronizerTask); - } - - protected void synchronizerTask(org.chorem.jtimer.entities.TimerTask timerTask) { - synchronizerProjectOrTask(timerTask); - timerTask.getSubTasks().forEach(this::synchronizerTask); - } - - protected void synchronizerProjectOrTask(org.chorem.jtimer.entities.TimerTask timerTask) { - timerTask.getSyncs().forEach(timerSync -> { - if (!DateUtils.isSameDay(new Date(), timerSync.getLastSync())) { - if (log.isDebugEnabled()) { - log.debug("Synchronizing task " + timerTask.getName() + "..."); - } - - JsonObject syncObject = TimeBundleHelper.taskToJsonObject(timerTask, timerSync); - boolean resultOk = synchronizeTaskOnURL(syncObject); - if (resultOk) { - timerSync.setLastSync(new Date()); - if (timerTask instanceof TimerProject) { - saver.modifyProject(TimerProject.class.cast(timerTask)); - } else { - saver.modifyTask(timerTask); - } - } - } - }); - } - - /** - * Sends one synchronization (one JSON object) - * @param object the object to sync - * @return an int (http response code or 0 in case of a problem) - */ - protected boolean synchronizeTaskOnURL(JsonObject object) { - boolean result = false; - // if it's an empty object, no synchronization is possible - if (!object.equals(new JsonObject())) { - String updateJsonString = object.toString(); - String syncURL = object.get("URL").getAsString(); - String charset = "UTF-8"; - HttpURLConnection connection; - URL url; - byte[] postDataBytes; - try { - url = new URL(syncURL); - connection = (HttpURLConnection) url.openConnection(); - connection.setUseCaches(false); - connection.setDoInput(true); - connection.setDoOutput(true); - connection.setRequestProperty("Content-Length", Integer.toString(updateJsonString.length())); - connection.setRequestProperty("Accept-Charset", charset); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestMethod("POST"); - postDataBytes = updateJsonString.getBytes(charset); - connection.getOutputStream().write(postDataBytes); - int upDateValue = connection.getResponseCode(); - if (upDateValue >= 200 && upDateValue < 300) { - result = true; - } - } catch (IOException ex) { - if (log.isErrorEnabled()) { - log.error("Problem with the connection " + syncURL, ex); - } - } - } - return result; - } - - /** - * When tasktime is modified, if it's before the last sync, - * the task is synchronized - */ - @Override - public void setTaskTime(org.chorem.jtimer.entities.TimerTask task, Date date, Long time) { - //check if it isn't the current day, to avoid sync every second - if (!DateUtils.isSameDay(new Date(), date)) { - if (!task.getSyncs().isEmpty()) { - for (TimerSync timerSync : task.getSyncs()) { - if (!DateUtils.isSameDay(date, timerSync.getLastSync())) { - timerSync.setLastSync(date); - } - } - } - - if (task.getParent() != null) { - setTaskTime(task.getParent(), date, time); - } - } - } - - /** - * Set saver. - * @param saver - * @deprecated since 1.5.1 this is ugly, need a proper centralized way to save a task modified by current class - */ - @Deprecated - public void setSaver(TimeBundleSaver saver) { - this.saver = saver; - } -} diff --git a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleVetoable.java b/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleVetoable.java deleted file mode 100644 index b911ed8..0000000 --- a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimeBundleVetoable.java +++ /dev/null @@ -1,56 +0,0 @@ -/*- - * #%L - * jTimer - * %% - * Copyright (C) 2016 CodeLutin, Charlène Servantie - * %% - * 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.plugin.timebundle; - -import org.chorem.jtimer.data.DataViolationException; -import org.chorem.jtimer.data.VetoableDataEventListener; -import org.chorem.jtimer.entities.TimerSync; -import org.chorem.jtimer.entities.TimerTask; - -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * Vetoable for forbidden action on synchronized tasks. - */ -public class TimeBundleVetoable implements VetoableDataEventListener { - - /** - * Merge project violation key. - */ - protected static final String INVALID_SYNC_LIST_VIOLATION = "vetoable.timebundle.invalid.sync.list"; - - @Override - public void checkMergeTasks(TimerTask destinationTask, List<TimerTask> otherTasks) { - Set<String> allUrls = otherTasks.stream() - .flatMap(t -> t.getSyncs().stream()) - .map(TimerSync::getUrl) - .collect(Collectors.toSet()); - Set<String> destUrls = destinationTask.getSyncs().stream() - .map(TimerSync::getUrl) - .collect(Collectors.toSet()); - if (!allUrls.equals(destUrls)) { - throw new DataViolationException("Can't merge tasks", INVALID_SYNC_LIST_VIOLATION); - } - } -} diff --git a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimerSyncCellRenderer.java b/src/main/java/org/chorem/jtimer/plugin/timebundle/TimerSyncCellRenderer.java deleted file mode 100644 index a9e124c..0000000 --- a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimerSyncCellRenderer.java +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * #%L - * jTimer - * %% - * Copyright (C) 2016 CodeLutin, Charlène Servantie - * %% - * 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.plugin.timebundle; - -import javax.swing.table.DefaultTableCellRenderer; -import java.text.SimpleDateFormat; -import java.util.Date; - -/** - * Renderer for last sync date column. - */ -public class TimerSyncCellRenderer extends DefaultTableCellRenderer { - - private Date dateValue; - private SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); - private String valueToString = ""; - - @Override - public void setValue(Object value) { - if ((value != null)) { - dateValue = (Date) value; - valueToString = dateFormat.format(dateValue); - value = valueToString; - super.setValue(value); - } - } -} diff --git a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimerSyncEditor.java b/src/main/java/org/chorem/jtimer/plugin/timebundle/TimerSyncEditor.java deleted file mode 100644 index 5740577..0000000 --- a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimerSyncEditor.java +++ /dev/null @@ -1,245 +0,0 @@ -/*- - * #%L - * jTimer - * %% - * Copyright (C) 2016 CodeLutin, Charlène Servantie - * %% - * 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.plugin.timebundle; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.chorem.jtimer.data.TimerCore; -import org.chorem.jtimer.entities.TimerProject; -import org.chorem.jtimer.entities.TimerSync; -import org.chorem.jtimer.entities.TimerTask; -import org.jdesktop.application.Application; -import org.jdesktop.application.FrameView; - -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.table.TableColumnModel; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * UI to modify Synchronization Info of a task. - */ -public class TimerSyncEditor extends FrameView implements ActionListener { - - /** - * Class logger - */ - protected static Log log = LogFactory.getLog(TimerSyncEditor.class); - - /** - * Timer core. - */ - protected TimerCore core; - - /** - * button to add a URL - */ - protected JButton addButton; - - /** - * button to delete a URL - */ - protected JButton deleteButton; - - /** - * button to test a url - */ - protected JButton testSyncUrlButton; - - /** - * JTable of URLs - */ - protected JTable urlJTable; - - /** - * task to update - */ - protected TimerTask task; - - /** - * timezone - */ - protected String timezone; - - /** - * UpdaterView constructor. - * - * @param application parent reference - * @param core core reference - * @param task the task to update - */ - public TimerSyncEditor(Application application, TimerCore core, TimerTask task) { - - super(application); - // modify frame name - getFrame().setName("syncFrame"); - getFrame().setTitle(getResourceMap().getString("syncTitle")); - - this.core = core; - this.task = task; - timezone = "+01:00"; - - setComponent(getMainComponent()); - } - - /** - * Get main view component. - * - * @return main component - */ - protected JComponent getMainComponent() { - - JPanel configComponent = new JPanel(); - configComponent.setLayout(new BorderLayout(5, 5)); - - JPanel urlPanel = new JPanel(); - urlPanel.setLayout(new BorderLayout(5, 5)); - - urlJTable = new JTable(new TimerSyncTableModel(this, task)); - //try to have coherent width of columns - TableColumnModel tableColModel = urlJTable.getColumnModel(); - tableColModel.getColumn(0).setPreferredWidth(200); - tableColModel.getColumn(1).setPreferredWidth(40); - tableColModel.getColumn(2).setPreferredWidth(60); - tableColModel.getColumn(3).setPreferredWidth(200); - - //render the date properly - tableColModel.getColumn(3).setCellRenderer(new TimerSyncCellRenderer()); - - JScrollPane scrollTablePane = new JScrollPane(urlJTable); - configComponent.add(scrollTablePane, BorderLayout.CENTER); - - //panel to hold the buttons - JPanel buttonsPane = new JPanel(new BorderLayout()); - JPanel buttonPane = new JPanel(); - buttonPane.setAlignmentX(Component.CENTER_ALIGNMENT); - - addButton = new JButton(getResourceMap().getString("addButton")); - addButton.addActionListener(this); - addButton.setActionCommand("addURL"); - - deleteButton = new JButton(getResourceMap().getString("deleteButton")); - deleteButton.addActionListener(this); - deleteButton.setActionCommand("deleteURL"); - - testSyncUrlButton = new JButton(getResourceMap().getString("testSyncButton")); - testSyncUrlButton.addActionListener(this); - testSyncUrlButton.setActionCommand("testURL"); - - buttonPane.add(addButton); - buttonPane.add(testSyncUrlButton); - buttonPane.add(deleteButton); - // button to close - JButton closeButton = new JButton(); - closeButton.setAction(getContext().getActionMap(this).get("closeView")); - - //adding components to the main one - buttonsPane.add(buttonPane, BorderLayout.CENTER); - buttonsPane.add(closeButton, BorderLayout.SOUTH); - configComponent.add(buttonsPane, BorderLayout.SOUTH); - - // color fix on linux ? - configComponent.setBackground(urlPanel.getBackground()); - // set minimum size to prevent "packed size" (too big) - configComponent.setMinimumSize(new Dimension(200, 200)); - - return configComponent; - } - - /** - * Close action. - */ - @org.jdesktop.application.Action - public void closeView() { - TimerSyncTableModel model = (TimerSyncTableModel) urlJTable.getModel(); - task.setSyncs(model.getTimerSyncList()); - if (task instanceof TimerProject) { - core.getData().modifyProject(TimerProject.class.cast(task)); - } else { - core.getData().modifyTask(task); - } - getApplication().hide(this); - } - - /** - * Method to display an error message - * - * @param errorMessage the message to display - * @param titleBar the title of the frame - */ - public static void errorBox(String errorMessage, String titleBar) { - JOptionPane.showMessageDialog(null, errorMessage, titleBar, JOptionPane.ERROR_MESSAGE); - } - - /** - * Method to display an info message - * - * @param infoMessage the message to display - * @param titleBar the title of the frame - */ - public static void infoBox(String infoMessage, String titleBar) { - JOptionPane.showMessageDialog(null, infoMessage, titleBar, JOptionPane.INFORMATION_MESSAGE); - } - - @Override - public void actionPerformed(ActionEvent actionEvent) { - - String actionCommand = actionEvent.getActionCommand(); - TimerSyncTableModel model = (TimerSyncTableModel) urlJTable.getModel(); - - if ("addURL".equals(actionCommand)) { - model.add(new TimerSync("")); - } else if ("deleteURL".equals(actionCommand)) { - TimerSync timerSync = model.getValueAt(urlJTable.getSelectedRow()); - model.remove(timerSync); - } - /*else if ("testURL".equals(actionCommand)) { - //if the test button has been clicked, test the sync on the URL and returns a message to the user - //tests only if the info exists - if (task.getSynchronizingInfoList().contains(infoToUse)) { - JsonObject testObject = TimerTaskHelper.taskToJsonObject(task, infoToUse, timezone); - int responseCode = TimerTaskSynchronizer.synchronizeTaskOnURL(testObject); - - if (responseCode > 199 && responseCode < 300) { - infoBox(getResourceMap().getString("testSyncSuccessMessage"), getResourceMap().getString("testSyncSuccessTitle")); - Calendar cal = Calendar.getInstance(); - infoToUse.setLastSync(cal.getTime()); - core.getData().syncInfoChanged(task, infoToUse); - } else { - errorBox(getResourceMap().getString("testSyncFailureMessage"), getResourceMap().getString("testSyncFailureTitle")); - } - - if (log.isDebugEnabled()) { - log.debug("Response code : " + responseCode); - } - } - } */ - } -} diff --git a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimerSyncTableModel.java b/src/main/java/org/chorem/jtimer/plugin/timebundle/TimerSyncTableModel.java deleted file mode 100644 index d38f80a..0000000 --- a/src/main/java/org/chorem/jtimer/plugin/timebundle/TimerSyncTableModel.java +++ /dev/null @@ -1,203 +0,0 @@ -/*- - * #%L - * jTimer - * %% - * Copyright (C) 2016 CodeLutin, Charlène Servantie - * %% - * 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.plugin.timebundle; - -import org.chorem.jtimer.entities.TimerSync; -import org.chorem.jtimer.entities.TimerTask; -import org.jdesktop.application.View; - -import javax.swing.table.AbstractTableModel; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -/** - * Class to deal with the syncs in a table. - */ -public class TimerSyncTableModel extends AbstractTableModel { - - /** the syncInfo list. */ - protected List<TimerSync> timerSyncList; - - /** headers of the columns. */ - protected String[] columnHeaders; - - public TimerSyncTableModel(View view, TimerTask task) { - timerSyncList = new ArrayList<>(task.getSyncs()); - columnHeaders = new String[]{ - view.getResourceMap().getString("syncURLHeader"), - view.getResourceMap().getString("activeHeader"), - view.getResourceMap().getString("withAnnotationsHeader"), - view.getResourceMap().getString("lastSyncHeader") - }; - } - - /** - * Gets the column headers - * - * @param col the column - * @return a string for the header - */ - @Override - public String getColumnName(int col) { - return columnHeaders[col]; - } - - - @Override - public int getRowCount() { - return timerSyncList.size(); - } - - /** - * returns the column number (url, activity, annotations and last sync, so 4) - */ - @Override - public int getColumnCount() { - return columnHeaders.length; - } - - /** - * Returns the value at rowIndex, columnIndex - * column 0 is url String, column 1 is activity boolean, - * column 2 is annotations boolean, column 3 is lastSync Date - * - * @param rowIndex - * @param columnIndex - * @return an Object - */ - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - Object value = ""; - TimerSync timerSync = timerSyncList.get(rowIndex); - switch (columnIndex) { - case 0: - value = timerSync.getUrl(); - break; - case 1: - value = timerSync.isActive(); - break; - case 2: - value = timerSync.isWithAnnotations(); - break; - case 3: - value = timerSync.getLastSync(); - break; - } - return value; - } - - /** - * When the data is changed - * - * @param value an object -a string- - * @param rowIndex the row selected - * @param columnIndex the column modified - */ - @Override - public void setValueAt(Object value, int rowIndex, int columnIndex) { - TimerSync timerSync = timerSyncList.get(rowIndex); - // if the url changes - switch (columnIndex) { - case 0: - timerSync.setUrl((String) value); - break; - case 1: - timerSync.setActive((Boolean) value); - break; - case 2: - timerSync.setWithAnnotations((Boolean) value); - break; - } - } - - /** - * To mark the url and checkbox cells as editable but not the date - * - * @param rowIndex - * @param columnIndex - * @return - */ - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - // the sync date is not editable - return columnIndex < 3; - } - - /** - * Returns the class of objects in the columns - * - * @param columnIndex - * @return the class - */ - - @Override - public Class<?> getColumnClass(int columnIndex) { - Class<?> result; - switch (columnIndex) { - case 0: - result = String.class; - break; - case 1: - case 2: - result = Boolean.class; - break; - case 3: - result = Date.class; - break; - default: - result = Object.class; - break; - } - - return result; - } - - /** - * Adds a syncInfo - * - * @param sync - */ - public void add(TimerSync sync) { - timerSyncList.add(sync); - fireTableRowsInserted(timerSyncList.indexOf(sync), timerSyncList.indexOf(sync)); - } - - /** - * removes a syncInfo - * - * @param sync - */ - public void remove(TimerSync sync) { - int index = timerSyncList.indexOf(sync); - timerSyncList.remove(sync); - fireTableRowsDeleted(index, index); - } - - public TimerSync getValueAt(int selectedRow) { - return timerSyncList.get(selectedRow); - } - - public List<TimerSync> getTimerSyncList() { - return timerSyncList; - } -} diff --git a/src/main/java/org/chorem/jtimer/plugins/Plugin.java b/src/main/java/org/chorem/jtimer/plugins/Plugin.java new file mode 100644 index 0000000..e57e300 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/Plugin.java @@ -0,0 +1,30 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins; + +import org.chorem.jtimer.JTimerService; + +public abstract class Plugin { + + public abstract void register(JTimerService JTimerService); + +} diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/Constants.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/Constants.java new file mode 100644 index 0000000..cabdf09 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/Constants.java @@ -0,0 +1,27 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle; + +public interface Constants { + String META = "timebundle"; +} diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/LocalSynchronizer.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/LocalSynchronizer.java new file mode 100644 index 0000000..b70c2f9 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/LocalSynchronizer.java @@ -0,0 +1,30 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle; + +/** + * Synchroniser that fallback to local cache in case remote call are not working. + */ +public class LocalSynchronizer implements Synchronizer { + +} diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/RemoteSynchronizer.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/RemoteSynchronizer.java new file mode 100644 index 0000000..1e85162 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/RemoteSynchronizer.java @@ -0,0 +1,257 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.chorem.jtimer.entities.TimerProject; +import org.chorem.jtimer.entities.TimerTask; +import org.chorem.jtimer.plugins.timebundle.data.RemoteProject; +import org.chorem.jtimer.plugins.timebundle.data.RemoteTask; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class RemoteSynchronizer implements Synchronizer { + + protected static Log log = LogFactory.getLog(RemoteSynchronizer.class); + + protected static final String DATE_MIDNIGHT_PATTERN = "yyyy-MM-dd'T'00:00:00XXX"; + + /** + * Fetch project from url such as : + * http://localhost:8080/api/v1/codelutin/contribute/a7e14ea2-fde7-4e80-aff3-03... + * + * As parse content: <pre> + * { + * project: { + * oid:"#49:0", + * parentTaskUuid:null, + * pathToProjectUuid:null, + * uuid:"01d57d63-dcd3-4a82-87e4-6698312c75c6", + * name:"jTimer", + * info:"", + * duration:0, + * startDate:"2017-03-02T13:14:09+01:00", + * endDate:null, + * contributionValidation:false, + * isPublic:false, + * openToContribution:false, + * logo:"" + * }, + * email:"chatellier@codelutin.com", + * tasks: { + * http://localhost:8080/api/v1/codelutin/contribute/a7e14ea2-fde7-4e80-aff3-03...: { + * oid:"#42:0", + * parentTaskUuid:null, + * pathToProjectUuid:null, + * uuid:"75ba149e-ac2b-470f-a44f-93d2a9bfe065", + * name:"service", + * info:"", + * duration:0, + * startDate:null, + * endDate:null, + * contributionValidation:false + * }, + * http://localhost:8080/api/v1/codelutin/contribute/a7e14ea2-fde7-4e80-aff3-03...: { + * oid:"#41:0", + * parentTaskUuid:null, + * pathToProjectUuid:null, + * uuid:"7ffb0a59-960f-483a-bd5b-1cde56aacb6d", + * name:"UI", + * info:"", + * duration:0, + * startDate:null, + * endDate:null, + * contributionValidation:false + * }, + * http://localhost:8080/api/v1/codelutin/contribute/a7e14ea2-fde7-4e80-aff3-03...: { + * oid:"#41:1", + * parentTaskUuid:null, + * pathToProjectUuid:null, + * uuid:"98132e1e-c792-4d81-99d3-5bc01dd9b8b6", + * name:"release", + * info:"", + * duration:0, + * startDate:null, + * endDate:null, + * contributionValidation:false + * }, + * http://localhost:8080/api/v1/codelutin/contribute/a7e14ea2-fde7-4e80-aff3-03398806525d/5195fa60-18cd-43af-8379-b893b523716a:{ + * oid:"#43:0", + * parentTaskUuid:null, + * pathToProjectUuid:null, + * uuid:"5195fa60-18cd-43af-8379-b893b523716a", + * name:"env", + * info:"", + * duration:0, + * startDate:null, + * endDate:null, + * contributionValidation:false + * } + * } + * } + * </pre> + * @param url + * @return + */ + public RemoteProject fetchProject(String url) { + RemoteProject project = null; + + try { + JSONObject json = new JSONObject(IOUtils.toString(new URL(url), Charset.forName("UTF-8"))); + JSONObject jsonProject = json.getJSONObject("project"); + + JSONObject jsonTasks = json.getJSONObject("tasks"); + Map<String, Object> mapTasks = jsonTasks.toMap(); + List<RemoteTask> tasks = mapTasks.entrySet().stream() + .map(entry -> { + RemoteTask task = new RemoteTask(); + task.setUrl(entry.getKey()); + + Map<String, String> value = (Map<String, String>) entry.getValue(); + task.setUuid(value.get("uuid")); + task.setName(value.get("name")); + return task; + }) + .collect(Collectors.toList()); + + project = new RemoteProject(); + project.setUuid(jsonProject.getString("uuid")); + project.setName(jsonProject.getString("name")); + project.setUrl(url); + project.setSubTasks(tasks); + } catch (IOException ex) { + + } + return project; + } + + /** + * Sync project by pushing all sub tasks times on: + * http://localhost:8080/api/v1/codelutin/contribute/a7e14ea2-fde7-4e80-aff3-03... + * + * with content:<pre> + * { + * "startDate": Date, + * "endDate": Date, + * "periods": [ // list of contributions + * { + * "id": String, // unique client id + * "startDate": Date, + * "duration": long, + * "info": String + * }, + * /....../ + * ] + * } + * </pre> + * @param timerProject + */ + public void sync(TimerProject timerProject) { + List<RemoteProject> projects = (List<RemoteProject>) timerProject.getMeta().get(Constants.META); + if (CollectionUtils.isNotEmpty(projects)) { + if (log.isDebugEnabled()) { + log.debug("Syncing timebundle project " + timerProject.getName()); + } + projects.stream() + .flatMap(tbProject -> tbProject.getSubTasks().stream()) + .forEach(this::syncTask); + } + } + + protected void syncTask(RemoteTask remoteTask) { + String url = remoteTask.getUrl(); + Set<TimerTask> syncTasks = remoteTask.getSyncTasks(); + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("startDate", DateFormatUtils.format(new Date(0), DATE_MIDNIGHT_PATTERN)); + jsonObject.put("endDate", DateFormatUtils.format(new Date(), DATE_MIDNIGHT_PATTERN)); + JSONArray periodArray = new JSONArray(); + syncTasks.forEach(timerTask -> { + timerTask.getAllDaysAndTimes().entrySet().forEach(dateLongEntry -> { + JSONObject period = new JSONObject(); + period.put("id", String.valueOf(timerTask.getNumber()) + DateFormatUtils.format(dateLongEntry.getKey(), DATE_MIDNIGHT_PATTERN)); + period.put("startDate", DateFormatUtils.format(dateLongEntry.getKey(), DATE_MIDNIGHT_PATTERN)); + period.put("duration", dateLongEntry.getValue() / 1000L); + periodArray.put(period); + }); + }); + jsonObject.put("periods", periodArray); + post(url, jsonObject); + } + + protected static void post(String url, JSONObject data) { + try { + URI uri = new URI(url); + HttpURLConnection conn = (HttpURLConnection) uri.toURL().openConnection(); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + conn.addRequestProperty("Content-Type", "application/json"); + OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); + out.write(data.toString(2)); + out.close(); + System.out.println(conn.getResponseCode()); + } catch (IOException | URISyntaxException ex) { + log.error("ex", ex); + } + System.out.println("will send : " + data.toString(2)); + } + + public static void main(String... args) { + TimerProject project = new TimerProject("jTimer"); + List<RemoteProject> tbprojects = new ArrayList<>(); + RemoteProject tbProject = new RemoteProject(); + tbProject.setUrl("http://localhost:8080/api/v1/codelutin/contribute/3a526a69-59b9-45d2-bde2-09..."); + RemoteProject tbTask = new RemoteProject(); + tbTask.setUrl("http://localhost:8080/api/v1/codelutin/contribute/3a526a69-59b9-45d2-bde2-09..."); + + TimerTask task1 = new TimerTask(); + task1.setCreationDate(new Date()); + task1.setTime(new Date(), 42L); + tbTask.setSyncTasks(Collections.singleton(task1)); + tbProject.setSubTasks(Collections.singletonList(tbTask)); + tbprojects.add(tbProject); + project.getMeta().put(Constants.META, tbprojects); + + RemoteSynchronizer r = new RemoteSynchronizer(); + r.sync(project); + } +} diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/SyncIOSaver.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/SyncIOSaver.java new file mode 100644 index 0000000..3fea5e3 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/SyncIOSaver.java @@ -0,0 +1,211 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.chorem.jtimer.JTimerConfig; +import org.chorem.jtimer.entities.TimerProject; +import org.chorem.jtimer.entities.TimerTask; +import org.chorem.jtimer.plugins.timebundle.data.RemoteProject; +import org.chorem.jtimer.plugins.timebundle.data.RemoteTask; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class SyncIOSaver { + + protected static Log log = LogFactory.getLog(SyncIOSaver.class); + + protected static final String TIMEBUNDLE_DATA_DIRECTORY = "timebundledatabeta1"; + + protected static final String TIMEBUNDLE_CACHE_DIRECTORY = "timebundlecachebeta1"; + + protected File dataDirectory; + + protected File cacheDirectory; + + public SyncIOSaver(JTimerConfig config) { + File homeDirectory = config.getHomeDirectory(); + dataDirectory = new File(homeDirectory, TIMEBUNDLE_DATA_DIRECTORY); + dataDirectory.mkdirs(); + cacheDirectory = new File(homeDirectory, TIMEBUNDLE_CACHE_DIRECTORY); + cacheDirectory.mkdirs(); + } + + public void saveProject(TimerProject project) { + if (log.isDebugEnabled()) { + log.debug("Saving timebundle project " + project.getName()); + } + try { + List<RemoteProject> remoteProjects = (List<RemoteProject>) project.getMeta().get(Constants.META); + if (CollectionUtils.isEmpty(remoteProjects)) { + clearSyncInfos(project); + } else { + saveSyncInfo(project, remoteProjects); + saveTaskLinks(project, remoteProjects); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + protected void saveSyncInfo(TimerProject project, List<RemoteProject> remoteProjects) throws IOException { + Gson gson = new Gson(); + String json = gson.toJson(remoteProjects); + File jsonFile = new File(dataDirectory, project.getNumber() + ".json"); + FileUtils.writeStringToFile(jsonFile, json, StandardCharsets.UTF_8); + } + + protected void saveTaskLinks(TimerProject project, List<RemoteProject> remoteProjects) throws IOException { + + Properties props = new Properties(); + remoteProjects.forEach(remoteProject -> saveTaskLinks(props, remoteProject.getSubTasks())); + + + File syncFile = new File(dataDirectory, project.getNumber() + ".sync"); + if (props.isEmpty()) { + syncFile.delete(); + } else { + try (FileWriter writer = new FileWriter(syncFile)) { + props.store(writer, null); + } + } + } + + private void saveTaskLinks(Properties props, List<RemoteTask> remoteTasks) { + if (remoteTasks != null) { + remoteTasks.forEach(remoteTask -> { + String values = remoteTask.getSyncTasks() + .stream() + .mapToInt(TimerTask::getNumber) + .mapToObj(Integer::toString) + .collect(Collectors.joining(",")); + if (!values.isEmpty()) { + props.put(remoteTask.getUuid(), values); + } + saveTaskLinks(props, remoteTask.getSubTasks()); + }); + } + } + + public void deleteProject(TimerProject project) { + clearSyncInfos(project); + } + + protected void clearSyncInfos(TimerProject project) { + if (log.isDebugEnabled()) { + log.debug("Clearing timebundle project " + project.getName()); + } + File jsonFile = new File(dataDirectory, project.getNumber() + ".json"); + jsonFile.delete(); + File syncFile = new File(dataDirectory, project.getNumber() + ".sync"); + syncFile.delete(); + } + + public void loadSyncInfos(Collection<TimerProject> projects) { + projects.forEach(this::loadProjectSyncInfos); + } + + protected void loadProjectSyncInfos(TimerProject project) { + File jsonFile = new File(dataDirectory, project.getNumber() + ".json"); + if (jsonFile.isFile()) { + try (JsonReader reader = new JsonReader(new FileReader(jsonFile))) { + // load remote + Gson gson = new Gson(); + Type REVIEW_TYPE = new TypeToken<List<RemoteProject>>() { + }.getType(); + List<RemoteProject> data = gson.fromJson(reader, REVIEW_TYPE); + project.getMeta().put(Constants.META, data); + Map<String, RemoteTask> remoteTaskById = new HashMap<>(); + data.forEach(remoteProject -> loadRemoteTaskMap(remoteTaskById, remoteProject.getSubTasks())); + + // load sync + File syncFile = new File(dataDirectory, project.getNumber() + ".sync"); + if (syncFile.isFile()) { + try (Reader syncReader = new FileReader(syncFile)) { + // load sync + Properties props = new Properties(); + props.load(syncReader); + Map<Integer, TimerTask> timerTaskByNumber = new HashMap<>(); + loadTimerTaskMap(timerTaskByNumber, project.getSubTasks()); + + // match remote and sync + remoteTaskById.entrySet().forEach(entry -> { + RemoteTask value = entry.getValue(); + String uuid = value.getUuid(); + String syncList = (String)props.get(uuid); + if (syncList != null) { + Set<TimerTask> syncTasks = Arrays.stream(syncList.split("\\s*,\\s*")) + .map(Integer::valueOf) + .map(timerTaskByNumber::get) + .collect(Collectors.toSet()); + value.setSyncTasks(syncTasks); + } + }); + } + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private void loadTimerTaskMap(Map<Integer, TimerTask> taskByNumber, List<TimerTask> subTasks) { + if (subTasks != null) { + Map<Integer, TimerTask> result = subTasks.stream() + .collect(Collectors.toMap(TimerTask::getNumber, Function.identity())); + taskByNumber.putAll(result); + subTasks.forEach(task -> loadTimerTaskMap(taskByNumber, task.getSubTasks())); + } + } + + private void loadRemoteTaskMap(Map<String, RemoteTask> remoteTaskById, List<RemoteTask> subTasks) { + if (subTasks != null) { + Map<String, RemoteTask> result = subTasks.stream() + .collect(Collectors.toMap(RemoteTask::getUuid, Function.identity())); + remoteTaskById.putAll(result); + subTasks.forEach(task -> loadRemoteTaskMap(remoteTaskById, task.getSubTasks())); + } + } +} diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/SyncView.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/SyncView.java new file mode 100644 index 0000000..b8e32c2 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/SyncView.java @@ -0,0 +1,207 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle; + +import org.chorem.jtimer.JTimerService; +import org.chorem.jtimer.entities.TimerProject; +import org.chorem.jtimer.entities.TimerTask; +import org.chorem.jtimer.plugins.timebundle.data.RemoteProject; +import org.chorem.jtimer.plugins.timebundle.data.RemoteTask; +import org.chorem.jtimer.plugins.timebundle.model.RemoteTaskTreeModel; +import org.chorem.jtimer.plugins.timebundle.model.RemoveTaskCellRenderer; +import org.chorem.jtimer.ui.tree.CheckBoxTreeCellEditor; +import org.chorem.jtimer.ui.tree.CheckBoxTreeCellRenderer; +import org.chorem.jtimer.ui.tree.TaskTreeModel; +import org.jdesktop.application.Application; +import org.jdesktop.application.FrameView; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.TreePath; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +public class SyncView extends FrameView implements TreeSelectionListener, WindowListener { + + protected RemoteSynchronizer synchronizer; + protected SyncIOSaver saver; + protected JTimerService service; + protected TimerProject timerProject; + + protected JTree remoteProjectTree = new JTree(); + protected RemoteTaskTreeModel projectModel; + + protected JTree projectsTree = new JTree(); + protected TaskTreeModel treeModel; + + public SyncView(Application application, JTimerService service, SyncIOSaver saver, + RemoteSynchronizer synchronizer, TimerProject timerProject) { + super(application); + this.service = service; + this.timerProject = timerProject; + this.synchronizer = synchronizer; + this.saver = saver; + + // modify frame name + getFrame().setName("timebundleFrame"); + getFrame().setTitle("Time bundle"); + + List<RemoteProject> timebundle = getRemoteProjects(); + projectModel = new RemoteTaskTreeModel(timebundle); + treeModel = new TaskTreeModel(Collections.singletonList(timerProject)); + + setComponent(getMainComponent()); + + this.getFrame().addWindowListener(this); + } + + protected List<RemoteProject> getRemoteProjects() { + return (List<RemoteProject>)this.timerProject.getMeta().computeIfAbsent(Constants.META, k -> new ArrayList<>()); + } + + /** + * Get main view component. + * + * @return main component + */ + protected JComponent getMainComponent() { + JPanel mainPanel = new JPanel(new GridBagLayout()); + + JLabel projectLabel = new JLabel("Remote projects:"); + mainPanel.add(projectLabel, new GridBagConstraints(0, 0, 1, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(1, 1, 1, 1), 0, 0)); + + remoteProjectTree.setRootVisible(false); + remoteProjectTree.setShowsRootHandles(true); + remoteProjectTree.setModel(projectModel); + remoteProjectTree.setCellRenderer(new RemoveTaskCellRenderer()); + remoteProjectTree.addTreeSelectionListener(this); + JScrollPane projectScroll = new JScrollPane(remoteProjectTree); + mainPanel.add(projectScroll, new GridBagConstraints(0, 1, 1, 1, 1, 1, + GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(1, 1, 1, 1), 0, 0)); + + JButton addProject = new JButton("Add project"); + addProject.addActionListener(l -> addRemoteProject()); + mainPanel.add(addProject, new GridBagConstraints(0, 2, 1, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(1, 1, 1, 1), 0, 0)); + + JLabel treeLabel = new JLabel("Local projects:"); + mainPanel.add(treeLabel, new GridBagConstraints(2, 0, 1, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(1, 1, 1, 1), 0, 0)); + + projectsTree.setRootVisible(false); + projectsTree.setEditable(true); + projectsTree.setShowsRootHandles(true); + projectsTree.setModel(treeModel); + TreeSet<TimerTask> selection = new TreeSet<>(); + projectsTree.setCellRenderer(new CheckBoxTreeCellRenderer(service, projectsTree, selection, false)); + projectsTree.setCellEditor(new CheckBoxTreeCellEditor(service, projectsTree, selection, false)); + projectsTree.expandPath(new TreePath(treeModel.getRoot()).pathByAddingChild(timerProject)); + JScrollPane treeScroll = new JScrollPane(projectsTree); + mainPanel.add(treeScroll, new GridBagConstraints(2, 1, 1, 1, 1, 1, + GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(1, 1, 1, 1), 0, 0)); + + JButton syncAll = new JButton("Sync"); + syncAll.addActionListener(l -> syncProjects()); + mainPanel.add(syncAll, new GridBagConstraints(2, 2, 1, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(1, 1, 1, 1), 0, 0)); + + return mainPanel; + } + + public void addRemoteProject() { + String url = (String)JOptionPane.showInputDialog(this.getFrame(), + "New remote project url", "Add remote project", + JOptionPane.INFORMATION_MESSAGE, null, + new Object[] {"http://localhost:8080/api/v1/codelutin/contribute/9370ee7e-7767-482c-b798-7a7262bc417f/#jTimer"}, + "http://localhost:8080/api/v1/codelutin/contribute/9370ee7e-7767-482c-b798-7a..."); + + RemoteProject project = synchronizer.fetchProject(url); + getRemoteProjects().add(project); + projectModel.addElement(project); + remoteProjectTree.expandPath(new TreePath(projectModel.getRoot()).pathByAddingChild(project)); + } + + public void syncProjects() { + synchronizer.sync(timerProject); + } + + @Override + public void valueChanged(TreeSelectionEvent treeSelectionEvent) { + RemoteTask task = (RemoteTask)treeSelectionEvent.getPath().getLastPathComponent(); + Set<TimerTask> selection = task.getSyncTasks(); + projectsTree.setCellRenderer(new CheckBoxTreeCellRenderer(service, projectsTree, selection, false)); + projectsTree.setCellEditor(new CheckBoxTreeCellEditor(service, projectsTree, selection, false)); + projectsTree.validate(); + } + + @Override + public void windowOpened(WindowEvent e) { + + } + + @Override + public void windowClosing(WindowEvent e) { + saver.saveProject(timerProject); + } + + @Override + public void windowClosed(WindowEvent e) { + + } + + @Override + public void windowIconified(WindowEvent e) { + + } + + @Override + public void windowDeiconified(WindowEvent e) { + + } + + @Override + public void windowActivated(WindowEvent e) { + + } + + @Override + public void windowDeactivated(WindowEvent e) { + + } +} diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/Synchronizer.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/Synchronizer.java new file mode 100644 index 0000000..e15ba9f --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/Synchronizer.java @@ -0,0 +1,27 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle; + +public interface Synchronizer { + +} diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/TimeBundlePlugin.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/TimeBundlePlugin.java new file mode 100644 index 0000000..efe5be8 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/TimeBundlePlugin.java @@ -0,0 +1,131 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.chorem.jtimer.JTimer; +import org.chorem.jtimer.JTimerService; +import org.chorem.jtimer.data.DataEventListener; +import org.chorem.jtimer.data.TimerDataManager; +import org.chorem.jtimer.data.VetoableDataEventListener; +import org.chorem.jtimer.entities.TimerProject; +import org.chorem.jtimer.plugins.Plugin; +import org.chorem.jtimer.ui.TimerUIManager; +import org.chorem.jtimer.ui.UserInterfaceListener; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.KeyStroke; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class TimeBundlePlugin extends Plugin implements DataEventListener, VetoableDataEventListener, + UserInterfaceListener, PropertyChangeListener, Runnable { + + protected static Log log = LogFactory.getLog(TimeBundlePlugin.class); + + protected JTimerService service; + + protected JTimer application; + + protected Action timeBundleAction; + + protected RemoteSynchronizer synchronizer; + + protected SyncIOSaver saver; + + @Override + public void register(JTimerService service) { + this.service = service; + TimerDataManager data = service.getData(); + data.addDataEventListener(this); + data.addVetoableDataEventListener(this); + + TimerUIManager ui = service.getUi(); + ui.addUserInterfaceListener(this); + + synchronizer = new RemoteSynchronizer(); + saver = new SyncIOSaver(JTimer.config); + ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(); + ses.scheduleAtFixedRate(this, 1, 60, TimeUnit.MINUTES); + } + + @Override + public void initUI(JTimer application) { + this.application = application; + + timeBundleAction = new AbstractAction("Time bundle") { + @Override + public void actionPerformed(ActionEvent e) { + TimerProject project = application.getSelectedProject().get(0); + SyncView view = new SyncView(application, service, saver, synchronizer, project); + application.show(view); + } + }; + timeBundleAction.setEnabled(false); + timeBundleAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F3, KeyEvent.SHIFT_MASK)); + + JMenuItem menuItem = new JMenuItem(timeBundleAction); + + JMenuBar jMenuBar = application.getMainFrame().getJMenuBar(); + JMenu menuProject = jMenuBar.getMenu(0); + menuProject.add(menuItem, 2); + + if (log.isInfoEnabled()) { + log.info("Time bundle UI registered"); + } + + application.addPropertyChangeListener(this); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("selectedSingleProject")) { + timeBundleAction.setEnabled((boolean)evt.getNewValue()); + } + } + + @Override + public void dataLoaded(Collection<TimerProject> projects) { + saver.loadSyncInfos(projects); + } + + @Override + public void run() { + if (log.isInfoEnabled()) { + log.info("Auto sync projects"); + } + List<TimerProject> projectsList = service.getData().getProjectsList(); + projectsList.forEach(synchronizer::sync); + } +} diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/data/RemoteProject.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/data/RemoteProject.java new file mode 100644 index 0000000..3e33e01 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/data/RemoteProject.java @@ -0,0 +1,27 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle.data; + +public class RemoteProject extends RemoteTask { + +} diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/data/RemoteTask.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/data/RemoteTask.java new file mode 100644 index 0000000..699cf88 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/data/RemoteTask.java @@ -0,0 +1,85 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle.data; + +import org.chorem.jtimer.entities.TimerTask; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class RemoteTask implements Serializable { + + protected String uuid; + + protected String name; + + protected String url; + + protected List<RemoteTask> subTasks; + + protected transient Set<TimerTask> syncTasks = new HashSet<>(); + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUrl() { + return url; + } + + public void setSyncTasks(Set<TimerTask> syncTasks) { + this.syncTasks = syncTasks; + } + + public Set<TimerTask> getSyncTasks() { + return syncTasks; + } + + public void setSubTasks(List<RemoteTask> subTasks) { + this.subTasks = subTasks; + } + + public List<RemoteTask> getSubTasks() { + return subTasks; + } +} + + diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/model/RemoteTaskTreeModel.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/model/RemoteTaskTreeModel.java new file mode 100644 index 0000000..00357c6 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/model/RemoteTaskTreeModel.java @@ -0,0 +1,121 @@ +/* + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle.model; + +import org.chorem.jtimer.plugins.timebundle.data.RemoteTask; +import org.jdesktop.swingx.tree.TreeModelSupport; + +import javax.swing.event.TreeModelListener; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; +import java.util.List; + +/** + * Remote task tree data. + */ +public class RemoteTaskTreeModel implements TreeModel { + + protected TreeModelSupport modelSupport; + + protected List<? extends RemoteTask> projects; + + /** + * Constructor. + * + * @param projects root projects + */ + public RemoteTaskTreeModel(List<? extends RemoteTask> projects) { + this.projects = projects; + modelSupport = new TreeModelSupport(this); + } + + @Override + public Object getChild(Object parent, int index) { + RemoteTask child = getChildrenFor(parent).get(index); + return child; + } + + @Override + public int getChildCount(Object parent) { + List<? extends RemoteTask> childrenFor = getChildrenFor(parent); + int count = childrenFor != null ? childrenFor.size() : 0; + return count; + } + + /** + * Recupere la sous liste: projects si parent = root + * getSubTasks() sinon + * + * @param parent parent to task sublist + * @return children + */ + protected List<? extends RemoteTask> getChildrenFor(Object parent) { + + List<? extends RemoteTask> result; + + // get correct list + if (parent == getRoot()) { // case root node + result = projects; + } else { // not root node + result = RemoteTask.class.cast(parent).getSubTasks(); + } + + return result; + } + + @Override + public int getIndexOfChild(Object parent, Object child) { + int count = getChildrenFor(parent).indexOf(parent); + return count; + } + + @Override + public boolean isLeaf(Object node) { + return getChildCount(node) == 0; + } + + @Override + public void addTreeModelListener(TreeModelListener l) { + modelSupport.addTreeModelListener(l); + } + + @Override + public Object getRoot() { + return this; + } + + @Override + public void removeTreeModelListener(TreeModelListener l) { + modelSupport.removeTreeModelListener(l); + } + + @Override + public void valueForPathChanged(TreePath path, Object newValue) { + + } + + public void addElement(RemoteTask task) { + // FIXME change this + modelSupport.fireNewRoot(); + } +} diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/model/RemoveTaskCellRenderer.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/model/RemoveTaskCellRenderer.java new file mode 100644 index 0000000..d3211d7 --- /dev/null +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/model/RemoveTaskCellRenderer.java @@ -0,0 +1,42 @@ +/* + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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.plugins.timebundle.model; + +import org.chorem.jtimer.plugins.timebundle.data.RemoteTask; + +import javax.swing.JTree; +import javax.swing.tree.DefaultTreeCellRenderer; +import java.awt.Component; + +/** + * Remote task tree node cell renderer. + */ +public class RemoveTaskCellRenderer extends DefaultTreeCellRenderer { + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, + boolean leaf, int row, boolean hasFocus) { + Object value2 = value instanceof RemoteTask ? ((RemoteTask)value).getName() : value; + return super.getTreeCellRendererComponent(tree, value2, selected, expanded, leaf, row, hasFocus); + } +} diff --git a/src/main/java/org/chorem/jtimer/ui/NewTaskView.java b/src/main/java/org/chorem/jtimer/ui/NewTaskView.java index d8e4e12..39bd894 100644 --- a/src/main/java/org/chorem/jtimer/ui/NewTaskView.java +++ b/src/main/java/org/chorem/jtimer/ui/NewTaskView.java @@ -24,7 +24,7 @@ package org.chorem.jtimer.ui; import org.apache.commons.lang3.StringUtils; import org.chorem.jtimer.JTimer; import org.chorem.jtimer.data.DataViolationException; -import org.chorem.jtimer.data.TimerCore; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.entities.TimerTask; import org.chorem.jtimer.ui.widget.DialogView; import org.jdesktop.application.Action; @@ -59,17 +59,17 @@ import java.util.Set; public class NewTaskView extends DialogView { protected JTimer parent; - protected TimerCore core; + protected JTimerService service; protected ActionMap actionMap; protected TimerTask selectedTask; protected JTextField newTaskField; protected JComboBox<String> newTaskTemplateBox; - public NewTaskView(JTimer parent, TimerCore core, TimerTask selectedTask) { + public NewTaskView(JTimer parent, JTimerService service, TimerTask selectedTask) { super(parent.getMainFrame(), parent); this.parent = parent; - this.core = core; + this.service = service; this.selectedTask = selectedTask; actionMap = parent.getContext().getActionMap(this); @@ -157,7 +157,7 @@ public class NewTaskView extends DialogView { t.setCreationDate(new Date()); try { - core.getData().addTask(selectedTask, t, taskTemplate); + service.getData().addTask(selectedTask, t, taskTemplate); parent.selectTask(t); } catch (DataViolationException e) { parent.displayErrorMessage(e.getExceptionKey()); diff --git a/src/main/java/org/chorem/jtimer/ui/TimerTaskEditor.java b/src/main/java/org/chorem/jtimer/ui/TimerTaskEditor.java index 1b1e34f..0e6dce5 100644 --- a/src/main/java/org/chorem/jtimer/ui/TimerTaskEditor.java +++ b/src/main/java/org/chorem/jtimer/ui/TimerTaskEditor.java @@ -25,8 +25,8 @@ package org.chorem.jtimer.ui; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.jtimer.JTimer; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.data.DataViolationException; -import org.chorem.jtimer.data.TimerCore; import org.chorem.jtimer.data.TimerDataManager; import org.chorem.jtimer.entities.TimerTask; import org.chorem.jtimer.entities.TimerTaskHelper; @@ -103,8 +103,8 @@ public class TimerTaskEditor extends DialogView { protected TimerTask task; /** task to edit */ protected TimerTask cloneTask; - /** timer core */ - protected TimerCore core; + /** timer service */ + protected JTimerService service; /** task manager */ protected TimerDataManager dataManager; @@ -136,9 +136,9 @@ public class TimerTaskEditor extends DialogView { * * @param parent * @param task - * @param core + * @param service */ - public TimerTaskEditor(JTimer parent, TimerTask task, TimerCore core) { + public TimerTaskEditor(JTimer parent, TimerTask task, JTimerService service) { super(parent.getMainFrame(), parent); this.parent = parent; @@ -154,8 +154,8 @@ public class TimerTaskEditor extends DialogView { this.task = task; cloneTask = task.clone(); - this.core = core; - dataManager = core.getData(); + this.service = service; + dataManager = service.getData(); // init resources map //ApplicationContext ctxt = parent.getContext(); diff --git a/src/main/java/org/chorem/jtimer/ui/TimerUIManager.java b/src/main/java/org/chorem/jtimer/ui/TimerUIManager.java new file mode 100644 index 0000000..8a52add --- /dev/null +++ b/src/main/java/org/chorem/jtimer/ui/TimerUIManager.java @@ -0,0 +1,50 @@ +/*- + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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 org.chorem.jtimer.JTimer; + +import javax.swing.JPopupMenu; +import java.util.ArrayList; +import java.util.Collection; + +public class TimerUIManager { + + protected Collection<UserInterfaceListener> userInterfaceListeners = new ArrayList<>(); + + public void addUserInterfaceListener(UserInterfaceListener listener) { + userInterfaceListeners.add(listener); + } + + public void removeUserInterfaceListener(UserInterfaceListener listener) { + userInterfaceListeners.remove(listener); + } + + public void initUI(JTimer application) { + userInterfaceListeners.forEach(l -> l.initUI(application)); + } + + public void initTreePopupMenu(JPopupMenu menu) { + userInterfaceListeners.forEach(l -> l.initTreePopupMenu(menu)); + } + +} diff --git a/src/main/java/org/chorem/jtimer/ui/UserInterfaceListener.java b/src/main/java/org/chorem/jtimer/ui/UserInterfaceListener.java new file mode 100644 index 0000000..b416bff --- /dev/null +++ b/src/main/java/org/chorem/jtimer/ui/UserInterfaceListener.java @@ -0,0 +1,37 @@ +/* + * #%L + * jTimer + * %% + * Copyright (C) 2017 CodeLutin + * %% + * 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 org.chorem.jtimer.JTimer; + +import javax.swing.JPopupMenu; + +public interface UserInterfaceListener { + + default void initUI(JTimer application) { + + } + + default void initTreePopupMenu(JPopupMenu menu) { + + } +} diff --git a/src/main/java/org/chorem/jtimer/ui/report/ReportView.java b/src/main/java/org/chorem/jtimer/ui/report/ReportView.java index bd70f45..79469fc 100644 --- a/src/main/java/org/chorem/jtimer/ui/report/ReportView.java +++ b/src/main/java/org/chorem/jtimer/ui/report/ReportView.java @@ -25,7 +25,7 @@ package org.chorem.jtimer.ui.report; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.jtimer.JTimer; -import org.chorem.jtimer.data.TimerCore; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; import org.chorem.jtimer.ui.report.ReportGenerator.Type; @@ -88,8 +88,8 @@ public class ReportView extends FrameView implements DocumentListener { /** Class logger */ protected static Log log = LogFactory.getLog(ReportView.class); - /** Timer core. */ - protected TimerCore core; + /** Timer service. */ + protected JTimerService service; /** Unselected task set. */ protected Set<TimerTask> uncheckedTaskSet; @@ -136,9 +136,9 @@ public class ReportView extends FrameView implements DocumentListener { * Reposts constructor. * * @param application parent reference - * @param core core reference + * @param service service reference */ - public ReportView(Application application, TimerCore core) { + public ReportView(Application application, JTimerService service) { super(application); @@ -147,7 +147,7 @@ public class ReportView extends FrameView implements DocumentListener { getFrame().setName("reportFrame"); getFrame().setTitle(getResourceMap().getString("reportTitle")); - this.core = core; + this.service = service; this.uncheckedTaskSet = new HashSet<>(); // set title @@ -264,11 +264,12 @@ public class ReportView extends FrameView implements DocumentListener { GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); projectsTree = new JTree(); - projectsTree.setRootVisible(true); + projectsTree.setRootVisible(false); + projectsTree.setShowsRootHandles(true); projectsTree.setEditable(true); - projectsTree.setModel(new TaskTreeModel(core, getResourceMap().getString("reportProjectsList") + " :")); - projectsTree.setCellEditor(new CheckBoxTreeCellEditor(core, projectsTree, uncheckedTaskSet)); - projectsTree.setCellRenderer(new CheckBoxTreeCellRenderer(core, projectsTree, uncheckedTaskSet)); + projectsTree.setModel(new TaskTreeModel(service)); + projectsTree.setCellEditor(new CheckBoxTreeCellEditor(service, projectsTree, uncheckedTaskSet, true)); + projectsTree.setCellRenderer(new CheckBoxTreeCellRenderer(service, projectsTree, uncheckedTaskSet, true)); JScrollPane jspTable = new JScrollPane(projectsTree); panelProjects.add(jspTable, new GridBagConstraints(0, 1, 1, 1, 1, 1, @@ -408,8 +409,7 @@ public class ReportView extends FrameView implements DocumentListener { // get filtered project list // without non selected project and tasks - List<TimerProject> selectedProjects = getSelectedProjects(core - .getData().getProjectsList(), uncheckedTaskSet); + List<TimerProject> selectedProjects = getSelectedProjects(service.getData().getProjectsList(), uncheckedTaskSet); // make report String report = reportGenerator.getReportText(reportType, selectedProjects, datePickerFrom.getDate(), diff --git a/src/main/java/org/chorem/jtimer/ui/tasks/IdleDialog.java b/src/main/java/org/chorem/jtimer/ui/tasks/IdleDialog.java index 82624ea..c683cb3 100644 --- a/src/main/java/org/chorem/jtimer/ui/tasks/IdleDialog.java +++ b/src/main/java/org/chorem/jtimer/ui/tasks/IdleDialog.java @@ -26,7 +26,7 @@ import org.apache.commons.lang3.time.DurationFormatUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.jtimer.JTimer; -import org.chorem.jtimer.data.TimerCore; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.entities.TimerTask; import org.chorem.jtimer.ui.tree.ProjectsAndTasksTree; import org.chorem.jtimer.ui.tree.TaskTreeModel; @@ -105,8 +105,8 @@ public class IdleDialog extends JDialog { /** Parent application. */ protected SingleFrameApplication application; - /** Timer core. */ - protected TimerCore core; + /** Timer service. */ + protected JTimerService service; /** I18N resource map. */ protected ResourceMap resourceMap; @@ -147,13 +147,13 @@ public class IdleDialog extends JDialog { * Protected to force use of show static method. * * @param application parent application - * @param core timer core + * @param service timer service */ - protected IdleDialog(SingleFrameApplication application, TimerCore core) { + protected IdleDialog(SingleFrameApplication application, JTimerService service) { // don't make reference on other parent // windows, cause idle to unlock some task // if parent window is hidden by systray - this.core = core; + this.service = service; // init resources map this.application = application; @@ -284,7 +284,7 @@ public class IdleDialog extends JDialog { projectsTree = new ProjectsAndTasksTree(); projectsTree.setRootVisible(false); projectsTree.setShowsRootHandles(true); - projectsTree.setModel(new TaskTreeModel(core, null)); + projectsTree.setModel(new TaskTreeModel(service)); projectsTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); projectsTree.setCellRenderer(new ProjectsAndTasksCellRenderer()); projectsTree.addTreeSelectionListener(e -> { @@ -323,10 +323,10 @@ public class IdleDialog extends JDialog { * Init dialog idleDialog instance. * * @param parent parent reference - * @param core core reference + * @param service service reference */ - public static void init(SingleFrameApplication parent, TimerCore core) { - idleDialog = new IdleDialog(parent, core); + public static void init(SingleFrameApplication parent, JTimerService service) { + idleDialog = new IdleDialog(parent, service); } /** diff --git a/src/main/java/org/chorem/jtimer/ui/tasks/RefreshTreeTask.java b/src/main/java/org/chorem/jtimer/ui/tasks/RefreshTreeTask.java index 4be4c6b..774f28d 100644 --- a/src/main/java/org/chorem/jtimer/ui/tasks/RefreshTreeTask.java +++ b/src/main/java/org/chorem/jtimer/ui/tasks/RefreshTreeTask.java @@ -24,7 +24,7 @@ package org.chorem.jtimer.ui.tasks; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.chorem.jtimer.data.TimerCore; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.data.TimerDataManager; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; @@ -50,12 +50,12 @@ public class RefreshTreeTask extends java.util.TimerTask { protected TimerDataManager dataManager; /** - * Constructor with core. + * Constructor with service. * - * @param core core + * @param service service */ - public RefreshTreeTask(TimerCore core) { - dataManager = core.getData(); + public RefreshTreeTask(JTimerService service) { + dataManager = service.getData(); } /* diff --git a/src/main/java/org/chorem/jtimer/ui/tasks/RunTaskJob.java b/src/main/java/org/chorem/jtimer/ui/tasks/RunTaskJob.java index 7aed6ef..24f163f 100644 --- a/src/main/java/org/chorem/jtimer/ui/tasks/RunTaskJob.java +++ b/src/main/java/org/chorem/jtimer/ui/tasks/RunTaskJob.java @@ -49,7 +49,7 @@ import java.util.concurrent.atomic.AtomicLong; /** * RunTaskJob. * - * Notify every second the core controler. + * Notify every second the service controler. * * @author chatellier * @version $Revision$ diff --git a/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellComponent.java b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellComponent.java index 2bdbb8e..0a08e49 100644 --- a/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellComponent.java +++ b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellComponent.java @@ -22,7 +22,7 @@ package org.chorem.jtimer.ui.tree; -import org.chorem.jtimer.data.TimerCore; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.entities.TimerTask; import javax.swing.JCheckBox; @@ -45,26 +45,31 @@ public abstract class CheckBoxTreeCellComponent extends JCheckBox { /** serialVersionUID */ private static final long serialVersionUID = 2497464481840318274L; - /** Timer core. */ - protected TimerCore core; + /** Timer service. */ + protected JTimerService service; /** Parent tree. */ protected JTree parentTree; /** Unchecked task set. */ - protected Set<TimerTask> uncheckedTaskSet; + protected Set<TimerTask> checkedTaskSet; + + /** To uncheck instead of checking. */ + protected boolean uncheck; /** * Constructor. * - * @param core core reference + * @param service service reference * @param parentTree tree reference - * @param uncheckedTaskList common unselected tasks list + * @param checkedTaskSet common unselected tasks list + * @param uncheck to uncheck instead of check by default */ - protected CheckBoxTreeCellComponent(TimerCore core, JTree parentTree, Set<TimerTask> uncheckedTaskList) { - this.core = core; + protected CheckBoxTreeCellComponent(JTimerService service, JTree parentTree, Set<TimerTask> checkedTaskSet, boolean uncheck) { + this.service = service; this.parentTree = parentTree; - this.uncheckedTaskSet = uncheckedTaskList; + this.checkedTaskSet = checkedTaskSet; + this.uncheck = uncheck; } /** @@ -78,8 +83,7 @@ public abstract class CheckBoxTreeCellComponent extends JCheckBox { * @param row row * @return check box component */ - protected Component getCheckBoxComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, - int row) { + protected Component getCheckBoxComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) { // if this is a task if (value instanceof TimerTask) { @@ -96,7 +100,7 @@ public abstract class CheckBoxTreeCellComponent extends JCheckBox { } // set checked ? - if (uncheckedTaskSet.contains(task)) { + if (checkedTaskSet.contains(task) == uncheck) { this.setSelected(false); } else { this.setSelected(true); diff --git a/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellEditor.java b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellEditor.java index e260b25..b950161 100644 --- a/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellEditor.java +++ b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellEditor.java @@ -24,7 +24,7 @@ package org.chorem.jtimer.ui.tree; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.chorem.jtimer.data.TimerCore; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; @@ -66,12 +66,13 @@ public class CheckBoxTreeCellEditor extends CheckBoxTreeCellComponent implements /** * Constructor. * - * @param core core + * @param service service * @param parentTree tree - * @param uncheckedTaskList common unselected tasks list + * @param checkedTaskSet common unselected tasks list + * @param uncheck to uncheck instead of check by default */ - public CheckBoxTreeCellEditor(TimerCore core, JTree parentTree, Set<TimerTask> uncheckedTaskList) { - super(core, parentTree, uncheckedTaskList); + public CheckBoxTreeCellEditor(JTimerService service, JTree parentTree, Set<TimerTask> checkedTaskSet, boolean uncheck) { + super(service, parentTree, checkedTaskSet, uncheck); addItemListener(this); cellEditorListeners = new ArrayList<>(); @@ -130,9 +131,6 @@ public class CheckBoxTreeCellEditor extends CheckBoxTreeCellComponent implements return true; } - /* - * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) - */ @Override public void itemStateChanged(ItemEvent e) { @@ -173,15 +171,15 @@ public class CheckBoxTreeCellEditor extends CheckBoxTreeCellComponent implements + lastPathComponent.getName()); } - if (select) { - uncheckedTaskSet.remove(lastPathComponent); + if (select == uncheck) { + checkedTaskSet.remove(lastPathComponent); } else { - uncheckedTaskSet.add(lastPathComponent); + checkedTaskSet.add(lastPathComponent); } // special case, root node selection if (parentTree.getModel().getRoot() == lastPathComponent) { - for (TimerProject project : core.getData().getProjectsList()) { + for (TimerProject project : service.getData().getProjectsList()) { TreePath subTreePath = treePath.pathByAddingChild(project); updateChildren(subTreePath, select); } diff --git a/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellRenderer.java b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellRenderer.java index dcddacb..93f07ee 100644 --- a/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellRenderer.java +++ b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellRenderer.java @@ -22,7 +22,7 @@ package org.chorem.jtimer.ui.tree; -import org.chorem.jtimer.data.TimerCore; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.entities.TimerTask; import javax.swing.JTree; @@ -48,13 +48,14 @@ public class CheckBoxTreeCellRenderer extends CheckBoxTreeCellComponent /** * Constructor. * - * @param core core + * @param service service * @param parentTree tree - * @param uncheckedTaskList common unselected tasks list + * @param checkedTaskList common unselected tasks list + * @param uncheck to uncheck instead of check by default */ - public CheckBoxTreeCellRenderer(TimerCore core, JTree parentTree, - Set<TimerTask> uncheckedTaskList) { - super(core, parentTree, uncheckedTaskList); + public CheckBoxTreeCellRenderer(JTimerService service, JTree parentTree, + Set<TimerTask> checkedTaskList, boolean uncheck) { + super(service, parentTree, checkedTaskList, uncheck); } @Override diff --git a/src/main/java/org/chorem/jtimer/ui/tree/TaskTreeModel.java b/src/main/java/org/chorem/jtimer/ui/tree/TaskTreeModel.java index a74af61..8808349 100644 --- a/src/main/java/org/chorem/jtimer/ui/tree/TaskTreeModel.java +++ b/src/main/java/org/chorem/jtimer/ui/tree/TaskTreeModel.java @@ -24,7 +24,8 @@ package org.chorem.jtimer.ui.tree; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.chorem.jtimer.data.TimerCore; +import org.chorem.jtimer.JTimerService; +import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; import org.chorem.jtimer.entities.TimerTaskHelper; import org.jdesktop.swingx.tree.TreeModelSupport; @@ -37,7 +38,7 @@ import java.util.List; import java.util.stream.Collectors; /** - * Timer task tree model. + * Timer task tree data. * * @author chatellier * @version $Revision$ @@ -52,11 +53,8 @@ public class TaskTreeModel implements TreeModel { protected TreeModelSupport modelSupport; - /** Timer core. */ - protected TimerCore core; - - /** Tree model root. */ - protected TimerTask root; + /** Tree data root. */ + protected List<TimerProject> root; /** Show closed tasks. */ protected boolean showClosed; @@ -64,12 +62,15 @@ public class TaskTreeModel implements TreeModel { /** * Constructor. * - * @param core core - * @param rootName root node name + * @param service service + * @deprecated since 1.6 use constructor without service */ - public TaskTreeModel(TimerCore core, String rootName) { - this.core = core; - root = new TimerTask(rootName); + public TaskTreeModel(JTimerService service) { + this(service.getData().getProjectsList()); + } + + public TaskTreeModel(List<TimerProject> projects) { + root = projects; modelSupport = new TreeModelSupport(this); } @@ -94,7 +95,7 @@ public class TaskTreeModel implements TreeModel { */ protected List<TimerTask> getChildrenFor(Object parent) { - List<TimerTask> result = getFiteredSubListFor(parent); + List<TimerTask> result = getFilteredSubListFor(parent); return result; } @@ -106,13 +107,13 @@ public class TaskTreeModel implements TreeModel { * @param parent parent to task sublist * @return filtered list */ - protected List<TimerTask> getFiteredSubListFor(Object parent) { + protected List<TimerTask> getFilteredSubListFor(Object parent) { List<TimerTask> result = new ArrayList<>(); // get correct list if (parent == root) { // case root node - result.addAll(core.getData().getProjectsList()); + result.addAll(root); } else { // not root node TimerTask task = (TimerTask) parent; result.addAll(task.getSubTasks()); diff --git a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksModel.java b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksModel.java index 4ba03a3..9733bcd 100644 --- a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksModel.java +++ b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksModel.java @@ -25,8 +25,8 @@ package org.chorem.jtimer.ui.treetable; import org.apache.commons.lang3.time.DurationFormatUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.data.DataEventListener; -import org.chorem.jtimer.data.TimerCore; import org.chorem.jtimer.data.TimerDataManager; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; @@ -100,16 +100,16 @@ public class ProjectsAndTasksModel extends AbstractTreeTableModel implements * Constructor. * * @param projectsAndTaskTable table - * @param core timer core + * @param service timer service * @param columnIdentifiers column identifiers */ - public ProjectsAndTasksModel(ProjectsAndTasksTable projectsAndTaskTable, TimerCore core, + public ProjectsAndTasksModel(ProjectsAndTasksTable projectsAndTaskTable, JTimerService service, List<String> columnIdentifiers) { super(new TimerProject("root")); // remember this.projectsAndTaskTable = projectsAndTaskTable; - this.dataManager = core.getData(); + this.dataManager = service.getData(); this.columnIdentifiers = columnIdentifiers; taskNameCache = new HashMap<>(); diff --git a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksRunningCellRenderer.java b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksRunningCellRenderer.java index c099566..37bd432 100644 --- a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksRunningCellRenderer.java +++ b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksRunningCellRenderer.java @@ -25,7 +25,7 @@ package org.chorem.jtimer.ui.treetable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.jtimer.data.DataEventListener; -import org.chorem.jtimer.data.TimerCore; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.entities.TimerTask; import org.jdesktop.swingx.JXTreeTable; @@ -76,9 +76,9 @@ public class ProjectsAndTasksRunningCellRenderer extends ProjectsAndTasksCellRen * Constructor. * * @param treeTable Tree table reference for image observer - * @param core TimerCore + * @param service JTimerService */ - public ProjectsAndTasksRunningCellRenderer(JXTreeTable treeTable, TimerCore core) { + public ProjectsAndTasksRunningCellRenderer(JXTreeTable treeTable, JTimerService service) { this.treeTable = treeTable; // init @@ -91,7 +91,7 @@ public class ProjectsAndTasksRunningCellRenderer extends ProjectsAndTasksCellRen runningIcon.setImageObserver(nodeObserver); // be notified on events - core.getData().addDataEventListener(this); + service.getData().addDataEventListener(this); } @Override diff --git a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksTable.java b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksTable.java index aabb82d..95aec35 100644 --- a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksTable.java +++ b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksTable.java @@ -22,7 +22,7 @@ package org.chorem.jtimer.ui.treetable; -import org.chorem.jtimer.data.TimerCore; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; import org.chorem.jtimer.entities.TimerTaskHelper; @@ -71,9 +71,9 @@ public class ProjectsAndTasksTable extends JXTreeTable { * Constructor. * * @param application application - * @param core timer core + * @param service timer service */ - public ProjectsAndTasksTable(Application application, TimerCore core) { + public ProjectsAndTasksTable(Application application, JTimerService service) { // start with init i18n of table column name ApplicationContext ctxt = application.getContext(); @@ -86,10 +86,10 @@ public class ProjectsAndTasksTable extends JXTreeTable { columnIdentifiers.add(resourceMap.getString("totalTimeColumnName")); // set model - treeTableModel = new ProjectsAndTasksModel(this, core, columnIdentifiers); + treeTableModel = new ProjectsAndTasksModel(this, service, columnIdentifiers); // set renderer - treeCellRenderer = new ProjectsAndTasksRunningCellRenderer(this, core); + treeCellRenderer = new ProjectsAndTasksRunningCellRenderer(this, service); setTreeCellRenderer(treeCellRenderer); setTreeTableModel(treeTableModel); @@ -99,11 +99,11 @@ public class ProjectsAndTasksTable extends JXTreeTable { setBackground(Color.WHITE); //treeTableModel.setSortColumn("Projects & Tasks"); - core.getData().addDataEventListener(treeTableModel); + service.getData().addDataEventListener(treeTableModel); // enable drag n drop setDragEnabled(true); - setTransferHandler(new TimerTaskTransferHandler(application, core.getData())); + setTransferHandler(new TimerTaskTransferHandler(application, service.getData())); { // add action to collapse (left arrow) selected node Action action = new AbstractAction("collapseSelectedNode") { diff --git a/src/main/resources/META-INF/services/org.chorem.jtimer.plugins.Plugin b/src/main/resources/META-INF/services/org.chorem.jtimer.plugins.Plugin new file mode 100644 index 0000000..52aead6 --- /dev/null +++ b/src/main/resources/META-INF/services/org.chorem.jtimer.plugins.Plugin @@ -0,0 +1 @@ +org.chorem.jtimer.plugins.timebundle.TimeBundlePlugin \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 1f9a53b..dd8ab84 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -30,7 +30,7 @@ <Loggers> <Logger name="org.chorem.jtimer" level="info"/> - <Logger name="org.chorem.jtimer.plugin.timebundle" level="debug"/> + <Logger name="org.chorem.jtimer.plugins.timebundle" level="debug"/> <Root level="warn"> <AppenderRef ref="Console"/> diff --git a/src/main/resources/org/chorem/jtimer/ui/report/resources/ReportView.properties b/src/main/resources/org/chorem/jtimer/ui/report/resources/ReportView.properties index 74ef97d..a24f7b0 100644 --- a/src/main/resources/org/chorem/jtimer/ui/report/resources/ReportView.properties +++ b/src/main/resources/org/chorem/jtimer/ui/report/resources/ReportView.properties @@ -35,7 +35,6 @@ reportIncludeTime=Include task times reportAnnotationsTime=with time reportIntermediateTotalTime=Include intermediate total times reportProjects=Projects -reportProjectsList=Projects list currentWeek.Action.icon = date_current.png currentWeek.Action.shortDescription = Current week diff --git a/src/main/resources/org/chorem/jtimer/ui/report/resources/ReportView_fr.properties b/src/main/resources/org/chorem/jtimer/ui/report/resources/ReportView_fr.properties index de9dc69..ab037ee 100644 --- a/src/main/resources/org/chorem/jtimer/ui/report/resources/ReportView_fr.properties +++ b/src/main/resources/org/chorem/jtimer/ui/report/resources/ReportView_fr.properties @@ -35,7 +35,6 @@ reportIncludeTime=Afficher les temps reportAnnotationsTime=avec l'heure reportIntermediateTotalTime=Ajout des temps totaux interm\u00E9diaires reportProjects=Projets -reportProjectsList=Liste des projets currentWeek.Action.shortDescription = Semaine courante diff --git a/src/test/java/org/chorem/jtimer/AbstractJTimerTest.java b/src/test/java/org/chorem/jtimer/AbstractJTimerTest.java index c731bc7..5e56ded 100644 --- a/src/test/java/org/chorem/jtimer/AbstractJTimerTest.java +++ b/src/test/java/org/chorem/jtimer/AbstractJTimerTest.java @@ -105,8 +105,6 @@ public abstract class AbstractJTimerTest { // copy .svn folders FileUtils.copyDirectory(new File("src/test/resources/testdata"), new File(testDataDirectory, "data"), HiddenFileFilter.VISIBLE); - FileUtils.copyDirectory(new File("src/test/resources/testsync"), - new File(testDataDirectory, "timebundle"), HiddenFileFilter.VISIBLE); // force null, to force new instance JTimerFactory.saver = null; diff --git a/src/test/java/org/chorem/jtimer/data/CommonVetoableTest.java b/src/test/java/org/chorem/jtimer/data/CommonVetoableTest.java index 4f1f08c..2bdb3c9 100644 --- a/src/test/java/org/chorem/jtimer/data/CommonVetoableTest.java +++ b/src/test/java/org/chorem/jtimer/data/CommonVetoableTest.java @@ -23,6 +23,7 @@ package org.chorem.jtimer.data; import org.chorem.jtimer.AbstractJTimerTest; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; import org.testng.Assert; @@ -53,11 +54,11 @@ public class CommonVetoableTest extends AbstractJTimerTest { public void testAddProject() { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); // add new project TimerProject project = new TimerProject("jTimer"); @@ -73,11 +74,11 @@ public class CommonVetoableTest extends AbstractJTimerTest { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "IsisFish/UserInterface"); @@ -95,11 +96,11 @@ public class CommonVetoableTest extends AbstractJTimerTest { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findProject(projectsBefore, "Topia"); TimerTask task2 = findTask(projectsBefore, "jTimer/Add workspace support"); @@ -119,11 +120,11 @@ public class CommonVetoableTest extends AbstractJTimerTest { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "Chorem/Add webservice"); TimerTask task2 = findTask(projectsBefore, "jTimer"); @@ -147,11 +148,11 @@ public class CommonVetoableTest extends AbstractJTimerTest { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "jTimer/Add workspace support"); TimerTask task2 = findTask(projectsBefore, "jTimer/Interact with chorem services"); @@ -180,11 +181,11 @@ public class CommonVetoableTest extends AbstractJTimerTest { @Test(expectedExceptions = DataViolationException.class) public void testMergeTasks() { // first load all - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "Chorem"); TimerTask task2 = findTask(projectsBefore, "jTimer/Unit tests/UI tests"); diff --git a/src/test/java/org/chorem/jtimer/data/TimerDataManagerTest.java b/src/test/java/org/chorem/jtimer/data/TimerDataManagerTest.java index 018d073..8e8f625 100644 --- a/src/test/java/org/chorem/jtimer/data/TimerDataManagerTest.java +++ b/src/test/java/org/chorem/jtimer/data/TimerDataManagerTest.java @@ -23,6 +23,7 @@ package org.chorem.jtimer.data; import org.chorem.jtimer.AbstractJTimerTest; +import org.chorem.jtimer.JTimerService; import org.chorem.jtimer.entities.TimerAlert; import org.chorem.jtimer.entities.TimerAlert.Type; import org.chorem.jtimer.entities.TimerProject; @@ -56,11 +57,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { public void testAddProject() { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerProject project1 = findProject(projectsBefore, "Test project"); @@ -71,12 +72,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { TimerProject project = new TimerProject("Test project"); project.setCreationDate(new Date()); dataManager.addProject(project); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerProject project1a = findProject(projectsAfter, "Test project"); @@ -91,11 +92,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { public void testEditProject() { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerProject project1 = findProject(projectsBefore, "jTimer"); @@ -104,12 +105,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // edit project dataManager.editProject(project1, "Edit Name"); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerProject project1a = findProject(projectsBefore, "Edit Name"); @@ -125,11 +126,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { public void testDeleteProject() { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerProject project1 = findProject(projectsBefore, "jTimer"); @@ -138,12 +139,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // delete project dataManager.deleteProject(project1); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); Assert.assertNull(findProject(projectsAfter, "jTimer")); @@ -158,11 +159,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "IsisFish/UserInterface"); @@ -173,12 +174,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { TimerTask newTask = new TimerTask("new task"); newTask.setCreationDate(new Date()); dataManager.addTask(task1, newTask, null); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerTask task1a = findTask(projectsAfter, "IsisFish/UserInterface"); TimerTask task2a = findTask(projectsAfter, "IsisFish/UserInterface/new task"); @@ -196,11 +197,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "IsisFish/UserInterface"); @@ -209,12 +210,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // edit task name dataManager.editTask(task1, "UI"); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerTask task1a = findTask(projectsAfter, "IsisFish/UI"); TimerTask task2a = findTask(projectsAfter, "IsisFish/UI/Debug"); @@ -232,11 +233,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerProject project1 = findProject(projectsBefore, "IsisFish"); TimerTask task1 = findTask(projectsBefore, "IsisFish/UserInterface"); @@ -247,12 +248,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // delete task dataManager.deleteTask(task1); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerProject project1a = findProject(projectsAfter, "IsisFish"); TimerTask task1a = findTask(projectsAfter, "IsisFish/UserInterface"); @@ -270,11 +271,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "Topia"); TimerTask task2 = findTask(projectsBefore, "jTimer/Add workspace support"); @@ -286,12 +287,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // move task 3 in jTimer/3 dataManager.moveTask(task1, Collections.singleton(task2)); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerTask task1a = findTask(projectsAfter, "Topia"); TimerTask task2a = findTask(projectsAfter, "jTimer/Add workspace support"); @@ -310,11 +311,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerProject project1 = findProject(projectsBefore, "Chorem"); TimerTask task1 = findTask(projectsBefore, "jTimer/Add workspace support"); @@ -336,12 +337,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // move task 3 in jTimer/3 dataManager.moveTask(project1, tasksToMove); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerTask task1a = findTask(projectsAfter, "Chorem/Add workspace support"); TimerTask task2a = findTask(projectsAfter, "Chorem/Interact with chorem services"); @@ -363,11 +364,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { * public void testMergeProjects() { // first load all - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerProject project1 = findProject(projectsBefore, "Topia"); TimerProject project2 = findProject(projectsBefore, "jTimer"); @@ -381,12 +382,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // merge projects dataManager.mergeProjects(project1, Collections.singletonList(project2)); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerProject project1a = findProject(projectsAfter, "Topia"); TimerProject project2a = findProject(projectsAfter, "jTimer"); @@ -403,11 +404,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { @Test public void testMergeTasks() { // first load all - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "jTimer/Refactoring"); TimerTask task2 = findTask(projectsBefore, "jTimer/Unit tests/UI tests"); @@ -425,12 +426,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // merge tasks dataManager.mergeTasks(task1, Collections.singletonList(task2)); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerTask task1a = findTask(projectsAfter, "jTimer/Refactoring"); TimerTask task2a = findTask(projectsAfter, "jTimer/Unit tests/UI tests"); @@ -453,11 +454,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { @Test public void testMergeTasksWithConflict() { // first load all - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "jTimer/Refactoring"); Assert.assertNotNull(task1); @@ -477,12 +478,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { // merge tasks dataManager.mergeTasks(task1, Collections.singletonList(task2)); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerTask task1a = findTask(projectsAfter, "jTimer/Refactoring"); TimerTask task2a = findTask(projectsAfter, "jTimer/Unit tests/UI tests"); @@ -505,11 +506,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { public void testAddAlert() { // first load all // and make a move operation - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "jTimer/Refactoring"); @@ -525,12 +526,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { task1.addAlert(alert2); task1.addAlert(alert3); dataManager.modifyAlert(task1); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerTask task1a = findTask(projectsAfter, "jTimer/Refactoring"); @@ -564,11 +565,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { @Test public void testMergeTasksWithAlerts() { // first load all - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsBefore = dataManager.getProjectsList(); TimerTask task1 = findTask(projectsBefore, "IsisFish/Storage"); TimerTask task2 = findTask(projectsBefore, "IsisFish/Support"); @@ -586,12 +587,12 @@ public class TimerDataManagerTest extends AbstractJTimerTest { othersTask.add(task1); othersTask.add(task3); dataManager.mergeTasks(task2, othersTask); - core.exit(); + service.exit(); // second reload // and test reloaded data - //core.init(); - core.load(); + //service.init(); + service.load(); List<TimerProject> projectsAfter = dataManager.getProjectsList(); TimerTask task1a = findTask(projectsAfter, "IsisFish/Storage"); TimerTask task2a = findTask(projectsAfter, "IsisFish/Support"); @@ -608,11 +609,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { */ @Test public void testGetTaskForPath() { - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); TimerTask task = dataManager.getTaskForPath("jTimer/Unit tests/UI tests"); Assert.assertEquals(task.getName(), "UI tests"); @@ -625,11 +626,11 @@ public class TimerDataManagerTest extends AbstractJTimerTest { */ @Test(expectedExceptions = IllegalArgumentException.class) public void testGetTaskForPathProject() { - TimerCore core = new TimerCore(); - TimerDataManager dataManager = core.getData(); + JTimerService service = new JTimerService(); + TimerDataManager dataManager = service.getData(); - //core.init(); - core.load(); + //service.init(); + service.load(); TimerTask task = dataManager.getTaskForPath("jTimer"); Assert.assertNotNull(task); diff --git a/src/test/java/org/chorem/jtimer/plugin/timebundle/TimeBundleHelperTest.java b/src/test/java/org/chorem/jtimer/plugin/timebundle/TimeBundleHelperTest.java deleted file mode 100644 index 5fcbe84..0000000 --- a/src/test/java/org/chorem/jtimer/plugin/timebundle/TimeBundleHelperTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * #%L - * jTimer - * %% - * Copyright (C) 2016 CodeLutin - * %% - * 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.plugin.timebundle; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import org.apache.commons.lang3.time.DateFormatUtils; -import org.apache.commons.lang3.time.DateUtils; -import org.chorem.jtimer.AbstractJTimerTest; -import org.chorem.jtimer.entities.TimerSync; -import org.chorem.jtimer.entities.TimerTask; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.util.Calendar; -import java.util.Date; - -/** - * Test related to TimeBundleHelper. - */ -public class TimeBundleHelperTest extends AbstractJTimerTest { - - /** - * Test json production - */ - @Test - public void taskToJSONFormatTest() { - TimerTask task = new TimerTask(); - task.setNumber(42); - task.setName("JsonBuilder Test"); - TimerSync sync = new TimerSync("http://localhost:3000"); - task.addSync(sync); - //set the creation date at same date as first timing date (to fit test object) - task.setCreationDate(new Date(1451602800000L)); - sync.setLastSync(new Date(1451602800000L)); - //date : 2016-01-18 - task.setTime(new Date(1453071600000L), 452000L); - //date : 2016-05-12 - task.setTime(new Date(1463004000000L), 4533000L); - - - //create json object - JsonObject objectToHave = new JsonObject(); - JsonArray periodArray = new JsonArray(); - JsonObject periodElement1 = new JsonObject(); - periodElement1.addProperty("id", "2016-01-18_42"); - periodElement1.addProperty("startDate", "2016-01-18T00:00:00+01:00"); - periodElement1.addProperty("duration", 452); - periodArray.add(periodElement1); - JsonObject periodElement2 = new JsonObject(); - periodElement2.addProperty("id", "2016-05-12_42"); - periodElement2.addProperty("startDate", "2016-05-12T00:00:00+02:00"); - periodElement2.addProperty("duration", 4533); - periodArray.add(periodElement2); - - objectToHave.addProperty("URL", "http://localhost:3000"); - objectToHave.addProperty("startDate", "2016-01-01T00:00:00+01:00"); - Date endDate = DateUtils.ceiling(new Date(), Calendar.DAY_OF_MONTH); - String endPeriodString = DateFormatUtils.format(endDate, TimeBundleHelper.DATE_MIDNIGHT_PATTERN); - - objectToHave.addProperty("endDate", endPeriodString); - objectToHave.add("periods", periodArray); - - //make a list of json objects from the task - JsonObject jsonObject = TimeBundleHelper.taskToJsonObject(task, sync); - Assert.assertEquals(jsonObject, objectToHave); - } -} diff --git a/src/test/java/org/chorem/jtimer/plugin/timebundle/TimeBundleSaverTest.java b/src/test/java/org/chorem/jtimer/plugin/timebundle/TimeBundleSaverTest.java deleted file mode 100644 index 06708ec..0000000 --- a/src/test/java/org/chorem/jtimer/plugin/timebundle/TimeBundleSaverTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * #%L - * jTimer - * %% - * Copyright (C) 2007 - 2016 CodeLutin - * %% - * 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.plugin.timebundle; - -import org.chorem.jtimer.AbstractJTimerTest; -import org.chorem.jtimer.entities.TimerProject; -import org.chorem.jtimer.entities.TimerTask; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import java.io.IOException; -import java.util.Collections; - -/** - * Test class for TimeBundleSaver. - */ -public class TimeBundleSaverTest extends AbstractJTimerTest { - - protected TimeBundleSaver saver; - - @BeforeMethod - @Override - public void beforeTest() throws IOException { - super.beforeTest(); - saver = new TimeBundleSaver(); - } - - /** - * Test that synchronization Info is properly parsed - * @throws IOException - */ - @Test - public void parseSyncInfoTest() throws IOException { - - TimerTask task = new TimerTask(); - task.setNumber(41); - TimerProject project = new TimerProject(); - project.setNumber(1); - project.addTask(task); - saver.dataLoaded(Collections.singletonList(project)); - - Assert.assertNotNull(task.getSyncs()); - Assert.assertEquals(task.getSyncs().get(0).getUrl(), "http://localhost:3000"); - - } -} diff --git a/src/test/resources/testsync/41.task.sync b/src/test/resources/testsync/41.task.sync deleted file mode 100644 index 3a085bf..0000000 --- a/src/test/resources/testsync/41.task.sync +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "url": "http://localhost:3000", - "lastSync": "Jan 1, 1970 1:00:00 AM", - "active": true, - "withAnnotations": false - } -] \ No newline at end of file -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.