diff --git a/src/main/java/forge/gui/DialogMigrateProfile.java b/src/main/java/forge/gui/DialogMigrateProfile.java index 58630fd8d5d..e76f062ef5d 100644 --- a/src/main/java/forge/gui/DialogMigrateProfile.java +++ b/src/main/java/forge/gui/DialogMigrateProfile.java @@ -59,19 +59,19 @@ import forge.gui.toolbox.FTextField; import forge.properties.NewConstants; public class DialogMigrateProfile { - private final Runnable _onImportDone; + private final Runnable _onImportSuccessful; private final FButton _btnStart; private final JPanel _selectionPanel; private volatile boolean _cancel; - public DialogMigrateProfile(String srcDir, boolean showMigrationBlurb, final Runnable onImportDone) { + public DialogMigrateProfile(String srcDir, boolean showMigrationBlurb, final Runnable onImportSuccessful) { FPanel p = new FPanel(new MigLayout("insets dialog, gap 0, center, wrap")); p.setOpaque(false); p.setBackgroundTexture(FSkin.getIcon(FSkin.Backgrounds.BG_TEXTURE)); // header - p.add(new FLabel.Builder().text("Migrate profile data (in progress: not fully functional)").fontSize(15).build(), "center"); + p.add(new FLabel.Builder().text("Migrate profile data").fontSize(15).build(), "center"); if (showMigrationBlurb) { FPanel blurbPanel = new FPanel(new MigLayout("insets dialog, gap 10, center, wrap")); @@ -134,12 +134,12 @@ public class DialogMigrateProfile { @Override public void actionPerformed(ActionEvent e) { _cancel = true; cleanup.run(); } }); - _onImportDone = new Runnable() { + _onImportSuccessful = new Runnable() { @Override public void run() { - cleanup.run(); - if (null != onImportDone) { - onImportDone.run(); + if (null != onImportSuccessful) { + onImportSuccessful.run(); } + btnCancel.setText("Done"); } }; @@ -160,8 +160,10 @@ public class DialogMigrateProfile { @Override public void run() { btnCancel.requestFocusInWindow(); } }); - _AnalyzerUpdater analyzer = new _AnalyzerUpdater(srcDir); - analyzer.execute(); + if (!emptySrcDir) { + _AnalyzerUpdater analyzer = new _AnalyzerUpdater(srcDir); + analyzer.execute(); + } } private class _UnknownDeckChoice { @@ -192,9 +194,6 @@ public class DialogMigrateProfile { private final JTextArea _operationLog; private final JProgressBar _progressBar; - // used to ensure we only have one UI update pending at a time - private volatile boolean _uiUpdateAck; - public _AnalyzerUpdater(String srcDir) { _srcDir = srcDir; @@ -222,7 +221,7 @@ public class DialogMigrateProfile { _unknownDeckCombo.addItem(new _UnknownDeckChoice("Planar", NewConstants.DECK_PLANE_DIR)); _unknownDeckCombo.addItem(new _UnknownDeckChoice("Scheme", NewConstants.DECK_SCHEME_DIR)); _unknownDeckCombo.addItem(new _UnknownDeckChoice("Sealed", NewConstants.DECK_SEALED_DIR)); - unknownDeckPanel.add(new FLabel.Builder().text("Treat decks of unknown type as:").build()); + unknownDeckPanel.add(new FLabel.Builder().text("Treat unknown decks as:").build()); unknownDeckPanel.add(_unknownDeckCombo); knownDeckPanel.add(unknownDeckPanel, "span"); cbPanel.add(knownDeckPanel, "aligny top"); @@ -276,8 +275,7 @@ public class DialogMigrateProfile { // add progress bar _progressBar = new JProgressBar(); - _progressBar.setIndeterminate(true); - _progressBar.setString("Analyzing source directory..."); + _progressBar.setString("Preparing to analyze source directory..."); _progressBar.setStringPainted(true); _selectionPanel.add(_progressBar, "w 100%!"); @@ -297,6 +295,7 @@ public class DialogMigrateProfile { } // must be called from GUI event loop thread + // TODO: move string calculation to a background thread private void _updateUI() { // set operation summary StringBuilder log = new StringBuilder(); @@ -332,7 +331,6 @@ public class DialogMigrateProfile { log.append("verwriting existing files"); _operationLog.setText(log.toString()); - _uiUpdateAck = true; } private void _disableAll() { @@ -341,6 +339,7 @@ public class DialogMigrateProfile { } _unknownDeckCombo.setEnabled(false); _moveCheckbox.setEnabled(false); + _overwriteCheckbox.setEnabled(false); } @Override @@ -377,11 +376,6 @@ public class DialogMigrateProfile { // timers run in the gui event loop, so it's ok to interact with widgets _progressBar.setValue(msa.getNumFilesAnalyzed()); - - // only update if we don't already have an update pending. we may not be prompt in - // updating sometimes, but that's ok - if (!_uiUpdateAck) { return; } - _uiUpdateAck = false; _stateChangedListener.stateChanged(null); } }); @@ -492,39 +486,55 @@ public class DialogMigrateProfile { @Override protected Void doInBackground() throws Exception { - // working with textbox text is thread safe - _operationLog.setText(""); - - // assumes all destination directories have been created - int numOps = 0; - for (Map.Entry op : _operations.entrySet()) { - final int curOpNum = ++numOps; - SwingUtilities.invokeLater(new Runnable() { - @Override public void run() { _progressBar.setValue(curOpNum); } - }); + try { + // working with textbox text is thread safe + _operationLog.setText(""); - File srcFile = op.getKey(); - File destFile = op.getValue(); - - try { - if (_overwrite || !destFile.exists()) { - _copyFile(srcFile, destFile); - } + // assumes all destination directories have been created + int numOps = 0; + for (Map.Entry op : _operations.entrySet()) { + if (_cancel) { break; } - if (_move) { - srcFile.delete(); - } + final int curOpNum = ++numOps; + SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { + if (_cancel) { return; } + _progressBar.setValue(curOpNum); + } + }); - // working with textbox text is thread safe - _operationLog.append(String.format("%s %s -> %s\n", - _move ? "Moved" : "Copied", - srcFile.getAbsolutePath(), destFile.getAbsolutePath())); - } catch (IOException e) { - _operationLog.append(String.format("Failed to %s %s -> %s (%s)\n", - _move ? "move" : "copy", - srcFile.getAbsolutePath(), destFile.getAbsolutePath(), - e.getMessage())); + File srcFile = op.getKey(); + File destFile = op.getValue(); + + try { + if (_overwrite || !destFile.exists()) { + _copyFile(srcFile, destFile); + } + + if (_move) { + srcFile.delete(); + } + + // working with textbox text is thread safe + _operationLog.append(String.format("%s %s -> %s\n", + _move ? "Moved" : "Copied", + srcFile.getAbsolutePath(), destFile.getAbsolutePath())); + } catch (IOException e) { + _operationLog.append(String.format("Failed to %s %s -> %s (%s)\n", + _move ? "move" : "copy", + srcFile.getAbsolutePath(), destFile.getAbsolutePath(), + e.getMessage())); + } } + } catch (final Exception e) { + _cancel = true; + + SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { + _progressBar.setString("Error"); + BugReporter.reportException(e); + } + }); } return null; @@ -532,11 +542,15 @@ public class DialogMigrateProfile { @Override protected void done() { - _onImportDone.run(); + if (_cancel) { return; } + + _progressBar.setValue(_progressBar.getMaximum()); + _progressBar.setString("Import complete"); + _onImportSuccessful.run(); } private void _copyFile(File srcFile, File destFile) throws IOException { - if(!destFile.exists()) { + if (!destFile.exists()) { destFile.createNewFile(); } diff --git a/src/main/java/forge/gui/MigrationSourceAnalyzer.java b/src/main/java/forge/gui/MigrationSourceAnalyzer.java index 2f4c2986889..7f9564e821c 100644 --- a/src/main/java/forge/gui/MigrationSourceAnalyzer.java +++ b/src/main/java/forge/gui/MigrationSourceAnalyzer.java @@ -121,12 +121,52 @@ public class MigrationSourceAnalyzer { // private void _analyzeDecksDir(File root) { - System.out.println("analyzing decks directory: " + root); _analyzeDir(root, new _Analyzer() { @Override void onFile(File file) { + // we don't really expect any files in here, but if we find a .dck file, add it to the unknown list + String filename = file.getName(); + if (filename.endsWith(".dck")) { + File targetFile = new File(filename); + _cb.addOp(OpType.UNKNOWN_DECK, file, targetFile); + } } + @Override boolean onDir(File dir) { - return false; + String dirname = dir.getName(); + if ("constructed".equals(dirname)) { + _analyzeKnownDeckDir(dir, NewConstants.DECK_CONSTRUCTED_DIR, OpType.CONSTRUCTED_DECK); + } else if ("cube".equals(dirname)) { + return false; + } else if ("draft".equals(dirname)) { + _analyzeKnownDeckDir(dir, NewConstants.DECK_DRAFT_DIR, OpType.DRAFT_DECK); + } else if ("plane".equals(dirname) || "planar".equals(dirname)) { + _analyzeKnownDeckDir(dir, NewConstants.DECK_PLANE_DIR, OpType.PLANAR_DECK); + } else if ("scheme".equals(dirname)) { + _analyzeKnownDeckDir(dir, NewConstants.DECK_SCHEME_DIR, OpType.SCHEME_DECK); + } else if ("sealed".equals(dirname)) { + _analyzeKnownDeckDir(dir, NewConstants.DECK_SEALED_DIR, OpType.SEALED_DECK); + } else { + _analyzeKnownDeckDir(dir, null, OpType.UNKNOWN_DECK); + } + return true; + } + }); + } + + private void _analyzeKnownDeckDir(File root, final String targetDir, final OpType opType) { + _analyzeDir(root, new _Analyzer() { + @Override void onFile(File file) { + String filename = file.getName(); + if (filename.endsWith(".dck")) { + File targetFile = new File(targetDir, filename); + _cb.addOp(opType, file, targetFile); + } + } + + @Override boolean onDir(File dir) { + // if there's a dir beneath a known directory, assume the same kind of decks are in there + _analyzeKnownDeckDir(dir, targetDir, opType); + return true; } }); } @@ -136,13 +176,12 @@ public class MigrationSourceAnalyzer { // private void _analyzeGauntletDataDir(File root) { - System.out.println("analyzing gauntlet data directory: " + root); _analyzeDir(root, new _Analyzer() { @Override void onFile(File file) { // find *.dat files, but exclude LOCKED_* String filename = file.getName(); if (filename.endsWith(".dat") && !filename.startsWith("LOCKED_")) { - File targetFile = new File(NewConstants.GAUNTLET_DIR.userPrefLoc, file.getName()); + File targetFile = new File(NewConstants.GAUNTLET_DIR.userPrefLoc, filename); if (!file.equals(targetFile)) { _cb.addOp(OpType.GAUNTLET_DATA, file, targetFile); } @@ -156,7 +195,6 @@ public class MigrationSourceAnalyzer { // private void _analyzeLayoutsDir(File root) { - System.out.println("analyzing layouts directory: " + root); _analyzeDir(root, new _Analyzer() { @Override void onFile(File file) { // find *_preferred.xml files @@ -216,7 +254,6 @@ public class MigrationSourceAnalyzer { private Map _defaultPicOldNameToCurrentName; private void _analyzeCardPicsDir(File root) { if (null == _defaultPicNames) { - // build structures _defaultPicNames = new HashSet(); _defaultPicOldNameToCurrentName = new HashMap(); @@ -231,7 +268,6 @@ public class MigrationSourceAnalyzer { } } - System.out.println("analyzing default card pics directory: " + root); _analyzeListedDir(root, NewConstants.CACHE_CARD_PICS_DIR, new _ListedAnalyzer() { @Override public String map(String filename) { if (_defaultPicOldNameToCurrentName.containsKey(filename)) { @@ -282,7 +318,6 @@ public class MigrationSourceAnalyzer { } } - System.out.println("analyzing set card pics directory: " + root); EditionCollection editions = Singletons.getModel().getEditions(); String editionCode = root.getName(); CardEdition edition = editions.get(editionCode); @@ -319,8 +354,7 @@ public class MigrationSourceAnalyzer { _iconFileNames.add(nameurl.getLeft()); } } - - System.out.println("analyzing icon pics directory: " + root); + _analyzeListedDir(root, NewConstants.CACHE_ICON_PICS_DIR, new _ListedAnalyzer() { @Override public String map(String filename) { return _iconFileNames.contains(filename) ? filename : null; } @Override public OpType getOpType(String filename) { return OpType.QUEST_PIC; } @@ -341,7 +375,6 @@ public class MigrationSourceAnalyzer { } } - System.out.println("analyzing token pics directory: " + root); _analyzeListedDir(root, NewConstants.CACHE_TOKEN_PICS_DIR, new _ListedAnalyzer() { @Override public String map(String filename) { return (_questTokenFileNames.contains(filename) || _tokenFileNames.contains(filename)) ? filename : null; @@ -353,14 +386,17 @@ public class MigrationSourceAnalyzer { } private void _analyzeProductPicsDir(File root) { - System.out.println("analyzing product pics directory: " + root); - // we don't care about files in the root dir -- the new files are .png, not the current .jpg ones + // we don't care about the files in the root dir -- the new files are .png, not the current .jpg ones _analyzeDir(root, new _Analyzer() { @Override boolean onDir(File dir) { if ("booster".equals(dir.getName())) { + _analyzeSimpleListedDir(dir, NewConstants.IMAGE_LIST_QUEST_BOOSTERS_FILE, NewConstants.CACHE_BOOSTER_PICS_DIR, OpType.QUEST_PIC); } else if ("fatpacks".equals(dir.getName())) { + _analyzeSimpleListedDir(dir, NewConstants.IMAGE_LIST_QUEST_FATPACKS_FILE, NewConstants.CACHE_FATPACK_PICS_DIR, OpType.QUEST_PIC); } else if ("precons".equals(dir.getName())) { + _analyzeSimpleListedDir(dir, NewConstants.IMAGE_LIST_QUEST_PRECONS_FILE, NewConstants.CACHE_PRECON_PICS_DIR, OpType.QUEST_PIC); } else if ("tournamentpacks".equals(dir.getName())) { + _analyzeSimpleListedDir(dir, NewConstants.IMAGE_LIST_QUEST_TOURNAMENTPACKS_FILE, NewConstants.CACHE_TOURNAMENTPACK_PICS_DIR, OpType.QUEST_PIC); } else { return false; } @@ -374,7 +410,6 @@ public class MigrationSourceAnalyzer { // private void _analyzePreferencesDir(File root) { - System.out.println("analyzing preferences directory: " + root); _analyzeDir(root, new _Analyzer() { @Override void onFile(File file) { String filename = file.getName(); @@ -393,8 +428,16 @@ public class MigrationSourceAnalyzer { // private void _analyzeQuestDir(File root) { - System.out.println("analyzing quest directory: " + root); _analyzeDir(root, new _Analyzer() { + @Override void onFile(File file) { + if ("all-prices.txt".equals(file.getName())) { + File targetFile = new File(NewConstants.DB_DIR, file.getName()); + if (!file.equals(targetFile)) { + _cb.addOp(OpType.DB_FILE, file, targetFile); + } + } + } + @Override boolean onDir(File dir) { if ("data".equals(dir.getName())) { _analyzeQuestDataDir(dir); @@ -406,7 +449,6 @@ public class MigrationSourceAnalyzer { } private void _analyzeQuestDataDir(File root) { - System.out.println("analyzing quest data directory: " + root); _analyzeDir(root, new _Analyzer() { @Override void onFile(File file) { if (file.getName().endsWith(".dat")) { @@ -445,6 +487,23 @@ public class MigrationSourceAnalyzer { } } + private Map> _fileNameDb = new HashMap>(); + private void _analyzeSimpleListedDir(File root, String listFile, String targetDir, final OpType opType) { + if (!_fileNameDb.containsKey(listFile)) { + Set fileNames = new HashSet(); + for (Pair nameurl : FileUtil.readNameUrlFile(listFile)) { + fileNames.add(nameurl.getLeft()); + } + _fileNameDb.put(listFile, fileNames); + } + + final Set dbSet = _fileNameDb.get(listFile); + _analyzeListedDir(root, targetDir, new _ListedAnalyzer() { + @Override public String map(String filename) { return dbSet.contains(filename) ? filename : null; } + @Override public OpType getOpType(String filename) { return opType; } + }); + } + private abstract class _ListedAnalyzer { abstract String map(String filename); abstract OpType getOpType(String filename); diff --git a/src/main/java/forge/properties/NewConstants.java b/src/main/java/forge/properties/NewConstants.java index 0d1c6b2475b..8ae8c35385b 100644 --- a/src/main/java/forge/properties/NewConstants.java +++ b/src/main/java/forge/properties/NewConstants.java @@ -81,15 +81,15 @@ public final class NewConstants { 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 _DB_DIR = CACHE_DIR + "db/"; - private static final String _PICS_DIR = CACHE_DIR + "pics/"; + private static final String _PICS_DIR = CACHE_DIR + "pics/"; + public static final String DB_DIR = CACHE_DIR + "db/"; public static final String CACHE_TOKEN_PICS_DIR = _PICS_DIR + "tokens/"; public static final String CACHE_ICON_PICS_DIR = _PICS_DIR + "icons/"; public static final String CACHE_BOOSTER_PICS_DIR = _PICS_DIR + "boosters/"; public static final String CACHE_FATPACK_PICS_DIR = _PICS_DIR + "fatpacks/"; public static final String CACHE_PRECON_PICS_DIR = _PICS_DIR + "precons/"; public static final String CACHE_TOURNAMENTPACK_PICS_DIR = _PICS_DIR + "tournamentpacks/"; - public static final String QUEST_CARD_PRICE_FILE = _DB_DIR + "all-prices.txt"; + public static final String QUEST_CARD_PRICE_FILE = DB_DIR + "all-prices.txt"; public static final String CACHE_MORPH_IMAGE_FILE = "morph"; public static final String[] PROFILE_DIRS = { @@ -97,7 +97,7 @@ public final class NewConstants { CACHE_DIR, CACHE_CARD_PICS_DIR, USER_PREFS_DIR, - _DB_DIR, + DB_DIR, DECK_CONSTRUCTED_DIR, DECK_DRAFT_DIR, DECK_SEALED_DIR,