/* * This file is part of jHaushalt. * jHaushalt 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. * jHaushalt 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 jHaushalt; if not, see <http://www.gnu.org/licenses/>. * (C)opyright 2002-2010 Dr. Lars H. Hahn */ package haushalt.auswertung; import haushalt.auswertung.bloecke.AbstractBlock; import haushalt.auswertung.bloecke.LeererBlock; import haushalt.auswertung.bloecke.TabellenBlock; import haushalt.auswertung.bloecke.TextBlock; import haushalt.daten.Datenbasis; import haushalt.daten.Datum; import haushalt.daten.Euro; import haushalt.daten.zeitraum.AbstractZeitraum; import haushalt.daten.zeitraum.Jahr; import haushalt.gui.Haushalt; import haushalt.gui.TextResource; import haushalt.gui.generischerdialog.AbstractGDPane; import haushalt.gui.generischerdialog.GenerischerDialog; import haushalt.gui.generischerdialog.TextGDP; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Toolkit; import java.awt.print.PageFormat; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Date; import java.util.logging.Logger; import javax.print.attribute.HashPrintRequestAttributeSet; import javax.print.attribute.ResolutionSyntax; import javax.print.attribute.standard.PrinterResolution; import javax.swing.JFrame; import javax.swing.JTextField; import javax.swing.SwingUtilities; /** * Abstrakte Klasse, die Auswertungen standardisiert. * Die Auswertung wird hierzu in einzelne Blöcke aufgeteilt, diese * können für unterschiedliche Auswertungen wiederverwertet werden. * Darüber hinaus werden die Parameter der Auswertung über einen * generischen Dialog eingestellt, der ebenfalls wiederverwendet werden * kann. In der abgeleiteten Auswertung muss lediglich die Methode * 'berechneAuswertung' überladen werden. * * @see AbstractBlockAuswertung#berechneAuswertung(Object[]) * * @author Dr. Lars H. Hahn * @version 2.6/2011.02.08 * @since 2.0 */ /* * 2011.02.08 BuxFix: Laden/Speichern von Auswertungen ohne spezielle * Eigenschaften * ermöglicht * 2010.09.19 Graphics2D in der Methode 'print' verwendet; DoubleBuffering * beim Drucken ausgeschaltet * 2009.08.10 Auswertungen ohne spezifische Eigenschaften ermöglicht * 2008.01.17 Internationalisierung * 2007.05.24 BugFix: Letzte Zeile eines Blocks wurde nicht ausgedruckt * 2004.08.22 Erste Version (2.0) */ public abstract class AbstractBlockAuswertung extends AbstractAuswertung { private static final long serialVersionUID = 1L; private static final boolean DEBUG = false; private static final TextResource RES = TextResource.get(); private static final Logger LOGGER = Logger.getLogger(AbstractBlockAuswertung.class.getName()); private final Haushalt haushalt; private final ArrayList<AbstractBlock> bloecke = new ArrayList<AbstractBlock>(); private final Image wasserzeichen; private int seitenZaehler = 0; private int blockZaehler = 0; private int zeilenZaehler = 0; private int blockStart = 0; private int zeilenStart = 0; private AbstractGDPane[] panes; private TextGDP namenPane; private GenerischerDialog dlgEigenschaften; public AbstractBlockAuswertung(final Haushalt haushalt, final Datenbasis db, final String name) { super(db, name); this.haushalt = haushalt; final URLClassLoader urlLoader = (URLClassLoader) getClass().getClassLoader(); final URL fileLoc = urlLoader.findResource("RES/jhh-grau.gif"); this.wasserzeichen = Toolkit.getDefaultToolkit().createImage(fileLoc); } public void addDokumentenBlock(final AbstractBlock block) { this.bloecke.add(block); if (DEBUG) { LOGGER.info("AbstractBlockAuswertung: Block hinzugefügt."); } } public void loescheBloecke() { this.bloecke.clear(); if (DEBUG) { LOGGER.info("AbstractBlockAuswertung: Alle Blöcke gelöscht."); } } @Override public void paintComponent(final Graphics g) { setBackground(Color.white); super.paintComponent(g); // paint background final int breite = getSize().width - 2; int y = 0; for (int i = 0; i < this.bloecke.size(); i++) { final AbstractBlock block = this.bloecke.get(i); y += block.paint(g, 0, y, breite); } setPreferredSize(new Dimension(breite, y)); revalidate(); } @Override public int print(final Graphics g, final PageFormat seitenFormat, final int gesuchteSeite) throws PrinterException { if (DEBUG) { LOGGER.info("AbstractBlockAuswertung: Drucke Seite " + gesuchteSeite); LOGGER.info("AbstractBlockAuswertung: Pagesize = " + seitenFormat.getImageableWidth() + " x " + seitenFormat.getImageableHeight()); LOGGER.info("AbstractBlockAuswertung: PanelSize = " + getSize()); } if (gesuchteSeite == 0) { // Die erste Seite ist gewünscht => alle Zähler zurücksetzen this.seitenZaehler = 0; this.blockZaehler = 0; this.zeilenZaehler = 0; this.blockStart = 0; this.zeilenStart = 0; } else if (gesuchteSeite == this.seitenZaehler) { // Die aktuelle Seite wird wiederholt abgefragt => Zähler wieder auf // die // Anfangswerte this.blockZaehler = this.blockStart; this.zeilenZaehler = this.zeilenStart; } else if (gesuchteSeite == (this.seitenZaehler + 1)) { // Die nächste Seite ist gewünscht this.seitenZaehler++; this.blockStart = this.blockZaehler; this.zeilenStart = this.zeilenZaehler; } else { throw new PrinterException("Seiten nicht in der richtigen Reihenfolge angefodert."); } if (this.blockZaehler == this.bloecke.size()) { return NO_SUCH_PAGE; } int hoehe = (int) seitenFormat.getImageableHeight() - 2; final int breite = (int) seitenFormat.getImageableWidth() - 2; final int xStart = (int) seitenFormat.getImageableX() + 1; final int yStart = (int) seitenFormat.getImageableY() + 1; setDoubleBuffered(false); final Graphics2D g2d = (Graphics2D) g; if (DEBUG) { g2d.setColor(Color.RED); g2d.drawRect(xStart, yStart, breite, hoehe); g2d.drawLine(xStart, yStart, xStart + breite, yStart + hoehe); g2d.drawLine(xStart, yStart + hoehe, xStart + breite, yStart); g2d.setColor(Color.BLACK); } String fontname = "SansSerif"; int fontgroesse = 12; if (this.haushalt != null) { fontname = this.haushalt.getFontname(); fontgroesse = this.haushalt.getFontgroesse(); } // Fusszeile drucken g2d.setFont(new Font(fontname, Font.PLAIN, fontgroesse - 2)); final int textHoehe = g2d.getFontMetrics().getHeight(); final int bildBreite = textHoehe * 169 / 32; final String seitenzahl = "" + new Datum() + " / Seite " + (gesuchteSeite + 1); int y = yStart + hoehe - g2d.getFontMetrics().getDescent(); final int x = xStart + breite - g2d.getFontMetrics().stringWidth(seitenzahl); g2d.drawImage(this.wasserzeichen, xStart, yStart + hoehe - textHoehe, bildBreite, textHoehe, Color.white, null); g2d.drawString(seitenzahl, x, y); hoehe -= textHoehe; if (DEBUG) { g2d.setColor(Color.BLUE); g2d.drawRect(xStart, y - textHoehe, breite, textHoehe); g2d.setColor(Color.BLACK); } y = 0; int verbrauchteHoehe; do { if (DEBUG) { LOGGER.info("AbstractBlockAuswertung: Block " + this.blockZaehler + " wird gedruckt."); } final AbstractBlock block = this.bloecke.get(this.blockZaehler); // Aktuelle Zeile ausgeben: verbrauchteHoehe = block.print(g2d, this.zeilenZaehler, xStart, yStart + y, hoehe - y, breite); if (DEBUG) { g2d.setColor(Color.GREEN); g2d.drawRect(xStart, yStart + y, hoehe - y - 1, breite - 1); g2d.drawString("#" + this.blockZaehler, xStart, yStart + y); g2d.setColor(Color.BLACK); } if (verbrauchteHoehe == -1) { // keine Zeilen mehr in diesem Block this.blockZaehler++; this.zeilenZaehler = 0; } else if (verbrauchteHoehe == 0) { // Zeile passt nicht in die (Rest-)Höhe if (y == 0) { // ... und wir sind am Anfang der Seite! throw new PrinterException("Block ist zu hoch für die Seite."); // Wir versuchen es auf der nächsten Seite. Achtung: // Zeilenzähler nicht inkrementieren! } } else { // PRIMA! Nächste Zeile ... y += verbrauchteHoehe; this.zeilenZaehler++; } } while ((this.blockZaehler < this.bloecke.size()) && (verbrauchteHoehe != 0)); // Es gibt noch Blöcke und es wurde etwas ausgegeben --> also weiter! setDoubleBuffered(true); return PAGE_EXISTS; } protected abstract String berechneAuswertung(Object[] werte); /** * Ermöglicht die Auswertung neu zu berechnen, wenn sich die allgemeinen * Eigenschaften ändern. */ @Override public final String berechneAuswertung() { Object[] werte = null; final long start = new Date().getTime(); if (this.panes != null) { werte = new Object[this.panes.length]; for (int i = 0; i < this.panes.length; i++) { werte[i] = this.panes[i].getRefreshedWert(); } } final String titel = berechneAuswertung(werte); if (DEBUG) { LOGGER.info(toString() + " in " + (new Date().getTime() - start) + " ms berechnet."); } return titel; } public final void erzeugeEigenschaften(final JFrame frame, final String ueberschrift, final AbstractGDPane[] gdPanes) { this.panes = gdPanes; this.dlgEigenschaften = new GenerischerDialog(ueberschrift, frame); if (gdPanes != null) { final Object[] werte = new Object[this.panes.length]; for (int i = 0; i < this.panes.length; i++) { this.dlgEigenschaften.addPane(this.panes[i]); werte[i] = this.panes[i].getRefreshedWert(); } } this.namenPane = new TextGDP(RES.getString("report_name"), toString()); this.dlgEigenschaften.addPane(this.namenPane); } @Override public final boolean zeigeEigenschaften() { if (this.panes != null) { for (int i = 0; i < this.panes.length; i++) { this.panes[i].refreshRegisterUndKategorien(); } } if (this.dlgEigenschaften.showDialog()) { final String titel = berechneAuswertung(); // Wenn der Benutzer die Auswertung nicht benannt hat, wird sie mit // einem automatischen Namen versehen. if (this.namenPane.getRefreshedWert().toString().startsWith(RES.getString("unnamed"))) { ((JTextField) this.namenPane.getZentraleKomponente()).setText(titel); setAuswertungName(titel); } else { setAuswertungName("" + this.namenPane.getRefreshedWert()); } return true; } return false; } @Override public final void laden(final DataInputStream in) throws IOException { if (this.panes != null) { for (int i = 0; i < this.panes.length; i++) { this.panes[i].laden(in); } } } @Override public final void speichern(final DataOutputStream out) throws IOException { if (this.panes != null) { for (int i = 0; i < this.panes.length; i++) { this.panes[i].speichern(out); } } } // -- TEST-MAIN // ------------------------------------------------------------------- public static void main(final String[] args) { class BATest extends AbstractBlockAuswertung { private static final long serialVersionUID = 1L; public BATest() { super(null, null, "TEST"); } @Override protected String berechneAuswertung(final Object[] werte) { final AbstractZeitraum zeitraum = new Jahr(2010); final String register = "Testregister"; final String[][] tabelle = { { "Datum 1", "Buchungstext 1", "IKategorie 1", "Wert 1" }, { "Datum 2", "Buchungstext 2", "IKategorie 2", "Wert 2" }, { "Datum 3", "Buchungstext 3", "IKategorie 3", "Wert 3" }, { "Datum 4", "Buchungstext 4", "IKategorie 4", "Wert 4" }, { "Datum 5", "Buchungstext 5", "IKategorie 5", "Wert 5" }, { "Datum 6", "Buchungstext 6", "IKategorie 6", "Wert 6" }, { "Datum 7", "Buchungstext 7", "IKategorie 7", "Wert 7" }, { "Datum 8", "Buchungstext 8", "IKategorie 8", "Wert 8" }, { "Datum 9", "Buchungstext 9", "IKategorie 9", "Wert 9" } }; final String fontname = "SansSerif"; final Euro summe = new Euro(99.99); String titel = "Ausgewählte Buchungen (" + zeitraum; titel += " / " + register + ")"; loescheBloecke(); final AbstractBlock block1 = new TextBlock(titel); final Font font = new Font(fontname, Font.BOLD, 18); block1.setFont(font); addDokumentenBlock(block1); addDokumentenBlock(new LeererBlock(1)); final double[] relTabs = { 0.0, 12.0, 50.0, 80.0 }; final TabellenBlock.Ausrichtung[] attribute = { TabellenBlock.Ausrichtung.LINKS, TabellenBlock.Ausrichtung.LINKS, TabellenBlock.Ausrichtung.LINKS, TabellenBlock.Ausrichtung.RECHTS }; final TabellenBlock block2 = new TabellenBlock(tabelle); block2.setFont(new Font(fontname, Font.PLAIN, 12)); block2.setRelTabs(relTabs); block2.setLinienFarbe("Weiß"); block2.setAusrichtung(attribute); addDokumentenBlock(block2); final String[][] text = { { "", RES.getString("total") + ":", "", "" + summe } }; final TabellenBlock block3 = new TabellenBlock(text); block3.setFont(new Font(fontname, Font.ITALIC, 12)); block3.setRelTabs(relTabs); block3.setHgFarbe("Grau"); block3.setLinienFarbe("Grau"); block3.setAusrichtung(attribute); addDokumentenBlock(block3); return titel; } } final BATest test = new BATest(); final PageFormat seitenFormat = PrinterJob.getPrinterJob().defaultPage(); test.berechneAuswertung(); SwingUtilities.invokeLater(new Runnable() { public void run() { final JFrame frame = new JFrame(); frame.getContentPane().add(test); frame.pack(); frame.setVisible(true); } }); final PrinterJob job = PrinterJob.getPrinterJob(); job.setJobName("Test - Report"); job.setPrintable(test, seitenFormat); final HashPrintRequestAttributeSet set = new HashPrintRequestAttributeSet(); final PrinterResolution pr = new PrinterResolution(300, 300, ResolutionSyntax.DPI); set.add(pr); if (job.printDialog(set)) { try { job.print(); } catch (final PrinterException e) { LOGGER.warning(e.getMessage()); } } } protected Haushalt getHaushalt() { return haushalt; } protected AbstractGDPane[] getPanes() { return panes; } }