5e82f253c37e47cd535faea739d69f83c4940cd2
1 package be
.nikiroo
.fanfix
.output
;
4 import java
.io
.IOException
;
5 import java
.util
.ArrayList
;
8 import be
.nikiroo
.fanfix
.Instance
;
9 import be
.nikiroo
.fanfix
.bundles
.StringId
;
10 import be
.nikiroo
.fanfix
.data
.Chapter
;
11 import be
.nikiroo
.fanfix
.data
.Paragraph
;
12 import be
.nikiroo
.fanfix
.data
.Paragraph
.ParagraphType
;
13 import be
.nikiroo
.fanfix
.data
.Story
;
14 import be
.nikiroo
.utils
.Progress
;
17 * This class is the base class used by the other output classes. It can be used
18 * outside of this package, and have static method that you can use to get
19 * access to the correct support class.
23 public abstract class BasicOutput
{
25 * The supported output types for which we can get a {@link BasicOutput}
30 public enum OutputType
{
31 /** EPUB files created with this program */
33 /** Pure text file with some rules */
35 /** TEXT but with associated .info file */
37 /** DEBUG output to console */
39 /** ZIP with (PNG) images */
41 /** LaTeX file with "book" template */
43 /** HTML files in a dedicated directory */
48 public String
toString() {
49 return super.toString().toLowerCase();
53 * A description of this output type.
55 * @return the description
57 public String
getDesc() {
58 String desc
= Instance
.getTrans().getStringX(StringId
.OUTPUT_DESC
,
62 desc
= Instance
.getTrans()
63 .getString(StringId
.OUTPUT_DESC
, this);
70 * The default extension to add to the output files.
72 * @return the extension
74 public String
getDefaultExtension() {
75 BasicOutput output
= BasicOutput
.getOutput(this, false);
77 return output
.getDefaultExtension();
84 * Call {@link OutputType#valueOf(String.toUpperCase())}.
87 * the possible type name
89 * @return NULL or the type
91 public static OutputType
valueOfUC(String typeName
) {
92 return OutputType
.valueOf(typeName
== null ?
null : typeName
97 * Call {@link OutputType#valueOf(String.toUpperCase())} but return NULL
98 * for NULL and empty instead of raising an exception.
101 * the possible type name
103 * @return NULL or the type
105 public static OutputType
valueOfNullOkUC(String typeName
) {
106 if (typeName
== null || typeName
.isEmpty()) {
110 return OutputType
.valueOfUC(typeName
);
114 * Call {@link OutputType#valueOf(String.toUpperCase())} but return NULL
115 * in case of error instead of raising an exception.
118 * the possible type name
120 * @return NULL or the type
122 public static OutputType
valueOfAllOkUC(String typeName
) {
124 return OutputType
.valueOfUC(typeName
);
125 } catch (Exception e
) {
131 /** The creator name (this program, by me!) */
132 static final String EPUB_CREATOR
= "Fanfix (by Niki)";
134 /** The current best name for an image */
135 private String imageName
;
136 private File targetDir
;
137 private String targetName
;
138 private OutputType type
;
139 private boolean writeCover
;
140 private boolean writeInfo
;
141 private Progress storyPg
;
142 private Progress chapPg
;
145 * Process the {@link Story} into the given target.
148 * the {@link Story} to export
150 * the target where to save to (will not necessary be taken as is
151 * by the processor, for instance an extension can be added)
153 * the optional progress reporter
155 * @return the actual main target saved, which can be slightly different
158 * @throws IOException
159 * in case of I/O error
161 public File
process(Story story
, String target
, Progress pg
)
165 target
= new File(target
).getAbsolutePath();
166 File targetDir
= new File(target
).getParentFile();
167 String targetName
= new File(target
).getName();
169 String ext
= getDefaultExtension();
170 if (ext
!= null && !ext
.isEmpty()) {
171 if (targetName
.toLowerCase().endsWith(ext
)) {
172 targetName
= targetName
.substring(0,
173 targetName
.length() - ext
.length());
177 return process(story
, targetDir
, targetName
);
181 * Process the {@link Story} into the given target.
183 * This method is expected to be overridden in most cases.
186 * the {@link Story} to export
188 * the target dir where to save to
190 * the target filename (will not necessary be taken as is by the
191 * processor, for instance an extension can be added)
194 * @return the actual main target saved, which can be slightly different
197 * @throws IOException
198 * in case of I/O error
200 protected File
process(Story story
, File targetDir
, String targetName
)
202 this.targetDir
= targetDir
;
203 this.targetName
= targetName
;
215 public OutputType
getType() {
225 * TRUE to enable the creation of a .info file and a cover if
230 protected BasicOutput
setType(OutputType type
, boolean writeCover
,
233 this.writeCover
= writeCover
;
234 this.writeInfo
= writeInfo
;
240 * The default extension to add to the output files.
242 * @return the extension
244 public String
getDefaultExtension() {
248 protected void writeStoryHeader(Story story
) throws IOException
{
251 protected void writeChapterHeader(Chapter chap
) throws IOException
{
254 protected void writeParagraphHeader(Paragraph para
) throws IOException
{
257 protected void writeStoryFooter(Story story
) throws IOException
{
260 protected void writeChapterFooter(Chapter chap
) throws IOException
{
263 protected void writeParagraphFooter(Paragraph para
) throws IOException
{
266 protected void writeStory(Story story
) throws IOException
{
267 if (storyPg
== null) {
268 storyPg
= new Progress(0, story
.getChapters().size() + 2);
270 storyPg
.setMinMax(0, story
.getChapters().size() + 2);
273 String chapterNameNum
= String
.format("%03d", 0);
274 String paragraphNumber
= String
.format("%04d", 0);
275 imageName
= paragraphNumber
+ "_" + chapterNameNum
+ ".png";
277 if (story
.getMeta() != null) {
278 story
.getMeta().setType("" + getType());
282 InfoCover
.writeCover(targetDir
, targetName
, story
.getMeta());
285 InfoCover
.writeInfo(targetDir
, targetName
, story
.getMeta());
288 storyPg
.setProgress(1);
290 List
<Progress
> chapPgs
= new ArrayList
<Progress
>(story
.getChapters()
292 for (Chapter chap
: story
) {
293 chapPg
= new Progress(0, chap
.getParagraphs().size());
294 storyPg
.addProgress(chapPg
, 1);
299 writeStoryHeader(story
);
300 for (int i
= 0; i
< story
.getChapters().size(); i
++) {
301 chapPg
= chapPgs
.get(i
);
302 writeChapter(story
.getChapters().get(i
));
303 chapPg
.setProgress(chapPg
.getMax());
306 writeStoryFooter(story
);
308 storyPg
.setProgress(storyPg
.getMax());
312 protected void writeChapter(Chapter chap
) throws IOException
{
313 String chapterNameNum
;
314 if (chap
.getName() == null || chap
.getName().isEmpty()) {
315 chapterNameNum
= String
.format("%03d", chap
.getNumber());
317 chapterNameNum
= String
.format("%03d", chap
.getNumber()) + "_"
318 + chap
.getName().replace(" ", "_");
322 String paragraphNumber
= String
.format("%04d", num
++);
323 imageName
= chapterNameNum
+ "_" + paragraphNumber
+ ".png";
325 writeChapterHeader(chap
);
327 for (Paragraph para
: chap
) {
328 paragraphNumber
= String
.format("%04d", num
++);
329 imageName
= chapterNameNum
+ "_" + paragraphNumber
+ ".png";
330 writeParagraph(para
);
331 if (chapPg
!= null) {
332 chapPg
.setProgress(i
++);
335 writeChapterFooter(chap
);
338 protected void writeParagraph(Paragraph para
) throws IOException
{
339 writeParagraphHeader(para
);
340 writeTextLine(para
.getType(), para
.getContent());
341 writeParagraphFooter(para
);
344 protected void writeTextLine(ParagraphType type
, String line
)
349 * Return the current best guess for an image name, based upon the current
350 * {@link Chapter} and {@link Paragraph}.
353 * add the original target name as a prefix
355 * @return the guessed name
357 protected String
getCurrentImageBestName(boolean prefix
) {
359 return targetName
+ "_" + imageName
;
366 * Return the given word or sentence as <b>bold</b>.
371 * @return the bold output
373 protected String
enbold(String word
) {
378 * Return the given word or sentence as <i>italic</i>.
383 * @return the italic output
385 protected String
italize(String word
) {
390 * Decorate the given text with <b>bold</b> and <i>italic</i> words,
391 * according to {@link BasicOutput#enbold(String)} and
392 * {@link BasicOutput#italize(String)}.
397 * @return the decorated output
399 protected String
decorateText(String text
) {
400 StringBuilder builder
= new StringBuilder();
405 for (char car
: text
.toCharArray()) {
408 if (bold
>= 0 && prev
!= ' ') {
409 String data
= builder
.substring(bold
);
410 builder
.setLength(bold
);
411 builder
.append(enbold(data
));
414 && (prev
== ' ' || prev
== '\0' || prev
== '\n')) {
415 bold
= builder
.length();
422 if (italic
>= 0 && prev
!= ' ') {
423 String data
= builder
.substring(italic
);
424 builder
.setLength(italic
);
425 builder
.append(enbold(data
));
427 } else if (italic
< 0
428 && (prev
== ' ' || prev
== '\0' || prev
== '\n')) {
429 italic
= builder
.length();
444 builder
.insert(bold
, '*');
448 builder
.insert(italic
, '_');
451 return builder
.toString();
455 * Return a {@link BasicOutput} object compatible with the given
456 * {@link OutputType}.
461 * force the <tt>.info</tt> file and the cover to be saved next
462 * to the main target file
464 * @return the {@link BasicOutput}
466 public static BasicOutput
getOutput(OutputType type
, boolean infoCover
) {
470 return new Epub().setType(type
, infoCover
, infoCover
);
472 return new Text().setType(type
, true, infoCover
);
474 return new InfoText().setType(type
, true, true);
476 return new Sysout().setType(type
, false, false);
478 return new Cbz().setType(type
, infoCover
, infoCover
);
480 return new LaTeX().setType(type
, infoCover
, infoCover
);
482 return new Html().setType(type
, infoCover
, infoCover
);