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 5c38397c9a701f39e6057f8645533205225dbf83 Author: Eric Chatellier <chatellier@codelutin.com> Date: Tue Mar 7 16:59:27 2017 +0100 Add reload project option. Add doc --- src/main/java/org/chorem/jtimer/JTimer.java | 1 + src/main/java/org/chorem/jtimer/JTimerConfig.java | 12 ++- src/main/java/org/chorem/jtimer/JTimerService.java | 16 +++- .../plugins/timebundle/LocalSynchronizer.java | 30 ------ .../plugins/timebundle/RemoteSynchronizer.java | 28 +++++- .../chorem/jtimer/plugins/timebundle/SyncView.java | 103 +++++++++++++++------ .../jtimer/plugins/timebundle/Synchronizer.java | 27 ------ .../jtimer/plugins/timebundle/data/RemoteTask.java | 15 +++ .../timebundle/model/RemoteTaskTreeModel.java | 13 ++- .../jtimer/ui/tree/CheckBoxCellEditorRenderer.java | 2 +- src/site/rst/configuration.rst | 9 ++ src/site/rst/timebundle.rst | 30 ------ 12 files changed, 159 insertions(+), 127 deletions(-) diff --git a/src/main/java/org/chorem/jtimer/JTimer.java b/src/main/java/org/chorem/jtimer/JTimer.java index 96ec4b8..b2eb5ab 100644 --- a/src/main/java/org/chorem/jtimer/JTimer.java +++ b/src/main/java/org/chorem/jtimer/JTimer.java @@ -194,6 +194,7 @@ public class JTimer extends SingleFrameApplication implements // init timerservice service = new JTimerService(); + service.initPlugins(config); // Systray mgr systrayManager = new SystrayManager(this); diff --git a/src/main/java/org/chorem/jtimer/JTimerConfig.java b/src/main/java/org/chorem/jtimer/JTimerConfig.java index bc1f2c2..4084dca 100644 --- a/src/main/java/org/chorem/jtimer/JTimerConfig.java +++ b/src/main/java/org/chorem/jtimer/JTimerConfig.java @@ -38,6 +38,7 @@ import java.nio.file.DirectoryStream; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -178,11 +179,12 @@ public class JTimerConfig { } /** - * Returns the synchronizer class - * @return + * Returns the activated plugins. + * + * @return activated plugins */ - public Class<?> getIOSynchronizerClass() { - return appConfig.getOptionAsClass(JTimerOption.IO_SYNC_CLASS.key); + public List<String> getPlugins() { + return appConfig.getOptionAsList(JTimerOption.PLUGINS.key).getOption(); } /** @@ -297,7 +299,7 @@ public class JTimerConfig { GTIMER_BACKUP_DIRECTORY("jtimer.io.backup.directory", "${jtimer.io.saver.directory}/backups"), IO_SAVER_AUTOSAVEDELAY("jtimer.io.saver.autosavedelay", "300"), - IO_SYNC_CLASS("jtimer.io.synchronizer.class", null), + PLUGINS("jtimer.plugins", null), UI_IDLE_TIME("jtimer.ui.idletime", "300"), UI_SHOW_CLOSED("jtimer.ui.showclosed", "false"), diff --git a/src/main/java/org/chorem/jtimer/JTimerService.java b/src/main/java/org/chorem/jtimer/JTimerService.java index 342fb92..0a7ee51 100644 --- a/src/main/java/org/chorem/jtimer/JTimerService.java +++ b/src/main/java/org/chorem/jtimer/JTimerService.java @@ -96,7 +96,11 @@ public class JTimerService { data.addVetoableDataEventListener(saver); data.addDataEventListener(saver); } + } + + public void initPlugins(JTimerConfig config) { + List<String> configPlugins = config.getPlugins(); ServiceLoader<Plugin> load = ServiceLoader.load(Plugin.class); load.forEach(plugin -> { // extract package name @@ -105,10 +109,16 @@ public class JTimerService { String pluginName = StringUtils.substringBefore(pluginPackage, "."); // loading - if (log.isInfoEnabled()) { - log.info("Loading plugin : " + pluginName); + if (configPlugins.contains(pluginName)) { + if (log.isInfoEnabled()) { + log.info("Loading plugin : " + pluginName); + } + activePlugins.add(plugin); + } else { + if (log.isInfoEnabled()) { + log.info("Plugin disabled : " + pluginName); + } } - activePlugins.add(plugin); }); activePlugins.forEach(p -> p.register(this)); diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/LocalSynchronizer.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/LocalSynchronizer.java deleted file mode 100644 index b70c2f9..0000000 --- a/src/main/java/org/chorem/jtimer/plugins/timebundle/LocalSynchronizer.java +++ /dev/null @@ -1,30 +0,0 @@ -/*- - * #%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 index 7ab4853..2d76ad5 100644 --- a/src/main/java/org/chorem/jtimer/plugins/timebundle/RemoteSynchronizer.java +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/RemoteSynchronizer.java @@ -22,7 +22,8 @@ package org.chorem.jtimer.plugins.timebundle; -import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.commons.logging.Log; @@ -47,7 +48,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -public class RemoteSynchronizer implements Synchronizer { +public class RemoteSynchronizer { protected static Log log = LogFactory.getLog(RemoteSynchronizer.class); @@ -162,6 +163,29 @@ public class RemoteSynchronizer implements Synchronizer { return project; } + public void reloadProject(RemoteProject project) { + RemoteProject newProject = fetchProject(project.getUrl()); + merge(project, newProject); + } + + public void merge(RemoteTask currentTask, RemoteTask newTask) { + currentTask.setName(newTask.getName()); + currentTask.setUrl(newTask.getUrl()); + + if (currentTask.getSubTasks() != null && newTask.getSubTasks() != null) { + List<RemoteTask> currentTasks = ListUtils.retainAll(currentTask.getSubTasks(), newTask.getSubTasks()); // still existing tasks + currentTasks.forEach(subTask -> { + RemoteTask newSubTask = newTask.getSubTasks().stream() + .filter(task -> task.getUuid().equals(subTask.getUuid())) + .findFirst().orElse(null); + merge(subTask, newSubTask); + }); + List<RemoteTask> newTasks = ListUtils.removeAll(newTask.getSubTasks(), currentTask.getSubTasks()); + currentTasks.addAll(newTasks); + currentTask.setSubTasks(currentTasks); + } + } + /** * Sync project by pushing all sub tasks times on: * http://localhost:8080/api/v1/codelutin/contribute/a7e14ea2-fde7-4e80-aff3-03... diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/SyncView.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/SyncView.java index 2c31658..17be4eb 100644 --- a/src/main/java/org/chorem/jtimer/plugins/timebundle/SyncView.java +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/SyncView.java @@ -43,8 +43,10 @@ import javax.swing.JTree; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; +import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; @@ -60,10 +62,13 @@ public class SyncView extends FrameView implements TreeSelectionListener, Window protected TimerProject timerProject; protected JTree remoteProjectTree = new JTree(); - protected RemoteTaskTreeModel projectModel; + protected RemoteTaskTreeModel remoteProjectModel; protected JTree projectsTree = new JTree(); - protected TaskTreeModel treeModel; + protected TaskTreeModel projectModel; + + protected JButton removeProject; + protected JButton reloadProject; public SyncView(Application application, JTimerService service, SyncIOSaver saver, RemoteSynchronizer synchronizer, TimerProject timerProject) { @@ -78,8 +83,8 @@ public class SyncView extends FrameView implements TreeSelectionListener, Window getFrame().setTitle("Time bundle"); List<RemoteProject> timebundle = getRemoteProjects(); - projectModel = new RemoteTaskTreeModel(timebundle); - treeModel = new TaskTreeModel(Collections.singletonList(timerProject)); + remoteProjectModel = new RemoteTaskTreeModel(timebundle); + projectModel = new TaskTreeModel(Collections.singletonList(timerProject)); setComponent(getMainComponent()); @@ -104,39 +109,53 @@ public class SyncView extends FrameView implements TreeSelectionListener, Window remoteProjectTree.setRootVisible(false); remoteProjectTree.setShowsRootHandles(true); - remoteProjectTree.setModel(projectModel); + remoteProjectTree.setModel(remoteProjectModel); remoteProjectTree.setCellRenderer(new RemoveTaskCellRenderer()); remoteProjectTree.addTreeSelectionListener(this); + remoteProjectTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 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, + mainPanel.add(treeLabel, new GridBagConstraints(1, 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); + projectsTree.setModel(projectModel); + projectsTree.setEnabled(false); + projectsTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); CheckBoxCellEditorRenderer checkBoxCellEditorRenderer = new CheckBoxCellEditorRenderer(service, projectsTree); projectsTree.setCellRenderer(checkBoxCellEditorRenderer); projectsTree.setCellEditor(checkBoxCellEditorRenderer); - projectsTree.expandPath(new TreePath(treeModel.getRoot()).pathByAddingChild(timerProject)); + projectsTree.expandPath(new TreePath(projectModel.getRoot()).pathByAddingChild(timerProject)); JScrollPane treeScroll = new JScrollPane(projectsTree); - mainPanel.add(treeScroll, new GridBagConstraints(2, 1, 1, 1, 1, 1, + mainPanel.add(treeScroll, new GridBagConstraints(1, 1, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(1, 1, 1, 1), 0, 0)); + JPanel buttonPanel = new JPanel(new GridLayout(0, 4)); + JButton addProject = new JButton("Add project"); + addProject.addActionListener(l -> addRemoteProject()); + buttonPanel.add(addProject); + + reloadProject = new JButton("Reload project"); + reloadProject.addActionListener(l -> reloadRemoteProject()); + reloadProject.setEnabled(false); + buttonPanel.add(reloadProject); + + removeProject = new JButton("Remove project"); + removeProject.addActionListener(l -> removeRemoteProject()); + removeProject.setEnabled(false); + buttonPanel.add(removeProject); + 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)); + buttonPanel.add(syncAll); + mainPanel.add(buttonPanel, new GridBagConstraints(0, 2, 2, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(1, 1, 1, 1), 0, 0)); return mainPanel; } @@ -144,10 +163,26 @@ public class SyncView extends FrameView implements TreeSelectionListener, Window String url = JOptionPane.showInputDialog(this.getFrame(), "New remote project url", "Add remote project"); - RemoteProject project = synchronizer.fetchProject(url); - getRemoteProjects().add(project); - projectModel.addElement(project); - remoteProjectTree.expandPath(new TreePath(projectModel.getRoot()).pathByAddingChild(project)); + RemoteProject remoteProject = synchronizer.fetchProject(url); + if (remoteProject != null) { + getRemoteProjects().add(remoteProject); + remoteProjectModel.addElement(remoteProject); + remoteProjectTree.expandPath(new TreePath(remoteProjectModel.getRoot()).pathByAddingChild(remoteProject)); + } + } + + public void removeRemoteProject() { + TreePath selectionPath = remoteProjectTree.getSelectionPath(); + RemoteProject remoteProject = (RemoteProject)selectionPath.getLastPathComponent(); + remoteProjectModel.removeElement(remoteProject); + getRemoteProjects().remove(remoteProject); + } + + public void reloadRemoteProject() { + TreePath selectionPath = remoteProjectTree.getSelectionPath(); + RemoteProject remoteProject = (RemoteProject)selectionPath.getLastPathComponent(); + synchronizer.reloadProject(remoteProject); + remoteProjectModel.changeElement(remoteProject); } public void syncProjects() { @@ -156,13 +191,27 @@ public class SyncView extends FrameView implements TreeSelectionListener, Window @Override public void valueChanged(TreeSelectionEvent treeSelectionEvent) { - RemoteTask task = (RemoteTask)treeSelectionEvent.getPath().getLastPathComponent(); - CheckBoxCellEditorRenderer checkBoxCellEditorRenderer = new CheckBoxCellEditorRenderer(service, projectsTree); - checkBoxCellEditorRenderer.setCheckedTaskSet(task.getSyncTasks()); - checkBoxCellEditorRenderer.setDisableSubChecked(true); - projectsTree.setCellRenderer(checkBoxCellEditorRenderer); - projectsTree.setCellEditor(checkBoxCellEditorRenderer); - projectsTree.validate(); + projectsTree.setEnabled(false); + removeProject.setEnabled(false); + reloadProject.setEnabled(false); + + TreePath newLeadSelectionPath = treeSelectionEvent.getNewLeadSelectionPath(); + if (newLeadSelectionPath != null) { + RemoteTask task = (RemoteTask) newLeadSelectionPath.getLastPathComponent(); + if (task instanceof RemoteProject) { + removeProject.setEnabled(true); + reloadProject.setEnabled(true); + } else { + CheckBoxCellEditorRenderer checkBoxCellEditorRenderer = new CheckBoxCellEditorRenderer(service, projectsTree); + checkBoxCellEditorRenderer.setCheckedTaskSet(task.getSyncTasks()); + checkBoxCellEditorRenderer.setDisableSubChecked(true); + projectsTree.setCellRenderer(checkBoxCellEditorRenderer); + projectsTree.setCellEditor(checkBoxCellEditorRenderer); + projectsTree.validate(); + projectsTree.setEnabled(true); + } + } + } @Override diff --git a/src/main/java/org/chorem/jtimer/plugins/timebundle/Synchronizer.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/Synchronizer.java deleted file mode 100644 index e15ba9f..0000000 --- a/src/main/java/org/chorem/jtimer/plugins/timebundle/Synchronizer.java +++ /dev/null @@ -1,27 +0,0 @@ -/*- - * #%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/data/RemoteTask.java b/src/main/java/org/chorem/jtimer/plugins/timebundle/data/RemoteTask.java index 699cf88..0a98ffd 100644 --- a/src/main/java/org/chorem/jtimer/plugins/timebundle/data/RemoteTask.java +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/data/RemoteTask.java @@ -80,6 +80,21 @@ public class RemoteTask implements Serializable { public List<RemoteTask> getSubTasks() { return subTasks; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RemoteTask that = (RemoteTask) o; + + return uuid != null ? uuid.equals(that.uuid) : that.uuid == null; + } + + @Override + public int hashCode() { + return uuid != null ? uuid.hashCode() : 0; + } } 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 index 00357c6..22dca99 100644 --- a/src/main/java/org/chorem/jtimer/plugins/timebundle/model/RemoteTaskTreeModel.java +++ b/src/main/java/org/chorem/jtimer/plugins/timebundle/model/RemoteTaskTreeModel.java @@ -22,6 +22,7 @@ package org.chorem.jtimer.plugins.timebundle.model; +import org.chorem.jtimer.plugins.timebundle.data.RemoteProject; import org.chorem.jtimer.plugins.timebundle.data.RemoteTask; import org.jdesktop.swingx.tree.TreeModelSupport; @@ -85,8 +86,8 @@ public class RemoteTaskTreeModel implements TreeModel { @Override public int getIndexOfChild(Object parent, Object child) { - int count = getChildrenFor(parent).indexOf(parent); - return count; + int index = getChildrenFor(parent).indexOf(parent); + return index; } @Override @@ -118,4 +119,12 @@ public class RemoteTaskTreeModel implements TreeModel { // FIXME change this modelSupport.fireNewRoot(); } + + public void removeElement(RemoteProject remoteProject) { + modelSupport.fireChildRemoved(new TreePath(getRoot()), projects.indexOf(remoteProject), remoteProject); + } + + public void changeElement(RemoteProject remoteProject) { + modelSupport.fireChildChanged(new TreePath(getRoot()), projects.indexOf(remoteProject), remoteProject); + } } diff --git a/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxCellEditorRenderer.java b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxCellEditorRenderer.java index 25114af..0cb22e8 100644 --- a/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxCellEditorRenderer.java +++ b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxCellEditorRenderer.java @@ -277,7 +277,7 @@ public class CheckBoxCellEditorRenderer extends JCheckBox implements TreeCellRen // fix a strange bug where checkbox does have a "gray" background c.setBackground(tree.getBackground()); c.setFocusable(false); - c.setEnabled(enable); + c.setEnabled(tree.isEnabled() && enable); return c; } diff --git a/src/site/rst/configuration.rst b/src/site/rst/configuration.rst index c5b78d6..79093fc 100644 --- a/src/site/rst/configuration.rst +++ b/src/site/rst/configuration.rst @@ -58,3 +58,12 @@ For example, in file ``templatename1.yml``:: sub database task2: meetings: releases: + +Plugin: TimeBundle +------------------ + +Synchronization with time bundle is currently under developpement and can be enabled as a plugin. + +To enable it, modify configuration with following line:: + + jtimer.plugins=timebundle diff --git a/src/site/rst/timebundle.rst b/src/site/rst/timebundle.rst deleted file mode 100644 index 386d032..0000000 --- a/src/site/rst/timebundle.rst +++ /dev/null @@ -1,30 +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% -.. - - -Time bundle -=========== - -Synchronization with time bundle is currently under developpement and disabled by default. - -To enable it, modify configuration with following line:: - - jtimer.io.synchronizer.class=org.chorem.jtimer.plugin.timebundle.TimeBundleSynchronizer -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.