/*
* GenerateMobiDialog.java
*
* created: 4.11.2011
* charset: UTF-8
* license: MIT (X11) (See LICENSE file for full license)
*/
package cz.mp.k3bg.gui;
import cz.mp.k3bg.BookState;
import cz.mp.k3bg.Images;
import cz.mp.k3bg.core.BookFiles;
import cz.mp.k3bg.core.KindlegenRunner;
import cz.mp.k3bg.core.Metadata;
import cz.mp.k3bg.core.NcxGenerator;
import cz.mp.k3bg.core.OpfGenerator;
import cz.mp.k3bg.log.LoggerManager;
import cz.mp.util.GuiUtils;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingWorker;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import net.miginfocom.swing.MigLayout;
import static cz.mp.k3bg.TextSource.*;
import static cz.mp.k3bg.Application.*;
/**
* Dialog pro generování knihy ve formátu {@code mobi}.
* Zde se také generuje {@code OPF} a {@code NCX}.
* Soubory se generují na pozadí.
*
* @author Martin Pokorný
* @version 0.1
* @see KindlegenPanel
* @see KindlegenRunner
*/
public class GenerateMobiDialog extends GenerateDialog {
private static final boolean DEBUG = false;
private static final Logger logger =
LoggerManager.getLogger(GenerateMobiDialog.class, DEBUG);
private static GenerateMobiDialog instance = null;
private JLabel progressLabel = new JLabel(getLocText("gui.kindlegen.generate.progress"));
private DefaultStyledDocument progressDocument =
new DefaultStyledDocument();
private JTextPane progressTextPane =
new JTextPane(progressDocument);
private JScrollPane progressScrollTextPane =
new JScrollPane(progressTextPane);
private JProgressBar progressBar = new JProgressBar();
private JButton stopButton = new JButton(
getLocText("gui.kindlegen.generate.stop"),
Images.getImage(Images.STOP));
private JButton closeButton = new JButton(
getLocText("gui.close"),
Images.getImage(Images.CANCEL));
// pro styl v progressTextPane
private static final SimpleAttributeSet ATTRIB_TYPO_BOLD =
new SimpleAttributeSet();
private static final SimpleAttributeSet ATTRIB_TYPO =
new SimpleAttributeSet();
static {
StyleConstants.setBold(ATTRIB_TYPO_BOLD, true);
StyleConstants.setFontFamily(ATTRIB_TYPO_BOLD, "monospaced");
StyleConstants.setFontFamily(ATTRIB_TYPO, "monospaced");
}
private ProgressTextOutputStream progressOutputStream =
new ProgressTextOutputStream();
private GenerateTask generateTask;
// -----
/** */
public GenerateMobiDialog() {
super(MainFrame.getInstance());
this.bookFiles = null;
initComponents();
initLayout();
initEventHandlers();
initDialog();
}
/**
*
* @return
*/
private static GenerateMobiDialog getInstance() {
if (instance == null) {
logger.fine("new");
instance = new GenerateMobiDialog();
}
return instance;
}
/**
*
*/
public static void showDialog() {
getInstance();
instance.showThisDialog();
}
/**
*
*/
private void showThisDialog() {
logger.info("");
progressTextPane.setText("");
generate();
setVisible(true);
}
/**
*
*/
private void initDialog() {
setTitle(getLocText("gui.kindlegen.generate"));
pack();
setMinimumSize(new Dimension(400, getHeight() + 50));
setSize(MainFrame.getInstance().getWidth() - 60, MainFrame.getInstance().getHeight() - 150);
setLocationRelativeTo(MainFrame.getInstance());
}
/**
*
*/
private void initComponents() {
setProcessingState(false);
progressTextPane.setEditable(false);
GuiUtils.adjustBackground(progressTextPane);
progressBar.setIndeterminate(true);
progressScrollTextPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
progressScrollTextPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
}
/**
*
*/
private void initLayout() {
this.setLayout(new MigLayout("",
"unrel[fill,grow]unrel",
"unrel[]rel[fill,grow]para[bottom,nogrid]unrel"));
this.add(progressLabel, "wrap");
this.add(progressScrollTextPane, "wrap");
this.add(progressBar, "hidemode 3, w 100:pref:pref, split");
this.add(stopButton, "hidemode 3, tag cancel");
this.add(closeButton, "hidemode 3, tag cancel");
}
/**
*
*/
private void initEventHandlers() {
stopButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stopGeneration();
}
});
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
closeDialog();
}
});
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
closeDialog();
}
});
}
/**
*
*/
private void stopGeneration() {
if (BookState.getMainInstance() != null
&& BookState.getMainInstance().getKindlegenRunner() != null) {
BookState.getMainInstance().getKindlegenRunner().stop();
}
if (generateTask != null) {
generateTask.cancel(false);
}
setProcessingState(false);
}
/**
*
*/
@Override
protected void closeDialog() {
stopGeneration();
setVisible(false);
}
@Override
protected void generate() {
generateTask = new GenerateTask();
setProcessingState(true);
generateTask.execute();
}
/**
*
* @param processing
*/
private void setProcessingState(boolean processing) {
stopButton.setVisible(processing);
progressBar.setVisible(processing);
closeButton.setVisible(!processing);
}
/**
*
* @param text
*/
private void appendToProgressLog(String text) {
try {
AttributeSet attrib = ATTRIB_TYPO;
if (text.startsWith(">")
|| text.startsWith("$")
|| text.startsWith("#")
|| text.startsWith("/")
|| text.startsWith("\\")
// || text.toLowerCase().contains("v8")
|| text.toLowerCase().contains("error")
|| text.toLowerCase().contains("canceled")
|| text.toLowerCase().contains("successfully")
|| text.toLowerCase().contains("generated")
|| text.toLowerCase().contains("exception")) {
attrib = ATTRIB_TYPO_BOLD;
}
progressDocument.insertString(
progressDocument.getLength(), text, attrib);
progressTextPane.setCaretPosition(progressDocument.getLength());
} catch (BadLocationException ex) {
logger.warning(ex.getMessage());
if (DEBUG) { ex.printStackTrace(); }
Dialogs.showErrorDialog(ex);
}
}
// -------------------------------------------------------------------------
/**
* {@code OutputStream}, který zapisuje do {@linkplain progressTextPane}.
*
* @see #appendToProgressLog(java.lang.String)
*/
private class ProgressTextOutputStream extends OutputStream {
public ProgressTextOutputStream() {
super();
}
@Override
public void write(int b) throws IOException {
// super.write(b);
String line = new String(new char[]{ (char)b });
appendToProgressLog(line);
}
@Override
public void write(byte[] b) throws IOException {
// super.write(b);
String line = new String(b);
appendToProgressLog(line);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
// super.write(b, off, len);
String line = new String(b, off, len);
appendToProgressLog(line);
}
public void write(String line) throws IOException {
appendToProgressLog(line);
}
}
// -------------------------------------------------------------------------
/**
* Úloha prováděná na pozadí GUI, která generuje soubory {@code ncx},
* {@code opf} a soubor knihy {@code mobi}.
*
* @see BookState
* @see NcxGenerator
* @see OpfGenerator
* @see KindlegenRunner
*/
private class GenerateTask extends SwingWorker<Boolean, Integer> {
private Metadata metadata;
private BookFiles bookFiles;
private KindlegenRunner kindlegenRunner;
/**
*
*/
private void init() {
logger.fine("");
if (progressOutputStream == null) {
throw new IllegalStateException("progressOutputStream = null");
}
BookState bookState = BookState.getMainInstance();
if (bookState == null) {
throw new IllegalStateException("bookState = null");
}
metadata = bookState.getMetadata();
logger.fine("metadata = null ? " + (metadata == null));
if (metadata == null) {
throw new IllegalStateException("metadata = null");
}
bookFiles = bookState.getBookFiles();
logger.fine("bookFiles = null ? " + (bookFiles == null));
if (bookFiles == null) {
throw new IllegalStateException("bookFiles = null");
}
kindlegenRunner = bookState.getKindlegenRunner();
logger.fine("kindlegen = null ? " + (kindlegenRunner == null));
if (kindlegenRunner == null) {
throw new IllegalStateException("kindlegenRunner = null");
}
if (kindlegenRunner.getKindlegen() == null) {
throw new IllegalStateException("kindlegen = null");
}
logger.fine("kindlegen command = " +
kindlegenRunner.getKindlegen().getCommand());
}
/**
*
* @throws IOException
*/
private void generateNcx() throws IOException {
logger.info("# NCX");
progressOutputStream.write("# NCX" + EOL);
bookFiles.setDefaultNcx();
NcxGenerator ncxg = new NcxGenerator(bookFiles, metadata);
ncxg.generate();
}
/**
*
* @throws IOException
*/
private void generateOpf() throws IOException {
logger.info("# OPF");
progressOutputStream.write("# OPF" + EOL);
bookFiles.setDefaultOpf(metadata);
OpfGenerator opfg = new OpfGenerator(bookFiles, metadata);
opfg.generate();
}
/**
*
* @throws IOException
*/
private void generateMobi() throws IOException {
logger.info("# MOBI");
progressOutputStream.write("# MOBI" + EOL + EOL);
kindlegenRunner.setKindlegenCommandOutputStream(
progressOutputStream);
kindlegenRunner.setOpfFileNamePath(
bookFiles.getOpf().getAbsolutePath());
kindlegenRunner.setOutputFileName(
metadata.createStdBaseFileName()+".mobi");
kindlegenRunner.run();
}
@Override
protected Boolean doInBackground() throws Exception {
logger.fine("");
try {
init();
} catch (IllegalStateException ex) {
logger.warning(ex.getMessage());
if (DEBUG) { ex.printStackTrace(); }
Dialogs.showErrorDialog(ex);
return Boolean.FALSE;
}
try {
generateBaseStyle(this.bookFiles);
if(isCancelled()) {
return Boolean.FALSE;
}
generateNcx();
if(isCancelled()) {
return Boolean.FALSE;
}
progressOutputStream.write("OK" + EOL + EOL);
generateOpf();
if(isCancelled()) {
return Boolean.FALSE;
}
progressOutputStream.write("OK" + EOL + EOL);
// if (kindlegen == null) {
// return Boolean.FALSE;
// }
generateMobi();
if(isCancelled()) {
return Boolean.FALSE;
}
progressOutputStream.write("OK" + EOL);
return Boolean.TRUE;
} catch (IOException ex) {
logger.warning(ex.getMessage());
if (DEBUG) { ex.printStackTrace(); }
Dialogs.showErrorDialog(ex);
try {
progressOutputStream.write(EOL + ex + EOL);
} catch(IOException ex2) {
// nic
}
return Boolean.FALSE;
}
}
@Override
protected void done() {
try {
if (isCancelled()) {
logger.info("Canceled!");
progressOutputStream.write(EOL + "Canceled!" + EOL);
}
} catch (IOException ex) {
logger.warning(ex.getMessage());
if (DEBUG) { ex.printStackTrace(); }
Dialogs.showErrorDialog(ex);
}
setProcessingState(false);
}
}
} // GenerateMobiDialog.java