This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository jtimer. See http://git.chorem.org/jtimer.git commit 7b7277a1517fbbf182c20e82a585522d9789ea18 Author: Eric Chatellier <chatellier@codelutin.com> Date: Thu Mar 3 17:45:32 2016 +0100 fixes #880: Add the ability to assign idle time to a task. --- pom.xml | 6 - src/main/java/org/chorem/jtimer/JTimer.java | 2 +- .../java/org/chorem/jtimer/ui/TimerTaskEditor.java | 6 +- .../org/chorem/jtimer/ui/report/ReportView.java | 10 +- .../org/chorem/jtimer/ui/tasks/IdleDialog.java | 227 ++++++++++++++----- .../org/chorem/jtimer/ui/tasks/RunTaskJob.java | 30 ++- .../tree/CheckBoxTreeCellComponent.java | 2 +- .../{report => }/tree/CheckBoxTreeCellEditor.java | 2 +- .../tree/CheckBoxTreeCellRenderer.java | 2 +- .../TaskTreeModel.java} | 8 +- .../ui/treetable/ProjectsAndTasksCellRenderer.java | 244 +-------------------- ...va => ProjectsAndTasksRunningCellRenderer.java} | 55 +---- .../jtimer/ui/treetable/ProjectsAndTasksTable.java | 4 +- .../ui/tasks/resources/IdleDialog.properties | 10 +- .../ui/tasks/resources/IdleDialog_fr.properties | 11 +- .../ui/tasks/resources/document-revert-3.png | Bin 0 -> 2043 bytes 16 files changed, 235 insertions(+), 384 deletions(-) diff --git a/pom.xml b/pom.xml index b64b3ae..f2e8538 100644 --- a/pom.xml +++ b/pom.xml @@ -68,12 +68,6 @@ <connection>scm:git:git@gitlab.nuiton.org:chorem/jtimer.git</connection> <developerConnection>scm:git:git@gitlab.nuiton.org:chorem/jtimer.git</developerConnection> </scm> - <distributionManagement> - <site> - <id>${site.server}</id> - <url>${site.url}</url> - </site> - </distributionManagement> <properties> diff --git a/src/main/java/org/chorem/jtimer/JTimer.java b/src/main/java/org/chorem/jtimer/JTimer.java index 1e66768..ccbd29a 100644 --- a/src/main/java/org/chorem/jtimer/JTimer.java +++ b/src/main/java/org/chorem/jtimer/JTimer.java @@ -201,7 +201,7 @@ public class JTimer extends SingleFrameApplication implements systrayManager = new SystrayManager(this); core.getData().addDataEventListener(systrayManager); - IdleDialog.init(this); + IdleDialog.init(this, core); } /** diff --git a/src/main/java/org/chorem/jtimer/ui/TimerTaskEditor.java b/src/main/java/org/chorem/jtimer/ui/TimerTaskEditor.java index a0117c7..ca301fb 100644 --- a/src/main/java/org/chorem/jtimer/ui/TimerTaskEditor.java +++ b/src/main/java/org/chorem/jtimer/ui/TimerTaskEditor.java @@ -247,11 +247,11 @@ public class TimerTaskEditor extends JDialog implements ActionListener { addMnemonic("apply.Action.mnemonic", applyButton); // apply and quit button - applyAndQuitButton= new JButton(resourceMap.getString("applyAndQuit.Action.text")); + /*applyAndQuitButton= new JButton(resourceMap.getString("applyAndQuit.Action.text")); applyAndQuitButton.setActionCommand("applyAndQuit"); applyAndQuitButton.addActionListener(this); applyAndQuitButton.setEnabled(false); - addMnemonic("applyAndQuit.Action.mnemonic", applyAndQuitButton); + addMnemonic("applyAndQuit.Action.mnemonic", applyAndQuitButton);*/ // revert button revertButton = new JButton(resourceMap.getString("revert.Action.text")); @@ -271,7 +271,7 @@ public class TimerTaskEditor extends JDialog implements ActionListener { JPanel panel = new JPanel(); panel.setLayout(new FlowLayout(FlowLayout.RIGHT, 1, 0)); panel.add(applyButton); - panel.add(applyAndQuitButton); + //panel.add(applyAndQuitButton); panel.add(revertButton); panel.add(cancelButton); return panel; 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 6a4288d..a9637da 100644 --- a/src/main/java/org/chorem/jtimer/ui/report/ReportView.java +++ b/src/main/java/org/chorem/jtimer/ui/report/ReportView.java @@ -62,9 +62,9 @@ import org.chorem.jtimer.data.TimerCore; import org.chorem.jtimer.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; import org.chorem.jtimer.ui.report.ReportGenerator.Type; -import org.chorem.jtimer.ui.report.tree.CheckBoxTreeCellEditor; -import org.chorem.jtimer.ui.report.tree.CheckBoxTreeCellRenderer; -import org.chorem.jtimer.ui.report.tree.CheckBoxTreeModel; +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.Action; import org.jdesktop.application.Application; import org.jdesktop.application.FrameView; @@ -264,7 +264,7 @@ public class ReportView extends FrameView implements DocumentListener { projectsTree = new JTree(); projectsTree.setRootVisible(true); projectsTree.setEditable(true); - projectsTree.setModel(new CheckBoxTreeModel(core, getResourceMap().getString("reportProjectsList") + " :")); + projectsTree.setModel(new TaskTreeModel(core, getResourceMap().getString("reportProjectsList") + " :")); projectsTree.setCellEditor(new CheckBoxTreeCellEditor(core, projectsTree, uncheckedTaskSet)); projectsTree.setCellRenderer(new CheckBoxTreeCellRenderer(core, projectsTree, uncheckedTaskSet)); @@ -494,7 +494,7 @@ public class ReportView extends FrameView implements DocumentListener { */ @Action public void showHiddenProjects() { - CheckBoxTreeModel model = (CheckBoxTreeModel)projectsTree.getModel(); + TaskTreeModel model = (TaskTreeModel)projectsTree.getModel(); model.setShowClosed(showHiddenProjectBox.isSelected()); } 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 801a8c0..49258b6 100644 --- a/src/main/java/org/chorem/jtimer/ui/tasks/IdleDialog.java +++ b/src/main/java/org/chorem/jtimer/ui/tasks/IdleDialog.java @@ -33,15 +33,24 @@ import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.JScrollPane; import javax.swing.JSeparator; +import javax.swing.JToggleButton; +import javax.swing.JTree; import javax.swing.SwingConstants; import javax.swing.WindowConstants; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; 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.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; +import org.chorem.jtimer.ui.tree.TaskTreeModel; +import org.chorem.jtimer.ui.treetable.ProjectsAndTasksCellRenderer; import org.jdesktop.application.Action; import org.jdesktop.application.ApplicationContext; import org.jdesktop.application.ResourceManager; @@ -57,9 +66,10 @@ import org.jdesktop.application.TaskMonitor; * * Also composed of three resume option : * <ul> - * <li>Stop task - * <li>Continue (with idle time summed) - * <li>Resume (without idle time summed) + * <li>Stop task</li> + * <li>Continue (with idle time summed)</li> + * <li>Resume (without idle time summed)</li> + * <li>Set time to another task</li> * </ul> * * @author chatellier @@ -73,6 +83,11 @@ public class IdleDialog extends JDialog { /** serialVersionUID. */ private static final long serialVersionUID = 7669429291708466753L; + /** Dialog response type. */ + public static enum IdleOption { + REVERT, CONTINUE, RESUME, ASSIGN + } + /** log */ private static Log log = LogFactory.getLog(IdleDialog.class); @@ -83,11 +98,17 @@ public class IdleDialog extends JDialog { protected static IdleDialog idleDialog; /** Resume option. */ - protected static int lastResumeOption; + protected static IdleOption lastResumeOption; + + /** Selected task (only valid for assign option). */ + protected static TimerTask assignSelectedTask; /** Parent application. */ protected SingleFrameApplication application; + /** Timer core. */ + protected TimerCore core; + /** I18N resource map. */ protected ResourceMap resourceMap; @@ -106,14 +127,17 @@ public class IdleDialog extends JDialog { /** Duration label. */ protected JLabel idleDurationLabel; - /** Revert option after idle detect. */ - public static final int REVERT = 0; + /** Assign toogle button. */ + protected JToggleButton assignButton; - /** Continue option after idle detect. */ - public static final int CONTINUE = 1; + /** Assign panel (non visible by default). */ + protected JPanel assignPanel; - /** Resume option after idle detect. */ - public static final int RESUME = 2; + /** Assign project tree. */ + protected JTree projectsTree; + + /** Task selected in tree. */ + protected boolean selectedTask; /** * IdleDialog constructor. @@ -121,11 +145,13 @@ public class IdleDialog extends JDialog { * Protected to force use of show static method. * * @param application parent application + * @param core timer core */ - protected IdleDialog(SingleFrameApplication application) { + protected IdleDialog(SingleFrameApplication application, TimerCore core) { // don't make reference on other parent // windows, cause idle to unlock some task // if parent window is hidden by systray + this.core = core; // init resources map this.application = application; @@ -137,7 +163,7 @@ public class IdleDialog extends JDialog { // http://chorem.org/issues/484 and // http://kenai.com/jira/browse/BSAF-107 // cause infinite loop under openjdk - setName(null); // force nameExplicitlySet to true + setName(null); setTitle(resourceMap.getString("idleTitle")); setResizable(false); @@ -161,71 +187,131 @@ public class IdleDialog extends JDialog { // label JLabel idleIcon = new JLabel(resourceMap.getIcon("idleIcon")); - mainComponent.add(idleIcon, new GridBagConstraints(0, 0, 1, 5, 0, 1, - GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets( - 10, 5, 10, 10), 0, 0)); + mainComponent.add(idleIcon, new GridBagConstraints(0, 0, 1, 6, 0, 1, + GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(10, 5, 10, 10), 0, 0)); // label JLabel idleLabel = new JLabel(resourceMap.getString("idleMessage", JTimer.config.getIdleTime() / (60))); - mainComponent.add(idleLabel, new GridBagConstraints(1, 0, 3, 1, 1, 0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(5, 0, 0, 3), 0, 0)); + mainComponent.add(idleLabel, new GridBagConstraints(1, 0, 4, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 3), 0, 0)); taskNameLabel = new JLabel(" "); - mainComponent.add(taskNameLabel, new GridBagConstraints(1, 1, 3, 1, - 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(5, 0, 3, 5), 0, 0)); + mainComponent.add(taskNameLabel, new GridBagConstraints(1, 1, 4, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 3, 5), 0, 0)); idleDurationLabel = new JLabel(" "); - mainComponent.add(idleDurationLabel, new GridBagConstraints(1, 2, 3, 1, - 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(0, 0, 3, 5), 0, 0)); + mainComponent.add(idleDurationLabel, new GridBagConstraints(1, 2, 4, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 3, 5), 0, 0)); // separator - mainComponent.add(new JSeparator(), new GridBagConstraints(1, 3, 3, 1, - 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(0, 0, 0, 5), 0, 0)); + mainComponent.add(new JSeparator(), new GridBagConstraints(1, 3, 4, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 5), 0, 0)); // label JLabel idleRestart = new JLabel(resourceMap.getString("idleRestart")); - mainComponent.add(idleRestart, new GridBagConstraints(1, 4, 3, 1, 1, 0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(3, 0, 0, 5), 0, 0)); + mainComponent.add(idleRestart, new GridBagConstraints(1, 4, 4, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(3, 0, 0, 5), 0, 0)); JButton revertButton = new JButton(); - revertButton.setHorizontalAlignment(SwingConstants.LEFT); - revertButton.setAction(application.getContext().getActionMap(this).get( - "chooseRevertOption")); - mainComponent.add(revertButton, new GridBagConstraints(1, 5, 1, 1, 1, - 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(3, 0, 5, 5), 0, 0)); + revertButton.setAction(application.getContext().getActionMap(this).get("chooseRevertOption")); + revertButton.setHorizontalTextPosition(SwingConstants.CENTER); + revertButton.setVerticalTextPosition(SwingConstants.BOTTOM); + mainComponent.add(revertButton, new GridBagConstraints(1, 5, 1, 1, 1, 0, + GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 0, 5, 5), 0, 0)); JButton continueButton = new JButton(); - continueButton.setHorizontalAlignment(SwingConstants.LEFT); - continueButton.setAction(application.getContext().getActionMap(this) - .get("chooseContinueOption")); - mainComponent.add(continueButton, new GridBagConstraints(2, 5, 1, 1, 1, - 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(3, 0, 5, 5), 0, 0)); + continueButton.setAction(application.getContext().getActionMap(this).get("chooseContinueOption")); + continueButton.setHorizontalTextPosition(SwingConstants.CENTER); + continueButton.setVerticalTextPosition(SwingConstants.BOTTOM); + mainComponent.add(continueButton, new GridBagConstraints(2, 5, 1, 1, 1, 0, + GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 0, 5, 5), 0, 0)); JButton resumeButton = new JButton(); - resumeButton.setHorizontalAlignment(SwingConstants.LEFT); - resumeButton.setAction(application.getContext().getActionMap(this).get( - "chooseResumeOption")); - mainComponent.add(resumeButton, new GridBagConstraints(3, 5, 1, 1, 1, - 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(3, 0, 5, 5), 0, 0)); + resumeButton.setAction(application.getContext().getActionMap(this).get("chooseResumeOption")); + resumeButton.setHorizontalTextPosition(SwingConstants.CENTER); + resumeButton.setVerticalTextPosition(SwingConstants.BOTTOM); + mainComponent.add(resumeButton, new GridBagConstraints(3, 5, 1, 1, 1, 0, + GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 0, 5, 5), 0, 0)); + + assignButton = new JToggleButton(); + assignButton.setAction(application.getContext().getActionMap(this).get("chooseAssignOption")); + assignButton.setHorizontalTextPosition(SwingConstants.CENTER); + assignButton.setVerticalTextPosition(SwingConstants.BOTTOM); + mainComponent.add(assignButton, new GridBagConstraints(4, 5, 1, 1, 1, 0, + GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 0, 5, 5), 0, 0)); + + assignPanel = getAssignPanel(); + assignPanel.setVisible(false); + mainComponent.add(assignPanel, new GridBagConstraints(1, 6, 4, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(3, 0, 5, 0), 0, 0)); return mainComponent; } /** + * Build assign panel. + * + * @return assign panel + */ + protected JPanel getAssignPanel() { + JPanel panel = new JPanel(new GridBagLayout()); + + // separator + panel.add(new JSeparator(), new GridBagConstraints(0, 0, 1, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(3, 0, 5, 5), 0, 0)); + + // label + JLabel labelIdle = new JLabel(); + labelIdle.setText(resourceMap.getString("assignIdleTimeTo")); + panel.add(labelIdle, new GridBagConstraints(0, 1, 1, 1, 0, 0, + GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(3, 0, 0, 5), 0, 0)); + + // Tree + projectsTree = new JTree(); + projectsTree.setRootVisible(false); + projectsTree.setShowsRootHandles(true); + projectsTree.setModel(new TaskTreeModel(core, null)); + projectsTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + projectsTree.setCellRenderer(new ProjectsAndTasksCellRenderer()); + projectsTree.addTreeSelectionListener(e -> { + TreePath path = e.getPath(); + if (path.getPathCount() > 2) { + assignSelectedTask = (TimerTask)path.getLastPathComponent(); + } else { + assignSelectedTask = null; + } + setSelectedTask(assignSelectedTask != null); + }); + panel.add(new JScrollPane(projectsTree), new GridBagConstraints(0, 2, 1, 1, 1, 1, + GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 5, 5), 0, 0)); + + // ok + JButton assignValidButton = new JButton(); + assignValidButton.setAction(application.getContext().getActionMap(this).get("validAssignOption")); + panel.add(assignValidButton, new GridBagConstraints(0, 3, 1, 1, 0, 0, + GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0)); + + return panel; + } + + public boolean isSelectedTask() { + return selectedTask; + } + + public void setSelectedTask(boolean selectedTask) { + boolean oldValue = this.selectedTask; + this.selectedTask = selectedTask; + firePropertyChange("selectedTask", oldValue, selectedTask); + } + + /** * Init dialog idleDialog instance. * * @param parent parent reference + * @param core core reference */ - public static void init(SingleFrameApplication parent) { - idleDialog = new IdleDialog(parent); + public static void init(SingleFrameApplication parent, TimerCore core) { + idleDialog = new IdleDialog(parent, core); } /** @@ -233,7 +319,7 @@ public class IdleDialog extends JDialog { */ @Action public void chooseRevertOption() { - lastResumeOption = REVERT; + lastResumeOption = IdleOption.REVERT; idleEnded(); } @@ -242,7 +328,7 @@ public class IdleDialog extends JDialog { */ @Action public void chooseContinueOption() { - lastResumeOption = CONTINUE; + lastResumeOption = IdleOption.CONTINUE; idleEnded(); } @@ -251,11 +337,42 @@ public class IdleDialog extends JDialog { */ @Action public void chooseResumeOption() { - lastResumeOption = RESUME; + lastResumeOption = IdleOption.RESUME; + idleEnded(); + } + + /** + * Assign button action. + */ + @Action + public void chooseAssignOption() { + assignPanel.setVisible(assignButton.isSelected()); + if (assignButton.isSelected()) { + //projectsTree.expandRow(0); // all hidden without this + projectsTree.expandPath(new TreePath(projectsTree.getModel().getRoot())); + } + this.pack(); + } + + /** + * Action when validating assign option. + */ + @Action(enabledProperty = "selectedTask") + public void validAssignOption() { + lastResumeOption = IdleOption.ASSIGN; idleEnded(); } /** + * Reset some part of the UI. + */ + protected void reset() { + assignButton.setSelected(false); + assignPanel.setVisible(assignButton.isSelected()); + this.pack(); + } + + /** * Unblock all waiting threads on {@link #mutex}. */ protected void idleEnded() { @@ -281,6 +398,8 @@ public class IdleDialog extends JDialog { // schedule timer updateIdleTime = new UpdateIdleTime(); timer.schedule(updateIdleTime, 0, 1000 * 60 /* every minutes */); + + reset(); } else { updateIdleTime.cancel(); timer.purge(); @@ -298,7 +417,7 @@ public class IdleDialog extends JDialog { * @param idleStartTimestamp time stamp when idle start * @return idle option */ - public static int showIdleDialog(long idleStartTimestamp) { + public static IdleOption showIdleDialog(long idleStartTimestamp) { // only the first call must display dialog // (can happen if multiples task are running) 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 243954b..0b3d0b4 100644 --- a/src/main/java/org/chorem/jtimer/ui/tasks/RunTaskJob.java +++ b/src/main/java/org/chorem/jtimer/ui/tasks/RunTaskJob.java @@ -2,7 +2,7 @@ * #%L * jTimer * %% - * Copyright (C) 2007 - 2012 CodeLutin, Chatellier Eric + * Copyright (C) 2007 - 2016 CodeLutin, Chatellier Eric * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as @@ -45,6 +45,7 @@ import org.chorem.jtimer.entities.TimerTaskHelper; import org.chorem.jtimer.ui.system.SystemInfo; import org.chorem.jtimer.ui.system.SystemInfoFactory; import org.chorem.jtimer.ui.system.UnsupportedSystemInfoException; +import org.chorem.jtimer.ui.tasks.IdleDialog.IdleOption; import org.jdesktop.application.Task; /** @@ -190,7 +191,7 @@ public class RunTaskJob extends Task<Void, Void> { // time have to be published, even if idle is detected // because time adjustment will remove more time than published // one if done after - addTaskDelta(lastUserActivity.get(), delta); + addTaskDelta(managedTask, lastUserActivity.get(), delta); // check user idle time long idleTime = 0; @@ -207,12 +208,12 @@ public class RunTaskJob extends Task<Void, Void> { long userIdleTime = Math.max(delta, idleTime); // remove delta from now - addTaskDelta(lastUserActivity.get() + delta, -userIdleTime); + addTaskDelta(managedTask, lastUserActivity.get() + delta, -userIdleTime); // display idle detected (blocking call) JTimer parentApplication = (JTimer) getApplication(); parentApplication.preIdleDetect(); - int option = IdleDialog.showIdleDialog(lastUserActivity.get() - userIdleTime); + IdleOption option = IdleDialog.showIdleDialog(lastUserActivity.get() - userIdleTime); parentApplication.postIdleDetect(); // restart timing from current time after idle @@ -222,14 +223,20 @@ public class RunTaskJob extends Task<Void, Void> { delta = lastUserActivity.get() - oldUserActivity; switch (option) { - case IdleDialog.REVERT: + case REVERT: // just stop the task ((JTimer) getApplication()).stopTask(managedTask); break; - case IdleDialog.CONTINUE: + case CONTINUE: // readd delta since oldUserActivity - addTaskDelta(oldUserActivity - userIdleTime, delta + userIdleTime); + addTaskDelta(managedTask, oldUserActivity - userIdleTime, delta + userIdleTime); + break; + + case ASSIGN: + // readd delta since oldUserActivity to another task + TimerTask otherTask = IdleDialog.assignSelectedTask; + addTaskDelta(otherTask, oldUserActivity - userIdleTime, delta + userIdleTime); break; } } @@ -248,10 +255,11 @@ public class RunTaskJob extends Task<Void, Void> { /** * Add task delta. * + * @param task task to apply delta * @param from time when delta was notified * @param delta delta to add */ - protected void addTaskDelta(long from, long delta) { + protected void addTaskDelta(TimerTask task, long from, long delta) { long localDelta = delta; @@ -266,7 +274,7 @@ public class RunTaskJob extends Task<Void, Void> { Date todayMidnight = DateUtils.truncate(currentDate, Calendar.DAY_OF_MONTH); long msToMidnight = currentDate.getTime() - todayMidnight.getTime(); long toRemove = Math.min(-localDelta, msToMidnight); - dataManager.changeTaskTime(managedTask, currentDate, managedTask.getTime(currentDate) - toRemove); + dataManager.changeTaskTime(task, currentDate, task.getTime(currentDate) - toRemove); if (log.isDebugEnabled()) { log.debug(" remove delta to task on " + currentDate + " : " + toRemove); } @@ -282,7 +290,7 @@ public class RunTaskJob extends Task<Void, Void> { today235959 = DateUtils.addMilliseconds(today235959, -1); long msToMidnight = today235959.getTime() - currentDate.getTime(); long toAdd = Math.min(localDelta, msToMidnight); - dataManager.changeTaskTime(managedTask, currentDate, managedTask.getTime(currentDate) + toAdd); + dataManager.changeTaskTime(task, currentDate, task.getTime(currentDate) + toAdd); if (log.isDebugEnabled()) { log.debug(" adding delta to task on " + currentDate + " : " + toAdd); } @@ -291,7 +299,7 @@ public class RunTaskJob extends Task<Void, Void> { } } - checkTaskAlerts(managedTask); + checkTaskAlerts(task); } /** diff --git a/src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeCellComponent.java b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellComponent.java similarity index 98% rename from src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeCellComponent.java rename to src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellComponent.java index f89ebc9..532fe53 100644 --- a/src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeCellComponent.java +++ b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellComponent.java @@ -20,7 +20,7 @@ * #L% */ -package org.chorem.jtimer.ui.report.tree; +package org.chorem.jtimer.ui.tree; import java.awt.Color; import java.awt.Component; diff --git a/src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeCellEditor.java b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellEditor.java similarity index 99% rename from src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeCellEditor.java rename to src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellEditor.java index e1541a8..57ac9d6 100644 --- a/src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeCellEditor.java +++ b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellEditor.java @@ -20,7 +20,7 @@ * #L% */ -package org.chorem.jtimer.ui.report.tree; +package org.chorem.jtimer.ui.tree; import java.awt.Component; import java.awt.event.ItemEvent; diff --git a/src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeCellRenderer.java b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellRenderer.java similarity index 97% rename from src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeCellRenderer.java rename to src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellRenderer.java index bc2d477..a6aaf18 100644 --- a/src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeCellRenderer.java +++ b/src/main/java/org/chorem/jtimer/ui/tree/CheckBoxTreeCellRenderer.java @@ -20,7 +20,7 @@ * #L% */ -package org.chorem.jtimer.ui.report.tree; +package org.chorem.jtimer.ui.tree; import java.awt.Component; import java.util.Set; diff --git a/src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeModel.java b/src/main/java/org/chorem/jtimer/ui/tree/TaskTreeModel.java similarity index 95% rename from src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeModel.java rename to src/main/java/org/chorem/jtimer/ui/tree/TaskTreeModel.java index 3ed9d41..78c6e87 100644 --- a/src/main/java/org/chorem/jtimer/ui/report/tree/CheckBoxTreeModel.java +++ b/src/main/java/org/chorem/jtimer/ui/tree/TaskTreeModel.java @@ -20,7 +20,7 @@ * #L% */ -package org.chorem.jtimer.ui.report.tree; +package org.chorem.jtimer.ui.tree; import java.util.ArrayList; import java.util.List; @@ -46,10 +46,10 @@ import org.jdesktop.swingx.tree.TreeModelSupport; * Last update : $Date$ * By : $Author$ */ -public class CheckBoxTreeModel implements TreeModel { +public class TaskTreeModel implements TreeModel { /** Class logger. */ - private static Log log = LogFactory.getLog(CheckBoxTreeModel.class); + private static Log log = LogFactory.getLog(TaskTreeModel.class); protected TreeModelSupport modelSupport; @@ -68,7 +68,7 @@ public class CheckBoxTreeModel implements TreeModel { * @param core core * @param rootName root node name */ - public CheckBoxTreeModel(TimerCore core, String rootName) { + public TaskTreeModel(TimerCore core, String rootName) { this.core = core; root = new TimerTask(rootName); modelSupport = new TreeModelSupport(this); diff --git a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksCellRenderer.java b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksCellRenderer.java index d333227..1971f5a 100644 --- a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksCellRenderer.java +++ b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksCellRenderer.java @@ -25,83 +25,27 @@ package org.chorem.jtimer.ui.treetable; import java.awt.Color; import java.awt.Component; import java.awt.Font; -import java.awt.Image; -import java.awt.Rectangle; -import java.awt.image.ImageObserver; -import java.net.URL; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import javax.swing.ImageIcon; import javax.swing.JTree; import javax.swing.tree.DefaultTreeCellRenderer; -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.entities.TimerProject; import org.chorem.jtimer.entities.TimerTask; -import org.jdesktop.swingx.JXTreeTable; /** * Gere l'affichage des noeuds de l'arbre. * - * Comme une icone quand la taches est lancee... - * * @author chatellier * @version $Revision$ * * Last update : $Date$ * By : $Author$ */ -public class ProjectsAndTasksCellRenderer extends DefaultTreeCellRenderer - implements DataEventListener { +public class ProjectsAndTasksCellRenderer extends DefaultTreeCellRenderer { /** serialVersionUID. */ private static final long serialVersionUID = 1383276150996517529L; - /** Logger. */ - private static Log log = LogFactory.getLog(ProjectsAndTasksCellRenderer.class); - - /** Running task icon. */ - protected ImageIcon runningIcon; - - /** Running tasks. */ - protected Collection<TimerTask> runningTasks; - - /** Tree table reference for image observer. */ - protected JXTreeTable treeTable; - - /** Node image nodeObserver for running task animated icon. */ - protected NodeImageObserver nodeObserver; - - /** - * Constructor. - * - * @param treeTable Tree table reference for image observer - * @param core TimerCore - */ - public ProjectsAndTasksCellRenderer(JXTreeTable treeTable, TimerCore core) { - this.treeTable = treeTable; - - // init - runningTasks = new HashSet<>(); - - URL runnigIconUrl = ProjectsAndTasksCellRenderer.class - .getResource("/org/chorem/jtimer/resources/running.gif"); - runningIcon = new ImageIcon(runnigIconUrl); - nodeObserver = new NodeImageObserver(); - runningIcon.setImageObserver(nodeObserver); - - // be notified on events - core.getData().addDataEventListener(this); - } - /* * @see org.jdesktop.swingx.renderer.DefaultTreeRenderer#getTreeCellRendererComponent(javax.swing.JTree, java.lang.Object, boolean, boolean, boolean, int, boolean) */ @@ -133,6 +77,8 @@ public class ProjectsAndTasksCellRenderer extends DefaultTreeCellRenderer // le toString() suivit du setName() super.getTreeCellRendererComponent(tree, localValue, selected, expanded, leaf, row, hasFocus); + + setIcon(null); // if this is a task if (value instanceof TimerTask) { @@ -146,17 +92,6 @@ public class ProjectsAndTasksCellRenderer extends DefaultTreeCellRenderer setFont(getFont().deriveFont(Font.PLAIN)); } - // add icon if task is running - if (runningTasks.contains(task)) { - setIcon(runningIcon); - nodeObserver.addRow(row); - } - else { - // force no default icon - setIcon(null); - nodeObserver.removeRow(row); - } - // add color if task is closed if (task.isClosed()) { // fix selection color @@ -170,177 +105,4 @@ public class ProjectsAndTasksCellRenderer extends DefaultTreeCellRenderer return this; } - - /** - * Enclosed class to manage gif image refresh. - */ - class NodeImageObserver implements ImageObserver { - - protected Set<Integer> rows = Collections.synchronizedSet(new HashSet<>()); - - public void addRow(Integer row) { - rows.add(row); - } - - public void removeRow(Integer row) { - rows.remove(row); - } - - /* - * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) - */ - @Override - public boolean imageUpdate(Image img, int flags, int x, int y, int w, - int h) { - if ((flags & (FRAMEBITS | ALLBITS)) != 0) { - for (Integer row : rows) { - Rectangle rowBounds = treeTable.getCellRect(row, 0, true); - treeTable.repaint(rowBounds); - } - } - return (flags & (ALLBITS | ABORT)) == 0; - } - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#addProject(org.chorem.jtimer.entities.TimerProject) - */ - @Override - public void addProject(TimerProject project) { - - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#addTask(org.chorem.jtimer.entities.TimerTask) - */ - @Override - public void addTask(TimerTask task) { - - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#dataLoaded(java.util.Collection) - */ - @Override - public void dataLoaded(Collection<TimerProject> projects) { - - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#deleteProject(org.chorem.jtimer.entities.TimerProject) - */ - @Override - public void deleteProject(TimerProject project) { - - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#deleteTask(org.chorem.jtimer.entities.TimerTask) - */ - @Override - public void deleteTask(TimerTask task) { - - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#modifyProject(org.chorem.jtimer.entities.TimerProject) - */ - @Override - public void modifyProject(TimerProject project) { - - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#modifyTask(org.chorem.jtimer.entities.TimerTask) - */ - @Override - public void modifyTask(TimerTask task) { - - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#changeClosedState(org.chorem.jtimer.entities.TimerTask) - */ - @Override - public void changeClosedState(TimerTask task) { - - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#startTask(org.chorem.jtimer.entities.TimerTask) - */ - @Override - public void startTask(TimerTask task) { - - if (log.isDebugEnabled()) { - log.debug("startTask on " + task.getName()); - } - - // remember running task - runningTasks.add(task); - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#stopTask(org.chorem.jtimer.entities.TimerTask) - */ - @Override - public void stopTask(TimerTask task) { - - if (log.isDebugEnabled()) { - log.debug("stopTask on " + task.getName()); - } - - // remember don't running task - runningTasks.remove(task); - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#postMoveTask(org.chorem.jtimer.entities.TimerTask) - */ - @Override - public void moveTask(TimerTask task) { - - } - - /* - * @see org.chorem.jtimer.data.event.DataEventListener#preMoveTask(org.chorem.jtimer.entities.TimerTask) - */ - @Override - public void preMoveTask(TimerTask task) { - - } - - /* - * @see org.chorem.jtimer.data.DataEventListener#postMergeTasks(org.chorem.jtimer.entities.TimerTask, java.util.List) - */ - @Override - public void postMergeTasks(TimerTask destinationTask, - List<TimerTask> otherTasks) { - - } - - /* - * @see org.chorem.jtimer.data.DataEventListener#preMergeTasks(org.chorem.jtimer.entities.TimerTask, java.util.List) - */ - @Override - public void preMergeTasks(TimerTask destinationTask, - List<TimerTask> otherTasks) { - - } - - /* - * @see org.chorem.jtimer.event.DataEventListener#setTaskTime(org.chorem.jtimer.entities.TimerTask, java.util.Date, java.lang.Long) - */ - @Override - public void setTaskTime(TimerTask task, Date date, Long time) { - - } - - /* - * @see org.chorem.jtimer.event.DataEventListener#setAnnotation(org.chorem.jtimer.entities.TimerTask, java.util.Date, java.lang.String) - */ - @Override - public void setAnnotation(TimerTask task, Date date, String annotation) { - - } } diff --git a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksCellRenderer.java b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksRunningCellRenderer.java similarity index 82% copy from src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksCellRenderer.java copy to src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksRunningCellRenderer.java index d333227..1ee3b36 100644 --- a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksCellRenderer.java +++ b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksRunningCellRenderer.java @@ -22,9 +22,7 @@ package org.chorem.jtimer.ui.treetable; -import java.awt.Color; import java.awt.Component; -import java.awt.Font; import java.awt.Image; import java.awt.Rectangle; import java.awt.image.ImageObserver; @@ -38,7 +36,6 @@ import java.util.Set; import javax.swing.ImageIcon; import javax.swing.JTree; -import javax.swing.tree.DefaultTreeCellRenderer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -59,14 +56,13 @@ import org.jdesktop.swingx.JXTreeTable; * Last update : $Date$ * By : $Author$ */ -public class ProjectsAndTasksCellRenderer extends DefaultTreeCellRenderer - implements DataEventListener { +public class ProjectsAndTasksRunningCellRenderer extends ProjectsAndTasksCellRenderer implements DataEventListener { /** serialVersionUID. */ private static final long serialVersionUID = 1383276150996517529L; /** Logger. */ - private static Log log = LogFactory.getLog(ProjectsAndTasksCellRenderer.class); + private static Log log = LogFactory.getLog(ProjectsAndTasksRunningCellRenderer.class); /** Running task icon. */ protected ImageIcon runningIcon; @@ -86,13 +82,13 @@ public class ProjectsAndTasksCellRenderer extends DefaultTreeCellRenderer * @param treeTable Tree table reference for image observer * @param core TimerCore */ - public ProjectsAndTasksCellRenderer(JXTreeTable treeTable, TimerCore core) { + public ProjectsAndTasksRunningCellRenderer(JXTreeTable treeTable, TimerCore core) { this.treeTable = treeTable; // init runningTasks = new HashSet<>(); - URL runnigIconUrl = ProjectsAndTasksCellRenderer.class + URL runnigIconUrl = ProjectsAndTasksRunningCellRenderer.class .getResource("/org/chorem/jtimer/resources/running.gif"); runningIcon = new ImageIcon(runnigIconUrl); nodeObserver = new NodeImageObserver(); @@ -110,62 +106,23 @@ public class ProjectsAndTasksCellRenderer extends DefaultTreeCellRenderer boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { - Object localValue = value; - - // if this is a task - if (value instanceof TimerTask) { - TimerTask task = (TimerTask) value; - - // add style in project in sync - String taskName = task.getName(); - if (task instanceof TimerProject - && ((TimerProject) task).isSynchronized()) { - taskName = taskName - .substring(TimerProject.SYNCHRONIZED_PROJECT_NAME_PREFIX - .length()); - } - - // task name should not be "null" - localValue = taskName; - } - // le fait en 2 temps car sinon, on voit de temps en temps // le toString() suivit du setName() - super.getTreeCellRendererComponent(tree, localValue, - selected, expanded, leaf, row, hasFocus); + super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); // if this is a task if (value instanceof TimerTask) { TimerTask task = (TimerTask) value; - // add style in project in sync - if (task instanceof TimerProject - && ((TimerProject) task).isSynchronized()) { - setFont(getFont().deriveFont(Font.ITALIC)); - } else { - setFont(getFont().deriveFont(Font.PLAIN)); - } - // add icon if task is running if (runningTasks.contains(task)) { setIcon(runningIcon); nodeObserver.addRow(row); - } - else { + } else { // force no default icon setIcon(null); nodeObserver.removeRow(row); } - - // add color if task is closed - if (task.isClosed()) { - // fix selection color - if (selected) { - setForeground(Color.GRAY.brighter()); - } else { - setForeground(Color.GRAY); - } - } } return this; 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 9d41b9a..fac743b 100644 --- a/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksTable.java +++ b/src/main/java/org/chorem/jtimer/ui/treetable/ProjectsAndTasksTable.java @@ -65,7 +65,7 @@ public class ProjectsAndTasksTable extends JXTreeTable { protected ProjectsAndTasksModel treeTableModel; /** Table renderer. */ - protected ProjectsAndTasksCellRenderer treeCellRenderer; + protected ProjectsAndTasksRunningCellRenderer treeCellRenderer; /** * Constructor. @@ -91,7 +91,7 @@ public class ProjectsAndTasksTable extends JXTreeTable { treeTableModel = new ProjectsAndTasksModel(this, core, columnIdentifiers); // set renderer - treeCellRenderer = new ProjectsAndTasksCellRenderer(this, core); + treeCellRenderer = new ProjectsAndTasksRunningCellRenderer(this, core); setTreeCellRenderer(treeCellRenderer); setTreeTableModel(treeTableModel); diff --git a/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog.properties b/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog.properties index 090cf06..2ac1837 100644 --- a/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog.properties +++ b/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog.properties @@ -2,7 +2,7 @@ # #%L # jTimer # %% -# Copyright (C) 2007 - 2011 CodeLutin, Chatellier Eric +# Copyright (C) 2007 - 2016 CodeLutin, Chatellier Eric # %% # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as @@ -26,6 +26,7 @@ idleMessage = You have been idle for %d minutes on task '%s'. idleRestart = Choose restart option : currentTask = Task : %s idleDuration = Idle duration : %s +assignIdleTimeTo = Assign idle time to task: chooseRevertOption.Action.text=Stop chooseRevertOption.Action.shortDescription=Stop task without counting elapsed time @@ -38,3 +39,10 @@ chooseContinueOption.Action.icon=go-next.png chooseResumeOption.Action.text=Resume chooseResumeOption.Action.shortDescription=Resume task without counting elapsed time chooseResumeOption.Action.icon=go-jump.png + +chooseAssignOption.Action.text=Assign +chooseAssignOption.Action.shortDescription=Assign time to another task +chooseAssignOption.Action.icon=document-revert-3.png + +validAssignOption.Action.text=OK + diff --git a/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog_fr.properties b/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog_fr.properties index 475e755..b8914b7 100644 --- a/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog_fr.properties +++ b/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog_fr.properties @@ -2,7 +2,7 @@ # #%L # jTimer # %% -# Copyright (C) 2007 - 2011 CodeLutin, Chatellier Eric +# Copyright (C) 2007 - 2016 CodeLutin, Chatellier Eric # %% # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as @@ -25,15 +25,18 @@ idleMessage = Vous avez \u00E9t\u00E9 inactif pendant %d minutes. idleRestart = Choisissez une option : currentTask = T\u00E2che : %s idleDuration = Dur\u00E9e de l'inactivit\u00E9 : %s +assignIdleTimeTo = Assigner le temps d'inactivit\u00E9 \u00E0 la t\u00E2che : chooseRevertOption.Action.text=Stopper chooseRevertOption.Action.shortDescription=Annuler le temps \u00E9coul\u00E9 et stopper la t\u00E2che -chooseRevertOption.Action.icon=process-stop.png chooseContinueOption.Action.text=Continuer chooseContinueOption.Action.shortDescription=Continuer la t\u00E2che en comptant le temps \u00E9coul\u00E9 -chooseContinueOption.Action.icon=go-next.png chooseResumeOption.Action.text=Reprendre chooseResumeOption.Action.shortDescription=Reprendre la t\u00E2che en ne comptant pas le temps \u00E9coul\u00E9 -chooseResumeOption.Action.icon=go-jump.png + +chooseAssignOption.Action.text=Assigner +chooseAssignOption.Action.shortDescription=Assigner le temps \u00E0 une autre t\u00E2che + +validAssignOption.Action.text=OK diff --git a/src/main/resources/org/chorem/jtimer/ui/tasks/resources/document-revert-3.png b/src/main/resources/org/chorem/jtimer/ui/tasks/resources/document-revert-3.png new file mode 100644 index 0000000..09cd5a5 Binary files /dev/null and b/src/main/resources/org/chorem/jtimer/ui/tasks/resources/document-revert-3.png differ -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.