diff --git a/src/main/java/forge/gui/DialogMigrateProfile.java b/src/main/java/forge/gui/DialogMigrateProfile.java index e76f062ef5d..85486de44d9 100644 --- a/src/main/java/forge/gui/DialogMigrateProfile.java +++ b/src/main/java/forge/gui/DialogMigrateProfile.java @@ -65,7 +65,7 @@ public class DialogMigrateProfile { 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")); p.setOpaque(false); p.setBackgroundTexture(FSkin.getIcon(FSkin.Backgrounds.BG_TEXTURE)); @@ -131,14 +131,17 @@ public class DialogMigrateProfile { final FButton btnCancel = new FButton("Cancel"); 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() { @Override public void run() { - if (null != onImportSuccessful) { - onImportSuccessful.run(); - } btnCancel.setText("Done"); } }; @@ -492,6 +495,8 @@ public class DialogMigrateProfile { // assumes all destination directories have been created int numOps = 0; + int numSucceeded = 0; + int numFailed = 0; for (Map.Entry op : _operations.entrySet()) { if (_cancel) { break; } @@ -519,13 +524,18 @@ public class DialogMigrateProfile { _operationLog.append(String.format("%s %s -> %s\n", _move ? "Moved" : "Copied", srcFile.getAbsolutePath(), destFile.getAbsolutePath())); + ++numSucceeded; } catch (IOException e) { _operationLog.append(String.format("Failed to %s %s -> %s (%s)\n", _move ? "move" : "copy", srcFile.getAbsolutePath(), destFile.getAbsolutePath(), e.getMessage())); + ++numFailed; } } + + _operationLog.append(String.format("\nImport complete. %d files %s, %d errors", + numSucceeded, _move ? "moved" : "copied", numFailed)); } catch (final Exception e) { _cancel = true; diff --git a/src/main/java/forge/properties/NewConstants.java b/src/main/java/forge/properties/NewConstants.java index 8ae8c35385b..b4a8f1f010b 100644 --- a/src/main/java/forge/properties/NewConstants.java +++ b/src/main/java/forge/properties/NewConstants.java @@ -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 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 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 private static final String _PICS_DIR = CACHE_DIR + "pics/"; @@ -97,6 +97,7 @@ public final class NewConstants { CACHE_DIR, CACHE_CARD_PICS_DIR, USER_PREFS_DIR, + GAUNTLET_DIR.userPrefLoc, DB_DIR, DECK_CONSTRUCTED_DIR, DECK_DRAFT_DIR, diff --git a/src/main/java/forge/view/FView.java b/src/main/java/forge/view/FView.java index 56e3e0ff505..0d2aeae7839 100644 --- a/src/main/java/forge/view/FView.java +++ b/src/main/java/forge/view/FView.java @@ -3,28 +3,39 @@ package forge.view; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; +import java.util.Deque; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.swing.JFrame; import javax.swing.JLayeredPane; import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; import javax.swing.WindowConstants; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import net.miginfocom.swing.MigLayout; +import org.apache.commons.lang3.StringUtils; + import com.google.common.collect.Lists; import forge.Singletons; import forge.control.FControl; import forge.gui.DialogMigrateProfile; +import forge.gui.SOverlayUtils; import forge.gui.deckeditor.VDeckEditorUI; import forge.gui.framework.DragCell; import forge.gui.framework.EDocID; @@ -32,6 +43,8 @@ import forge.gui.framework.SLayoutConstants; import forge.gui.home.VHomeUI; import forge.gui.match.TargetingOverlay; import forge.gui.match.VMatchUI; +import forge.gui.toolbox.FButton; +import forge.gui.toolbox.FLabel; import forge.gui.toolbox.FOverlay; import forge.gui.toolbox.FPanel; 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 // try to migrate it - Set profileDirs = new HashSet(); + final Set profileDirs = new HashSet(); for (String dname : NewConstants.PROFILE_DIRS) { profileDirs.add(new File(dname)); } + + final List resDirs = new ArrayList(); + 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 boolean hasData = false; - for (String resDir : Lists.newArrayList("decks", "gauntlet", "layouts", "pics", "pics_product", "preferences", "quest/data")) { - File f = new File("res", resDir); - if (f.exists() && !profileDirs.contains(f)) { - System.out.println("profile data found in obsolete location: " + f.getAbsolutePath()); + for (File resDir : resDirs) { + if (resDir.exists() && !profileDirs.contains(resDir)) { + // 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: " + resDir.getAbsolutePath()); hasData = true; - // cycle through all dirs instead of breaking immediately so each dir is printed to stdout } } if (hasData) { new DialogMigrateProfile("res", true, new Runnable() { @Override public void run() { - // TODO: reload appropriate data structures + // attempt to remove old directories and assemble a list of remaining files. + Deque stack = new LinkedList(resDirs); + Set seenDirs = new HashSet(); + List remainingFiles = new LinkedList(); + 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 - // TODO: telling them that there is some data remaining and it should be moved or deleted manually - // TODO: they will continue to be prompted for migration until the directories are gone + // if any files remain, show a dialog saying so and that they should be moved or + // deleted manually or the user will continue to be prompted for migration + 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("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!").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 } }); }