Package pspdash

Source Code of pspdash.PauseButton

// PSP Dashboard - Data Automation Tool for PSP-like processes
// Copyright (C) 2003 Software Process Dashboard Initiative
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// The author(s) may be contacted at:
// OO-ALC/TISHD
// Attn: PSP Dashboard Group
// 6137 Wardleigh Road
// Hill AFB, UT 84056-5843
//
// E-Mail POC:  processdash-devel@lists.sourceforge.net


package pspdash;

import java.io.FileOutputStream;
import java.io.IOException;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.StringTokenizer;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.Icon;
import pspdash.data.SaveableData;
import pspdash.data.DateData;
import pspdash.data.DoubleData;


public class PauseButton extends DropDownButton implements ActionListener {
    PSPDashboard parent = null;
    Icon pause_icon = null;
    Icon continue_icon = null;
    boolean showCurrent = false;
    boolean paused = true;
    Timer stopwatch = null;
    PropertyKey currentPhase = null;
    String timeElementName = null;
    SoundClip timingSound = null;
    int maxNumHistoryItems = 10;
    private String pause_string, continue_string, pause_tip, continue_tip;

    private javax.swing.Timer activeRefreshTimer = null;
    int refreshIntervalMillis = MILLIS_PER_MINUTE; // default: one minute
    private static final int FAST_REFRESH_INTERVAL = 5 * 1000;

    PauseButton(PSPDashboard dash) {
        super();
        PCSH.enableHelp(this, "PlayPause");
        PCSH.enableHelpKey(getMenu(), "PlayPause");
        loadUserSettings();

        Resources res = Resources.getDashBundle("pspdash.PSPDashboard");
        pause_string = res.getString("Pause_String");
        pause_tip = res.getString("Pause_Tip");
        continue_string = res.getString("Continue_String");
        continue_tip = res.getString("Continue_Tip");

        try {
          pause_icon = DashboardIconFactory.getPauseIcon();
          continue_icon = DashboardIconFactory.getContinueIcon();
        } catch (Exception e) {
          pause_icon = continue_icon = null;
        }
        updateAppearance();
        getButton().setMargin(new Insets(1,2,1,2));
        getButton().setFocusPainted(false);
        getButton().addActionListener(this);
        setRunFirstMenuOption(false);
        parent = dash;


        activeRefreshTimer =
            new javax.swing.Timer(refreshIntervalMillis, this);
        activeRefreshTimer.setInitialDelay
            (Math.min(MILLIS_PER_MINUTE, refreshIntervalMillis) + 1000);
        activeRefreshTimer.start();

        // Load the audio clip
        if (!"true".equalsIgnoreCase(Settings.getVal("pauseButton.quiet"))) {
            timingSound = new SoundClip(getClass().getResource("timing.wav"));
        } else
            timingSound = new SoundClip(null);

        dash.getContentPane().add(this);
    }

    private static final int MILLIS_PER_MINUTE = 60 * 1000;

