r2694 - in trunk/src/main: java/org/chorem/jtimer/ui/tasks resources/org/chorem/jtimer/ui/tasks/resources
Author: echatellier Date: 2009-11-16 10:21:54 +0100 (Mon, 16 Nov 2009) New Revision: 2694 Added: trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/appointment-new.png Removed: trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/alert.png Modified: trunk/src/main/java/org/chorem/jtimer/ui/tasks/IdleDialog.java trunk/src/main/java/org/chorem/jtimer/ui/tasks/RunTaskJob.java trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog.properties trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog_fr.properties Log: Affichage de la dur?\195?\169e d'inactivit?\195?\169 Modified: trunk/src/main/java/org/chorem/jtimer/ui/tasks/IdleDialog.java =================================================================== --- trunk/src/main/java/org/chorem/jtimer/ui/tasks/IdleDialog.java 2009-11-16 09:19:51 UTC (rev 2693) +++ trunk/src/main/java/org/chorem/jtimer/ui/tasks/IdleDialog.java 2009-11-16 09:21:54 UTC (rev 2694) @@ -22,15 +22,18 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.util.Timer; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; -import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSeparator; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; +import org.apache.commons.lang.time.DurationFormatUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.chorem.jtimer.JTimerFactory; @@ -41,7 +44,7 @@ import org.jdesktop.application.SingleFrameApplication; /** - * Idle dialog showed to user when idle has been detected. + * Modal idle dialog showed to user when idle has been detected. * * Composed of an unique blocking show method. * @@ -66,23 +69,42 @@ /** log */ private static Log log = LogFactory.getLog(IdleDialog.class); + /** Mutex object (multiples running tasks are waiting on it) */ + protected static Object mutex = new Object(); + + /** Singleton dialog instance. */ + protected static IdleDialog idleDialog; + + /** Resume option. */ + protected static int lastResumeOption; + + /** Parent application. */ protected SingleFrameApplication application; + /** I18N resource map. */ protected ResourceMap resourceMap; - - protected static IdleDialog mutex; - protected static int lastResumeOption; + /** Timer (for idle duration scheduling). */ + protected Timer timer; + /** Current Idle duration refresh task. */ + protected UpdateIdleTime updateIdleTime; + + /** Timestamp when idle starts. */ + protected long idleStartTimestamp; + + /** Duration label. */ protected JLabel idleDurationLabel; - /** Option after idle detect */ + /** Revert option after idle detect. */ public static final int REVERT = 0; - /** Option after idle detect */ + + /** Continue option after idle detect. */ public static final int CONTINUE = 1; - /** Option after idle detect */ + + /** Resume option after idle detect. */ public static final int RESUME = 2; - + /** * IdleDialog constructor. * @@ -91,23 +113,28 @@ * @param parent parent application */ protected IdleDialog(SingleFrameApplication application) { - super(application.getMainFrame()); - + // don't make reference on other parent + // windows, cause idle to unlock some task + // if parent window is hidden by systray + super(); + // init resources map this.application = application; ApplicationContext ctxt = application.getContext(); ResourceManager mgr = ctxt.getResourceManager(); resourceMap = mgr.getResourceMap(IdleDialog.class); - - //setName("idleFrame"); + + setName("idleFrame"); setTitle(resourceMap.getString("idleTitle")); setResizable(false); - - // TODO : must be modal , but break mecanism - //setModal(true); - - getRootPane().setLayout(new BorderLayout(1,1)); + setModal(true); + setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + + getRootPane().setLayout(new BorderLayout(1, 1)); getRootPane().add(getMainComponent(), BorderLayout.CENTER); + + // timer + timer = new Timer(); } /** @@ -121,103 +148,117 @@ // 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, 10, 10, 10), 0, 0)); - + GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets( + 10, 5, 10, 10), 0, 0)); + // label - JLabel idleLabel = new JLabel(resourceMap.getString("idleMessage", - Long.valueOf(JTimerFactory.getIdleTime() / (60 * 1000)))); + JLabel idleLabel = new JLabel(resourceMap.getString("idleMessage", Long + .valueOf(JTimerFactory.getIdleTime() / (60 * 1000)))); mainComponent.add(idleLabel, new GridBagConstraints(1, 0, 3, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 3), 0, 0)); idleDurationLabel = new JLabel(" "); - mainComponent.add(idleDurationLabel, new GridBagConstraints(1, 1, 3, 1, 1, 0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(5, 0, 5, 5), 0, 0)); - + mainComponent.add(idleDurationLabel, new GridBagConstraints(1, 1, 3, 1, + 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, + new Insets(5, 0, 3, 5), 0, 0)); + // separator - mainComponent.add(new JSeparator(), new GridBagConstraints(1, 2, 3, 1, 1, 0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, + mainComponent.add(new JSeparator(), new GridBagConstraints(1, 2, 3, 1, + 1, 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, 3, 3, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(5, 0, 0, 3), 0, 0)); - + new Insets(3, 0, 0, 5), 0, 0)); + JButton revertButton = new JButton(); - revertButton.setHorizontalAlignment(JLabel.LEFT); - revertButton.setAction(application.getContext().getActionMap(this).get("chooseRevertOption")); - mainComponent.add(revertButton, new GridBagConstraints(1, 4, 1, 1, 1, 0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(5, 0, 5, 5), 0, 0)); + revertButton.setHorizontalAlignment(SwingConstants.LEFT); + revertButton.setAction(application.getContext().getActionMap(this).get( + "chooseRevertOption")); + mainComponent.add(revertButton, new GridBagConstraints(1, 4, 1, 1, 1, + 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, + new Insets(3, 0, 5, 5), 0, 0)); JButton continueButton = new JButton(); - continueButton.setHorizontalAlignment(JLabel.LEFT); - continueButton.setAction(application.getContext().getActionMap(this).get("chooseContinueOption")); - mainComponent.add(continueButton, new GridBagConstraints(2, 4, 1, 1, 1, 0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(5, 0, 5, 5), 0, 0)); + continueButton.setHorizontalAlignment(SwingConstants.LEFT); + continueButton.setAction(application.getContext().getActionMap(this) + .get("chooseContinueOption")); + mainComponent.add(continueButton, new GridBagConstraints(2, 4, 1, 1, 1, + 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, + new Insets(3, 0, 5, 5), 0, 0)); JButton resumeButton = new JButton(); - resumeButton.setHorizontalAlignment(JLabel.LEFT); - resumeButton.setAction(application.getContext().getActionMap(this).get("chooseResumeOption")); - mainComponent.add(resumeButton, new GridBagConstraints(3, 4, 1, 1, 1, 0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(5, 0, 5, 5), 0, 0)); + resumeButton.setHorizontalAlignment(SwingConstants.LEFT); + resumeButton.setAction(application.getContext().getActionMap(this).get( + "chooseResumeOption")); + mainComponent.add(resumeButton, new GridBagConstraints(3, 4, 1, 1, 1, + 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, + new Insets(3, 0, 5, 5), 0, 0)); return mainComponent; } - public void run () { - idleDurationLabel.setText(resourceMap.getString("idleDuration", - Long.valueOf(JTimerFactory.getIdleTime() / (60 * 1000)))); - } /** - * Init dialog mutex instance. + * Init dialog idleDialog instance. * * @param parent parent reference */ public static void init(SingleFrameApplication parent) { - mutex = new IdleDialog(parent); + idleDialog = new IdleDialog(parent); } + /** + * Revert button action. + */ @Action public void chooseRevertOption() { lastResumeOption = REVERT; idleEnded(); } + /** + * Continue button action. + */ @Action public void chooseContinueOption() { lastResumeOption = CONTINUE; idleEnded(); } - + + /** + * Resume button action. + */ @Action public void chooseResumeOption() { lastResumeOption = RESUME; idleEnded(); } + /** + * Unblock all waiting threads on {@link #mutex}. + */ protected void idleEnded() { - synchronized(this) { - notifyAll(); + synchronized (mutex) { + mutex.notifyAll(); } setVisible(false); } - protected synchronized void waitForIdleEnd() { - try { - wait(); - log.debug("Thread unwaiting"); - } catch (InterruptedException e) { - if (log.isErrorEnabled()) { - log.error("Thread inturrupted", e); - } + @Override + public void setVisible(boolean b) { + + if (b) { + updateIdleTime = new UpdateIdleTime(); + timer.schedule(updateIdleTime, 0, 1000 * 60 /* every minutes */); + } else { + updateIdleTime.cancel(); + timer.purge(); } + + super.setVisible(b); } /** @@ -226,19 +267,55 @@ * This function is thread safe and show only one dialog even if * function is called multiples times. * - * @param lastActivityTimestamp + * @param idleStartTimestamp time stamp when idle start * @return idle option */ - public static int showIdleDialog(long lastActivityTimestamp) { - //synchronized(mutex) { - if (!mutex.isVisible()) { - mutex.application.show(mutex); - mutex.run(); + public static int showIdleDialog(long idleStartTimestamp) { + + // only the first call must display dialog + // (can happen if multiples task are running) + boolean mustShow = false; + synchronized (idleDialog) { + mustShow = !idleDialog.isVisible(); + } + + // the first frame will be blocked by show modal + // blocking status... + if (mustShow) { + idleDialog.idleStartTimestamp = idleStartTimestamp; + idleDialog.application.show(idleDialog); + } else { + // ...the others by wait(); + synchronized (mutex) { + try { + mutex.wait(); + } catch (InterruptedException e) { + if (log.isErrorEnabled()) { + log.error("Thread inturrupted", e); + } + } } - //} + } - mutex.waitForIdleEnd(); - return lastResumeOption; } + + /** + * Task to update idle time duration while dialog is showed. + */ + protected class UpdateIdleTime extends java.util.TimerTask { + + /* + * @see java.util.TimerTask#run() + */ + @Override + public void run() { + if (log.isDebugEnabled()) { + log.debug("Update idle duration"); + } + String duration = DurationFormatUtils.formatDuration( + System.currentTimeMillis() - idleStartTimestamp, "HH:mm"); + idleDurationLabel.setText(resourceMap.getString("idleDuration", duration)); + } + } } Modified: trunk/src/main/java/org/chorem/jtimer/ui/tasks/RunTaskJob.java =================================================================== --- trunk/src/main/java/org/chorem/jtimer/ui/tasks/RunTaskJob.java 2009-11-16 09:19:51 UTC (rev 2693) +++ trunk/src/main/java/org/chorem/jtimer/ui/tasks/RunTaskJob.java 2009-11-16 09:21:54 UTC (rev 2694) @@ -104,7 +104,7 @@ TimerDataManager dataManager) { super(parentApp); this.parentApp = parentApp; - + // init with False bWantToStop = Boolean.FALSE; @@ -140,10 +140,11 @@ Date now = new Date(); // check alert to be fired for (TimerAlert alert : task.getAlerts()) { - if (alert.getType().equals(Type.REACH_DAILY_TIME) && TimerTaskHelper.getTotalTime(task, now) > alert.getDuration()) { + if (alert.getType().equals(Type.REACH_DAILY_TIME) + && TimerTaskHelper.getTotalTime(task, now) > alert.getDuration()) { alreadyTrownAlerts.add(alert.clone()); - } - else if (alert.getType().equals(Type.REACH_TOTAL_TIME) && TimerTaskHelper.getAllTotalTime(task) > alert.getDuration()) { + } else if (alert.getType().equals(Type.REACH_TOTAL_TIME) + && TimerTaskHelper.getAllTotalTime(task) > alert.getDuration()) { alreadyTrownAlerts.add(alert.clone()); } } @@ -153,7 +154,7 @@ if (task.getParent() != null) { checkAlreadyThrownAlerts(task.getParent()); } - + } /** @@ -282,17 +283,15 @@ // idle detected // update time without idle time offsetTimeInMs -= configIdleTime; - publish(taskTimingBeforeStartInMs + loopTimestamp - - taskStartCalendar.getTimeInMillis() + offsetTimeInMs); + publish(taskTimingBeforeStartInMs + loopTimestamp - taskStartCalendar.getTimeInMillis() + offsetTimeInMs); // parent application JTimer parentApplication = (JTimer)getApplication(); - + // send idle detect event parentApplication.preIdleDetect(); // ask user what to do - //int option = ((JTimer) getApplication()).askIdleOption(); - int option = IdleDialog.showIdleDialog(lastPublishTimestamp); + int option = IdleDialog.showIdleDialog(loopTimestamp - idleTime); // send idle detect event parentApplication.postIdleDetect(); @@ -356,8 +355,9 @@ // for example, if UI lag... long currentDuration = durations.get(durations.size() - 1); - dataManager.changeTaskTime(managedTask, new Date(), currentDuration / 1000); - + dataManager.changeTaskTime(managedTask, new Date(), + currentDuration / 1000); + checkTaskAlerts(managedTask); } @@ -368,25 +368,22 @@ */ protected void checkTaskAlerts(TimerTask task) { Date now = new Date(); - + // check alert to be fired for (TimerAlert alert : task.getAlerts()) { if (!alreadyTrownAlerts.contains(alert)) { - if (alert.getType().equals(Type.REACH_DAILY_TIME) && TimerTaskHelper.getTotalTime(task, now) >= alert.getDuration()) { - //String alertMessage = "Task '%s' has reached %s for current day !"; - //displayAlert(String.format(alertMessage, task.getName(), DurationFormatUtils.formatDuration(alert.getDuration() * 1000, "HH:mm:ss"))); + if (alert.getType().equals(Type.REACH_DAILY_TIME) + && TimerTaskHelper.getTotalTime(task, now) >= alert.getDuration()) { displayAlert(task, Type.REACH_DAILY_TIME, alert.getDuration()); alreadyTrownAlerts.add(alert.clone()); - } - else if (alert.getType().equals(Type.REACH_TOTAL_TIME) && TimerTaskHelper.getAllTotalTime(task) >= alert.getDuration()) { - //String alertMessage = "Task '%s' has reached %s !"; - //displayAlert(String.format(alertMessage, task.getName(), DurationFormatUtils.formatDuration(alert.getDuration() * 1000, "HH:mm:ss"))); + } else if (alert.getType().equals(Type.REACH_TOTAL_TIME) + && TimerTaskHelper.getAllTotalTime(task) >= alert.getDuration()) { displayAlert(task, Type.REACH_TOTAL_TIME, alert.getDuration()); alreadyTrownAlerts.add(alert.clone()); } } } - + // lance aussi les alertes sur les taches parentes // par exemple, si une tache passe en temps journaliers a 1h // sont parent y passe aussi, donc les alertes doivent être levée. @@ -400,21 +397,24 @@ * * @param alertMessage alert message */ - protected void displayAlert(final TimerTask task, final Type alertType, final long alertDuration) { + protected void displayAlert(final TimerTask task, final Type alertType, + final long alertDuration) { SwingUtilities.invokeLater(new Runnable() { public void run() { String alertMessage = null; String formattedTime = DurationFormatUtils.formatDuration(alertDuration * 1000, "HH:mm:ss"); if (Type.REACH_DAILY_TIME.equals(alertType)) { - alertMessage = getResourceMap().getString("alert.dailyAlertMessage", task.getName(), formattedTime); + alertMessage = getResourceMap().getString( + "alert.dailyAlertMessage", task.getName(), formattedTime); + } else if (Type.REACH_TOTAL_TIME.equals(alertType)) { + alertMessage = getResourceMap().getString( + "alert.totalAlertMessage", task.getName(), formattedTime); } - else if (Type.REACH_TOTAL_TIME.equals(alertType)) { - alertMessage = getResourceMap().getString("alert.totalAlertMessage", task.getName(), formattedTime); - } - + JOptionPane.showMessageDialog(null, alertMessage, - getResourceMap().getString("alert.title"), JOptionPane.INFORMATION_MESSAGE, - getResourceMap().getIcon("alert.alertIcon")); + getResourceMap().getString("alert.title"), + JOptionPane.INFORMATION_MESSAGE, getResourceMap() + .getIcon("alert.alertIcon")); } }); } Modified: trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog.properties =================================================================== --- trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog.properties 2009-11-16 09:19:51 UTC (rev 2693) +++ trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog.properties 2009-11-16 09:21:54 UTC (rev 2694) @@ -1,9 +1,9 @@ # idle i18n idleTitle = Idle detect -idleIcon = alert.png +idleIcon = appointment-new.png idleMessage = You have been idle for %d minutes. idleRestart = Choose restart option : -idleDuration = Idle duration : %s +idleDuration = Idle duration : %s. chooseRevertOption.Action.text=Stop chooseRevertOption.Action.shortDescription=Stop task without counting elapsed time Modified: trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog_fr.properties =================================================================== --- trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog_fr.properties 2009-11-16 09:19:51 UTC (rev 2693) +++ trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/IdleDialog_fr.properties 2009-11-16 09:21:54 UTC (rev 2694) @@ -2,7 +2,7 @@ idleTitle = Inactivit\u00E9 d\u00E9tect\u00E9e idleMessage = Vous avez \u00E9t\u00E9 inactif pendant %d minutes. idleRestart = Choisissez une option : -idleDuration = Dur\u00E9e d'inactivit\u00E9 : %s +idleDuration = Dur\u00E9e de l'inactivit\u00E9 : %s. chooseRevertOption.Action.text=Stopper chooseRevertOption.Action.shortDescription=Annuler le temps \u00E9coul\u00E9 et stopper la t\u00E2che Deleted: trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/alert.png =================================================================== (Binary files differ) Added: trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/appointment-new.png =================================================================== (Binary files differ) Property changes on: trunk/src/main/resources/org/chorem/jtimer/ui/tasks/resources/appointment-new.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
participants (1)
-
echatellier@users.chorem.org