gui: change name, author
authorNiki Roo <niki@nikiroo.be>
Sun, 17 Mar 2019 18:05:07 +0000 (19:05 +0100)
committerNiki Roo <niki@nikiroo.be>
Sun, 17 Mar 2019 18:05:07 +0000 (19:05 +0100)
changelog-fr.md
changelog.md
src/be/nikiroo/fanfix/library/BasicLibrary.java
src/be/nikiroo/fanfix/library/CacheLibrary.java
src/be/nikiroo/fanfix/library/LocalLibrary.java
src/be/nikiroo/fanfix/library/RemoteLibrary.java
src/be/nikiroo/fanfix/library/RemoteLibraryServer.java
src/be/nikiroo/fanfix/reader/ui/GuiReader.java
src/be/nikiroo/fanfix/reader/ui/GuiReaderFrame.java

index 27f0348eb79782005f5e7040c9f2a15906ceca9c..cdc426f134b5841dec355e7754f9178a564c5466 100644 (file)
@@ -3,6 +3,7 @@
 # Version WIP
 
 - gui: new Properties page for stories
+- gui: rename stories, change author
 - tui: now working well enough to be considered stable
 - remote: fix setSourceCover (was not seen by client)
 - remote: can now import local files into a remote library
index b25774779c7920ef0dbc65fa8105703351d5efe2..954a1825cbcb09bb347dbf627e48b09e40a14d48 100644 (file)
@@ -3,6 +3,7 @@
 # Version WIP
 
 - gui: nouvelle page pour voir les propriétés d'une histoire
