/*
* Zettelkasten - nach Luhmann
* Copyright (C) 2001-2015 by Daniel Lüdecke (http://www.danielluedecke.de)
*
* Homepage: http://zettelkasten.danielluedecke.de
*
*
* This program 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.
*
* This program 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 this program;
* if not, see <http://www.gnu.org/licenses/>.
*
*
* Dieses Programm ist freie Software. Sie können es unter den Bedingungen der GNU
* General Public License, wie von der Free Software Foundation veröffentlicht, weitergeben
* und/oder modifizieren, entweder gemäß Version 3 der Lizenz oder (wenn Sie möchten)
* jeder späteren Version.
*
* Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, daß es Ihnen von Nutzen sein
* wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder
* der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der
* GNU General Public License.
*
* Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm
* erhalten haben. Falls nicht, siehe <http://www.gnu.org/licenses/>.
*/
package de.danielluedecke.zettelkasten;
import de.danielluedecke.zettelkasten.database.Daten;
import de.danielluedecke.zettelkasten.database.Settings;
import de.danielluedecke.zettelkasten.util.Constants;
import de.danielluedecke.zettelkasten.util.ExtractFormInformation;
import de.danielluedecke.zettelkasten.util.FileOperationsUtil;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
/**
*
* @author danielludecke
*/
public class CMakeFormImage {
private BufferedImage formimage;
private final Settings settingsObj;
private final Daten dataObj;
private final String formtag;
private final File formImageDir;
private boolean saveImgOk;
private final File formImageFilepath;
private final File formLargeImageFilepath;
private static final int IMG_SIZE_SMALL = 1;
private static final int IMG_SIZE_LARGE = 2;
private static final int MARK_DISTANCE = 6;
private static final int MARK_THICKNESS = 2;
private static final int IMG_PADDING = 2;
public boolean isSaveImgOk() {
return saveImgOk;
}
/**
* get the strings for file descriptions from the resource map
*/
private final org.jdesktop.application.ResourceMap resourceMap =
org.jdesktop.application.Application.getInstance(de.danielluedecke.zettelkasten.ZettelkastenApp.class).
getContext().getResourceMap(NewEntryFrame.class);
public CMakeFormImage(Daten dat, Settings set, String ftag) {
settingsObj = set;
dataObj = dat;
formtag = ftag;
saveImgOk = false;
// retrieve user defined or default path to form-image-directory
formImageDir = new File(settingsObj.getFormImagePath(dataObj.getUserImagePath(), false));
// check whether image file already exists
formImageFilepath = new File(formImageDir+String.valueOf(File.separatorChar)+FileOperationsUtil.convertFormtagToImagepath(formtag, true, false));
// create large image for export
formLargeImageFilepath = new File(formImageDir+String.valueOf(File.separatorChar)+FileOperationsUtil.convertFormtagToImagepath(formtag, true, true));
}
public void createFormImage() {
// check whether this form-image has already been created before
if (!formImageFilepath.exists()) {
// if not, draw image
drawForms(IMG_SIZE_SMALL);
// save image to disk
saveImage(formImageFilepath);
// also draw large image
drawForms(IMG_SIZE_LARGE);
// save image to disk
saveImage(formLargeImageFilepath);
}
else {
saveImgOk = true;
}
}
private void drawForms(int size) {
// determine mark-distance
int markdist = size * MARK_DISTANCE;
// first, extract form-information
ExtractFormInformation extractedforms = new ExtractFormInformation(formtag);
// retrieve default font-size
int fsize = Integer.parseInt(settingsObj.getMainfont(Settings.FONTSIZE));
// create font, with double font size (for printing resolution)
// Font font = new Font(settingsObj.getMainfont(Settings.FONTNAME),Font.PLAIN,3*fsize);
Font font = new Font(settingsObj.getMainfont(Settings.FONTNAME),Font.PLAIN,(int)(size*fsize*1.3));
// create new image. we use very large dimensions here, and crop the image later
formimage = new BufferedImage(3000, 1000, BufferedImage.TYPE_INT_RGB);
Graphics2D g =(Graphics2D) formimage.getGraphics();
// set font
g.setFont(font);
// fill color white
// fill white background
g.fillRect(0, 0, 3000, 1000);
// draw color black
g.setPaint(Color.BLACK);
// line-thickness 2px
g.setStroke(new BasicStroke(MARK_THICKNESS*size));
// get font metrics. needed to calculate width of text-portions, so
// we know where to draw the vertically form-lines
FontMetrics fm = g.getFontMetrics(font);
// x-pos. of textstart
int textStartX = size*IMG_PADDING;
// x-pos. of marks
int markStartX = size*IMG_PADDING;
// calclulate y-position for text. depending on the amount of
// marks we have, we increase the y-position of text-start by the mark's pixel-distance
// per mark. finally, we need to add the line height, since the y-pos
// of text is depending on the font's baseline
int textStartY = extractedforms.getMarkCount()*markdist + fm.getHeight()+(size*IMG_PADDING);
// if we also have a reentry-hook, we increase it by one more mark's pixel-distance
if (extractedforms.hasReentry()) textStartY += markdist;
// y-start-pos. of marks. we take the text-y-position, substract the lineheight (so we have
// the y-position of the text-top-line and substract one mark-distance, so the mark-line
// does not cross the text
int markStartY = textStartY - markdist - fm.getHeight();
// create array which contains the end-x-position of each mark
int[] markEndX = new int[extractedforms.getMarkCount()];
// y-end-pos. of marks. these end at the bottom-line of the drawn text strings
int markEndY = textStartY;
// x-end for reentry-mark
int reentryEndX = -1;
//
// draw description here
//
// check whether we have a description
String desc = extractedforms.getDescription();
if (desc!=null && !desc.isEmpty()) {
// draw description-text
g.drawString(desc+" = ", 0, textStartY);
// retrieve width of textstring and calculate the new textstart-x-pos.
// of the text behind the = sign (the distinctions)
textStartX = markStartX = fm.stringWidth(desc+" = ");
}
//
// draw distinctions here
//
// retrieve distinctions
String[] dist = extractedforms.getDistinctions();
// get unmarked space text
String unmarkedSpace = extractedforms.getUnmarkedSpace();
// check whether we have any distincions
if (dist!=null && dist.length>0) {
// draw all distinction strings
for (int cnt=0; cnt<dist.length; cnt++) {
// draw distinction text
g.drawString(dist[cnt], textStartX, textStartY);
// we have less marks than distinctions, so keep array index bounds in mind
if (cnt<markEndX.length) {
// save mark's end-x-position, which is exact one mark-distance behind
// the end of the text-string
markEndX[cnt] = textStartX + markdist + fm.stringWidth(dist[cnt]);
}
// reentry-mark x-pos ends after last text-string
reentryEndX = textStartX + markdist + fm.stringWidth(dist[cnt]);
// determine new x-pos of textstart, which starts exact one mark-distance
// behind the mark (which means: two mark-distances behind the end of the
// previous text string)
textStartX = textStartX + 2*markdist + fm.stringWidth(dist[cnt]);
}
// check for valid value
if (unmarkedSpace!=null && !unmarkedSpace.isEmpty()) {
// draw text
g.drawString(unmarkedSpace, textStartX, textStartY);
}
}
//
// draw marks here
//
// go through all marks
for (int cnt=0; cnt<markEndX.length; cnt++) {
// draw mark, horizontal line
g.drawLine(markStartX, markStartY, markEndX[cnt], markStartY);
// draw mark, vertical line
g.drawLine(markEndX[cnt], markStartY, markEndX[cnt], markEndY);
// determine new y-start
markStartY -= markdist;
}
//
// draw reentry-mark here
//
// draw reentry-hook, if requested
if (extractedforms.hasReentry()) {
// draw reentry, horizontal line
g.drawLine(markStartX, markStartY, reentryEndX, markStartY);
// draw reentry, vertical line
g.drawLine(reentryEndX, markStartY, reentryEndX, markEndY+(int)(2.5*markdist));
// draw reentry, horizontal line
g.drawLine(markStartX, markEndY+(int)(2.5*markdist), reentryEndX, markEndY+(int)(2.5*markdist));
// draw reentry, vertical reentry
g.drawLine(markStartX, markEndY+(int)(2.5*markdist), markStartX, markEndY+(int)(1.3*markdist));
}
//
// crop image
//
// determine final width
int width = reentryEndX+(size*IMG_PADDING);
if (!extractedforms.hasReentry()) width -= markdist;
if (unmarkedSpace!=null && !unmarkedSpace.isEmpty()) width += (fm.stringWidth(unmarkedSpace) + 2*markdist);
// determine final height
int height = markEndY+(size*IMG_PADDING);
height += (extractedforms.hasReentry()) ? (int)(2.5*markdist) : size*IMG_PADDING;
// crop image to necessary size
formimage = formimage.getSubimage(0, 0, width, height);
}
private void saveImage(File fp) {
// check whether image dir exists. if not, create image dir
if (createFormImageDir()) {
// when image dir exists or was successfully created, continue
// and save file
try {
// write file image
ImageIO.write(formimage, "png", fp);
// saving the image succeeded
saveImgOk = true;
}
catch(IOException ex) {
Constants.zknlogger.log(Level.SEVERE, ex.getLocalizedMessage());
}
}
}
private boolean createFormImageDir() {
// first, check whether we already have a form image directory
// create the file-object with the necessary directory path
// if the directory does not exist, create it
if (!formImageDir.exists()) {
// create directory
try {
if (!formImageDir.mkdir()) {
// if it fails, show warning message and leave method
// create a message string including the filepath of the directory
// which could not be created
JOptionPane.showMessageDialog(null,resourceMap.getString("errMsgCreateImgDirMsg",formImageDir.toString()),resourceMap.getString("errMsgCreateDirTitle"),JOptionPane.PLAIN_MESSAGE);
return false;
}
}
catch (SecurityException e) {
Constants.zknlogger.log(Level.SEVERE,e.getLocalizedMessage());
// if it fails, show warning message and leave method
// create a message string including the filepath of the directory
// which could not be created
JOptionPane.showMessageDialog(null,resourceMap.getString("errMsgCreateImgDirMsg",formImageDir.toString()),resourceMap.getString("errMsgCreateDirTitle"),JOptionPane.PLAIN_MESSAGE);
return false;
}
}
return true;
}
}