    private void updateAppearance() {
        if (pause_icon == null)
            getButton().setText
                (showCurrent == paused ? pause_string : continue_string);
        else
            getButton().setIcon
                (showCurrent == paused ? pause_icon : continue_icon);

        getButton().setToolTipText(paused ? continue_tip : pause_tip);
    }


    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == activeRefreshTimer) {
            saveCurrentTimeLogEntry();

            // Possibly commit the current row.  If a user clicks
            // pause, then goes home for the evening, and comes back
            // the next day and starts working on the same activity,
            // it really isn't meaningful to log 15 hours of interrupt
            // time.  So if the interrupt time passes some "critical
            // point", just commit the current row.
            if (paused && stopwatch != null) {
                double interruptMinutes = stopwatch.runningMinutesInterrupt();
                if (interruptMinutes > 5.0 &&
                    interruptMinutes > (0.25 * elapsedMinutes))
                    releaseCurrentTimeLogEntry();
            }

        } else if (e.getSource() instanceof JMenuItem) {
            JMenuItem item = (JMenuItem) e.getSource();
            if (setPath(item.getText()))
                cont();
            else
                getMenu().remove(item);
        } else {
            if (paused) cont(); else pause();
        }
    }

    public void pause() {
        paused = true;
        if (stopwatch != null) {
            stopwatch.stop();
            saveCurrentTimeLogEntry();
        }
        updateAppearance();
    }

    public void cont() {
        paused = false;
        if (stopwatch == null) {
            stopwatch = newTimer();
        } else {
            stopwatch.start();
        }
        updateAppearance();

        timingSound.play();
    }

    public void setCurrentPhase(PropertyKey newCurrentPhase) {
        if (currentTimeLogEntry != null)
            addToMenu(currentPhase.path());

        boolean needCleanup = (entryHasBeenSaved > 1);
        releaseCurrentTimeLogEntry();
        if (needCleanup)
            cleanupTimeLog();

        if (newCurrentPhase != null) {
            currentPhase = newCurrentPhase;
            timeElementName = parent.data.createDataName
                (currentPhase.path(), "Time");
        }

        if (TimeLog.timeLoggingAllowed
            (currentPhase, parent.props, parent.data)) {

            getButton().setEnabled(true);
            if (!paused) cont();

        } else {
            pause();
            getButton().setEnabled(false);
        }
    }

    public boolean setPath(String path) {
        if (parent.hierarchy.setPath(path))
            return true;
        else {
            // They've gone and edited their hierarchy, and the
            // requested node no longer exists! Beep to let them
            // know there was a problem, then remove this item
            // from the history list so they can't select it again
            // in the future.
            pause();
            Toolkit.getDefaultToolkit().beep();
            return false;
        }
    }

    public boolean setPhase(String phase) {
        if (parent.hierarchy.setPhase(phase))
            return true;
        else {
            // They have navigated to a new portion of the hierarchy,
            // where the current phase is not present.  Beep to let them
            // know there was a problem.
            pause();
            Toolkit.getDefaultToolkit().beep();
            return false;
        }
    }

    public void addToMenu(String path) {
        JMenu menu = getMenu();
        JMenuItem itemToAdd = null, oneItem;

        // if the menu already contains a menu item for this path, remove
        // that menu item.
        for (int i = menu.getItemCount();  i-- > 0; ) {
            oneItem = menu.getItem(i);
            if (oneItem != null && path.equals(oneItem.getText())) {
                itemToAdd = oneItem;
                menu.remove(i);
                break;
            }
        }

        if (itemToAdd == null) {
            itemToAdd = new JMenuItem(path);
            itemToAdd.addActionListener(this);
        }

        menu.insert(itemToAdd, 0);

        while (menu.getItemCount() > maxNumHistoryItems)
            menu.remove(maxNumHistoryItems);
    }

    public void quit() {
        saveUserSettings();
    }

    private static boolean WRITE_ZERO =
        "true".equalsIgnoreCase(Settings.getVal("timeLog.writeZero"));

    /** The time log entry for the current activity. */
    TimeLogEntry currentTimeLogEntry = null;

    /** How many times has the current time log entry been saved to the time
     *  log file? */
    int entryHasBeenSaved = 0;

    /** How much elapsed stopwatch time has been saved to the data
     *  repository?  Note: since we round items off when adding them
     *  to the repository, this value will rarely ever equal
     *  elapsedMinutes.
     */
    double savedElapsedMinutes = 0.0;

    /** How many minutes are currently on the stopwatch? (We need to
     *  keep track of this separately, because the TimeLogEntry only
     *  keeps information accurate to a minute.
     */
    double elapsedMinutes = 0.0;

    /** Update the current time log entry with information from the
     *  stopwatch. Creates the current time log entry if it doesn't
     *  already exist.
     */
    private synchronized void updateCurrentTimeLogEntry() {
        if (stopwatch == null) return;

        double previousElapsedMinutes = elapsedMinutes;
        elapsedMinutes = stopwatch.minutesElapsedDouble();
        long roundedElapsedMinutes = (long) (elapsedMinutes + 0.5);

        if (currentTimeLogEntry == null) {
            if (elapsedMinutes < 1.0 && !WRITE_ZERO) return;
            if (previousElapsedMinutes == elapsedMinutes) return;

            currentTimeLogEntry = new TimeLogEntry
                (currentPhase,
                 stopwatch.createTime,
                 roundedElapsedMinutes,
                 stopwatch.minutesInterrupt());
            entryHasBeenSaved = 0;

            // When we began timing this phase, we set the timer for a
            // fast, 5 second interval (so we could catch the top of
            // the minute as it went by).  This allows us to create
            // the new time log entry within 5 seconds of the one
            // minute point.  Once we've created the new time log
            // entry, slow the timer back down to the user-requested
            // refresh interval.
            activeRefreshTimer.setDelay(refreshIntervalMillis);

        } else {
            currentTimeLogEntry.minutesElapsed  = roundedElapsedMinutes;
            currentTimeLogEntry.minutesInterrupt= stopwatch.minutesInterrupt();
        }
    }

    /** Write the current time log entry out to the file.
     *  Create a current time log entry if it doesn't exist.
     */
    private synchronized void saveCurrentTimeLogEntry() {
        updateCurrentTimeLogEntry();

        if (currentTimeLogEntry == null) return// nothing to save.

        String timeLogFilename = parent.getTimeLog();
        if (timeLogFilename != null && timeLogFilename.length() != 0) try {
                                // write an entry to the time log.
            String log_msg = currentTimeLogEntry.toString();
            FileOutputStream timeLogFile =
                new FileOutputStream(timeLogFilename, true);

            if (entryHasBeenSaved > 0)
                log_msg = TimeLog.CONTINUATION_FLAG + log_msg;

            parent.addToTimeLogEditor (currentTimeLogEntry);
            timeLogFile.write(log_msg.getBytes());
            timeLogFile.close();
            entryHasBeenSaved++;

            if (entryHasBeenSaved > 30)
                cleanupTimeLog();
        } catch (IOException ioe) {
            System.err.println("Couldn't update time log " + timeLogFilename);
            ioe.printStackTrace();
        }

        // Need to make changes to the data elements.
        SaveableData d = parent.data.getValue(timeElementName);
                                // Calculate the amount of time in this phase,
                                // NOT COUNTING the current time log entry.
        double previousTime = (d == null ? 0.0 : ((DoubleData) d).getDouble())
            - savedElapsedMinutes;
                                // Calculate the amount of time in this phase,
                                // INCLUDING the current time log entry.
        long currentMinutes =
            (long) (previousTime + currentTimeLogEntry.minutesElapsed);
        savedElapsedMinutes = currentMinutes - previousTime;
        parent.data.putValue(timeElementName,
                             new DoubleData(currentMinutes, false));
        //System.out.println("updating time to " + currentMinutes);

        if (stopwatch != null)
            parent.hierarchy.workPerformed
                (new DateData(stopwatch.createTime, true));
    }

    private void releaseCurrentTimeLogEntry() {
        saveCurrentTimeLogEntry();
        activeRefreshTimer.setDelay(refreshIntervalMillis);

        stopwatch = (paused ? null : newTimer());
        currentTimeLogEntry = null;
        entryHasBeenSaved = 0;
        savedElapsedMinutes = elapsedMinutes = 0.0;
    }

    private Timer newTimer() {
        // The instructions below will cause the timer to wait for 61
        // seconds (starting right now), then fire once every 5
        // seconds.  This quick firing interval allows it to catch the
        // one minute mark fairly closely.
        activeRefreshTimer.setDelay(FAST_REFRESH_INTERVAL);
        activeRefreshTimer.restart();

        return new Timer();
    }

    public void maybeReleaseEntry(TimeLogEntry tle) {
        if (tle == null ||
            (currentTimeLogEntry != null &&
             currentTimeLogEntry.isSimilarTo(tle)))
            setCurrentPhase(null);
    }

    private void cleanupTimeLog() {
        String timeLogFilename = parent.getTimeLog();
        if (timeLogFilename != null || timeLogFilename.length() != 0) try {
            TimeLog log = new TimeLog();
            log.read(timeLogFilename);
            log.save(timeLogFilename);
            if (entryHasBeenSaved > 0)
                entryHasBeenSaved = 1;
            //System.err.println("Cleaned up time log.");
        } catch (IOException ioe) {}
    }

    private void loadUserSettings() {
        // Load the user setting for button appearance
        showCurrent = "true".equalsIgnoreCase(Settings.getVal
                                              ("pauseButton.showCurrent"));

        // Load the user setting for refresh interval
        String refreshInterval = Settings.getVal("timelog.updateInterval");
        if (refreshInterval != null) try {
            refreshIntervalMillis = (int)
                (Double.parseDouble(refreshInterval) * MILLIS_PER_MINUTE);
        } catch (NumberFormatException nfe) {}

        // Load time multiplier setting
        double multiplier = 1.0;
        String mult = Settings.getVal("timer.multiplier");
        if (mult != null) try {
            multiplier = Double.parseDouble(mult);
        } catch (NumberFormatException nfe) {}
        refreshIntervalMillis = (int) (refreshIntervalMillis / multiplier);

        // Load the user setting for history size
        String historySize = Settings.getVal("pauseButton.historySize");
        if (historySize != null) try {
            maxNumHistoryItems = Integer.parseInt(historySize);
            if (maxNumHistoryItems < 1)
                maxNumHistoryItems = 10;
        } catch (NumberFormatException nfe) {}

        // Load the saved history list, if it is available.
        String history = Settings.getVal("pauseButton.historyList");
        if (history != null) {
            StringTokenizer tok = new StringTokenizer(history, "\t");
            while (tok.hasMoreTokens())
                addToMenu(tok.nextToken());
        }
    }

    private void saveUserSettings() {
        // the only item that could have changed is the history list.
        JMenu menu = getMenu();
        JMenuItem oneItem;
        StringBuffer setting = new StringBuffer();

        // Walk through the history items in reverse order, and build
        // up a list.
        for (int i = menu.getItemCount();  i-- > 0; ) {
            oneItem = menu.getItem(i);
            setting.append(oneItem.getText());
            if (i > 0) setting.append("\t");
        }

        // save the setting.
        InternalSettings.set("pauseButton.historyList", setting.toString());
    }

}
TOP

Related Classes of pspdash.PauseButton

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.