/*
* Copyright 2011 Christian Thiemann <christian@spato.net>
* Developed at Northwestern University <http://rocs.northwestern.edu>
*
* This file is part of the SPaTo Visual Explorer (SPaTo).
*
* SPaTo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SPaTo 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SPaTo. If not, see <http://www.gnu.org/licenses/>.
*/
package net.spato.sve.app;
import java.awt.event.ActionEvent;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import net.spato.sve.app.util.*;
import processing.core.PApplet;
import processing.core.PGraphics;
import de.cthiemann.tGUI.*;
public class Screenshot {
protected SPaTo_Visual_Explorer app = null;
protected SPaToView view = null;
protected String basename = null;
protected static SettingsWindow sw = null; // make sure that only one settings window is visible at a time
public Screenshot(SPaTo_Visual_Explorer app) {
this.app = app;
this.view = app.doc.view;
}
public void save() {
SPaToView.fastNodes = false; // always draw circles in screenshots
if (getSavePDF()) savePDF();
if (getSavePNG()) savePNG();
if (getSaveLayout()) saveLayout();
}
public void showSettingsWindow() {
if (sw == null)
sw = new SettingsWindow();
sw.requestFocus();
}
protected String getBasename() {
if (basename == null) {
basename = "SPaTo_screenshot_" + (new SimpleDateFormat("yyyyMMdd'T'HHmmss").format(new Date()));
basename = getOutputDirectory().getAbsolutePath() + File.separator + basename;
}
return basename;
}
protected void savePDF() {
app.console.logNote("Recording screenshot to " + getBasename() + ".pdf");
PGraphics g = app.createGraphics(getWidth(), getHeight(), PGraphics.PDF, getBasename() + ".pdf");
g.hint(PGraphics.ENABLE_NATIVE_FONTS);
g.beginDraw(); g.textMode(PGraphics.SHAPE); view.draw(g, false); g.endDraw();
g.dispose();
}
protected void savePNG() {
PGraphics g = app.createGraphics(getWidth(), getHeight(), PGraphics.JAVA2D);
g.beginDraw(); g.smooth(); view.draw(g, false); g.endDraw();
g.save(getBasename() + ".png");
g.dispose();
app.console.logNote("Saved screenshot to " + getBasename() + ".png");
}
protected void saveLayout() {
if (!getSavePDF() && !getSavePNG()) {
// make sure node positions are correct -- FIXME: break up SPaToView.draw() into smaller functions
PGraphics g = app.createGraphics(getWidth(), getHeight(), PGraphics.JAVA2D);
g.beginDraw(); view.draw(g, false); g.endDraw();
g.dispose();
}
view.writeLayout(getBasename() + "_layout.txt");
app.console.logNote("Node layout written to " + getBasename() + "_layout.txt");
}
public File getOutputDirectory() {
File dir = new File(System.getProperty("user.home")); // default: save in user's home directory...
if (new File(dir, "Desktop").exists()) dir = new File(dir, "Desktop"); // ... or better yet: on their desktop
return new File(app.prefs.get("screenshot.directory", dir.getAbsolutePath())); // or whatever they chose
}
public void setOutputDirectory(File f) { app.prefs.put("screenshot.directory", f.getAbsolutePath()); }
public boolean getSavePDF() { return app.prefs.getBoolean("screenshot.save.pdf", true); }
public void setSavePDF(boolean b) { app.prefs.putBoolean("screenshot.save.pdf", b); }
public boolean getSavePNG() { return app.prefs.getBoolean("screenshot.save.png", false); }
public void setSavePNG(boolean b) { app.prefs.putBoolean("screenshot.save.png", b); }
public boolean getSaveLayout() { return app.prefs.getBoolean("screenshot.save.layout", false); }
public void setSaveLayout(boolean b) { app.prefs.putBoolean("screenshot.save.layout", b); }
public int getWidth() { int w = app.prefs.getInt("screenshot.width", 0); return (w > 0) ? w : app.width; }
public void setWidth(int w) { app.prefs.putInt("screenshot.width", w); }
public int getHeight() { int h = app.prefs.getInt("screenshot.height", 0); return (h > 0) ? h : app.height; }
public void setHeight(int h) { app.prefs.putInt("screenshot.height", h); }
// FIXME: all the accessors should be static as they modify preferences rather than Screenshot members
// FIXME: implement static SPaTo_Visual_Explorer.getInstance()
// FIXME: things are getting rather messy in SettingsWindow
public class SettingsWindow extends TFrame {
protected TButton btnOutput;
protected TCheckBox cbSavePDF, cbSavePNG, cbSaveLayout;
protected NonSpammingTextField tfWidth, tfHeight;
protected TLabel lblX;
protected TCheckBox cbUseWindowSize;
protected TButton btnSave, btnCancel;
public class NonSpammingTextField extends TTextField {
protected int numDigits;
public NonSpammingTextField(TransparentGUI gui, String actionCommandPrefix, int numDigits) {
super(gui, actionCommandPrefix);
this.numDigits = numDigits;
setActionEventHandler(this);
}
public TComponent.Dimension getMinimumSize() {
TComponent.Dimension d = super.getMinimumSize();
d.width = Screenshot.this.app.g.textWidth("0")*numDigits;
return d;
}
public void actionPerformed(String cmd) { /* ignore */ }
public void handleFocusLost() {
super.handleFocusLost();
SettingsWindow.this.actionPerformed(getActionCommand() + "##textChanged");
}
}
public SettingsWindow() {
super(app.gui, "Screenshot Settings");
//
cbSavePDF = gui.createCheckBox("PDF");
cbSavePDF.setActionCommand("savePDF");
cbSavePDF.setToolTip("Save the current visualization as a scalable vector image.");
cbSavePNG = gui.createCheckBox("PNG");
cbSavePNG.setActionCommand("savePNG");
cbSavePNG.setToolTip("Save the current visualization as a bitmap (with transparent background).");
cbSaveLayout = gui.createCheckBox("Layout");
cbSaveLayout.setActionCommand("saveLayout");
cbSaveLayout.setToolTip("Save the current node positions to a text file.");
btnOutput = gui.createButton("");
btnOutput.setActionCommand("output");
btnOutput.setAlignment(TButton.ALIGN_LEFT);
btnOutput.setToolTip("All selected output files will be saved to this directory.");
add(gui.createCompactGroup(new TComponent[] {
gui.createLabel("Save"), cbSavePDF, cbSavePNG, cbSaveLayout,
gui.createLabel("to"), btnOutput },
new TComponent.Spacing(10, 0)), TBorderLayout.NORTH);
//
tfWidth = new NonSpammingTextField(gui, "width", 4);
lblX = gui.createLabel("x");
tfHeight = new NonSpammingTextField(gui, "height", 4);
cbUseWindowSize = gui.createCheckBox("use current window size");
cbUseWindowSize.setActionCommand("winsize");
add(gui.createCompactGroup(new TComponent[] {
gui.createLabel("Size:"), tfWidth, lblX, tfHeight,
gui.createLabel(" "), cbUseWindowSize },
new TComponent.Spacing(10, 0)), TBorderLayout.NORTH);
//
TPanel p = gui.createPanel(new TBorderLayout()); p.setMargin(10, 0);
btnSave = gui.createButton("Save");
btnSave.setActionCommand("close##save");
btnSave.setToolTip("Save selected output files.\n" +
"Afterwards, you can use Shift-S to take another screenshot with the same settings.");
TButton btnCancel = gui.createButton("Cancel");
btnCancel.setActionCommand("close##cancel");
p.add(gui.createPanel(new TComponent[] {
gui.createCompactGroup(new TComponent[] { btnCancel }),
gui.createCompactGroup(new TComponent[] { btnSave }) }), TBorderLayout.EAST);
add(p, TBorderLayout.SOUTH);
//
setActionEventHandler(this);
setLocation(50, 150);
//
gui.add(this);
update();
}
public void update() {
btnOutput.setText(Screenshot.this.getOutputDirectory().getAbsolutePath());
cbSavePDF.setSelected(Screenshot.this.getSavePDF());
cbSavePNG.setSelected(Screenshot.this.getSavePNG());
cbSaveLayout.setSelected(Screenshot.this.getSaveLayout());
cbUseWindowSize.setSelected((app.prefs.getInt("screenshot.width", 0) == 0) || (app.prefs.getInt("screenshot.height", 0) == 0));
tfWidth.setText("" + Screenshot.this.getWidth());
tfWidth.setEnabled(!cbUseWindowSize.isSelected());
tfHeight.setText("" + Screenshot.this.getHeight());
tfHeight.setEnabled(!cbUseWindowSize.isSelected());
lblX.setEnabled(!cbUseWindowSize.isSelected());
setSize(getPreferredSize());
}
public void actionPerformed(String cmd) {
if (cmd.equals("savePDF"))
Screenshot.this.setSavePDF(!Screenshot.this.getSavePDF());
else if (cmd.equals("savePNG"))
Screenshot.this.setSavePNG(!Screenshot.this.getSavePNG());
else if (cmd.equals("saveLayout"))
Screenshot.this.setSaveLayout(!Screenshot.this.getSaveLayout());
else if (cmd.equals("output")) {
File dir = FileDialogUtils.selectDirectory(app, Screenshot.this.getOutputDirectory());
if ((dir != null) && dir.exists())
Screenshot.this.setOutputDirectory(dir);
} else if (cmd.startsWith("width##"))
Screenshot.this.setWidth(PApplet.parseInt(tfWidth.getText(), Screenshot.this.getWidth()));
else if (cmd.startsWith("height##"))
Screenshot.this.setHeight(PApplet.parseInt(tfHeight.getText(), Screenshot.this.getHeight()));
else if (cmd.equals("winsize")) {
Screenshot.this.setWidth(cbUseWindowSize.isSelected() ? 0 : Screenshot.this.getWidth());
Screenshot.this.setHeight(cbUseWindowSize.isSelected() ? 0 : Screenshot.this.getHeight());
if (tfWidth.isFocusOwner()) gui.requestFocus(this);
if (tfHeight.isFocusOwner()) gui.requestFocus(this);
} else if (cmd.startsWith("close##")) {
if (cmd.endsWith("##save")) Screenshot.this.save();
Screenshot.this.app.gui.remove(this);
Screenshot.this.sw = null;
}
update();
}
protected int lastWidth = Screenshot.this.app.width, lastHeight = Screenshot.this.app.height;
public void draw(PGraphics g) {
if (cbUseWindowSize.isSelected() && ((app.width != lastWidth) || (app.height != lastHeight))) {
update();
lastWidth = app.width;
lastHeight = app.height;
}
super.draw(g);
}
}
}