clean up empty directories after migration and prompt user about remaining files

This commit is contained in:
myk
2013-03-12 08:59:54 +00:00
parent ef5ee3329e
commit 460401e027
3 changed files with 107 additions and 16 deletions

View File

@@ -65,7 +65,7 @@ public class DialogMigrateProfile {
private volatile boolean _cancel; private volatile boolean _cancel;
public DialogMigrateProfile(String srcDir, boolean showMigrationBlurb, final Runnable onImportSuccessful) { public DialogMigrateProfile(String srcDir, boolean showMigrationBlurb, final Runnable onDialogClose) {
FPanel p = new FPanel(new MigLayout("insets dialog, gap 0, center, wrap")); FPanel p = new FPanel(new MigLayout("insets dialog, gap 0, center, wrap"));
p.setOpaque(false); p.setOpaque(false);
p.setBackgroundTexture(FSkin.getIcon(FSkin.Backgrounds.BG_TEXTURE)); p.setBackgroundTexture(FSkin.getIcon(FSkin.Backgrounds.BG_TEXTURE));
@@ -131,14 +131,17 @@ public class DialogMigrateProfile {
final FButton btnCancel = new FButton("Cancel"); final FButton btnCancel = new FButton("Cancel");
btnCancel.addActionListener(new ActionListener() { btnCancel.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) { _cancel = true; cleanup.run(); } @Override public void actionPerformed(ActionEvent e) {
_cancel = true;
cleanup.run();
if (null != onDialogClose) {
onDialogClose.run();
}
}
}); });
_onImportSuccessful = new Runnable() { _onImportSuccessful = new Runnable() {
@Override public void run() { @Override public void run() {
if (null != onImportSuccessful) {
onImportSuccessful.run();
}
btnCancel.setText("Done"); btnCancel.setText("Done");
} }
}; };
@@ -492,6 +495,8 @@ public class DialogMigrateProfile {
// assumes all destination directories have been created // assumes all destination directories have been created
int numOps = 0; int numOps = 0;
int numSucceeded = 0;
int numFailed = 0;
for (Map.Entry<File, File> op : _operations.entrySet()) { for (Map.Entry<File, File> op : _operations.entrySet()) {
if (_cancel) { break; } if (_cancel) { break; }
@@ -519,13 +524,18 @@ public class DialogMigrateProfile {
_operationLog.append(String.format("%s %s -> %s\n", _operationLog.append(String.format("%s %s -> %s\n",
_move ? "Moved" : "Copied", _move ? "Moved" : "Copied",
srcFile.getAbsolutePath(), destFile.getAbsolutePath())); srcFile.getAbsolutePath(), destFile.getAbsolutePath()));
++numSucceeded;
} catch (IOException e) { } catch (IOException e) {
_operationLog.append(String.format("Failed to %s %s -> %s (%s)\n", _operationLog.append(String.format("Failed to %s %s -> %s (%s)\n",
_move ? "move" : "copy", _move ? "move" : "copy",
srcFile.getAbsolutePath(), destFile.getAbsolutePath(), srcFile.getAbsolutePath(), destFile.getAbsolutePath(),
e.getMessage())); e.getMessage()));
++numFailed;
} }
} }
_operationLog.append(String.format("\nImport complete. %d files %s, %d errors",
numSucceeded, _move ? "moved" : "copied", numFailed));
} catch (final Exception e) { } catch (final Exception e) {
_cancel = true; _cancel = true;

View File

@@ -78,7 +78,7 @@ public final class NewConstants {
public static final FileLocation HOME_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "home.xml"); public static final FileLocation HOME_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "home.xml");
public static final FileLocation MATCH_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "match.xml"); public static final FileLocation MATCH_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "match.xml");
public static final FileLocation EDITOR_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "editor.xml"); public static final FileLocation EDITOR_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "editor.xml");
public static final FileLocation GAUNTLET_DIR = new FileLocation(_DEFAULTS_DIR, USER_DIR, "gauntlet/"); public static final FileLocation GAUNTLET_DIR = new FileLocation(_DEFAULTS_DIR, USER_DIR, "gauntlet/");
// data that is only in the cached dir // data that is only in the cached dir
private static final String _PICS_DIR = CACHE_DIR + "pics/"; private static final String _PICS_DIR = CACHE_DIR + "pics/";
@@ -97,6 +97,7 @@ public final class NewConstants {
CACHE_DIR, CACHE_DIR,
CACHE_CARD_PICS_DIR, CACHE_CARD_PICS_DIR,
USER_PREFS_DIR, USER_PREFS_DIR,
GAUNTLET_DIR.userPrefLoc,
DB_DIR, DB_DIR,
DECK_CONSTRUCTED_DIR, DECK_CONSTRUCTED_DIR,
DECK_DRAFT_DIR, DECK_DRAFT_DIR,

View File

@@ -3,28 +3,39 @@ package forge.view;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame; import java.awt.Frame;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Deque;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JLayeredPane; import javax.swing.JLayeredPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants; import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder; import javax.swing.border.LineBorder;
import net.miginfocom.swing.MigLayout; import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.Singletons; import forge.Singletons;
import forge.control.FControl; import forge.control.FControl;
import forge.gui.DialogMigrateProfile; import forge.gui.DialogMigrateProfile;
import forge.gui.SOverlayUtils;
import forge.gui.deckeditor.VDeckEditorUI; import forge.gui.deckeditor.VDeckEditorUI;
import forge.gui.framework.DragCell; import forge.gui.framework.DragCell;
import forge.gui.framework.EDocID; import forge.gui.framework.EDocID;
@@ -32,6 +43,8 @@ import forge.gui.framework.SLayoutConstants;
import forge.gui.home.VHomeUI; import forge.gui.home.VHomeUI;
import forge.gui.match.TargetingOverlay; import forge.gui.match.TargetingOverlay;
import forge.gui.match.VMatchUI; import forge.gui.match.VMatchUI;
import forge.gui.toolbox.FButton;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FOverlay; import forge.gui.toolbox.FOverlay;
import forge.gui.toolbox.FPanel; import forge.gui.toolbox.FPanel;
import forge.gui.toolbox.FSkin; import forge.gui.toolbox.FSkin;
@@ -128,30 +141,97 @@ public enum FView {
{ {
// get profile directories -- if one of them is actually under the res directory, don't // get profile directories -- if one of them is actually under the res directory, don't
// try to migrate it // try to migrate it
Set<File> profileDirs = new HashSet<File>(); final Set<File> profileDirs = new HashSet<File>();
for (String dname : NewConstants.PROFILE_DIRS) { for (String dname : NewConstants.PROFILE_DIRS) {
profileDirs.add(new File(dname)); profileDirs.add(new File(dname));
} }
final List<File> resDirs = new ArrayList<File>();
for (String resDir : Lists.newArrayList("decks", "gauntlet", "layouts", "pics", "pics_product", "preferences", "quest/data")) {
resDirs.add(new File("res", resDir));
}
// check quickly whether we have any data to migrate // check quickly whether we have any data to migrate
boolean hasData = false; boolean hasData = false;
for (String resDir : Lists.newArrayList("decks", "gauntlet", "layouts", "pics", "pics_product", "preferences", "quest/data")) { for (File resDir : resDirs) {
File f = new File("res", resDir); if (resDir.exists() && !profileDirs.contains(resDir)) {
if (f.exists() && !profileDirs.contains(f)) { // cycle through all dirs instead of breaking after the first found so each dir is printed to stdout
System.out.println("profile data found in obsolete location: " + f.getAbsolutePath()); System.out.println("profile data found in obsolete location: " + resDir.getAbsolutePath());
hasData = true; hasData = true;
// cycle through all dirs instead of breaking immediately so each dir is printed to stdout
} }
} }
if (hasData) { if (hasData) {
new DialogMigrateProfile("res", true, new Runnable() { new DialogMigrateProfile("res", true, new Runnable() {
@Override public void run() { @Override public void run() {
// TODO: reload appropriate data structures // attempt to remove old directories and assemble a list of remaining files.
Deque<File> stack = new LinkedList<File>(resDirs);
Set<File> seenDirs = new HashSet<File>();
List<File> remainingFiles = new LinkedList<File>();
while (!stack.isEmpty()) {
File cur = stack.peek();
if (profileDirs.contains(cur)) {
// don't touch active profile dirs
stack.pop();
continue;
}
if (seenDirs.contains(cur)) {
boolean succeeded = stack.pop().delete();
System.out.println(String.format("attempting to remove old profile dir: %s (%s)",
cur, succeeded ? "succeeded" : "failed"));
continue;
}
seenDirs.add(cur);
File[] curListing = cur.listFiles();
if (null == curListing) {
continue;
}
for (File f : curListing) {
if (f.isDirectory()) {
stack.push(f);
} else {
remainingFiles.add(f);
}
}
}
// TODO: attempt to remove old directories. if they are not empty, show a dialog // if any files remain, show a dialog saying so and that they should be moved or
// TODO: telling them that there is some data remaining and it should be moved or deleted manually // deleted manually or the user will continue to be prompted for migration
// TODO: they will continue to be prompted for migration until the directories are gone FPanel p = new FPanel(new MigLayout("insets dialog, gap 10, center, wrap"));
p.setOpaque(false);
p.setBackgroundTexture(FSkin.getIcon(FSkin.Backgrounds.BG_TEXTURE));
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" +
" migration message pop up again!</html>").build());
JTextArea files = new JTextArea(StringUtils.join(remainingFiles, '\n'));
files.setFont(new Font("Monospaced", Font.PLAIN, 10));
files.setOpaque(false);
files.setWrapStyleWord(true);
files.setLineWrap(true);
files.setEditable(false);
JScrollPane scroller = new JScrollPane(files);
p.add(scroller, "w 600:100%:100%, h 60:100%:100%");
final FButton btnOk = new FButton("OK");
btnOk.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) { SOverlayUtils.hideOverlay(); }
});
p.add(btnOk, "center, w 40%, h pref+12!");
JPanel overlay = FOverlay.SINGLETON_INSTANCE.getPanel();
overlay.setLayout(new MigLayout("insets 0, gap 0, wrap, ax center, ay center"));
overlay.add(p, "w 800::80%, h 500::90%");
SOverlayUtils.showOverlay();
SwingUtilities.invokeLater(new Runnable() {
@Override public void run() { btnOk.requestFocusInWindow(); }
});
// TODO: reload appropriate data structures
} }
}); });
} }