001    /*
002     * Copyright (C) 2008-2010 by Holger Arndt
003     *
004     * This file is part of the Universal Java Matrix Package (UJMP).
005     * See the NOTICE file distributed with this work for additional
006     * information regarding copyright ownership and licensing.
007     *
008     * UJMP is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU Lesser General Public License as
010     * published by the Free Software Foundation; either version 2
011     * of the License, or (at your option) any later version.
012     *
013     * UJMP is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016     * GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public
019     * License along with UJMP; if not, write to the
020     * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
021     * Boston, MA  02110-1301  USA
022     */
023    
024    package org.ujmp.gui.renderer;
025    
026    import java.awt.Color;
027    import java.awt.Component;
028    import java.awt.Graphics;
029    import java.awt.Graphics2D;
030    import java.awt.image.BufferedImage;
031    import java.awt.image.DataBufferInt;
032    import java.util.ConcurrentModificationException;
033    import java.util.logging.Level;
034    import java.util.logging.Logger;
035    
036    import javax.swing.JTable;
037    import javax.swing.UIManager;
038    import javax.swing.border.Border;
039    import javax.swing.table.DefaultTableCellRenderer;
040    
041    import org.ujmp.core.Coordinates;
042    import org.ujmp.core.Matrix;
043    import org.ujmp.core.util.MathUtil;
044    import org.ujmp.core.util.UJMPFormat;
045    import org.ujmp.gui.MatrixGUIObject;
046    import org.ujmp.gui.util.ColorUtil;
047    import org.ujmp.gui.util.GraphicsUtil;
048    import org.ujmp.gui.util.UIDefaults;
049    
050    public class MatrixRenderer extends DefaultTableCellRenderer {
051            private static final long serialVersionUID = 942689931503793487L;
052    
053            private static final Logger logger = Logger.getLogger(MatrixRenderer.class
054                            .getName());
055    
056            private MatrixGUIObject matrix = null;
057    
058            private int width = 0;
059    
060            private int height = 0;
061    
062            private static int PADDINGX = UIManager.getInt("Table.paddingX");
063    
064            private static int PADDINGY = UIManager.getInt("Table.paddingY");
065    
066            public MatrixRenderer() {
067            }
068    
069            public MatrixRenderer(MatrixGUIObject m) {
070                    setMatrix(m);
071            }
072    
073            public void setMatrix(MatrixGUIObject m) {
074                    this.matrix = m;
075            }
076    
077            public Component getTableCellRendererComponent(JTable table, Object value,
078                            boolean isSelected, boolean hasFocus, int row, int column) {
079    
080                    if (value instanceof MatrixGUIObject) {
081                            matrix = (MatrixGUIObject) value;
082                    } else if (value instanceof Matrix) {
083                            matrix = (MatrixGUIObject) ((Matrix) value).getGUIObject();
084                    } else {
085                            matrix = null;
086                    }
087    
088                    width = table.getColumnModel().getColumn(column).getWidth() - 1;
089                    height = table.getRowHeight(row) - 1;
090    
091                    if (isSelected) {
092                            super.setForeground(table.getSelectionForeground());
093                            super.setBackground(table.getSelectionBackground());
094                    } else {
095                            super.setForeground(table.getForeground());
096                            super.setBackground(table.getBackground());
097                    }
098    
099                    setFont(table.getFont());
100    
101                    if (hasFocus) {
102                            Border border = null;
103                            if (isSelected) {
104                                    border = UIManager
105                                                    .getBorder("Table.focusSelectedCellHighlightBorder");
106                            }
107                            if (border == null) {
108                                    border = UIManager.getBorder("Table.focusCellHighlightBorder");
109                            }
110                            setBorder(border);
111    
112                            if (!isSelected && table.isCellEditable(row, column)) {
113                                    Color col;
114                                    col = UIManager.getColor("Table.focusCellForeground");
115                                    if (col != null) {
116                                            super.setForeground(col);
117                                    }
118                                    col = UIManager.getColor("Table.focusCellBackground");
119                                    if (col != null) {
120                                            super.setBackground(col);
121                                    }
122                            }
123                    } else {
124                            setBorder(noFocusBorder);
125                    }
126    
127                    return this;
128            }
129    
130            public void paintComponent(Graphics g) {
131                    Graphics2D g2d = (Graphics2D) g;
132    
133                    g2d.setColor(getBackground());
134                    g2d.fillRect(0, 0, width, height);
135    
136                    try {
137                            if (matrix != null) {
138                                    matrix = (MatrixGUIObject) MathUtil.getMatrix(
139                                                    matrix.getMatrix()).getGUIObject();
140    
141                                    int width = getWidth();
142                                    int height = getHeight();
143                                    width = width == 0 ? 1 : width;
144                                    height = height == 0 ? 1 : height;
145                                    int totalColumn = matrix.getColumnCount();
146                                    int totalRows = matrix.getRowCount();
147                                    int xsize = Math.min(totalColumn, width);
148                                    int ysize = Math.min(totalRows, height);
149                                    xsize = xsize == 0 ? 1 : xsize;
150                                    ysize = ysize == 0 ? 1 : ysize;
151    
152                                    double stepsizeX = (double) totalColumn / (double) width;
153                                    double stepsizeY = (double) totalRows / (double) height;
154                                    if (stepsizeX < 1.0) {
155                                            stepsizeX = 1.0;
156                                    }
157                                    if (stepsizeY < 1.0) {
158                                            stepsizeY = 1.0;
159                                    }
160    
161                                    BufferedImage bufferedImage = new BufferedImage(xsize, ysize,
162                                                    BufferedImage.TYPE_INT_RGB);
163    
164                                    int[] pixels = ((DataBufferInt) bufferedImage.getRaster()
165                                                    .getDataBuffer()).getData();
166    
167                                    if (stepsizeX != 1.0 || stepsizeY != 1.0) {
168                                            int pos = 0;
169                                            for (int y = 0; y < ysize; y++) {
170                                                    for (int x = 0; x < xsize; x++) {
171                                                            int mx = (int) Math.floor(x * stepsizeX);
172                                                            int my = (int) Math.floor(y * stepsizeY);
173                                                            Color col = ColorUtil.fromObject(matrix.getValueAt(
174                                                                            my, mx));
175                                                            pixels[pos++] = (col.getRed() << 16)
176                                                                            + (col.getGreen() << 8) + col.getBlue();
177                                                    }
178                                            }
179                                    } else {
180                                            Iterable<long[]> cos = matrix.coordinates();
181                                            if (cos != null) {
182                                                    for (long[] c : cos) {
183                                                            if (c != null) {
184                                                                    Color col = ColorUtil.fromObject(matrix
185                                                                                    .getValueAt(c));
186                                                                    int pos = getPosition(totalColumn,
187                                                                                    c[Coordinates.ROW],
188                                                                                    c[Coordinates.COLUMN]);
189                                                                    pixels[pos] = (col.getRed() << 16)
190                                                                                    + (col.getGreen() << 8) + col.getBlue();
191                                                            }
192                                                    }
193                                            }
194                                    }
195    
196                                    g2d.drawImage(bufferedImage, PADDINGX, PADDINGY, width
197                                                    - PADDINGX - PADDINGX, height - PADDINGY - PADDINGY,
198                                                    null);
199    
200                                    if (width > 20 && matrix.isScalar()) {
201                                            Color col = ColorUtil.fromObject(matrix.getValueAt(0, 0));
202                                            g2d.setColor(ColorUtil.contrastBW(col));
203                                            String s = UJMPFormat.getSingleLineInstance().format(
204                                                            matrix.getValueAt(0, 0));
205                                            if (s != null && s.length() > 25) {
206                                                    s = s.substring(0, 25) + "...";
207                                            }
208                                            GraphicsUtil.drawString(g2d, width / 2.0,
209                                                            height / 2.0 - 1.0, GraphicsUtil.ALIGNCENTER,
210                                                            GraphicsUtil.ALIGNCENTER, s);
211                                    }
212    
213                            } else {
214                                    g2d.setColor(Color.GRAY);
215                                    g2d.drawLine(PADDINGX, PADDINGY, width - PADDINGX, height
216                                                    - PADDINGY);
217                                    g2d.drawLine(PADDINGX, height - PADDINGY, width - PADDINGX,
218                                                    0 + PADDINGY);
219                            }
220                    } catch (ConcurrentModificationException e) {
221                            // not too bad
222                    } catch (Exception e) {
223                            logger.log(Level.WARNING, "could not paint", e);
224                    }
225            }
226    
227            private static int getPosition(long totalColumn, long currentRow,
228                            long currentColumn) {
229                    return (int) (totalColumn * currentRow + currentColumn);
230            }
231    
232            public static void paintMatrix(Graphics g, Matrix matrix, int width,
233                            int height) {
234                    if (g == null)
235                            return;
236    
237                    Graphics2D g2d = (Graphics2D) g;
238                    g2d.addRenderingHints(UIDefaults.AALIAS);
239    
240                    if (matrix == null) {
241                            g2d.setColor(Color.GRAY);
242                            g2d.drawLine(PADDINGX, PADDINGY, width - PADDINGX, height
243                                            - PADDINGY);
244                            g2d.drawLine(width - PADDINGX, PADDINGY, PADDINGX, height
245                                            - PADDINGY);
246                    } else {
247                            g2d.translate(PADDINGX, PADDINGX);
248                            if (matrix.getColumnCount() > matrix.getRowCount()) {
249                                    paintMatrixOriginal(g2d, matrix, width - PADDINGX - PADDINGX,
250                                                    height - PADDINGY - PADDINGY);
251                            } else {
252                                    paintMatrixTransposed(g2d, matrix, width - PADDINGX - PADDINGX,
253                                                    height - PADDINGY - PADDINGY);
254                            }
255                            g2d.translate(-PADDINGX, -PADDINGX);
256                    }
257            }
258    
259            private static void paintMatrixOriginal(Graphics g, Matrix matrix,
260                            int width, int height) {
261                    try {
262                            int cols = (int) matrix.getColumnCount();
263                            int rows = (int) matrix.getRowCount();
264    
265                            width = width < 1 ? 1 : width;
266                            height = height < 1 ? 1 : height;
267                            int xSize = cols > 0 ? cols : 1;
268                            int ySize = rows > 0 ? rows : 1;
269    
270                            xSize = xSize > 0 ? xSize : 1;
271                            ySize = ySize > 0 ? ySize : 1;
272    
273                            int xStepSize = (int) Math.ceil((double) xSize / (double) width);
274                            int yStepSize = (int) Math.ceil((double) ySize / (double) height);
275    
276                            int imgX = xSize / xStepSize;
277                            int imgY = ySize / yStepSize;
278                            imgX = imgX > 0 ? imgX : 1;
279                            imgY = imgY > 0 ? imgX : 1;
280    
281                            BufferedImage bufferedImage = new BufferedImage(imgX, imgY,
282                                            BufferedImage.TYPE_INT_RGB);
283                            Graphics2D g2d = (Graphics2D) g;
284                            Graphics2D bg = (Graphics2D) bufferedImage.getGraphics();
285                            bg.addRenderingHints(UIDefaults.AALIAS);
286    
287                            for (int col = 0; col < cols; col += xStepSize) {
288                                    for (int row = 0; row < rows; row += yStepSize) {
289                                            bg.setColor(ColorUtil.fromDouble(matrix.getAsDouble(row,
290                                                            col)));
291                                            bg.fillRect(col / xStepSize, row / yStepSize, 1, 1);
292                                    }
293                            }
294                            g2d.drawImage(bufferedImage, 0, 0, width, height, 0, 0,
295                                            bufferedImage.getWidth(), bufferedImage.getHeight(), null);
296                            if (width > 20 && matrix.isScalar()) {
297                                    String s = UJMPFormat.getSingleLineInstance().format(
298                                                    matrix.getAsObject(0, 0));
299                                    if (s != null && s.length() > 25) {
300                                            s = s.substring(0, 25) + "...";
301                                    }
302                                    g2d.setColor(ColorUtil.contrastBW(bg.getColor()));
303                                    GraphicsUtil.drawString(g2d, width / 2.0, height / 2.0 - 1.0,
304                                                    GraphicsUtil.ALIGNCENTER, GraphicsUtil.ALIGNCENTER, s);
305                            }
306                    } catch (Exception e) {
307                            logger.log(Level.WARNING, "error painting matrix", e);
308                    }
309            }
310    
311            private static void paintMatrixSquared(Graphics g, Matrix matrix,
312                            int width, int height) {
313                    try {
314                            long valueCount = matrix.getValueCount();
315    
316                            width = width < 1 ? 1 : width;
317                            height = height < 1 ? 1 : height;
318                            int xSize = (int) Math.floor(Math.sqrt(valueCount));
319                            int ySize = (int) Math.ceil((double) valueCount / (double) xSize);
320    
321                            xSize = xSize > 0 ? xSize : 1;
322                            ySize = ySize > 0 ? ySize : 1;
323    
324                            int xStepSize = (int) Math.ceil((double) xSize / (double) width);
325                            int yStepSize = (int) Math.ceil((double) ySize / (double) height);
326    
327                            int imgX = xSize / xStepSize;
328                            int imgY = ySize / yStepSize;
329                            imgX = imgX > 0 ? imgX : 1;
330                            imgY = imgY > 0 ? imgX : 1;
331    
332                            BufferedImage bufferedImage = new BufferedImage(imgX, imgY,
333                                            BufferedImage.TYPE_INT_RGB);
334                            Graphics2D g2d = (Graphics2D) g;
335                            Graphics2D bg = (Graphics2D) bufferedImage.getGraphics();
336                            bg.addRenderingHints(UIDefaults.AALIAS);
337                            int x = 0;
338                            int y = 0;
339    
340                            for (int i = 0; i < valueCount; i++) {
341                                    bg.setColor(ColorUtil.fromDouble(matrix.getAsDouble(i
342                                                    % matrix.getRowCount(), i / matrix.getRowCount())));
343                                    bg.fillRect(x / xStepSize, y / yStepSize, 1, 1);
344                                    x++;
345                                    if (x >= xSize) {
346                                            x = 0;
347                                            y++;
348                                    }
349                            }
350    
351                            g2d.drawImage(bufferedImage, 0, 0, width, height, 0, 0,
352                                            bufferedImage.getWidth(), bufferedImage.getHeight(), null);
353                            if (width > 20 && matrix.isScalar()) {
354                                    g2d.setColor(ColorUtil.contrastBW(bg.getColor()));
355                                    GraphicsUtil.drawString(g2d, width / 2.0, height / 2.0 - 1.0,
356                                                    GraphicsUtil.ALIGNCENTER, GraphicsUtil.ALIGNCENTER,
357                                                    UJMPFormat.getSingleLineInstance().format(
358                                                                    matrix.getAsObject(0, 0)));
359                            }
360                    } catch (Exception e) {
361                            logger.log(Level.WARNING, "error painting matrix", e);
362                    }
363            }
364    
365            private static void paintMatrixTransposed(Graphics g, Matrix matrix,
366                            int width, int height) {
367                    try {
368                            int cols = (int) matrix.getColumnCount();
369                            int rows = (int) matrix.getRowCount();
370    
371                            width = width < 1 ? 1 : width;
372                            height = height < 1 ? 1 : height;
373                            int ySize = cols > 0 ? cols : 1;
374                            int xSize = rows > 0 ? rows : 1;
375    
376                            xSize = xSize > 0 ? xSize : 1;
377                            ySize = ySize > 0 ? ySize : 1;
378    
379                            int xStepSize = (int) Math.ceil((double) xSize / (double) width);
380                            int yStepSize = (int) Math.ceil((double) ySize / (double) height);
381    
382                            int imgX = xSize / xStepSize;
383                            int imgY = ySize / yStepSize;
384                            imgX = imgX > 0 ? imgX : 1;
385                            imgY = imgY > 0 ? imgX : 1;
386    
387                            BufferedImage bufferedImage = new BufferedImage(imgX, imgY,
388                                            BufferedImage.TYPE_INT_RGB);
389                            Graphics2D g2d = (Graphics2D) g;
390                            Graphics2D bg = (Graphics2D) bufferedImage.getGraphics();
391                            bg.addRenderingHints(UIDefaults.AALIAS);
392    
393                            for (int col = 0; col < cols; col += xStepSize) {
394                                    for (int row = 0; row < rows; row += yStepSize) {
395                                            bg.setColor(ColorUtil.fromDouble(matrix.getAsDouble(row,
396                                                            col)));
397                                            bg.fillRect(row / yStepSize, col / xStepSize, 1, 1);
398                                    }
399                            }
400    
401                            g2d.drawImage(bufferedImage, 0, 0, width, height, 0, 0,
402                                            bufferedImage.getWidth(), bufferedImage.getHeight(), null);
403                            if (width > 20 && matrix.isScalar()) {
404                                    g2d.setColor(ColorUtil.contrastBW(bg.getColor()));
405                                    String s = UJMPFormat.getSingleLineInstance().format(
406                                                    matrix.getAsObject(0, 0));
407                                    if (s != null && s.length() > 25) {
408                                            s = s.substring(0, 25) + "...";
409                                    }
410                                    GraphicsUtil.drawString(g2d, width / 2.0, height / 2.0 - 1.0,
411                                                    GraphicsUtil.ALIGNCENTER, GraphicsUtil.ALIGNCENTER, s);
412                            }
413                    } catch (Exception e) {
414                            logger.log(Level.WARNING, "error painting matrix", e);
415                    }
416            }
417    
418    }