//***************************************************************************** //* //* (c) Copyright 2003. Glub Tech, Incorporated. All Rights Reserved. //* //* $Id: DataTransferDialog.java 37 2009-05-11 22:46:15Z gary $ //* //***************************************************************************** package com.glub.secureftp.client.gui; import com.glub.secureftp.client.framework.*; import com.glub.secureftp.bean.*; import com.glub.gui.*; import com.glub.util.*; import java.awt.*; import java.awt.event.*; import java.lang.reflect.*; import java.text.*; import java.util.*; import javax.swing.*; import javax.swing.border.*; public class DataTransferDialog extends JDialog implements Progress { protected static final long serialVersionUID = 1L; private FTPSession session = null; private FTPAbortableTransfer abort = null; private short transferDirection; private JProgressBar progressBar = null; private JLabel fileNameLabel = new JLabel(""); private JLabel estimatedTimeLabel = new JLabel(""); private JLabel transferRateLabel = new JLabel(""); private JPanel progressPanel = null; private JPanel indeterminatePanel = null; private double percentDone = 0.0; private int totalPercent = 100; private long currentXfer = 0; private long total = 0; private boolean showProgress = true; private boolean abortAttempted = false; public DataTransferDialog( Frame parent, FTPSession session, short xferDir, FTPAbortableTransfer abort ) { super( parent, LString.getString("DataTransferDialog.title", "File Transfer"), false ); this.session = session; setAbortableTransfer( abort ); this.transferDirection = xferDir; buildDialog(); pack(); if ( null != session ) { addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { cancelDataTransfer(); } } ); } else { setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); } setLocationRelativeTo( SecureFTP.getBaseFrame() ); setResizable( false ); setVisible( true ); } public void dispose() { showProgress = false; super.dispose(); } protected void buildDialog() { JPanel dialogPanel = new JPanel(); dialogPanel.setLayout( new SpringLayout() ); dialogPanel.add( getInfoPanel() ); dialogPanel.add( getProgressPanel() ); dialogPanel.add( getStatsPanel() ); SpringUtilities.makeCompactGrid( dialogPanel, 3, 1, // rows, cols 5, 5, // init x, init y 5, 5 // pad x, pad y ); getContentPane().setLayout( new BorderLayout() ); getContentPane().add( dialogPanel, BorderLayout.CENTER ); getContentPane().add( getButtonPanel(), BorderLayout.SOUTH ); } protected JPanel getInfoPanel() { JPanel panel = new JPanel(); panel.setLayout( new BoxLayout(panel, BoxLayout.Y_AXIS) ); JLabel downloadLabel = new JLabel( LString.getString("DataTransferDialog.download", "Downloading:") ); JLabel uploadLabel = new JLabel( LString.getString("DataTransferDialog.upload", "Uploading:") ); if ( DataTransferManager.DOWNLOAD == transferDirection ) { panel.add( downloadLabel ); } else { panel.add( uploadLabel ); } panel.add( fileNameLabel ); String maxStr = LString.getString("DataTransferDialog.timeLeft", "Estimated time left: [^0] ([^1] [^2] of [^3] [^4] copied)"); FontMetrics fm = getFontMetrics( getFont() ); int size = fm.stringWidth(maxStr) + 50; panel.setPreferredSize( new java.awt.Dimension(size, 35) ); return panel; } public void setAbortableTransfer( FTPAbortableTransfer abort ) { this.abort = abort; } public void setFileName( String name ) { fileNameLabel.setText( name ); fileNameLabel.setToolTipText( name ); } protected JPanel getStatsPanel() { JPanel panel = new JPanel(); panel.setLayout( new BoxLayout(panel, BoxLayout.Y_AXIS) ); setTimeRemaining( (long)-1, (long)0, (long)0 ); panel.add( estimatedTimeLabel ); setTransferRate( (long)-1 ); panel.add( transferRateLabel ); return panel; } public void setTimeRemaining( long timeLeft, long xferBytes, long totalBytes ) { NumberFormat nf = NumberFormat.getIntegerInstance(); nf.setGroupingUsed( true ); nf.setMaximumFractionDigits( 2 ); LString timeLeftStr = new LString("DataTransferDialog.timeLeft", "Estimated time left: [^0] ([^1] [^2] of [^3] [^4] copied)"); if ( timeLeft < 0 && getProgressBar().isIndeterminate() ) { RateMetric xferRM = getRateMetric( xferBytes ); LString dataXferStr = new LString("DataTransferDialog.bytesXferBase", "Data Transferred: [^0] [^1] copied"); dataXferStr.replace( 0, nf.format(xferRM.getRate()) ); dataXferStr.replace( 1, xferRM.getMetric() ); estimatedTimeLabel.setText( dataXferStr.getString() ); return; } else if ( timeLeft < 0 ) { estimatedTimeLabel.setText( LString.getString("DataTransferDialog.timeLeftBase", "Estimated time left:") ); return; } Date date = new Date(); date.setTime( timeLeft * 1000 ); SimpleDateFormat dateFormat = new SimpleDateFormat( "HH:mm:ss" ); dateFormat.setTimeZone( TimeZone.getTimeZone("GMT") ); timeLeftStr.replace( 0, dateFormat.format(date) ); RateMetric currentRM = getRateMetric( xferBytes ); timeLeftStr.replace( 1, nf.format(currentRM.getRate()) ); timeLeftStr.replace( 2, currentRM.getMetric() ); RateMetric totalRM = getRateMetric( totalBytes ); timeLeftStr.replace( 3, nf.format(totalRM.getRate()) ); timeLeftStr.replace( 4, totalRM.getMetric() ); estimatedTimeLabel.setText( timeLeftStr.getString() ); } public void setTransferRate( long bytesPerSec ) { LString xferRateStr = new LString("DataTransferDialog.transferRate", "Transfer rate: [^0] [^1]/sec"); if ( bytesPerSec <= 0 ) { transferRateLabel.setText( LString.getString("DataTransferDialog.transferRateBase", "Transfer rate:") ); return; } RateMetric rm = getRateMetric( bytesPerSec ); NumberFormat nf = NumberFormat.getIntegerInstance(); nf.setGroupingUsed( true ); nf.setMaximumFractionDigits( 0 ); xferRateStr.replace( 0, nf.format(rm.getRate()) ); xferRateStr.replace( 1, rm.getMetric() ); transferRateLabel.setText( xferRateStr.getString() ); } private RateMetric getRateMetric( long totalBytes ) { RateMetric rm = new RateMetric(); short metric = 0; double bytes = totalBytes; // KB / sec if ( bytes / 1024 > 1 ) { bytes /= 1024; metric = 1; } // MB / sec if ( metric == 1 && bytes / 1024 > 1 ) { bytes /= 1024; metric = 2; } // GB / sec if ( metric == 2 && bytes / 1024 > 1 ) { bytes /= 1024; metric = 3; } rm.setRate( bytes ); String sMetric = null; switch ( metric ) { case 0: sMetric = LString.getString("Common.xferMetric.bytes", "bytes"); break; case 1: sMetric = LString.getString("Common.xferMetric.kb", "KB"); break; case 2: sMetric = LString.getString("Common.xferMetric.mb", "MB"); break; case 3: sMetric = LString.getString("Common.xferMetric.gb", "GB"); break; } rm.setMetric( sMetric ); return rm; } protected JPanel getProgressPanel() { if ( null == progressPanel ) { progressPanel = new JPanel( new BorderLayout() ); progressBar = new JProgressBar( 0, 100 ); progressPanel.add( progressBar, BorderLayout.CENTER ); } return progressPanel; } protected JPanel getButtonPanel() { JPanel panel = new JPanel(); JButton cancelButton = new JButton( LString.getString("Common.button.cancel", "Cancel") ); cancelButton.setEnabled( null != session ); SwingUtilities.getRootPane( this ).setDefaultButton( cancelButton ); cancelButton.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { Thread cancelThread = new Thread() { public void run() { setEnabled( false ); setVisible( false ); cancelDataTransfer(); } }; cancelThread.start(); } } ); panel.add( cancelButton ); return panel; } protected void cancelDataTransfer() { abortAttempted = true; try { if ( null != abort ) { try { session.getFTPBean().abort( abort ); } catch ( IllegalArgumentException iae ) { // the FTPData may not yet be set... // so wait a few ticks and try again try { Thread.sleep( 100 ); } catch ( InterruptedException ie ) {} session.getFTPBean().abort( abort ); } } } catch ( FTPException fe ) {} finally { SecureFTP.getCommandDispatcher().fireCommand(this, new LsCommand()); SecureFTP.getBaseFrame().setCursor( new Cursor(Cursor.DEFAULT_CURSOR) ); dispose(); } } public boolean abortAttempted() { return abortAttempted; } public void finishProgress() { if ( !progressBar.isIndeterminate() ) { progressBar.setValue( 100 ); } } public void startProgress() { showProgress = true; if ( !progressBar.isIndeterminate() ) { progressBar.setValue( 0 ); } DataTransferProgressThread dtpt = new DataTransferProgressThread( this ); dtpt.setPriority( Thread.MIN_PRIORITY ); dtpt.start(); } public void updateProgress( long pos, long total ) { this.percentDone = ((pos * 1.0) / total) * 100; this.currentXfer = pos; this.total = total; this.totalPercent = 100; String baseTitle = LString.getString("DataTransferDialog.title", "File Transfer"); if ( total > 0 ) { if ( progressBar.isIndeterminate() ) { setIndeterminate( false ); } LString percentDoneStr = new LString("DataTransferDialog.percentDone", "[^0]% completed"); NumberFormat nf = NumberFormat.getNumberInstance(); nf.setMaximumFractionDigits( 0 ); String sPercent = nf.format( percentDone ); if (percentDone > 100) sPercent = "--"; percentDoneStr.replace( 0, sPercent ); setTitle( baseTitle + ": " + percentDoneStr.getString() ); } else { if ( !progressBar.isIndeterminate() ) { setIndeterminate( true ); } } } private JPanel getIndeterminateProgress() { if ( null == indeterminatePanel ) { ImageIcon progress = new ImageIcon(getClass().getResource("images/progress.gif")); indeterminatePanel = new JPanel( new BorderLayout() ); indeterminatePanel.add( new JLabel(progress), BorderLayout.CENTER ); } return indeterminatePanel; } private void setIndeterminate( boolean state ) { getProgressBar().setIndeterminate( state ); if ( state ) { // lets use our image for non mac if ( !Util.isMacOS() ) { getProgressPanel().remove( getProgressBar() ); getProgressPanel().add( getIndeterminateProgress(), BorderLayout.CENTER ); } } else { // use the native progress bar getProgressPanel().remove( getIndeterminateProgress() ); getProgressPanel().add( getProgressBar(), BorderLayout.CENTER ); } } public double getPercentDone() { return percentDone; } public int getTotalPercent() { return totalPercent; } public long getCurrentXfer() { return currentXfer; } public long getTotal() { return total; } public JProgressBar getProgressBar() { return progressBar; } public boolean showProgress() { return showProgress; } class RateMetric { private double rate; private String metric; public RateMetric() { this( -1, null ); } public RateMetric( long rate, String metric ) { setRate( rate ); setMetric( metric ); } public double getRate() { return rate; } public void setRate( double rate ) { this.rate = rate; } public String getMetric() { return metric; } public void setMetric( String metric ) { this.metric = metric; } } } class DataTransferProgressThread extends Thread { private DataTransferDialog dialog = null; Runnable getMin, getMax, setValue, paintString, dontPaintString, xferMetrics; int minValue = 0, maxValue, value = 0; int tenthOfSec = 0; long bytesPerSec; public DataTransferProgressThread( final DataTransferDialog dialog ) { this.dialog = dialog; setValue = new Runnable() { public void run() { JProgressBar progressBar = dialog.getProgressBar(); if ( !progressBar.isIndeterminate() ) { progressBar.setValue(value); } } }; getMin = new Runnable() { public void run() { JProgressBar progressBar = dialog.getProgressBar(); if ( !progressBar.isIndeterminate() ) { minValue = progressBar.getMinimum(); } } }; getMax = new Runnable() { public void run() { JProgressBar progressBar = dialog.getProgressBar(); if ( !progressBar.isIndeterminate() ) { maxValue = progressBar.getMaximum(); } } }; xferMetrics = new Runnable() { public void run() { long byteRate = dialog.getCurrentXfer() - bytesPerSec; long secondsRemaining = (dialog.getTotal() - dialog.getCurrentXfer()) / byteRate; dialog.setTransferRate( byteRate ); dialog.setTimeRemaining( secondsRemaining, dialog.getCurrentXfer(), dialog.getTotal() ); } }; /* paintString = new Runnable() { public void run() { JProgressBar progressBar = dialog.getProgressBar(); if ( !progressBar.isIndeterminate() ) { progressBar.setStringPainted(true); } } }; dontPaintString = new Runnable() { public void run() { JProgressBar progressBar = dialog.getProgressBar(); if ( !progressBar.isIndeterminate() ) { progressBar.setStringPainted(false); } } }; */ } public void run() { while ( dialog.showProgress() ) { try { SwingUtilities.invokeAndWait(getMin); SwingUtilities.invokeAndWait(getMax); } catch ( InvocationTargetException ite ) {} catch ( InterruptedException ie ) {} try { sleep( 200 ); tenthOfSec++; if ( tenthOfSec > 9 ) { tenthOfSec = 0; try { SwingUtilities.invokeAndWait(xferMetrics); } catch ( InvocationTargetException ite ) {} catch ( InterruptedException ie ) {} bytesPerSec = dialog.getCurrentXfer(); } double completed = dialog.getPercentDone(); int total = dialog.getTotalPercent(); if (total <= 0 || completed > total) { value = minValue; SwingUtilities.invokeLater(setValue); //SwingUtilities.invokeLater(dontPaintString); } else { double percent = (double) completed / total; value = (int) (percent * maxValue); SwingUtilities.invokeLater(setValue); //SwingUtilities.invokeLater(paintString); } } catch (InterruptedException ie) {} } } } class FileExistsDialog { public static int DIRECTION_GET = 0; public static int DIRECTION_PUT = 1; public static int CANCEL = 0; public static int SKIP = 1; public static int REPLACE = 2; public static int REPLACE_ALL = 3; public static int RESUME = 4; public static int RESUME_ALL = 5; public static int SKIP_ALL = 6; private final static LString REMOTE_SMALLER = new LString( "DataTransfer.remote_file_smaller", "The remote file is smaller than the local file." ); private final static LString REMOTE_LARGER = new LString( "DataTransfer.remote_file_larger", "The remote file is larger than the local file." ); private final static LString REMOTE_OLDER = new LString( "DataTransfer.remote_file_older", "The remote file is older than the local file." ); private final static LString REMOTE_NEWER = new LString( "DataTransfer.remote_file_newer", "The remote file is newer than the local file." ); private final static LString REMOTE_SMALLER_OLDER = new LString( "DataTransfer.remote_file_smaller_older", "The remote file is smaller and older than the local file." ); private final static LString REMOTE_SMALLER_NEWER = new LString( "DataTransfer.remote_file_smaller_newer", "The remote file is smaller and newer than the local file." ); private final static LString REMOTE_LARGER_OLDER = new LString( "DataTransfer.remote_file_larger_older", "The remote file is larger and older than the local file." ); private final static LString REMOTE_LARGER_NEWER = new LString( "DataTransfer.remote_file_larger_newer", "The remote file is larger and newer than the local file." ); public static ButtonGroup choicesGroup = new ButtonGroup(); public static int showDialog( int direction, String fileName, Date remoteModTime, long localModTime, long remoteFileSize, long localFileSize, boolean resumable ) { if ( GTOverride.getBoolean("glub.transfer.force.replace_all") ) { return FileExistsDialog.REPLACE_ALL; } LString exists = new LString( "DataTransfer.file_exists", "The file \"[^0]\" already exists." ); exists.replace( 0, fileName ); JPanel infoPanel = new JPanel(); infoPanel.setLayout( new BoxLayout(infoPanel, BoxLayout.Y_AXIS) ); infoPanel.add( new GTLabel(exists, 300) ); infoPanel.add( Box.createVerticalStrut(10) ); LString moreInfo = null; boolean resumeDefault = resumable; // test to see if we have mod time of files if ( null != remoteModTime && remoteModTime.getTime() != localModTime ) { //resumable = false; resumeDefault = false; if ( remoteModTime.getTime() > localModTime ) { if ( remoteFileSize > localFileSize ) { // remote newer and larger moreInfo = REMOTE_LARGER_NEWER; if ( direction == DIRECTION_PUT ) { resumable = false; } } else if ( remoteFileSize < localFileSize ) { // remote newer and smaller moreInfo = REMOTE_SMALLER_NEWER; if ( direction == DIRECTION_GET ) { resumable = false; } } else { // remote newer moreInfo = REMOTE_NEWER; } } else { if ( remoteFileSize > localFileSize ) { // remote older and larger moreInfo = REMOTE_LARGER_OLDER; resumable = false; } else if ( remoteFileSize < localFileSize ) { // remote older and smaller moreInfo = REMOTE_SMALLER_OLDER; resumable = false; } else { // remote older moreInfo = REMOTE_OLDER; resumable = false; } } } else if ( remoteFileSize > localFileSize ) { // remote larger moreInfo = REMOTE_LARGER; if ( direction == DIRECTION_PUT ) { resumable = false; } } else if ( remoteFileSize < localFileSize ) { // remote smaller moreInfo = REMOTE_SMALLER; if ( direction == DIRECTION_GET ) { resumable = false; } } if ( null != moreInfo ) { infoPanel.add( new GTLabel(moreInfo, 300) ); infoPanel.add( Box.createVerticalStrut(10) ); } JPanel choicesPanel = new JPanel(); choicesPanel.setLayout( new BoxLayout(choicesPanel, BoxLayout.X_AXIS) ); JRadioButton replaceRB = new JRadioButton(LString.getString("DataTransfer.button.replace", "Replace")); JRadioButton skipRB = new JRadioButton(LString.getString("DataTransfer.button.skip", "Skip")); JRadioButton resumeRB = new JRadioButton(LString.getString("DataTransfer.button.resume", "Resume")); choicesPanel.add( replaceRB ); choicesPanel.add( skipRB ); choicesPanel.add( resumeRB ); choicesGroup.add( replaceRB ); choicesGroup.add( skipRB ); choicesGroup.add( resumeRB ); choicesPanel.setBorder( new TitledBorder(LString.getString("DataTransfer.options.title", "Options")) ); if ( resumeDefault ) { resumeRB.setSelected( true ); } else { replaceRB.setSelected( true ); } resumeRB.setEnabled( resumable ); JPanel mainPanel = new JPanel(); mainPanel.setLayout( new BorderLayout() ); mainPanel.add( infoPanel, BorderLayout.CENTER ); mainPanel.add( choicesPanel, BorderLayout.SOUTH ); LString title = new LString("DataTransfer.file_exists.title", "File Exists"); String[] buttons = { LString.getString("Common.button.ok", "OK"), LString.getString("Common.button.cancel", "Cancel"), LString.getString("DataTransfer.button.apply_to_all", "Apply to All") }; int r = JOptionPane.showOptionDialog( SecureFTP.getBaseFrame(), mainPanel, title.getString(), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, buttons, buttons[0] ); boolean applyToAll = ( r == JOptionPane.CANCEL_OPTION ); int result = CANCEL; if ( r == JOptionPane.YES_OPTION || applyToAll ) { if ( replaceRB.isSelected() ) { if ( applyToAll ) { result = REPLACE_ALL; } else { result = REPLACE; } } else if ( skipRB.isSelected() ) { if ( applyToAll ) { result = SKIP_ALL; } else { result = SKIP; } } else if ( resumeRB.isSelected() ) { if ( applyToAll ) { result = RESUME_ALL; } else { result = RESUME; } } } return result; } }