/*
* CharacterSheetPanel.java
* Copyright 2008 Connor Petty <cpmeister@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Created on Aug 19, 2008, 3:06:38 PM
*/
package pcgen.gui2.csheet;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadFactory;
import javax.swing.SwingUtilities;
import org.lobobrowser.html.HtmlRendererContext;
import org.lobobrowser.html.gui.HtmlPanel;
import org.lobobrowser.html.parser.DocumentBuilderImpl;
import org.lobobrowser.html.parser.InputSourceImpl;
import org.lobobrowser.html.test.SimpleHtmlRendererContext;
import org.lobobrowser.html.test.SimpleUserAgentContext;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import pcgen.core.Globals;
import pcgen.facade.core.CharacterFacade;
import pcgen.gui2.PCGenFrame;
import pcgen.gui2.PCGenStatusBar;
import pcgen.gui2.tools.CharacterSelectionListener;
import pcgen.io.ExportException;
import pcgen.io.ExportHandler;
import pcgen.system.ConfigurationSettings;
import pcgen.util.Logging;
/**
*
* @author Connor Petty <cpmeister@users.sourceforge.net>
*/
public class CharacterSheetPanel extends HtmlPanel implements CharacterSelectionListener
{
private enum CssColor
{
BLUE("preview_color_blue.css"),
LIGHTBLUE("preview_color_light_blue.css"),
GREEN("preview_color_green.css"),
LIGHTGREEN("preview_color_light_green.css"),
RED("preview_color_red.css"),
LIGHTRED("preview_color_light_red.css"),
YELLOW("preview_color_yellow.css"),
LIGHTYELLOW("preview_color_light_yellow.css"),
GREY("preview_color_grey.css"),
LIGHTGREY("preview_color_light_grey.css");
private final String cssfile;
CssColor(String cssfile) {
this.cssfile = cssfile;
}
public String getCssfile() {
return this.cssfile;
}
}
private final HtmlRendererContext theRendererContext;
private final DocumentBuilderImpl theDocBuilder;
private final CssColor cssColor = CssColor.BLUE;
private static final String COLOR_TAG = "preview_color.css";
private final ExecutorService refreshService;
private ExportHandler handler;
private CharacterFacade character;
private FutureTask<Document> refreshTask;
public CharacterSheetPanel()
{
theRendererContext = new SimpleHtmlRendererContext(this, new SimpleUserAgentContext());
theDocBuilder = new DocumentBuilderImpl(theRendererContext.getUserAgentContext(),
theRendererContext);
// KAW TODO rewrite to use StatusWorker and PCGenTask for better progress display
refreshService = Executors.newSingleThreadExecutor(new ThreadFactory()
{
@Override
public Thread newThread(Runnable r)
{
Thread thread = new Thread(r, "Character-Sheet-Refresher-Thread");
thread.setDaemon(true);
thread.setPriority(Thread.NORM_PRIORITY);
return thread;
}
});
}
@Override
public void setCharacter(CharacterFacade character)
{
this.character = character;
}
public void setCharacterSheet(File sheet)
{
handler = sheet == null ? null : new ExportHandler(sheet);
}
/**
*
*/
public void refresh()
{
if (handler == null || character == null)
{
return;
}
final PCGenStatusBar statusBar = ((PCGenFrame) Globals.getRootFrame()).getStatusBar();
// TODO externalize NLS strings
final String taskName = "Refreshing character...";
statusBar.startShowingProgress(taskName, true);
if (refreshTask != null && !refreshTask.isDone())
{
refreshTask.cancel(true);
}
refreshTask = new RefreshTask();
refreshService.execute(refreshTask);
}
/**
*
*/
// KAW TODO maybe rewrite to use PCGenTask instead?
private class RefreshTask extends FutureTask<Document>
{
public RefreshTask()
{
super(new DocumentConstructor());
}
@Override
protected void done()
{
if (!isCancelled())
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
Document doc = null;
try
{
doc = get();
}
catch (Throwable e)
{
final String errorMsg = String.format("<html><body>Unable to process sheet<br>%s</body></html>", e);
try (ByteArrayInputStream instream = new ByteArrayInputStream(errorMsg.getBytes())) {
doc = theDocBuilder.parse(instream);
} catch (IOException | SAXException e1) {
e1.printStackTrace();
}
Logging.errorPrint("Unable to process sheet: ", e);
}
if (doc != null)
{
setDocument(doc, theRendererContext);
}
// Re-set status bar and end progress bar display
final PCGenStatusBar statusBar = ((PCGenFrame) Globals.getRootFrame()).getStatusBar();
statusBar.endShowingProgress();
}
});
}
}
}
private class DocumentConstructor implements Callable<Document>
{
@Override
public Document call() throws URISyntaxException, IOException, ExportException, SAXException {
StringWriter out = new StringWriter();
BufferedWriter buf = new BufferedWriter(out);
character.export(handler, buf);
final String genText = out.toString().replace(COLOR_TAG, cssColor.getCssfile());
ByteArrayInputStream instream = new ByteArrayInputStream(genText.getBytes());
URI root = new URI("file", ConfigurationSettings.getPreviewDir().replaceAll("\\\\", "/"), null);
return theDocBuilder.parse(new InputSourceImpl(instream, root.toString(), "UTF-8"));
}
}
}