Fix cover not deleted, add new UI option "Move to"
authorNiki Roo <niki@nikiroo.be>
Sun, 2 Apr 2017 16:05:38 +0000 (18:05 +0200)
committerNiki Roo <niki@nikiroo.be>
Sun, 2 Apr 2017 16:05:38 +0000 (18:05 +0200)
Library: fix the covers that were not always removed when deleting a story
UI: Sources are now editable ("Move to...")

changelog.md
libs/nikiroo-utils-1.4.2-sources.jar [moved from libs/nikiroo-utils-1.4.1-sources.jar with 91% similarity]
src/be/nikiroo/fanfix/Library.java
src/be/nikiroo/fanfix/output/InfoCover.java
src/be/nikiroo/fanfix/reader/LocalReader.java
src/be/nikiroo/fanfix/reader/LocalReaderFrame.java

index 458c2e536cdc2860beafbbb38d9d9441f9233c77..3a99d86e4db4583d14a74e162f7b67c3de3f4413 100644 (file)
@@ -2,7 +2,9 @@
 
 ## Version wip
 - Library: perf improvement when retrieving the stories (cover not loaded when not needed)
+- Library: fix the covers that were not always removed when deleting a story
 - UI: perf improvement when displaying books (cover resized then cached)
+- UI: Sources are now editable ("Move to...")
 
 ## Version 1.4.2
 
similarity index 91%
rename from libs/nikiroo-utils-1.4.1-sources.jar
rename to libs/nikiroo-utils-1.4.2-sources.jar
index 721f7931413d53bac2dd29f125d5f6708f6bc1b5..2a4f7d1f6a630b4f4bee29d4d135505b783e043b 100644 (file)
Binary files a/libs/nikiroo-utils-1.4.1-sources.jar and b/libs/nikiroo-utils-1.4.2-sources.jar differ
index 7819eff65d15e665a97b124ac412260e79821927..f1f7121385faeab1bae5ba686dbdcf2fce993ae5 100644 (file)
@@ -17,6 +17,7 @@ import be.nikiroo.fanfix.data.MetaData;
 import be.nikiroo.fanfix.data.Story;
 import be.nikiroo.fanfix.output.BasicOutput;
 import be.nikiroo.fanfix.output.BasicOutput.OutputType;
+import be.nikiroo.fanfix.output.InfoCover;
 import be.nikiroo.fanfix.supported.BasicSupport;
 import be.nikiroo.fanfix.supported.BasicSupport.SupportType;
 import be.nikiroo.fanfix.supported.InfoReader;
@@ -72,7 +73,7 @@ public class Library {
        }
 
        /**
-        * List all the known types of stories.
+        * List all the known types (sources) of stories.
         * 
         * @return the types
         */