+- gui: renommer les histoires, changer l'auteur
 - tui: fonctionne maintenant assez bien que pour être déclaré stable
 - remote: fix de setSourceCover (ce n'était pas vu par le client)
 - remote: on peut maintenant importer un fichier local
index f6daed620f86347a5ec84a44ee3e8e80b600eb09..5898ac492c626a7fbc55da65072c3eaf0c202a3d 100644 (file)
@@ -158,8 +158,8 @@ abstract public class BasicLibrary {
         * Invalidate the {@link Story} cache (when the content should be re-read
         * because it was changed).
         */
-       protected void deleteInfo() {
-               deleteInfo(null);
+       protected void invalidateInfo() {
+               invalidateInfo(null);
        }
 
        /**
@@ -171,7 +171,7 @@ abstract public class BasicLibrary {
         *            the LUID of the {@link Story} to clear from the cache, or NULL
         *            for all stories
         */
-       protected abstract void deleteInfo(String luid);
+       protected abstract void invalidateInfo(String luid);
 
        /**
         * Invalidate the {@link Story} cache (when the content has changed, but we
@@ -705,7 +705,7 @@ abstract public class BasicLibrary {
                                this.getClass().getSimpleName() + ": deleting story " + luid);
 
                doDelete(luid);
-               deleteInfo(luid);
+               invalidateInfo(luid);
 
                Instance.getTraceHandler().trace(
                                this.getClass().getSimpleName() + ": story deleted (" + luid
@@ -732,7 +732,83 @@ abstract public class BasicLibrary {
                        throw new IOException("Story not found: " + luid);
                }
 
+               changeSTA(luid, newSource, meta.getTitle(), meta.getAuthor(), pg);
+       }
+
+       /**
+        * Change the title (name) of the given {@link Story}.
+        * 
+        * @param luid
+        *            the {@link Story} LUID
+        * @param newTitle
+        *            the new title
+        * @param pg
+        *            the optional progress reporter
+        * 
+        * @throws IOException
+        *             in case of I/O error or if the {@link Story} was not found
+        */
+       public synchronized void changeTitle(String luid, String newTitle,
+                       Progress pg) throws IOException {
+               MetaData meta = getInfo(luid);
+               if (meta == null) {
+                       throw new IOException("Story not found: " + luid);
+               }
+
+               changeSTA(luid, meta.getSource(), newTitle, meta.getAuthor(), pg);
+       }
+
+       /**
+        * Change the author of the given {@link Story}.
+        * 
+        * @param luid
+        *            the {@link Story} LUID
+        * @param newAuthor
+        *            the new author
+        * @param pg
+        *            the optional progress reporter
+        * 
+        * @throws IOException
+        *             in case of I/O error or if the {@link Story} was not found
+        */
+       public synchronized void changeAuthor(String luid, String newAuthor,
+                       Progress pg) throws IOException {
+               MetaData meta = getInfo(luid);
+               if (meta == null) {
+                       throw new IOException("Story not found: " + luid);
+               }
+
+               changeSTA(luid, meta.getSource(), meta.getTitle(), newAuthor, pg);
+       }
+
+       /**
+        * Change the Source, Title and Author of the {@link Story} in one single
+        * go.
+        * 
+        * @param luid
+        *            the {@link Story} LUID
+        * @param newSource
+        *            the new source
+        * @param newTitle
+        *            the new title
+        * @param newAuthor
+        *            the new author
+        * @param pg
+        *            the optional progress reporter
+        * 
+        * @throws IOException
+        *             in case of I/O error or if the {@link Story} was not found
+        */
+       protected synchronized void changeSTA(String luid, String newSource,
+                       String newTitle, String newAuthor, Progress pg) throws IOException {
+               MetaData meta = getInfo(luid);
+               if (meta == null) {
+                       throw new IOException("Story not found: " + luid);
+               }
+
                meta.setSource(newSource);
+               meta.setTitle(newTitle);
+               meta.setAuthor(newAuthor);
                saveMeta(meta, pg);
        }
 
@@ -743,7 +819,7 @@ abstract public class BasicLibrary {
         * By default, delete the old {@link Story} then recreate a new
         * {@link Story}.
         * <p>
-        * Note that this behaviour can lead to data loss.
+        * Note that this behaviour can lead to data loss in case of problems!
         * 
         * @param meta
         *            the new {@link MetaData} (LUID <b>MUST NOT</b> change)
@@ -769,8 +845,8 @@ abstract public class BasicLibrary {
                        throw new IOException("Story not found: " + meta.getLuid());
                }
 
+               // TODO: this is not safe!
                delete(meta.getLuid());
-
                story.setMeta(meta);
                save(story, meta.getLuid(), pgSet);
 
index a550740bafa7a9105d271ef9dd7df53515651d6e..918b763ff376b9a07075aceb41bff4023936f5e5 100644 (file)
@@ -159,7 +159,7 @@ public class CacheLibrary extends BasicLibrary {
        }
 
        @Override
-       protected void deleteInfo(String luid) {
+       protected void invalidateInfo(String luid) {
                if (luid == null) {
                        metas = null;
                } else if (metas != null) {
@@ -170,8 +170,8 @@ public class CacheLibrary extends BasicLibrary {
                        }
                }
 
-               cacheLib.deleteInfo(luid);
-               lib.deleteInfo(luid);
+               cacheLib.invalidateInfo(luid);
+               lib.invalidateInfo(luid);
        }
 
        @Override
@@ -210,8 +210,8 @@ public class CacheLibrary extends BasicLibrary {
        }
 
        @Override
-       public synchronized void changeSource(String luid, String newSource,
-                       Progress pg) throws IOException {
+       protected synchronized void changeSTA(String luid, String newSource,
+                       String newTitle, String newAuthor, Progress pg) throws IOException {
                if (pg == null) {
                        pg = new Progress();
                }
@@ -228,14 +228,16 @@ public class CacheLibrary extends BasicLibrary {
                }
 
                if (isCached(luid)) {
-                       cacheLib.changeSource(luid, newSource, pgCache);
+                       cacheLib.changeSTA(luid, newSource, newTitle, newAuthor, pgCache);
                }
                pgCache.done();
 
-               lib.changeSource(luid, newSource, pgOrig);
+               lib.changeSTA(luid, newSource, newTitle, newAuthor, pgOrig);
                pgOrig.done();
 
                meta.setSource(newSource);
+               meta.setTitle(newTitle);
+               meta.setAuthor(newAuthor);
                pg.done();
        }
 
index eafd18a6ecf642317c9e35c1e8e1c25aeea0ec5b..9ebff72c2151d7d6f6e7e0f6cf86fafc42911aed 100644 (file)
@@ -145,11 +145,11 @@ public class LocalLibrary extends BasicLibrary {
 
        @Override
        protected synchronized void updateInfo(MetaData meta) {
-               deleteInfo();
+               invalidateInfo();
        }
 
        @Override
-       protected void deleteInfo(String luid) {
+       protected void invalidateInfo(String luid) {
                stories = null;
                sourceCovers = null;
        }
@@ -199,8 +199,8 @@ public class LocalLibrary extends BasicLibrary {
                                try {
                                        String name = relatedFile.getName().replaceFirst(
                                                        "\\.info$", "");
-                                       InfoCover.writeInfo(newDir, name, meta);
                                        relatedFile.delete();
+                                       InfoCover.writeInfo(newDir, name, meta);
                                        relatedFile.getParentFile().delete();
                                } catch (IOException e) {
                                        Instance.getTraceHandler().error(e);
@@ -211,7 +211,7 @@ public class LocalLibrary extends BasicLibrary {
                        }
                }
 
-               deleteInfo();
+               invalidateInfo();
        }
 
        @Override
@@ -325,7 +325,7 @@ public class LocalLibrary extends BasicLibrary {
                                        pg.add(1);
                                }
 
-                               deleteInfo();
+                               invalidateInfo();
                                pg.done();
                                return;
                        }
@@ -466,7 +466,7 @@ public class LocalLibrary extends BasicLibrary {
         * {@link LocalLibrary#baseDir}.
         * <p>
         * Will use a cached list when possible (see
-        * {@link BasicLibrary#deleteInfo()}).
+        * {@link BasicLibrary#invalidateInfo()}).
         * 
         * @param pg
         *            the optional {@link Progress}
index 75f98be8bd62b18c9ab66801eb372ba6a0003389..c01275b62d5db57e95bf4b8542b64a09b09ea591 100644 (file)
@@ -348,8 +348,9 @@ public class RemoteLibrary extends BasicLibrary {
 
        @Override
        // Could work (more slowly) without it
-       public synchronized void changeSource(final String luid,
-                       final String newSource, Progress pg) throws IOException {
+       protected synchronized void changeSTA(final String luid,
+                       final String newSource, final String newTitle,
+                       final String newAuthor, Progress pg) throws IOException {
                final Progress pgF = pg == null ? new Progress() : pg;
 
                try {
@@ -358,8 +359,8 @@ public class RemoteLibrary extends BasicLibrary {
                                public void action(Version serverVersion) throws Exception {
                                        Progress pg = pgF;
 
-                                       Object rep = send(new Object[] { md5, "CHANGE_SOURCE",
-                                                       luid, newSource });
+                                       Object rep = send(new Object[] { md5, "CHANGE_STA", luid,
+                                                       newSource, newTitle, newAuthor });
                                        while (true) {
                                                if (!RemoteLibraryServer.updateProgress(pg, rep)) {
                                                        break;
@@ -427,7 +428,7 @@ public class RemoteLibrary extends BasicLibrary {
        }
 
        @Override
-       protected void deleteInfo(String luid) {
+       protected void invalidateInfo(String luid) {
                // Will be taken care of directly server side
        }
 
index 8d24c9f6d29c69cdea48ef0d41a6dfe1b654c500..aa5f3056a2536981850498c17fb5a6e560bd1f4f 100644 (file)
@@ -185,10 +185,10 @@ public class RemoteLibraryServer extends ServerObject {
                } else if ("SET_SOURCE_COVER".equals(command)) {
                        Instance.getLibrary().setSourceCover((String) args[0],
                                        (String) args[1]);
-               } else if ("CHANGE_SOURCE".equals(command)) {
+               } else if ("CHANGE_STA".equals(command)) {
                        Progress pg = createPgForwarder(action);
-                       Instance.getLibrary().changeSource((String) args[0],
-                                       (String) args[1], pg);
+                       Instance.getLibrary().changeSTA((String) args[0], (String) args[1],
+                                       (String) args[2], (String) args[3], pg);
                        forcePgDoneSent(pg);
                } else if ("EXIT".equals(command)) {
                        stop(0, false);
index 02f153cdf82d47dc8f2486f7e3a72cff94a75903..7dc373c7c54aad8037d4ebcf92a42cd30db31a2e 100644 (file)
@@ -292,4 +292,38 @@ class GuiReader extends BasicReader {
                        Instance.getTraceHandler().error(e);
                }
        }
+
+       /**
+        * Change the title of the given {@link Story}.
+        * 
+        * @param luid
+        *            the luid of the {@link Story} to change
+        * @param newTitle
+        *            the new title
+        */
+       void changeTitle(String luid, String newTitle) {
+               try {
+                       cacheLib.changeTitle(luid, newTitle, null);
+               } catch (IOException e) {
+                       Instance.getTraceHandler().error(e);
+               }
+       }
+
+       /**
+        * Change the author of the given {@link Story}.
+        * <p>
+        * The author can be a new one, it needs not exist before hand.
+        * 
+        * @param luid
+        *            the luid of the {@link Story} to change
+        * @param newAuthor
+        *            the new author
+        */
+       void changeAuthor(String luid, String newAuthor) {
+               try {
+                       cacheLib.changeAuthor(luid, newAuthor, null);
+               } catch (IOException e) {
+                       Instance.getTraceHandler().error(e);
+               }
+       }
 }
index d849a438388f139d2c236d9bc647c03b265c5c1c..f4c5eb3997cc97373788fe21c8bb2d1d3d52c061 100644 (file)
@@ -307,11 +307,14 @@ class GuiReaderFrame extends JFrame {
                                popup.add(createMenuItemOpenBook());
                                popup.addSeparator();
                                popup.add(createMenuItemExport());
-                               popup.add(createMenuItemMove(true));
+                               popup.add(createMenuItemMoveTo(true));
                                popup.add(createMenuItemSetCover());
                                popup.add(createMenuItemClearCache());
                                popup.add(createMenuItemRedownload());
                                popup.addSeparator();
+                               popup.add(createMenuItemRename(true));
+                               popup.add(createMenuItemSetAuthor(true));
+                               popup.addSeparator();
                                popup.add(createMenuItemDelete());
                                popup.addSeparator();
                                popup.add(createMenuItemProperties());
@@ -394,11 +397,14 @@ class GuiReaderFrame extends JFrame {
 
                file.add(createMenuItemOpenBook());
                file.add(createMenuItemExport());
-               file.add(createMenuItemMove(libOk));
+               file.add(createMenuItemMoveTo(libOk));
                file.addSeparator();
                file.add(imprt);
                file.add(imprtF);
                file.addSeparator();
+               file.add(createMenuItemRename(libOk));
+               file.add(createMenuItemSetAuthor(libOk));
+               file.addSeparator();
                file.add(exit);
 
                bar.add(file);
@@ -711,74 +717,155 @@ class GuiReaderFrame extends JFrame {
        }
 
        /**
-        * Create the delete menu item.
+        * Create the "move to" menu item.
         * 
         * @param libOk
         *            the library can be queried
         * 
         * @return the item
         */
-       private JMenuItem createMenuItemMove(boolean libOk) {
-               JMenu moveTo = new JMenu("Move to...");
-               moveTo.setMnemonic(KeyEvent.VK_M);
+       private JMenuItem createMenuItemMoveTo(boolean libOk) {
+               JMenuItem changeTo = new JMenu("Move to");
+               changeTo.setMnemonic(KeyEvent.VK_M);
 
-               List<String> types = new ArrayList<String>();
-               types.add(null);
+               List<String> values = new ArrayList<String>();
+               values.add(null);
                if (libOk) {
-                       types.addAll(reader.getLibrary().getSources());
+                       values.addAll(reader.getLibrary().getSources());
                }
 
-               for (String type : types) {
-                       JMenuItem item = new JMenuItem(type == null ? "New type..." : type);
+               for (String value : values) {
+                       JMenuItem item = new JMenuItem(value == null ? "New type..."
+                                       : value);
 
-                       moveTo.add(item);
-                       if (type == null) {
-                               moveTo.addSeparator();
-                       }
+                       item.addActionListener(createMoveAction("SOURCE", value));
 
-                       final String ftype = type;
-                       item.addActionListener(new ActionListener() {
-                               @Override
-                               public void actionPerformed(ActionEvent e) {
-                                       if (selectedBook != null) {
-                                               String type = ftype;
-                                               if (type == null) {
-                                                       Object rep = JOptionPane.showInputDialog(
-                                                                       GuiReaderFrame.this, "Move to:",
-                                                                       "Moving story",
-                                                                       JOptionPane.QUESTION_MESSAGE, null, null,
-                                                                       selectedBook.getMeta().getSource());
-
-                                                       if (rep == null) {
-                                                               return;
-                                                       }
+                       changeTo.add(item);
+                       if (value == null) {
+                               ((JMenu) changeTo).addSeparator();
+                       }
+               }
 
-                                                       type = rep.toString();
-                                               }
+               return changeTo;
+       }
 
-                                               final String ftype = type;
-                                               outOfUi(null, new Runnable() {
-                                                       @Override
-                                                       public void run() {
-                                                               reader.changeSource(selectedBook.getMeta()
-                                                                               .getLuid(), ftype);
+       /**
+        * Create the "set author" menu item.
+        * 
+        * @param libOk
+        *            the library can be queried
+        * 
+        * @return the item
+        */
+       private JMenuItem createMenuItemSetAuthor(boolean libOk) {
+               JMenu changeTo = new JMenu("Set author");
+               changeTo.setMnemonic(KeyEvent.VK_A);
 
-                                                               selectedBook = null;
+               // New author
+               JMenuItem newItem = new JMenuItem("New author...");
+               changeTo.add(newItem);
+               changeTo.addSeparator();
+               newItem.addActionListener(createMoveAction("AUTHOR", null));
 
-                                                               SwingUtilities.invokeLater(new Runnable() {
-                                                                       @Override
-                                                                       public void run() {
-                                                                               setJMenuBar(createMenu(true));
-                                                                       }
-                                                               });
-                                                       }
-                                               });
+               // Existing authors
+               if (libOk) {
+                       List<Entry<String, List<String>>> authorGroups = reader
+                                       .getLibrary().getAuthorsGrouped();
+
+                       if (authorGroups.size() > 1) {
+                               for (Entry<String, List<String>> entry : authorGroups) {
+                                       JMenu group = new JMenu(entry.getKey());
+                                       for (String value : entry.getValue()) {
+                                               JMenuItem item = new JMenuItem(value);
+                                               item.addActionListener(createMoveAction("AUTHOR", value));
+                                               group.add(item);
                                        }
+                                       changeTo.add(group);
                                }
-                       });
+                       } else if (authorGroups.size() == 1) {
+                               for (String value : authorGroups.get(0).getValue()) {
+                                       JMenuItem item = new JMenuItem(value);
+                                       item.addActionListener(createMoveAction("AUTHOR", value));
+                                       changeTo.add(item);
+                               }
+                       }
                }
 
-               return moveTo;
+               return changeTo;
+       }
+
+       /**
+        * Create the "rename" menu item.
+        * 
+        * @param libOk
+        *            the library can be queried
+        * 
+        * @return the item
+        */
+       private JMenuItem createMenuItemRename(
+                       @SuppressWarnings("unused") boolean libOk) {
+               JMenuItem changeTo = new JMenuItem("Rename...");
+               changeTo.setMnemonic(KeyEvent.VK_R);
+               changeTo.addActionListener(createMoveAction("TITLE", null));
+               return changeTo;
+       }
+
+       private ActionListener createMoveAction(final String what, final String type) {
+               return new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               if (selectedBook != null) {
+                                       String changeTo = type;
+                                       if (type == null) {
+                                               String init = "";
+                                               if (what.equals("SOURCE")) {
+                                                       init = selectedBook.getMeta().getSource();
+                                               } else if (what.equals("TITLE")) {
+                                                       init = selectedBook.getMeta().getTitle();
+                                               } else if (what.equals("AUTHOR")) {
+                                                       init = selectedBook.getMeta().getAuthor();
+                                               }
+
+                                               Object rep = JOptionPane.showInputDialog(
+                                                               GuiReaderFrame.this, "Move to:",
+                                                               "Moving story", JOptionPane.QUESTION_MESSAGE,
+                                                               null, null, init);
+
+                                               if (rep == null) {
+                                                       return;
+                                               }
+
+                                               changeTo = rep.toString();
+                                       }
+
+                                       final String fChangeTo = changeTo;
+                                       outOfUi(null, new Runnable() {
+                                               @Override
+                                               public void run() {
+                                                       if (what.equals("SOURCE")) {
+                                                               reader.changeSource(selectedBook.getMeta()
+                                                                               .getLuid(), fChangeTo);
+                                                       } else if (what.equals("TITLE")) {
+                                                               reader.changeTitle(selectedBook.getMeta()
+                                                                               .getLuid(), fChangeTo);
+                                                       } else if (what.equals("AUTHOR")) {
+                                                               reader.changeAuthor(selectedBook.getMeta()
+                                                                               .getLuid(), fChangeTo);
+                                                       }
+
+                                                       selectedBook = null;
+
+                                                       SwingUtilities.invokeLater(new Runnable() {
+                                                               @Override
+                                                               public void run() {
+                                                                       setJMenuBar(createMenu(true));
+                                                               }
+                                                       });
+                                               }
+                                       });
+                               }
+                       }
+               };
        }
 
        /**