- don't move by default when import dialog is not in migration mode

- warn the user and allow them to correct the situation if they attempt an incomplete migration
This commit is contained in:
myk
2013-03-14 17:57:17 +00:00
parent 0d3f49aa94
commit db7eac9d82
2 changed files with 67 additions and 21 deletions

View File

@@ -25,8 +25,10 @@ import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
@@ -34,6 +36,7 @@ import java.util.concurrent.ConcurrentSkipListMap;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JProgressBar; import javax.swing.JProgressBar;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
@@ -71,10 +74,10 @@ import forge.properties.NewConstants;
* processing done in this class, so most operations are asynchronous. * processing done in this class, so most operations are asynchronous.
*/ */
public class DialogMigrateProfile { public class DialogMigrateProfile {
private final Runnable _onImportSuccessful; private final FButton _btnStart;
private final FButton _btnStart; private final FButton _btnCancel;
private final FLabel _btnChooseDir; private final FLabel _btnChooseDir;
private final JPanel _selectionPanel; private final JPanel _selectionPanel;
// volatile since it is checked from multiple threads // volatile since it is checked from multiple threads
private volatile boolean _cancel; private volatile boolean _cancel;
@@ -197,7 +200,7 @@ public class DialogMigrateProfile {
_cancel = false; _cancel = false;
synchronized (_onAnalyzerDone) { synchronized (_onAnalyzerDone) {
// this will populate the panel with data selection widgets // this will populate the panel with data selection widgets
_AnalyzerUpdater analyzer = new _AnalyzerUpdater(text, _onAnalyzerDone); _AnalyzerUpdater analyzer = new _AnalyzerUpdater(text, _onAnalyzerDone, isMigration);
analyzer.execute(); analyzer.execute();
_analyzerActive = true; _analyzerActive = true;
} }
@@ -225,8 +228,8 @@ public class DialogMigrateProfile {
}; };
_btnStart = new FButton("Start import"); _btnStart = new FButton("Start import");
_btnStart.setEnabled(false); _btnStart.setEnabled(false);
final FButton btnCancel = new FButton("Cancel"); _btnCancel = new FButton("Cancel");
btnCancel.addActionListener(new ActionListener() { _btnCancel.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) { @Override public void actionPerformed(ActionEvent e) {
_cancel = true; _cancel = true;
cleanup.run(); cleanup.run();
@@ -236,16 +239,10 @@ public class DialogMigrateProfile {
} }
}); });
_onImportSuccessful = new Runnable() {
@Override public void run() {
btnCancel.setText("Done");
}
};
JPanel southPanel = new JPanel(new MigLayout("ax center")); JPanel southPanel = new JPanel(new MigLayout("ax center"));
southPanel.setOpaque(false); southPanel.setOpaque(false);
southPanel.add(_btnStart, "center, w pref+144!, h pref+12!"); southPanel.add(_btnStart, "center, w pref+144!, h pref+12!");
southPanel.add(btnCancel, "center, w pref+144!, h pref+12!, gap 72"); southPanel.add(_btnCancel, "center, w pref+144!, h pref+12!, gap 72");
p.add(southPanel, "growx"); p.add(southPanel, "growx");
JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel(); JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel();
@@ -255,7 +252,7 @@ public class DialogMigrateProfile {
// focus cancel button after the dialog is shown // focus cancel button after the dialog is shown
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override public void run() { btnCancel.requestFocusInWindow(); } @Override public void run() { _btnCancel.requestFocusInWindow(); }
}); });
// if our source dir is provided, set the text, which will fire off an analyzer // if our source dir is provided, set the text, which will fire off an analyzer
@@ -294,6 +291,7 @@ public class DialogMigrateProfile {
private final String _srcDir; private final String _srcDir;
private final Runnable _onAnalyzerDone; private final Runnable _onAnalyzerDone;
private final boolean _isMigration;
private final JComboBox _unknownDeckCombo; private final JComboBox _unknownDeckCombo;
private final FCheckBox _moveCheckbox; private final FCheckBox _moveCheckbox;
private final FCheckBox _overwriteCheckbox; private final FCheckBox _overwriteCheckbox;
@@ -303,9 +301,10 @@ public class DialogMigrateProfile {
// updates the _operationLog widget asynchronously to keep the UI responsive // updates the _operationLog widget asynchronously to keep the UI responsive
private final _OperationLogAsyncUpdater _operationLogUpdater; private final _OperationLogAsyncUpdater _operationLogUpdater;
public _AnalyzerUpdater(String srcDir, Runnable onAnalyzerDone) { public _AnalyzerUpdater(String srcDir, Runnable onAnalyzerDone, boolean isMigration) {
_srcDir = srcDir; _srcDir = srcDir;
_onAnalyzerDone = onAnalyzerDone; _onAnalyzerDone = onAnalyzerDone;
_isMigration = isMigration;
_selectionPanel.removeAll(); _selectionPanel.removeAll();
_selectionPanel.setLayout(new MigLayout("insets 0, gap 5, wrap")); _selectionPanel.setLayout(new MigLayout("insets 0, gap 5, wrap"));
@@ -364,10 +363,10 @@ public class DialogMigrateProfile {
JPanel ioOptionPanel = new JPanel(new MigLayout("insets 0, gap 10")); JPanel ioOptionPanel = new JPanel(new MigLayout("insets 0, gap 10"));
ioOptionPanel.setOpaque(false); ioOptionPanel.setOpaque(false);
_moveCheckbox = new FCheckBox("Remove source files after copy"); _moveCheckbox = new FCheckBox("Remove source files after copy");
_moveCheckbox.setSelected(true); _moveCheckbox.setSelected(isMigration);
_moveCheckbox.addChangeListener(_stateChangedListener); _moveCheckbox.addChangeListener(_stateChangedListener);
ioOptionPanel.add(_moveCheckbox); ioOptionPanel.add(_moveCheckbox);
_overwriteCheckbox = new FCheckBox("Overwrite existing files"); _overwriteCheckbox = new FCheckBox("Overwrite files in destination");
_overwriteCheckbox.addChangeListener(_stateChangedListener); _overwriteCheckbox.addChangeListener(_stateChangedListener);
ioOptionPanel.add(_overwriteCheckbox); ioOptionPanel.add(_overwriteCheckbox);
_selectionPanel.add(ioOptionPanel); _selectionPanel.add(ioOptionPanel);
@@ -530,6 +529,50 @@ public class DialogMigrateProfile {
// set up the start button to start the prepared import on click // set up the start button to start the prepared import on click
_btnStart.addActionListener(new ActionListener() { _btnStart.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent arg0) { @Override public void actionPerformed(ActionEvent arg0) {
// if this is a migration, warn if active settings will not complete a migration and give the
// user an option to fix
if (_isMigration) {
// assemble a list of selections that need to be selected to complete a full migration
List<String> unselectedButShouldBe = new ArrayList<String>();
for (Pair<FCheckBox, ? extends Map<File, File>> entry : _selections.values()) {
// add name to list if checkbox is unselected, but contains operations
FCheckBox cb = entry.getLeft();
if (!cb.isSelected() && 0 < entry.getRight().size()) {
unselectedButShouldBe.add(cb.getName());
}
}
if (!unselectedButShouldBe.isEmpty() || !_moveCheckbox.isSelected()) {
StringBuilder sb = new StringBuilder("<html>");
if (!unselectedButShouldBe.isEmpty()) {
sb.append("It looks like the following options are not selected, which will result in an incomplete migration:");
sb.append("<ul>");
for (String cbName : unselectedButShouldBe) {
sb.append("<li><b>").append(cbName).append("</b></li>");
}
sb.append("</ul>");
}
if (!_moveCheckbox.isSelected()) {
sb.append(unselectedButShouldBe.isEmpty() ? "It " : "It also ").append("looks like the <b>");
sb.append(_moveCheckbox.getText()).append("</b> option is not selected.<br><br>");
}
sb.append("You can continue anyway, but the migration will be incomplete, and the data migration prompt<br>");
sb.append("will come up again the next time you start Forge in order to migrate the remaining files<br>");
sb.append("unless you move or delete them manually.</html>");
Object[] options = { "Whoops, let me fix that!", "Continue with the import, I know what I'm doing." };
int chosen = JOptionPane.showOptionDialog(_operationLog, sb.toString(), "Migration warning",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]);
if (1 != chosen) {
// i.e. option 0 was chosen or the dialog was otherwise closed
return;
}
}
}
// ensure no other actions (except for cancel) can be taken while the import is in progress // ensure no other actions (except for cancel) can be taken while the import is in progress
_btnStart.setEnabled(false); _btnStart.setEnabled(false);
_btnChooseDir.setEnabled(false); _btnChooseDir.setEnabled(false);
@@ -549,6 +592,8 @@ public class DialogMigrateProfile {
_selections, _unknownDeckCombo, _operationLog, _progressBar, _selections, _unknownDeckCombo, _operationLog, _progressBar,
_moveCheckbox.isSelected(), _overwriteCheckbox.isSelected()); _moveCheckbox.isSelected(), _overwriteCheckbox.isSelected());
importer.execute(); importer.execute();
_btnCancel.requestFocusInWindow();
} }
}); });
@@ -801,11 +846,12 @@ public class DialogMigrateProfile {
@Override @Override
protected void done() { protected void done() {
_btnCancel.requestFocusInWindow();
if (_cancel) { return; } if (_cancel) { return; }
_progressBar.setValue(_progressBar.getMaximum()); _progressBar.setValue(_progressBar.getMaximum());
_progressBar.setString("Import complete"); _progressBar.setString("Import complete");
_onImportSuccessful.run(); _btnCancel.setText("Done");
} }
// actual file copy routine. uses java.nio classes for ultra-fast copying // actual file copy routine. uses java.nio classes for ultra-fast copying

View File

@@ -217,8 +217,8 @@ public enum FView {
" Now just restart Forge to load the data from its new home!</html>").build()); " Now just restart Forge to load the data from its new home!</html>").build());
} else { } else {
p.add(new FLabel.Builder().text("<html>There seem to be a few files left over in your old data" + p.add(new FLabel.Builder().text("<html>There seem to be a few files left over in your old data" +
" directories. They should be deleted or moved somewhere else to avoid having this data" + " directories. They should be deleted or moved somewhere else to avoid having the data" +
" migration message pop up again! If there are any empty directories left over after that," + " migration prompt pop up again! If there are any empty directories left over after that," +
" just run through this migration procedure one more time and that should get them cleared" + " just run through this migration procedure one more time and that should get them cleared" +
" up.</html>").build()); " up.</html>").build());