@@ -143,6 +144,11 @@ public class Library {
         * @return the stories
         */
        public synchronized List<MetaData> getListByType(String type) {
+               if (type != null) {
+                       // convert the type to dir name
+                       type = getDir(type).getName();
+               }
+
                List<MetaData> list = new ArrayList<MetaData>();
                for (Entry<MetaData, File> entry : getStories(null).entrySet()) {
                        String storyType = entry.getValue().getParentFile().getName();
@@ -372,8 +378,8 @@ public class Library {
                        key.setLuid(luid);
                }
 
-               getDir(key).mkdirs();
-               if (!getDir(key).exists()) {
+               getDir(key.getSource()).mkdirs();
+               if (!getDir(key.getSource()).exists()) {
                        throw new IOException("Cannot create library dir");
                }
 
@@ -404,63 +410,137 @@ public class Library {
        public synchronized boolean delete(String luid) {
                boolean ok = false;
 
+               List<File> files = getFiles(luid);
+               if (!files.isEmpty()) {
+                       for (File file : files) {
+                               IOUtils.deltree(file);
+                       }
+
+                       ok = true;
+
+                       // clear cache
+                       stories.clear();
+               }
+
+               return ok;
+       }
+
+       /**
+        * Change the type (source) of the given {@link Story}.
+        * 
+        * @param luid
+        *            the {@link Story} LUID
+        * @param newSourcethe
+        *            new source
+        * 
+        * @return TRUE if the {@link Story} was found
+        */
+       public synchronized boolean changeType(String luid, String newType) {
+               MetaData meta = getInfo(luid);
+               if (meta != null) {
+                       meta.setSource(newType);
+                       File newDir = getDir(meta.getSource());
+                       if (!newDir.exists()) {
+                               newDir.mkdir();
+                       }
+
+                       List<File> files = getFiles(luid);
+                       for (File file : files) {
+                               if (file.getName().endsWith(".info")) {
+                                       try {
+                                               String name = file.getName().replaceFirst("\\.info$",
+                                                               "");
+                                               InfoCover.writeInfo(newDir, name, meta);
+                                               file.delete();
+                                       } catch (IOException e) {
+                                               Instance.syserr(e);
+                                       }
+                               } else {
+                                       file.renameTo(new File(newDir, file.getName()));
+                               }
+                       }
+
+                       // clear cache
+                       stories.clear();
+
+                       return true;
+               }
+
+               return false;
+       }
+
+       /**
+        * Return the list of files/dirs on disk for this {@link Story}.
+        * <p>
+        * If the {@link Story} is not found, and empty list is returned.
+        * 
+        * @param luid
+        *            the {@link Story} LUID
+        * 
+        * @return the list of {@link File}s
+        */
+       private List<File> getFiles(String luid) {
+               List<File> files = new ArrayList<File>();
+
                MetaData meta = getInfo(luid);
                File file = getStories(null).get(meta);
 
                if (file != null) {
-                       if (file.delete()) {
-                               String readerExt = getOutputType(meta)
-                                               .getDefaultExtension(true);
-                               String fileExt = getOutputType(meta).getDefaultExtension(false);
-
-                               String path = file.getAbsolutePath();
-                               if (readerExt != null && !readerExt.equals(fileExt)) {
-                                       path = path
-                                                       .substring(0, path.length() - readerExt.length())
-                                                       + fileExt;
-                                       file = new File(path);
-                                       IOUtils.deltree(file);
-                               }
+                       files.add(file);
 
-                               File infoFile = new File(path + ".info");
-                               if (!infoFile.exists()) {
-                                       infoFile = new File(path.substring(0, path.length()
-                                                       - fileExt.length())
-                                                       + ".info");
-                               }
-                               infoFile.delete();
-
-                               String coverExt = "."
-                                               + Instance.getConfig().getString(
-                                                               Config.IMAGE_FORMAT_COVER);
-                               File coverFile = new File(path + coverExt);
-                               if (!coverFile.exists()) {
-                                       coverFile = new File(path.substring(0, path.length()
-                                                       - fileExt.length()));
+                       String readerExt = getOutputType(meta).getDefaultExtension(true);
+                       String fileExt = getOutputType(meta).getDefaultExtension(false);
+
+                       String path = file.getAbsolutePath();
+                       if (readerExt != null && !readerExt.equals(fileExt)) {
+                               path = path.substring(0, path.length() - readerExt.length())
+                                               + fileExt;
+                               file = new File(path);
+
+                               if (file.exists()) {
+                                       files.add(file);
                                }
-                               coverFile.delete();
+                       }
 
-                               ok = true;
+                       File infoFile = new File(path + ".info");
+                       if (!infoFile.exists()) {
+                               infoFile = new File(path.substring(0,
+                                               path.length() - fileExt.length())
+                                               + ".info");
                        }
 
-                       // clear cache
-                       stories.clear();
+                       if (infoFile.exists()) {
+                               files.add(infoFile);
+                       }
+
+                       String coverExt = "."
+                                       + Instance.getConfig().getString(Config.IMAGE_FORMAT_COVER);
+                       File coverFile = new File(path + coverExt);
+                       if (!coverFile.exists()) {
+                               coverFile = new File(path.substring(0,
+                                               path.length() - fileExt.length())
+                                               + coverExt);
+                       }
+
+                       if (coverFile.exists()) {
+                               files.add(coverFile);
+                       }
                }
 
-               return ok;
+               return files;
        }
 
        /**
         * The directory (full path) where the {@link Story} related to this
         * {@link MetaData} should be located on disk.
         * 
-        * @param key
-        *            the {@link Story} {@link MetaData}
+        * @param type
+        *            the type (source)
         * 
         * @return the target directory
         */
-       private File getDir(MetaData key) {
-               String source = key.getSource().replaceAll("[^a-zA-Z0-9._+-]", "_");
+       private File getDir(String type) {
+               String source = type.replaceAll("[^a-zA-Z0-9._+-]", "_");
                return new File(baseDir, source);
        }
 
@@ -479,7 +559,7 @@ public class Library {
                        title = "";
                }
                title = title.replaceAll("[^a-zA-Z0-9._+-]", "_");
-               return new File(getDir(key), key.getLuid() + "_" + title);
+               return new File(getDir(key.getSource()), key.getLuid() + "_" + title);
        }
 
        /**
index 4be150c268843285d952c5672db8fc9c65615118..c7c80cc0a30f791540df9a675afcf1d8d8d204b5 100644 (file)
@@ -12,7 +12,7 @@ import be.nikiroo.fanfix.Instance;
 import be.nikiroo.fanfix.bundles.Config;
 import be.nikiroo.fanfix.data.MetaData;
 
-class InfoCover {
+public class InfoCover {
        public static void writeInfo(File targetDir, String targetName,
                        MetaData meta) throws IOException {
                File info = new File(targetDir, targetName + ".info");
index 29a840f3300d77c49ece90df927b23cc3d596a0f..a3fdcab7b67d90d9404f4b77f101a0fb2d4531df 100644 (file)
@@ -254,4 +254,9 @@ class LocalReader extends BasicReader {
 
                }
        }
+
+       void changeType(String luid, String newType) {
+               lib.changeType(luid, newType);
+               Instance.getLibrary().changeType(luid, newType);
+       }
 }
index bb77655b7734c48c05ecf6eb4458662bbcdeb1fd..03df7fbdf5cf133d86ac5d11634392e7edb61632 100644 (file)
@@ -13,6 +13,7 @@ import java.awt.event.WindowEvent;
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -142,7 +143,8 @@ class LocalReaderFrame extends JFrame {
         * the selected type or author.
         * 
         * @param value
-        *            the author or the type
+        *            the author or the type, or NULL to get all the
+        *            authors-or-types
         * @param type
         *            TRUE for type, FALSE for author
         */
@@ -188,6 +190,7 @@ class LocalReaderFrame extends JFrame {
                                popup.add(createMenuItemOpenBook());
                                popup.addSeparator();
                                popup.add(createMenuItemExport());
+                               popup.add(createMenuItemMove());
                                popup.add(createMenuItemClearCache());
                                popup.add(createMenuItemRedownload());
                                popup.addSeparator();
@@ -265,6 +268,7 @@ class LocalReaderFrame extends JFrame {
 
                file.add(createMenuItemOpenBook());
                file.add(createMenuItemExport());
+               file.add(createMenuItemMove());
                file.addSeparator();
                file.add(imprt);
                file.add(imprtF);
@@ -527,6 +531,68 @@ class LocalReaderFrame extends JFrame {
                return refresh;
        }
 
+       /**
+        * Create the delete menu item.
+        * 
+        * @return the item
+        */
+       private JMenuItem createMenuItemMove() {
+               JMenu moveTo = new JMenu("Move to...");
+               moveTo.setMnemonic(KeyEvent.VK_M);
+
+               List<String> types = new ArrayList<String>();
+               types.add(null);
+               types.addAll(Instance.getLibrary().getTypes());
+
+               for (String type : types) {
+                       JMenuItem item = new JMenuItem(type == null ? "New type..." : type);
+
+                       moveTo.add(item);
+                       if (type == null) {
+                               moveTo.addSeparator();
+                       }
+
+                       final String ftype = type;
+                       item.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       if (selectedBook != null) {
+                                               String type = ftype;
+                                               if (type == null) {
+                                                       Object rep = JOptionPane.showInputDialog(
+                                                                       LocalReaderFrame.this, "Move to:",
+                                                                       "Moving story",
+                                                                       JOptionPane.QUESTION_MESSAGE, null, null,
+                                                                       selectedBook.getMeta().getSource());
+                                                       if (rep == null) {
+                                                               return;
+                                                       } else {
+                                                               type = rep.toString();
+                                                       }
+                                               }
+
+                                               final String ftype = type;
+                                               outOfUi(null, new Runnable() {
+                                                       public void run() {
+                                                               reader.changeType(selectedBook.getMeta()
+                                                                               .getLuid(), ftype);
+
+                                                               selectedBook = null;
+
+                                                               SwingUtilities.invokeLater(new Runnable() {
+                                                                       public void run() {
+                                                                               setJMenuBar(createMenu());
+                                                                       }
+                                                               });
+                                                       }
+                                               });
+                                       }
+                               }
+                       });
+               }
+
+               return moveTo;
+       }
+
        /**
         * Create the redownload (then delete original) menu item.
         *