001 /*
002 Copyright (C) 2003 Adam Olsen
003 This program is free software; you can redistribute it and/or modify
004 it under the terms of the GNU General Public License as published by
005 the Free Software Foundation; either version 1, or (at your option)
006 any later version.
007 This program is distributed in the hope that it will be useful,
008 but WITHOUT ANY WARRANTY; without even the implied warranty of
009 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
010 GNU General Public License for more details.
011 You should have received a copy of the GNU General Public License
012 along with this program; if not, write to the Free Software
013 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
014 */
015 package com.valhalla.jbother;
016
017 import com.valhalla.gui.*;
018 import javax.swing.*;
019
020 import java.awt.*;
021 import java.awt.event.*;
022 import javax.swing.table.*;
023 import java.util.*;
024 import javax.swing.*;
025 import java.beans.*;
026 import org.jivesoftware.smackx.filetransfer.*;
027
028 /**
029 *
030 * @author synic
031 */
032 public class FileProgressDialog extends JFrame {
033
034 private static FileProgressDialog instance = null;
035 private JPanel main;
036 private JButton clear = new JButton("Clean Up");
037 private JButton close = new JButton("Close");
038 private JButton cancel = new JButton("Cancel");
039 private Component glue = Box.createVerticalGlue();
040 private TableModel model = new TableModel();
041 private JTable table = new JTable(model);
042 java.text.NumberFormat nf = java.text.NumberFormat.getInstance();
043 java.text.NumberFormat nf2 = java.text.NumberFormat.getInstance();
044
045
046 /** Creates a new instance of FileProgressDialog */
047 private FileProgressDialog() {
048 super("File Transfer Manager");
049
050 setIconImage(Standard.getImage("frameicon.png"));
051
052 main = (JPanel)getContentPane();
053 main.setLayout(new BorderLayout());
054 main.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
055 nf.setMaximumFractionDigits(1);
056 nf.setMinimumFractionDigits(1);
057 JScrollPane scroll = new JScrollPane(table);
058 table.setBackground(Color.WHITE);
059 scroll.getViewport().setBackground(Color.WHITE);
060
061 main.add(scroll, BorderLayout.CENTER);
062 table.setShowGrid(false);
063 table.setShowHorizontalLines(true);
064 table.setTableHeader(null);
065
066 // get the height for each row
067 Window w = new Window(this);
068 w.setLayout(new BorderLayout());
069 TransferPanel tp = new TransferPanel(null,"", "",66, 0);
070 tp.bar.setValue(100);
071 w.add(tp, BorderLayout.CENTER);
072 w.pack();
073
074 table.setRowHeight(w.getHeight() + 18);
075 w.dispose();
076
077 TableColumn col = table.getColumnModel().getColumn(0);
078 col.setResizable(false);
079 col.setPreferredWidth(28);
080 col.setMaxWidth(28);
081 col = table.getColumnModel().getColumn(1);
082 col.setPreferredWidth(376);
083 table.setDefaultRenderer(TransferPanel.class, new CellRend());
084 table.setDefaultRenderer(IconLabel.class, new IconRend());
085
086 JPanel buttons = new JPanel();
087 buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
088 buttons.add(Box.createHorizontalGlue());
089 buttons.add(cancel);
090 buttons.add(clear);
091 buttons.add(close);
092 buttons.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
093 close.addActionListener(new ActionListener()
094 {
095 public void actionPerformed(ActionEvent e)
096 {
097 setVisible(false);
098 }
099 });
100
101 clear.addActionListener(new ActionListener()
102 {
103 public void actionPerformed(ActionEvent e)
104 {
105 cleanup();
106 }
107 } );
108
109 cancel.addActionListener(new ActionListener()
110 {
111 public void actionPerformed(ActionEvent e)
112 {
113 int row = table.getSelectedRow();
114 if(row != -1)
115 {
116 TransferPanel panel = (TransferPanel)model.getValueAt(row, 1);
117 if(!panel.getDone()) panel.cancel();
118 }
119 }
120 } );
121
122 main.add(buttons, BorderLayout.SOUTH);
123 pack();
124 setSize(new Dimension(450, 250));
125 Standard.cascadePlacement(this);
126 }
127
128 private void cleanup()
129 {
130 ArrayList items = model.getItems();
131 for( int i = 0; i < items.size(); i++ )
132 {
133 TransferPanel panel = (TransferPanel)items.get(i);
134 if(panel.getDone())
135 {
136 model.remove(panel);
137 i--;
138 }
139 }
140 }
141
142 public static FileProgressDialog getInstance()
143 {
144 if(instance == null) instance = new FileProgressDialog();
145 return instance;
146 }
147
148 public void addFile(FileTransfer transfer, String jid, String name, int type, long size)
149 {
150 setVisible(true);
151 new TransferPanel(transfer, jid, name, type, size);
152 }
153
154 class TransferPanel extends JPanel
155 {
156 JProgressBar bar = new JProgressBar(0, 100);
157 private String fileName = null;
158 private JLabel percent = new JLabel("0%");
159 private int status = 3;
160 private int type = 0;
161 private IconLabel l = new IconLabel(this);
162 private FileTransfer transfer;
163 private String name;
164 private long size;
165 private long current = 0;
166 private long lastSize = 0;
167 private long last = 0;
168 private javax.swing.Timer rateTimer = new javax.swing.Timer(1000, new RateHandler());
169 private double rate = 0;
170 private Vector avg = new Vector();
171 private int counter = 0;
172 private boolean popShown = false;
173 private String tooltip = null;
174 private String jid, from;
175
176 public TransferPanel(FileTransfer transfer, String jid, String name, int type, long size)
177 {
178 this.type = type;
179 this.transfer = transfer;
180 this.jid = jid;
181 this.from = ConnectorThread.getInstance().getConnection().getUser();
182 this.size = size;
183 setLayout(new BorderLayout());
184 setBackground(Color.WHITE);
185 setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
186 this.name = name;
187
188 JLabel n = new JLabel(name);
189 n.setToolTipText(getTooltip());
190 l.setToolTipText(getTooltip());
191 setToolTipText(getTooltip());
192 add(n, BorderLayout.NORTH);
193
194 bar.setToolTipText(getTooltip());
195 percent.setToolTipText(getTooltip());
196
197 add(bar, BorderLayout.CENTER);
198 add(percent, BorderLayout.SOUTH);
199
200 this.fileName = name;
201 if(type != 66) model.add(this);
202 startMonitor();
203 }
204
205 public String getTooltip()
206 {
207 if(transfer == null) return "";
208 if(tooltip == null)
209 {
210 StringBuffer buff = new StringBuffer();
211 buff.append("<html><table><tr><td><b>File: </b></td><td>");
212
213 String loc = name;
214 if(type == 1) loc = transfer.getFileName();
215 buff.append(loc).append("</td></tr>");
216 if(type == 0)
217 {
218 buff.append("<tr><td><b>To: </b></td><td>").append(jid).append("</td></tr>");
219 }
220 else {
221 buff.append("<tr><td><b>From: </b></td><td>").append(from).append("</td></tr>");
222 }
223
224 String desc = ""; //transfer.getDescription();
225 if(desc.equals("")) desc = "None given";
226 buff.append("<tr><td><b>Description:</b></td><td>").append(desc).append("</td></tr>");
227 buff.append("</table></html>\n");
228 tooltip = buff.toString();
229 }
230 return tooltip;
231 }
232
233 class RateHandler implements ActionListener
234 {
235 public void actionPerformed(ActionEvent e)
236 {
237 double diff = current - last;
238 last = current;
239
240 avg.add(0, new Double(diff));
241 if(avg.size() > 5) avg.setSize(5);
242
243 if(avg.size() < 5) rate = diff / 1024.0;
244 else {
245 double value = 0;
246 for(int i = 0; i < avg.size(); i++)
247 {
248 Double d = (Double)avg.get(i);
249 value += d.doubleValue();
250 }
251
252 rate = (value / avg.size()) / 1024.0;
253 }
254 }
255 }
256
257 public IconLabel getLabel()
258 {
259 return l;
260 }
261
262 public int getStatus()
263 {
264 return status;
265 }
266
267 public boolean getDone()
268 {
269 return transfer.isDone();
270 }
271
272 public void cancel()
273 {
274 transfer.cancel();
275 rateTimer.stop();
276 status = 4;
277 }
278
279 public void setSelected(boolean selected)
280 {
281 if(selected) setBackground(table.getSelectionBackground());
282 else setBackground(Color.WHITE);
283 }
284
285 class MonitorThread extends Thread
286 {
287 FileTransfer transfer;
288 public MonitorThread(FileTransfer transfer)
289 {
290 this.transfer = transfer;
291 }
292
293 public void run()
294 {
295 while( !transfer.isDone() )
296 {
297 current = transfer.getAmountWritten();
298 try {
299 Thread.sleep(500);
300 }
301 catch(Exception ex) { }
302 if( transfer.getStatus().equals(FileTransfer.Status.ERROR) )
303 {
304 status = 4;
305 }
306
307 SwingUtilities.invokeLater(new Runnable() {
308 public void run() {
309 int val = (int)(transfer.getProgress() * 100);
310 bar.setValue(val);
311 table.repaint();
312 table.validate();
313 percent.setText(val + "%");
314 }
315 } );
316 }
317
318 }
319 }
320
321 public void startMonitor()
322 {
323 if( transfer == null ) return;
324 if( !rateTimer.isRunning()) rateTimer.start();
325 status = type;
326 new MonitorThread(transfer).start();
327 }
328
329 public void update(final String event, final int percent, final long bytes)
330 {
331 if(!rateTimer.isRunning()) rateTimer.start();
332
333 if(event.equals("Transferring")) status = type;
334 else if(event.equals("Done")) status = 5;
335 else if(event.equals("Error") || event.equals("Cancelled")) status = 4;
336
337 if( status > 1 ) rateTimer.stop();
338
339 if(counter++ < 5 && status == type) return;
340 counter = 0;
341
342 SwingUtilities.invokeLater(new Runnable()
343 {
344 public void run()
345 {
346 long b = bytes;
347 if(bytes <= 0)
348 {
349 b = lastSize;
350 }
351 else {
352 bar.setValue(percent);
353 }
354 lastSize = b;
355 current = b;
356 String transferred = nf2.format(b / 1024) + "k";
357 String total = nf2.format(size / 1024) + "k";
358
359 TransferPanel.this.percent.setText(percent + "% - " + event + " - " +
360 transferred + "/" + total + " - " + nf.format(rate) + "KB/s");
361 table.repaint();
362
363 if(status == 5 && !popShown)
364 {
365 popShown = true;
366 NotificationPopup.showSingleton(FileProgressDialog.this, "Transfer Complete", transfer.getFileName(), TransferPanel.this);
367 }
368 }
369 });
370 }
371 }
372
373 class CellRend extends JPanel implements TableCellRenderer
374 {
375
376 public Component getTableCellRendererComponent(
377 JTable table, Object color,
378 boolean isSelected, boolean hasFocus,
379 int row, int column) {
380
381 TransferPanel panel = (TransferPanel)color;
382 setToolTipText(panel.getTooltip());
383 panel.setSelected(isSelected);
384 panel.validate();
385 return (JPanel)color;
386 }
387 }
388
389 class IconLabel extends JLabel
390 {
391 private ImageIcon up = Standard.getIcon("images/buttons/Up24.gif");
392 private ImageIcon down = Standard.getIcon("images/buttons/Down24.gif");
393 private ImageIcon error = Standard.getIcon("images/buttons/Error24.gif");
394 private ImageIcon wait = Standard.getIcon("images/buttons/Wait24.gif");
395 private ImageIcon done = Standard.getIcon("images/buttons/Done24.gif");
396
397 private TransferPanel panel;
398
399 public IconLabel(TransferPanel panel)
400 {
401 setPreferredSize(new Dimension(28, 28));
402 setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
403 this.panel = panel;
404 setOpaque(true);
405 }
406
407 public void updateIcon()
408 {
409 int status = panel.getStatus();
410
411 switch(status)
412 {
413 case 0:
414 setIcon(up);
415 break;
416 case 1:
417 setIcon(down);
418 break;
419 case 4:
420 setIcon(error);
421 break;
422 case 5:
423 setIcon(done);
424 break;
425 default:
426 setIcon(wait);
427 break;
428 }
429 }
430
431 public void setSelected(boolean selected)
432 {
433 if(selected) setBackground(table.getSelectionBackground());
434 else setBackground(Color.WHITE);
435 }
436
437 }
438
439 class IconRend extends JPanel implements TableCellRenderer
440 {
441 public Component getTableCellRendererComponent(
442 JTable table, Object color,
443 boolean isSelected, boolean hasFocus,
444 int row, int column) {
445
446 IconLabel panel = (IconLabel)color;
447 panel.setSelected(isSelected);
448
449 panel.setSelected(isSelected);
450 panel.updateIcon();
451 panel.validate();
452 return (JLabel)panel;
453 }
454 }
455
456 class TableModel extends AbstractTableModel
457 {
458 private ArrayList items = new ArrayList();
459
460 public synchronized void add(TransferPanel panel)
461 {
462 items.add(0, panel);
463 fireTableRowsInserted(items.size(), items.size());
464 }
465
466 public ArrayList getItems() { return items; }
467
468 public int getColumnCount() { return 2; }
469
470 public int getRowCount() { return items.size(); }
471
472 public Object getValueAt(int row, int col)
473 {
474 TransferPanel panel = (TransferPanel)items.get(row);
475 if(col == 0) return panel.getLabel();
476 else return panel;
477 }
478
479 public Class getColumnClass(int c)
480 {
481 if(c == 0) return IconLabel.class;
482 else return TransferPanel.class;
483 }
484
485 public synchronized void remove(TransferPanel panel)
486 {
487 int index = items.indexOf(panel);
488 if(index != -1) items.remove(index);
489 fireTableRowsDeleted(items.size(), items.size());
490 }
491
492
493 }
494 }