/*
* JFileSync
* Copyright (C) 2002-2007, Jens Heidrich
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301, USA
*/
package jfs.gui;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.border.TitledBorder;
import jfs.conf.JFSText;
import jfs.sync.JFSComparison;
import jfs.sync.JFSComparisonMonitor;
import jfs.sync.JFSCopyMonitor;
import jfs.sync.JFSDeleteMonitor;
import jfs.sync.JFSFormatter;
import jfs.sync.JFSProgress;
import jfs.sync.JFSProgress.ProgressActivity;
import jfs.sync.JFSProgress.ProgressState;
import jfs.sync.JFSProgressObserver;
import jfs.sync.JFSSynchronization;
/**
* A dialog that is shown during the comparison of a set of directory pairs und during the synchronization.
*
* @author Jens Heidrich
* @version $Id: JFSProgressView.java,v 1.29 2007/07/20 16:35:36 heidrich Exp $
*/
public class JFSProgressView extends JDialog implements JFSProgressObserver, ActionListener {
/**
* The UID.
*/
private static final long serialVersionUID = 52L;
/**
* The main frame ;-).
*/
private final JFSMainView mainView;
/**
* The completion bar for the algorithm.
*/
private final JProgressBar completionBar;
/**
* The estimated time until the current activity is done.
*/
private final JLabel remainingTime;
/**
* The panel containing details about comparison.
*/
private final JPanel comparisonPanel;
/**
* The panel containing details about delete statements.
*/
private final JPanel deletePanel;
/**
* The panel containing details about copy statements.
*/
private final JPanel copyPanel;
/**
* The relative path of the currently compared directory.
*/
private final JLabel comparisonCurrentDir;
/**
* The number of performed versus overall delete statements.
*/
private final JLabel deleteStmtsNo;
/**
* The relative path of the currently deleted file.
*/
private final JLabel deleteCurrentFile;
/**
* The number of performed versus overall copy statements.
*/
private final JLabel copyStmtsNo;
/**
* Bytes already transfered versus overall number of bytes.
*/
private final JLabel copyBytes;
/**
* The relative path of the currently copied file.
*/
private final JLabel copyCurrentFile;
/**
* Bytes transfered versus overall number of bytes for the current file.
*/
private final JLabel copyBytesCurrentFile;
/**
* Shows and hides synchronization details.
*/
private final JButton toggleDetailsButton;
/**
* Determines whether details should be shown.
*/
private boolean doShowDetails = false;
/**
* Initializes the progress view.
*
* @param mainView
* The main frame.
*/
public JFSProgressView(JFSMainView mainView) {
// Create the modal dialog:
super(mainView.getFrame(), true);
setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
this.mainView = mainView;
int width = 75*(int) (mainView.getFrame().getBounds().getWidth())/100;
// Get the translation object:
JFSText t = JFSText.getInstance();
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
// Create state panel:
JPanel statePanel = new JPanel(new BorderLayout());
statePanel.setBorder(new TitledBorder(t.get("progress.state")));
completionBar = new JProgressBar(JProgressBar.HORIZONTAL, 0, 100);
completionBar.setStringPainted(false);
statePanel.add(completionBar, BorderLayout.NORTH);
toggleDetailsButton = JFSSupport.getButton("progress.details.show", "TOGGLE_DETAILS", this);
statePanel.add(toggleDetailsButton, BorderLayout.EAST);
remainingTime = new JLabel();
statePanel.add(remainingTime, BorderLayout.WEST);
Dimension d = statePanel.getPreferredSize();
statePanel.setPreferredSize(new Dimension(width, d.height));
// Create comparison panel:
comparisonPanel = new JPanel(new GridLayout(1, 1));
comparisonPanel.setBorder(new TitledBorder(t.get("progress.details.title")));
JPanel comparisonRow1 = new JPanel();
BoxLayout comparisonBL1 = new BoxLayout(comparisonRow1, BoxLayout.X_AXIS);
comparisonRow1.setLayout(comparisonBL1);
comparisonPanel.add(comparisonRow1);
comparisonCurrentDir = new JLabel();
comparisonRow1.add(new JLabel(t.get("progress.details.current")+" "));
comparisonRow1.add(comparisonCurrentDir);
d = comparisonPanel.getPreferredSize();
comparisonPanel.setPreferredSize(new Dimension(width, d.height));
// Create delete panel:
deletePanel = new JPanel(new GridLayout(2, 1));
deletePanel.setBorder(new TitledBorder(t.get("progress.details.title")));
JPanel deleteRow1 = new JPanel();
BoxLayout deleteBL1 = new BoxLayout(deleteRow1, BoxLayout.X_AXIS);
deleteRow1.setLayout(deleteBL1);
deletePanel.add(deleteRow1);
deleteStmtsNo = new JLabel();
deleteRow1.add(new JLabel(t.get("progress.details.statementsNo")+" "));
deleteRow1.add(deleteStmtsNo);
JPanel deleteRow2 = new JPanel();
BoxLayout deleteBL2 = new BoxLayout(deleteRow2, BoxLayout.X_AXIS);
deleteRow2.setLayout(deleteBL2);
deletePanel.add(deleteRow2);
deleteCurrentFile = new JLabel();
deleteRow2.add(new JLabel(t.get("progress.details.current")+" "));
deleteRow2.add(deleteCurrentFile);
d = deletePanel.getPreferredSize();
deletePanel.setPreferredSize(new Dimension(width, d.height));
// Create copy panel:
copyPanel = new JPanel(new GridLayout(4, 1));
copyPanel.setBorder(new TitledBorder(t.get("progress.details.title")));
JPanel copyRow1 = new JPanel();
BoxLayout copyBL1 = new BoxLayout(copyRow1, BoxLayout.X_AXIS);
copyRow1.setLayout(copyBL1);
copyPanel.add(copyRow1);
copyStmtsNo = new JLabel();
copyRow1.add(new JLabel(t.get("progress.details.statementsNo")+" "));
copyRow1.add(copyStmtsNo);
JPanel copyRow2 = new JPanel();
BoxLayout copyBL2 = new BoxLayout(copyRow2, BoxLayout.X_AXIS);
copyRow2.setLayout(copyBL2);
copyPanel.add(copyRow2);
copyBytes = new JLabel();
copyRow2.add(new JLabel(t.get("progress.details.bytes")+" "));
copyRow2.add(copyBytes);
JPanel copyRow3 = new JPanel();
BoxLayout copyBL3 = new BoxLayout(copyRow3, BoxLayout.X_AXIS);
copyRow3.setLayout(copyBL3);
copyPanel.add(copyRow3);
copyCurrentFile = new JLabel();
copyRow3.add(new JLabel(t.get("progress.details.current")+" "));
copyRow3.add(copyCurrentFile);
JPanel copyRow4 = new JPanel();
BoxLayout copyBL4 = new BoxLayout(copyRow4, BoxLayout.X_AXIS);
copyRow4.setLayout(copyBL4);
copyPanel.add(copyRow4);
copyBytesCurrentFile = new JLabel();
copyRow4.add(new JLabel(t.get("progress.details.bytesCurrent")+" "));
copyRow4.add(copyBytesCurrentFile);
d = copyPanel.getPreferredSize();
copyPanel.setPreferredSize(new Dimension(width, d.height));
// Create panel containing all three details panels:
JPanel detailsPanel = new JPanel();
BoxLayout detailsBL = new BoxLayout(detailsPanel, BoxLayout.X_AXIS);
detailsPanel.setLayout(detailsBL);
detailsPanel.add(comparisonPanel);
detailsPanel.add(deletePanel);
detailsPanel.add(copyPanel);
// Create cancel button in a separate panel:
JPanel buttonPanel = new JPanel();
buttonPanel.add(JFSSupport.getButton("button.cancel", "button.cancel", this));
// Add all panels:
cp.add(statePanel, BorderLayout.NORTH);
cp.add(detailsPanel, BorderLayout.CENTER);
cp.add(buttonPanel, BorderLayout.SOUTH);
// Hide details and reset dialog:
// hideDetails();
pack();
reset();
}
/**
* Resets the dialog.
*/
public final void reset() {
synchronized (this) {
// Center the dialog before each computation to reflect changes of
// the main frame:
JFSSupport.center(mainView.getFrame(), this);
completionBar.setValue(0);
setTitle(JFSText.getInstance().get("progress.processing"));
}
}
/**
* Shows all details.
*/
private void showDetails() {
synchronized (this) {
JFSText t = JFSText.getInstance();
JFSProgress progress = JFSProgress.getInstance();
doShowDetails = true;
toggleDetailsButton.setText(t.get("progress.details.hide"));
ProgressActivity a = progress.getActivity();
if (a==ProgressActivity.COMPARISON) {
comparisonPanel.setVisible(true);
deletePanel.setVisible(false);
copyPanel.setVisible(false);
} else if (a==ProgressActivity.SYNCHRONIZATION_DELETE) {
comparisonPanel.setVisible(false);
deletePanel.setVisible(true);
copyPanel.setVisible(false);
} else if (a==ProgressActivity.SYNCHRONIZATION_COPY) {
comparisonPanel.setVisible(false);
deletePanel.setVisible(false);
copyPanel.setVisible(true);
}
}
}
/**
* Hides all details.
*/
private void hideDetails() {
synchronized (this) {
JFSText t = JFSText.getInstance();
doShowDetails = false;
toggleDetailsButton.setText(t.get("progress.details.show"));
comparisonPanel.setVisible(false);
deletePanel.setVisible(false);
copyPanel.setVisible(false);
}
}
/**
* Sets details about the current operation.
*/
public final void setDetails() {
if (!doShowDetails) {
return;
}
synchronized (this) {
JFSProgress progress = JFSProgress.getInstance();
ProgressActivity a = progress.getActivity();
if (a==ProgressActivity.COMPARISON&&comparisonPanel.isVisible()) {
JFSComparisonMonitor cm = JFSComparisonMonitor.getInstance();
if (cm.getCurrentDir()!=null) {
comparisonCurrentDir.setText(cm.getCurrentDir().getRelativePath());
}
} else if (a==ProgressActivity.SYNCHRONIZATION_DELETE&&deletePanel.isVisible()) {
JFSDeleteMonitor dm = JFSDeleteMonitor.getInstance();
deleteStmtsNo.setText(dm.getFilesDeleted()+"/"+dm.getFilesToDelete());
if (dm.getCurrentFile()!=null) {
deleteCurrentFile.setText(dm.getCurrentFile().getRelativePath());
}
} else if (a==ProgressActivity.SYNCHRONIZATION_COPY&©Panel.isVisible()) {
JFSCopyMonitor cm = JFSCopyMonitor.getInstance();
copyStmtsNo.setText(cm.getFilesCopied()+"/"+cm.getFilesToCopy());
copyBytes.setText(JFSFormatter.getLength(cm.getBytesTransfered())+"/"
+JFSFormatter.getLength(cm.getBytesToTransfer()));
if (cm.getCurrentFile()!=null) {
copyCurrentFile.setText(cm.getCurrentFile().getRelativePath());
copyBytesCurrentFile.setText(JFSFormatter.getLength(cm.getBytesTransferedCurrentFile())+"/"
+JFSFormatter.getLength(cm.getBytesToTransferCurrentFile()));
}
}
}
}
/**
* @see JFSProgressObserver#update(JFSProgress)
*/
@Override
public final void update(JFSProgress progress) {
synchronized (this) {
JFSText t = JFSText.getInstance();
ProgressActivity a = progress.getActivity();
ProgressState s = progress.getState();
remainingTime.setText(progress.getRemainingTime());
if (s==ProgressState.PREPARATION) {
reset();
setTitle(t.get(a.getName()));
if (doShowDetails) {
showDetails();
} else {
hideDetails();
}
pack();
JFSSupport.center(getParent(), this);
repaint();
mainView.updateComparisonTable();
} else if (s==ProgressState.DONE) {
completionBar.setValue(100);
repaint();
reset();
mainView.update();
} else if (s==ProgressState.ACTIVE) {
completionBar.setValue(progress.getCompletionRatio());
setDetails();
repaint();
mainView.updateComparisonTable();
}
}
}
/**
* @see ActionListener#actionPerformed(ActionEvent)
*/
@Override
public void actionPerformed(ActionEvent event) {
String cmd = event.getActionCommand();
if ("TOGGLE_DETAILS".equals(cmd)) {
if (doShowDetails) {
hideDetails();
} else {
showDetails();
}
pack();
JFSSupport.center(getParent(), this);
}
if ("button.cancel".equals(cmd)) {
JFSProgress.getInstance().cancel();
}
}
/**
* Performs the comparison as a separate thread.
*/
public final void compareInThread() {
final JDialog dialog = this;
// Create new thread:
final Thread thread = new Thread() {
@Override
public void run() {
// Wait for dialog to appear:
while (!dialog.isVisible()) {
}
// Compare:
JFSComparison.getInstance().compare();
// Hide dialog:
dialog.setVisible(false);
}
};
// Start thread:
thread.start();
// Make dialog window visible:
dialog.setVisible(true);
}
/**
* Performs the synchronization as a separate thread.
*/
public final void synchronizeInThread() {
final JDialog dialog = this;
// Create new thread:
final Thread thread = new Thread() {
@Override
public void run() {
// Wait for dialog to appear:
while (!dialog.isVisible()) {
}
// Synchronize:
JFSSynchronization.getInstance().synchronize();
// Hide dialog:
dialog.setVisible(false);
}
};
// Start thread:
thread.start();
// Make dialog window visible:
dialog.setVisible(true);
}
}