X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Flibrary%2FBasicLibrary.java;h=7f7a09dd528d63ce0322150de77c1c4bf683c4a8;hb=51bf906d225bd14db66c9961e01c54cdaa500c54;hp=ee7ee8d48c225994343579efec3f2f381be9eabc;hpb=e5714913b0f4611e4d5a8dd8ed1b4d204ecc81ee;p=fanfix.git diff --git a/src/be/nikiroo/fanfix/library/BasicLibrary.java b/src/be/nikiroo/fanfix/library/BasicLibrary.java index ee7ee8d..7f7a09d 100644 --- a/src/be/nikiroo/fanfix/library/BasicLibrary.java +++ b/src/be/nikiroo/fanfix/library/BasicLibrary.java @@ -7,6 +7,8 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.TreeMap; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.data.MetaData; @@ -17,6 +19,7 @@ import be.nikiroo.fanfix.supported.BasicSupport; import be.nikiroo.fanfix.supported.SupportType; import be.nikiroo.utils.Image; import be.nikiroo.utils.Progress; +import be.nikiroo.utils.StringUtils; /** * Manage a library of Stories: import, export, list, modify. @@ -94,7 +97,8 @@ abstract public class BasicLibrary { /** * Return the cover image associated to this source. *
- * By default, return the cover of the first story with this source.
+ * By default, return the custom cover if any, and if not, return the cover
+ * of the first story with this source.
*
* @param source
* the source
@@ -102,6 +106,11 @@ abstract public class BasicLibrary {
* @return the cover image or NULL
*/
public Image getSourceCover(String source) {
+ Image custom = getCustomSourceCover(source);
+ if (custom != null) {
+ return custom;
+ }
+
List
+ * By default, return the custom cover if any, and if not, return the cover
+ * of the first story with this author.
+ *
+ * @param author
+ * the author
+ *
+ * @return the cover image or NULL
+ */
+ public Image getAuthorCover(String author) {
+ Image custom = getCustomAuthorCover(author);
+ if (custom != null) {
+ return custom;
+ }
+
+ List
+ * By default, return NULL.
+ *
+ * @param source
+ * the source to look for
+ *
+ * @return the custom cover or NULL if none
+ */
+ public Image getCustomSourceCover(@SuppressWarnings("unused") String source) {
+ return null;
+ }
+
+ /**
+ * Return the custom cover image associated to this author.
+ *
+ * By default, return NULL.
+ *
+ * @param author
+ * the author to look for
+ *
+ * @return the custom cover or NULL if none
+ */
+ public Image getCustomAuthorCover(@SuppressWarnings("unused") String author) {
+ return null;
+ }
+
+ /**
+ * Set the source cover to the given story cover.
*
* @param source
* the source to change
@@ -120,6 +182,16 @@ abstract public class BasicLibrary {
*/
public abstract void setSourceCover(String source, String luid);
+ /**
+ * Set the author cover to the given story cover.
+ *
+ * @param author
+ * the author to change
+ * @param luid
+ * the story LUID
+ */
+ public abstract void setAuthorCover(String author, String luid);
+
/**
* Return the list of stories (represented by their {@link MetaData}, which
* MAY not have the cover included).
@@ -135,8 +207,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);
}
/**
@@ -148,7 +220,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
@@ -223,6 +295,47 @@ abstract public class BasicLibrary {
return list;
}
+ /**
+ * List all the known types (sources) of stories, grouped by directory
+ * ("Source_1/a" and "Source_1/b" will be grouped into "Source_1").
+ *
+ * Note that an empty item in the list means a non-grouped source (type) --
+ * e.g., you could have for Source_1:
+ *
+ * If the number of author is not too high, only one group with an empty
+ * name and all the authors will be returned.
+ *
+ * If not, the authors will be separated into groups:
+ *
- * Cover images not included.
+ * Cover images MAYBE not included.
*
* @return the stories
*/
@@ -332,6 +565,43 @@ abstract public class BasicLibrary {
* @return the corresponding {@link Story} or NULL if not found
*/
public synchronized Story getStory(String luid, Progress pg) {
+ Progress pgMetas = new Progress();
+ Progress pgStory = new Progress();
+ if (pg != null) {
+ pg.setMinMax(0, 100);
+ pg.addProgress(pgMetas, 10);
+ pg.addProgress(pgStory, 90);
+ }
+
+ MetaData meta = null;
+ for (MetaData oneMeta : getMetas(pgMetas)) {
+ if (oneMeta.getLuid().equals(luid)) {
+ meta = oneMeta;
+ break;
+ }
+ }
+
+ pgMetas.done();
+
+ Story story = getStory(luid, meta, pgStory);
+ pgStory.done();
+
+ return story;
+ }
+
+ /**
+ * Retrieve a specific {@link Story}.
+ *
+ * @param luid
+ * the meta of the story
+ * @param pg
+ * the optional progress reporter
+ *
+ * @return the corresponding {@link Story} or NULL if not found
+ */
+ public synchronized Story getStory(String luid,
+ @SuppressWarnings("javadoc") MetaData meta, Progress pg) {
+
if (pg == null) {
pg = new Progress();
}
@@ -344,38 +614,33 @@ abstract public class BasicLibrary {
pg.addProgress(pgProcess, 1);
Story story = null;
- for (MetaData meta : getMetas(null)) {
- if (meta.getLuid().equals(luid)) {
- File file = getFile(luid, pgGet);
- pgGet.done();
- try {
- SupportType type = SupportType.valueOfAllOkUC(meta
- .getType());
- URL url = file.toURI().toURL();
- if (type != null) {
- story = BasicSupport.getSupport(type, url) //
- .process(pgProcess);
-
- // Because we do not want to clear the meta cache:
- meta.setCover(story.getMeta().getCover());
- story.setMeta(meta);
- //
- } else {
- throw new IOException("Unknown type: " + meta.getType());
- }
- } catch (IOException e) {
- // We should not have not-supported files in the
- // library
- Instance.getTraceHandler().error(
- new IOException("Cannot load file from library: "
- + file, e));
- } finally {
- pgProcess.done();
- pg.done();
- }
-
- break;
+ File file = getFile(luid, pgGet);
+ pgGet.done();
+ try {
+ SupportType type = SupportType.valueOfAllOkUC(meta.getType());
+ URL url = file.toURI().toURL();
+ if (type != null) {
+ story = BasicSupport.getSupport(type, url) //
+ .process(pgProcess);
+
+ // Because we do not want to clear the meta cache:
+ meta.setCover(story.getMeta().getCover());
+ meta.setResume(story.getMeta().getResume());
+ story.setMeta(meta);
+ //
+ } else {
+ throw new IOException("Unknown type: " + meta.getType());
}
+ } catch (IOException e) {
+ // We should not have not-supported files in the
+ // library
+ Instance.getTraceHandler().error(
+ new IOException(String.format(
+ "Cannot load file of type '%s' from library: %s",
+ meta.getType(), file), e));
+ } finally {
+ pgProcess.done();
+ pg.done();
}
return story;
@@ -398,12 +663,24 @@ abstract public class BasicLibrary {
* in case of I/O error
*/
public Story imprt(URL url, Progress pg) throws IOException {
+ if (pg == null)
+ pg = new Progress();
+
+ pg.setMinMax(0, 1000);
+ Progress pgProcess = new Progress();
+ Progress pgSave = new Progress();
+ pg.addProgress(pgProcess, 800);
+ pg.addProgress(pgSave, 200);
+
BasicSupport support = BasicSupport.getSupport(url);
if (support == null) {
throw new UnknownHostException("" + url);
}
- return save(support.process(pg), null);
+ Story story = save(support.process(pgProcess), pgSave);
+ pg.done();
+
+ return story;
}
/**
@@ -519,6 +796,9 @@ abstract public class BasicLibrary {
public synchronized Story save(Story story, String luid, Progress pg)
throws IOException {
+ Instance.getTraceHandler().trace(
+ this.getClass().getSimpleName() + ": saving story " + luid);
+
// Do not change the original metadata, but change the original story
MetaData meta = story.getMeta().clone();
story.setMeta(meta);
@@ -537,6 +817,10 @@ abstract public class BasicLibrary {
updateInfo(story.getMeta());
+ Instance.getTraceHandler().trace(
+ this.getClass().getSimpleName() + ": story saved (" + luid
+ + ")");
+
return story;
}
@@ -550,8 +834,15 @@ abstract public class BasicLibrary {
* in case of I/O error
*/
public synchronized void delete(String luid) throws IOException {
+ Instance.getTraceHandler().trace(
+ this.getClass().getSimpleName() + ": deleting story " + luid);
+
doDelete(luid);
- deleteInfo(luid);
+ invalidateInfo(luid);
+
+ Instance.getTraceHandler().trace(
+ this.getClass().getSimpleName() + ": story deleted (" + luid
+ + ")");
}
/**
@@ -574,8 +865,86 @@ 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);
+
+ invalidateInfo(luid);
}
/**
@@ -585,7 +954,7 @@ abstract public class BasicLibrary {
* By default, delete the old {@link Story} then recreate a new
* {@link Story}.
*
- * 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 MUST NOT change)
@@ -611,8 +980,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);
+ *
+ *
+ * @return the grouped list
+ */
+ public synchronized Map
+ *
+ * Note that the letters used in the groups can vary (except * and
+ * 0-9, which may only be present or not).
+ *
+ * @return the authors' names, grouped by letter(s)
+ */
+ public Map
+ *
+ *
+ * @param authors
+ * the full list of authors
+ * @param car
+ * the starting character, *, 0 or a capital
+ * letter
+ * @return the authors that fulfill the starting letter
+ */
+ private List