001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package icy.gui.frame.progress;
020
021import icy.common.listener.ProgressListener;
022import icy.system.thread.ThreadUtil;
023import icy.util.StringUtil;
024
025import java.awt.BorderLayout;
026
027import javax.swing.BorderFactory;
028import javax.swing.JProgressBar;
029
030/**
031 * A progress TaskFrame (thread safe)
032 * 
033 * @author fab & stephane
034 */
035public class ProgressFrame extends TaskFrame implements ProgressListener, Runnable
036{
037    /**
038     * gui
039     */
040    JProgressBar progressBar;
041
042    /**
043     * length (in bytes) of download
044     */
045    protected double length;
046    /**
047     * current position (in bytes) of download
048     */
049    protected double position;
050
051    /**
052     * current message
053     */
054    protected String message;
055    /**
056     * current tooltip
057     */
058    protected String tooltip;
059
060    /**
061     * internals
062     */
063    // private final SingleProcessor processor;
064
065    public ProgressFrame(final String message)
066    {
067        super("");
068
069        // default
070        length = 100d;
071        position = -1d;
072        // processor = new SingleProcessor(true);
073        this.message = message;
074
075        ThreadUtil.invokeLater(new Runnable()
076        {
077            @Override
078            public void run()
079            {
080                progressBar = new JProgressBar();
081                progressBar.setString(buildMessage(message));
082                progressBar.setStringPainted(true);
083                progressBar.setIndeterminate(true);
084                progressBar.setBorder(BorderFactory.createEmptyBorder());
085                progressBar.setMinimum(0);
086                // this is enough for a smooth progress
087                progressBar.setMaximum(1000);
088
089                mainPanel.setLayout(new BorderLayout());
090                mainPanel.add(progressBar, BorderLayout.CENTER);
091
092                pack();
093            }
094        });
095    }
096
097    protected String buildMessage(String message)
098    {
099        return "  " + message + "  ";
100    }
101
102    @Override
103    public void run()
104    {
105        // don't spent too much time in EDT
106        ThreadUtil.sleep(10);
107        updateDisplay();
108    }
109
110    public void refresh()
111    {
112        // refresh (need single delayed execution)
113        ThreadUtil.runSingle(this);
114    }
115
116    protected void updateDisplay()
117    {
118        // repacking need to be done on EDT
119        ThreadUtil.invokeNow(new Runnable()
120        {
121            @Override
122            public void run()
123            {
124                // position information
125                if ((position != -1d) && (length > 0d))
126                {
127                    // remove indeterminate state
128                    if (progressBar.isIndeterminate())
129                        progressBar.setIndeterminate(false);
130
131                    // set progress
132                    final int value = (int) (position * 1000d / length);
133                    if (progressBar.getValue() != value)
134                        progressBar.setValue(value);
135                }
136                else
137                {
138                    // set indeterminate state
139                    if (!progressBar.isIndeterminate())
140                        progressBar.setIndeterminate(true);
141                }
142
143                final String text = buildMessage(message);
144
145                // set progress message
146                if (!StringUtil.equals(progressBar.getString(), text))
147                {
148                    progressBar.setString(text);
149                    // so component is resized according to its string length
150                    progressBar.invalidate();
151
152                    // repack frame
153                    pack();
154                }
155
156                // set tooltip
157                if (!StringUtil.equals(progressBar.getToolTipText(), tooltip))
158                    progressBar.setToolTipText(tooltip);
159            }
160        });
161    }
162
163    public String getMessage()
164    {
165        return message;
166    }
167
168    public void setMessage(String value)
169    {
170        if (message != value)
171        {
172            message = value;
173            refresh();
174        }
175    }
176
177    // we want tooltip set on the progress component only
178    @Override
179    public void setToolTipText(String value)
180    {
181        if (tooltip != value)
182        {
183            tooltip = value;
184            refresh();
185        }
186    }
187
188    /**
189     * @return the length
190     */
191    public double getLength()
192    {
193        return length;
194    }
195
196    /**
197     * @param value
198     *        the length to set
199     */
200    public void setLength(double value)
201    {
202        if (length != value)
203        {
204            length = value;
205            refresh();
206        }
207    }
208
209    /**
210     * @return the position
211     */
212    public double getPosition()
213    {
214        return position;
215    }
216
217    /**
218     * increment progress position
219     */
220    public void incPosition()
221    {
222        setPosition(position + 1);
223    }
224
225    /**
226     * @param value
227     *        the position to set
228     */
229    public void setPosition(double value)
230    {
231        if (position != value)
232        {
233            position = value;
234            refresh();
235        }
236    }
237
238    /**
239     * @deprecated use {@link #setPosition(double)} instead
240     */
241    @Deprecated
242    public void setProgress(int value)
243    {
244        setPosition(value);
245    }
246
247    @Override
248    public boolean notifyProgress(double position, double length)
249    {
250        setPosition(position);
251        setLength(length);
252
253        return true;
254    }
255
256}