Source Code Cross Referenced for KernelEditor.java in  » GIS » GeoTools-2.4.1 » org » geotools » gui » swing » image » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.gui.swing.image 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *    GeoTools - OpenSource mapping toolkit
0003:         *    http://geotools.org
0004:         *    (C) 2003-2006, Geotools Project Managment Committee (PMC)
0005:         *    (C) 2002, Institut de Recherche pour le Développement
0006:         *
0007:         *    This library is free software; you can redistribute it and/or
0008:         *    modify it under the terms of the GNU Lesser General Public
0009:         *    License as published by the Free Software Foundation; either
0010:         *    version 2.1 of the License, or (at your option) any later version.
0011:         *
0012:         *    This library is distributed in the hope that it will be useful,
0013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015:         *    Lesser General Public License for more details.
0016:         */
0017:        package org.geotools.gui.swing.image;
0018:
0019:        // JAI dependencies
0020:        import javax.media.jai.KernelJAI;
0021:        import javax.media.jai.operator.ConvolveDescriptor; // For Javadoc
0022:
0023:        // Graphical user interface
0024:        import java.awt.Component;
0025:        import java.awt.Dimension;
0026:        import java.awt.GridBagLayout;
0027:        import java.awt.GridBagConstraints;
0028:        import java.awt.IllegalComponentStateException;
0029:
0030:        // Graphical user interface (Swing)
0031:        import javax.swing.JFrame;
0032:        import javax.swing.JPanel;
0033:        import javax.swing.JLabel;
0034:        import javax.swing.JTable;
0035:        import javax.swing.JSpinner;
0036:        import javax.swing.JComboBox;
0037:        import javax.swing.JComponent;
0038:        import javax.swing.JScrollPane;
0039:        import javax.swing.BorderFactory;
0040:        import javax.swing.ComboBoxModel;
0041:        import javax.swing.table.TableModel;
0042:        import javax.swing.table.AbstractTableModel;
0043:
0044:        // Events
0045:        import java.awt.event.ItemEvent;
0046:        import java.awt.event.ItemListener;
0047:        import javax.swing.event.ChangeEvent;
0048:        import javax.swing.event.ListDataEvent;
0049:        import javax.swing.event.ChangeListener;
0050:        import javax.swing.event.ListDataListener;
0051:
0052:        // Utilities
0053:        import java.util.Map;
0054:        import java.util.TreeMap;
0055:        import java.util.HashMap;
0056:        import java.util.LinkedHashMap;
0057:        import java.util.Comparator;
0058:        import java.util.Iterator;
0059:        import java.util.Arrays;
0060:        import java.util.Locale;
0061:
0062:        // Geotools dependencies
0063:        import org.geotools.resources.XArray;
0064:        import org.geotools.resources.Utilities;
0065:        import org.geotools.resources.i18n.Vocabulary;
0066:        import org.geotools.resources.i18n.VocabularyKeys;
0067:        import org.geotools.resources.SwingUtilities;
0068:
0069:        /**
0070:         * A widget for selecting and/or editing a {@link KernelJAI} object. Kernels are used for
0071:         * {@linkplain ConvolveDescriptor image convolutions}. {@code KernelEditor} widgets are
0072:         * initially empty, but a set of default kernels can be added with {@link #addDefaultKernels}
0073:         * including (but not limited to)
0074:         *
0075:         * {@linkplain KernelJAI#ERROR_FILTER_FLOYD_STEINBERG Floyd & Steinberg (1975)},
0076:         * {@linkplain KernelJAI#ERROR_FILTER_JARVIS Jarvis, Judice & Ninke (1976)} and
0077:         * {@linkplain KernelJAI#ERROR_FILTER_STUCKI Stucki (1981)}.
0078:         *
0079:         * Each kernel can belong to an optional category. Example of categories includes
0080:         * "Error filters" and "Gradient masks".
0081:         *
0082:         * <p>&nbsp;</p>
0083:         * <p align="center"><img src="doc-files/KernelEditor.png"></p>
0084:         * <p>&nbsp;</p>
0085:         *
0086:         * @since 2.3
0087:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/widgets-swing/src/main/java/org/geotools/gui/swing/image/KernelEditor.java $
0088:         * @version $Id: KernelEditor.java 20883 2006-08-07 13:48:09Z jgarnett $
0089:         * @author Martin Desruisseaux
0090:         *
0091:         * @see GradientKernelEditor
0092:         * @see ConvolveDescriptor
0093:         * @see org.geotools.coverage.processing.operation.GradientMagnitude
0094:         */
0095:        public class KernelEditor extends JComponent {
0096:            /**
0097:             * The matrix coefficient as a table.
0098:             */
0099:            private final Model model = new Model();
0100:
0101:            /**
0102:             * The list of available filter's categories.
0103:             */
0104:            private final JComboBox categorySelector = new JComboBox();
0105:
0106:            /**
0107:             * The list of available kernels.
0108:             */
0109:            private final JComboBox kernelSelector = new JComboBox(model);
0110:
0111:            /**
0112:             * The matrix width.
0113:             */
0114:            private final JSpinner widthSelector = new JSpinner();
0115:
0116:            /**
0117:             * The matrix height.
0118:             */
0119:            private final JSpinner heightSelector = new JSpinner();
0120:
0121:            /**
0122:             * Constructs a new kernel editor. No kernel will be initially shown. The method
0123:             * {@link #setKernel} must be invoked, or the user must performs a selection in
0124:             * a combo box, in order to make a kernel visible.
0125:             */
0126:            public KernelEditor() {
0127:                setLayout(new GridBagLayout());
0128:                setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
0129:                final Vocabulary resources = Vocabulary
0130:                        .getResources(getDefaultLocale());
0131:
0132:                categorySelector.addItem(resources
0133:                        .getString(VocabularyKeys.ALL)); // Must be first category
0134:                categorySelector.addItemListener(model);
0135:                widthSelector.addChangeListener(model);
0136:                heightSelector.addChangeListener(model);
0137:
0138:                final JTable matrixView = new JTable(model);
0139:                matrixView.setTableHeader(null);
0140:                matrixView.setRowSelectionAllowed(false);
0141:                matrixView.setColumnSelectionAllowed(false);
0142:
0143:                final GridBagConstraints c = new GridBagConstraints();
0144:                final JPanel predefinedKernels = new JPanel(new GridBagLayout());
0145:
0146:                ////////////////////////////////////////////////////
0147:                ////                                            ////
0148:                ////    Put combo box for predefined kernels    ////
0149:                ////                                            ////
0150:                ////////////////////////////////////////////////////
0151:                c.gridx = 0;
0152:                c.fill = c.HORIZONTAL;
0153:                c.gridy = 2;
0154:                predefinedKernels.add(new JLabel(resources
0155:                        .getLabel(VocabularyKeys.CATEGORY), JLabel.RIGHT), c);
0156:                c.gridy = 3;
0157:                predefinedKernels.add(new JLabel(resources
0158:                        .getLabel(VocabularyKeys.KERNEL), JLabel.RIGHT), c);
0159:
0160:                c.gridx = 1;
0161:                c.weightx = 1;
0162:                c.insets.left = 0;
0163:                c.gridy = 2;
0164:                predefinedKernels.add(categorySelector, c);
0165:                c.gridy = 3;
0166:                predefinedKernels.add(kernelSelector, c);
0167:
0168:                c.gridx = 0;
0169:                c.gridy = 2;
0170:                c.gridwidth = c.REMAINDER;
0171:                add(predefinedKernels, c);
0172:                predefinedKernels.setBorder(BorderFactory.createCompoundBorder(
0173:                        BorderFactory.createTitledBorder(resources
0174:                                .getString(VocabularyKeys.PREDEFINED_KERNELS)),
0175:                        BorderFactory.createEmptyBorder(/*top*/3,/*left*/9,/*bottom*/
0176:                                6,/*right*/6)));
0177:
0178:                //////////////////////////////////////////////
0179:                ////                                      ////
0180:                ////    Put spinners for kernel's size    ////
0181:                ////                                      ////
0182:                //////////////////////////////////////////////
0183:                c.weightx = 0;
0184:                c.gridwidth = 1;
0185:                c.insets.bottom = 3;
0186:                c.gridy = 0;
0187:                add(new JLabel(resources.getLabel(VocabularyKeys.SIZE),
0188:                        JLabel.RIGHT), c);
0189:                c.gridx = 2;
0190:                add(new JLabel(' '
0191:                        + resources.getString(VocabularyKeys.LINES)
0192:                                .toLowerCase() + " \u00D7 ", JLabel.CENTER), c);
0193:                c.gridx = 4;
0194:                add(new JLabel(' ' + resources
0195:                        .getString(VocabularyKeys.COLUMNS).toLowerCase(),
0196:                        JLabel.LEFT), c);
0197:
0198:                c.weightx = 1;
0199:                c.gridx = 1;
0200:                add(heightSelector, c);
0201:                c.gridx = 3;
0202:                add(widthSelector, c);
0203:
0204:                /////////////////////////////////////////////////
0205:                ////                                         ////
0206:                ////    Put table for kernel coefficients    ////
0207:                ////                                         ////
0208:                /////////////////////////////////////////////////
0209:                c.gridx = 0;
0210:                c.gridwidth = c.REMAINDER;
0211:                c.fill = c.BOTH;
0212:                c.insets.bottom = 9;
0213:                c.gridy = 1;
0214:                c.weighty = 1;
0215:                c.insets.top = 6;
0216:                add(new JScrollPane(matrixView), c);
0217:                setPreferredSize(new Dimension(300, 220));
0218:            }
0219:
0220:            /**
0221:             * Returns the resources for the widget locale.
0222:             */
0223:            final Vocabulary getResources() {
0224:                Locale locale;
0225:                try {
0226:                    locale = getLocale();
0227:                } catch (IllegalComponentStateException exception) {
0228:                    locale = getDefaultLocale();
0229:                }
0230:                return Vocabulary.getResources(locale);
0231:            }
0232:
0233:            /**
0234:             * Add a set of predefined kernels. Default kernels includes (but is not limited to)
0235:             *
0236:             * {@linkplain KernelJAI#ERROR_FILTER_FLOYD_STEINBERG Floyd & Steinberg (1975)},
0237:             * {@linkplain KernelJAI#ERROR_FILTER_JARVIS Jarvis, Judice & Ninke (1976)} and
0238:             * {@linkplain KernelJAI#ERROR_FILTER_STUCKI Stucki (1981)}.
0239:             */
0240:            public void addDefaultKernels() {
0241:                final Vocabulary resources = getResources();
0242:                final String ERROR_FILTERS = resources
0243:                        .getString(VocabularyKeys.ERROR_FILTERS);
0244:                final String GRADIENT_MASKS = resources
0245:                        .getString(VocabularyKeys.GRADIENT_MASKS);
0246:                addKernel(ERROR_FILTERS, "Floyd & Steinberg (1975)",
0247:                        KernelJAI.ERROR_FILTER_FLOYD_STEINBERG);
0248:                addKernel(ERROR_FILTERS, "Jarvis, Judice & Ninke (1976)",
0249:                        KernelJAI.ERROR_FILTER_JARVIS);
0250:                addKernel(ERROR_FILTERS, "Stucki (1981)",
0251:                        KernelJAI.ERROR_FILTER_STUCKI);
0252:                /*
0253:                 * NOTE: Horizontal and vertical sobel masks seems to have been swapped in KernelJAI.
0254:                 *       See for example J.J. Simpson (1990) in Remote sensing environment, 33:17-33.
0255:                 *       See also some tests in a speadsheet.
0256:                 *       Is it an error in JAI 1.1.2 or a misunderstanding of mine?
0257:                 */
0258:                addKernel(GRADIENT_MASKS, "Sobel horizontal",
0259:                        KernelJAI.GRADIENT_MASK_SOBEL_VERTICAL);
0260:                addKernel(GRADIENT_MASKS, "Sobel vertical",
0261:                        KernelJAI.GRADIENT_MASK_SOBEL_HORIZONTAL);
0262:
0263:                addKernel("Sharp 1", new float[] { 0.0f, -1.0f, 0.0f, -1.0f,
0264:                        5.0f, -1.0f, 0.0f, -1.0f, 0.0f });
0265:
0266:                addKernel("Sharp 2", new float[] { -1.0f, -1.0f, -1.0f, -1.0f,
0267:                        9.0f, -1.0f, -1.0f, -1.0f, -1.0f });
0268:
0269:                addKernel("Sharp 3", new float[] { 1.0f, -2.0f, 1.0f, -2.0f,
0270:                        5.0f, -2.0f, 1.0f, -2.0f, 1.0f });
0271:
0272:                addKernel("Sharp 4", new float[] { -1.0f, 1.0f, -1.0f, 1.0f,
0273:                        1.0f, 1.0f, -1.0f, 1.0f, -1.0f });
0274:
0275:                addKernel("Laplace 1", new float[] { 0.0f, -1.0f, 0.0f, -1.0f,
0276:                        4.0f, -1.0f, 0.0f, -1.0f, 0.0f });
0277:
0278:                addKernel("Laplace 2", new float[] { -1.0f, -1.0f, -1.0f,
0279:                        -1.0f, 8.0f, -1.0f, -1.0f, -1.0f, -1.0f });
0280:
0281:                addKernel("Box", new float[] { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
0282:                        1.0f, 1.0f, 1.0f, 1.0f });
0283:
0284:                addKernel("Low pass", new float[] { 1.0f, 2.0f, 1.0f, 2.0f,
0285:                        4.0f, 2.0f, 1.0f, 2.0f, 1.0f });
0286:
0287:                if (model.getRowCount() * model.getColumnCount() == 0) {
0288:                    setKernel("Box");
0289:                }
0290:            }
0291:
0292:            /**
0293:             * Adds a 3x3 kernel to the list of available kernels.
0294:             */
0295:            private void addKernel(final String name, final float[] data) {
0296:                double sum = 0;
0297:                for (int i = 0; i < data.length; i++) {
0298:                    sum += data[i];
0299:                }
0300:                if (sum != 0) {
0301:                    for (int i = 0; i < data.length; i++) {
0302:                        data[i] /= sum;
0303:                    }
0304:                }
0305:                addKernel(null, name, new KernelJAI(3, 3, data));
0306:            }
0307:
0308:            /**
0309:             * Adds a kernel to the list of available kernels. The widget list kernels in the same order
0310:             * they were added, unless {@link #sortKernelNames} has been invoked. Each kernel can belong
0311:             * to an optional category. Example of categories includes "Error filters" and "Gradient masks".
0312:             *
0313:             * @param category The kernel's category name, or {@code null} if none.
0314:             * @param name The kernel name. Kernels will be displayed in alphabetic order.
0315:             * @param kernel The kernel. If an other kernel was registered with the same
0316:             *        name, the previous kernel will be discarted.
0317:             */
0318:            public void addKernel(String category, final String name,
0319:                    final KernelJAI kernel) {
0320:                if (category == null) {
0321:                    category = Vocabulary.getResources(getLocale()).getString(
0322:                            VocabularyKeys.OTHERS);
0323:                }
0324:                model.addKernel(category, name, kernel);
0325:            }
0326:
0327:            /**
0328:             * Adds a new category if not already present.
0329:             */
0330:            private void addCategory(final String category) {
0331:                final ComboBoxModel categories = categorySelector.getModel();
0332:                for (int i = categories.getSize(); --i >= 0;) {
0333:                    if (category.equals(categories.getElementAt(i))) {
0334:                        return;
0335:                    }
0336:                }
0337:                categorySelector.addItem(category);
0338:            }
0339:
0340:            /**
0341:             * Removes a kernel. If the kernel was the only one in
0342:             * its category, the category is removed as well.
0343:             */
0344:            public void removeKernel(final KernelJAI kernel) {
0345:                model.removeKernel(kernel);
0346:            }
0347:
0348:            /**
0349:             * Removes a kernel by its name. If the kernel was the only
0350:             * one in its category, the category is removed as well.
0351:             */
0352:            public void removeKernel(final String kernel) {
0353:                removeKernel(model.getKernel(kernel));
0354:            }
0355:
0356:            /**
0357:             * Removes all kernels and categories.
0358:             */
0359:            public void removeAllKernels() {
0360:                model.removeAllKernels();
0361:            }
0362:
0363:            /**
0364:             * Set the kernel. The table size will be set to the specified kernel size, add all
0365:             * coefficients will be copied in the table. If the specified kernel matches one of
0366:             * the kernel registered with the {@link #addKernel addKernel} method, then the kernel
0367:             * name and category will be updated according.
0368:             *
0369:             * @param kernel The new kernel.
0370:             */
0371:            public void setKernel(final KernelJAI kernel) {
0372:                model.setKernel(kernel);
0373:                model.findKernelName();
0374:            }
0375:
0376:            /**
0377:             * Set the kernel by its name. It must be one of the name registered with {@link #addKernel}.
0378:             * If {@code name} is not found, then nothing is done.
0379:             *
0380:             * @param name The name of the kernel to select.
0381:             */
0382:            public void setKernel(final String name) {
0383:                kernelSelector.setSelectedItem(name);
0384:                kernelSelector.repaint();
0385:            }
0386:
0387:            /**
0388:             * Set the size of the current kernel.
0389:             *
0390:             * @param width  The number of rows.
0391:             * @param height The number of columns.
0392:             */
0393:            public void setKernelSize(final int width, final int height) {
0394:                model.setKernelSize(height, width); // Inverse argument order.
0395:                model.findKernelName();
0396:            }
0397:
0398:            /**
0399:             * Returns the currently edited kernel.
0400:             *
0401:             * @return The edited kernel.
0402:             */
0403:            public KernelJAI getKernel() {
0404:                return model.getKernel();
0405:            }
0406:
0407:            /**
0408:             * Returns the category for the current kernel. This is the {@code category} argument
0409:             * given to <code>{@linkplain #addKernel addKernel}(category, name, kernel)</code>, where
0410:             * {@code kernel} is the {@linkplain #getKernel current kernel}.
0411:             *
0412:             * @return The category for the current kernel, or {@code null} if none.
0413:             */
0414:            public String getKernelCategory() {
0415:                // Category at index 0 is "all", which need a special handling.
0416:                return categorySelector.getSelectedIndex() <= 0 ? null
0417:                        : (String) categorySelector.getSelectedItem();
0418:            }
0419:
0420:            /**
0421:             * Sort all kernel names according the specified comparator.
0422:             *
0423:             * @param comparator The comparator, or {@code null} for the natural ordering.
0424:             */
0425:            public void sortKernelNames(final Comparator comparator) {
0426:                model.sortKernelNames(comparator);
0427:            }
0428:
0429:            /**
0430:             * Returns an array of kernel names in the current category.
0431:             * Changes in the returned array will not affect the {@code KernelEditor} state.
0432:             *
0433:             * @return The name of all kernels in the current category.
0434:             */
0435:            public String[] getKernelNames() {
0436:                return (String[]) model.getKernelNames().clone();
0437:            }
0438:
0439:            /**
0440:             * Returns the list of predefined kernels in the current category. The content of
0441:             * this list will changes every time a kernel is {@linkplain #addKernel added} or
0442:             * {@linkplain #removeKernel(KernelJAI) removed} and every time the user selects a
0443:             * new category. The selected item can change at any time as well, according user action.
0444:             */
0445:            public ComboBoxModel getKernelListModel() {
0446:                return model;
0447:            }
0448:
0449:            /**
0450:             * Returns the table model containing the current kernel coefficients. The content of this
0451:             * table will changes every time the user select a new predefined kernel, or when the user
0452:             * edit cell values.
0453:             */
0454:            public TableModel getKernelTableModel() {
0455:                return model;
0456:            }
0457:
0458:            /**
0459:             * The table and list model to use. The list model contains a list of
0460:             * predefined kernels. The table model contains coefficients for the
0461:             * currently selected kernel. This object is also a listener for various
0462:             * events (like changing the size of the table).
0463:             *
0464:             * @version $Id: KernelEditor.java 20883 2006-08-07 13:48:09Z jgarnett $
0465:             * @author Martin Desruisseaux
0466:             */
0467:            private final class Model extends AbstractTableModel implements 
0468:                    ComboBoxModel, ChangeListener, ItemListener {
0469:                /**
0470:                 * Dictionnary of kernels by their name.
0471:                 * Keys are {@link String} and values are {@link KernelJAI}.
0472:                 */
0473:                private final Map kernels = new HashMap();
0474:
0475:                /**
0476:                 * List of categories by kernel's name.
0477:                 * Keys and values are both {@link String}.
0478:                 */
0479:                private final Map categories = new LinkedHashMap();
0480:
0481:                /**
0482:                 * {@code true} if the keys into {@link #categories}
0483:                 * are sorted according their <em>natural</em> ordering.
0484:                 */
0485:                private boolean sorted;
0486:
0487:                /**
0488:                 * List of kernel names in alphabetical order.
0489:                 * This list is constructed only when first needed.
0490:                 */
0491:                private String[] names;
0492:
0493:                /**
0494:                 * Name of the current kernel, or {@code null}
0495:                 * if the user is editing a custom kernel.
0496:                 */
0497:                private String name;
0498:
0499:                /**
0500:                 * Array of elements for the current kernel.
0501:                 */
0502:                private float[][] elements = new float[0][];
0503:
0504:                /**
0505:                 * Returns the number of kernels in the list.
0506:                 * Used by the combox box of kernel names.
0507:                 */
0508:                public int getSize() {
0509:                    return getKernelNames().length;
0510:                }
0511:
0512:                /**
0513:                 * Returns the number of rows in the kernel.
0514:                 * Used by the table of kernel values.
0515:                 */
0516:                public int getRowCount() {
0517:                    return elements.length;
0518:                }
0519:
0520:                /**
0521:                 * Returns the number of columns in the model.
0522:                 * Used by the table of kernel values.
0523:                 */
0524:                public int getColumnCount() {
0525:                    return (elements.length != 0) ? elements[0].length : 0;
0526:                }
0527:
0528:                /**
0529:                 * Returns {@code true} regardless of row and column index
0530:                 * Used by the table of kernel values.
0531:                 */
0532:                public boolean isCellEditable(final int rowIndex,
0533:                        final int columnIndex) {
0534:                    return true;
0535:                }
0536:
0537:                /**
0538:                 * Returns {@code Float.class} regardless of column index
0539:                 * Used by the table of kernel values.
0540:                 */
0541:                public Class getColumnClass(final int columnIndex) {
0542:                    return Float.class;
0543:                }
0544:
0545:                /**
0546:                 * Returns the value for the cell at {@code columnIndex} and {@code rowIndex}.
0547:                 * This method is automatically invoked in order to paint the kernel as a table.
0548:                 */
0549:                public Object getValueAt(final int rowIndex,
0550:                        final int columnIndex) {
0551:                    return new Float(elements[rowIndex][columnIndex]);
0552:                }
0553:
0554:                /**
0555:                 * Set the value for the cell at {@code columnIndex} and {@code rowIndex}.
0556:                 * This method is automatically invoked when the user edited one of kernel values.
0557:                 */
0558:                public void setValueAt(final Object value, final int rowIndex,
0559:                        final int columnIndex) {
0560:                    elements[rowIndex][columnIndex] = (value != null) ? ((Number) value)
0561:                            .floatValue()
0562:                            : 0;
0563:                    fireTableCellUpdated(rowIndex, columnIndex);
0564:                    findKernelName();
0565:                }
0566:
0567:                /**
0568:                 * Returns the kernel at the specified index.
0569:                 * Used by the combox box of kernel names.
0570:                 */
0571:                public Object getElementAt(final int index) {
0572:                    return getKernelNames()[index];
0573:                }
0574:
0575:                /**
0576:                 * Returns the selected kernel name (never {@code null}).
0577:                 * Used by the combox box of kernel names.
0578:                 */
0579:                public Object getSelectedItem() {
0580:                    return (name != null) ? name
0581:                            : getString(VocabularyKeys.PERSONALIZED);
0582:                }
0583:
0584:                /**
0585:                 * Set the selected kernel by its name (never {@code null}).
0586:                 * Used by the combox box of kernel names.
0587:                 */
0588:                public void setSelectedItem(final Object item) {
0589:                    final String newName = item.toString();
0590:                    if (!newName.equals(name)) {
0591:                        // 'kernel' may be null if 'item' is the "Personalized" kernel name.
0592:                        final KernelJAI kernel = (KernelJAI) kernels
0593:                                .get(newName);
0594:                        if (kernel != null) {
0595:                            setKernel(kernel);
0596:                        }
0597:                        categorySelector.setSelectedItem(categories
0598:                                .get(newName));
0599:                        this .name = newName;
0600:                    }
0601:                }
0602:
0603:                /**
0604:                 * Returns the current kernel.
0605:                 *
0606:                 * @see KernelEditor#getKernel
0607:                 */
0608:                public KernelJAI getKernel() {
0609:                    final int height = elements.length;
0610:                    final int width = height != 0 ? elements[0].length : 0;
0611:                    final float[] data = new float[width * height];
0612:                    int c = 0;
0613:                    for (int j = 0; j < height; j++) {
0614:                        for (int i = 0; i < width; i++) {
0615:                            data[c++] = elements[j][i];
0616:                        }
0617:                    }
0618:                    return new KernelJAI(width, height, data);
0619:                }
0620:
0621:                /**
0622:                 * Set the kernel. The table size will be set to the specified kernel size, add all
0623:                 * coefficients will be copied in the table. If the specified kernel matches one of
0624:                 * the kernel registered with the {@link #addKernel addKernel} method, then the kernel
0625:                 * name and category will be updated according.
0626:                 *
0627:                 * @see KernelEditor#setKernel
0628:                 */
0629:                public void setKernel(final KernelJAI kernel) {
0630:                    final int rowCount = kernel.getHeight();
0631:                    final int colCount = kernel.getWidth();
0632:                    setKernelSize(rowCount, colCount);
0633:                    for (int j = 0; j < rowCount; j++) {
0634:                        for (int i = 0; i < colCount; i++) {
0635:                            elements[j][i] = kernel.getElement(i, j);
0636:                        }
0637:                    }
0638:                    fireTableDataChanged();
0639:                }
0640:
0641:                /**
0642:                 * Set the size of the current kernel.
0643:                 *
0644:                 * @param width  The number of rows.
0645:                 * @param height The number of columns.
0646:                 *
0647:                 * @see KernelEditor#setKernelSize
0648:                 */
0649:                public void setKernelSize(final int rowCount, final int colCount) {
0650:                    final int oldRowCount = elements.length;
0651:                    final int oldColCount = oldRowCount != 0 ? elements[0].length
0652:                            : 0;
0653:                    if (rowCount != oldRowCount || colCount != oldColCount) {
0654:                        elements = (float[][]) XArray
0655:                                .resize(elements, rowCount);
0656:                        for (int i = 0; i < elements.length; i++) {
0657:                            if (elements[i] == null) {
0658:                                elements[i] = new float[colCount];
0659:                            } else {
0660:                                elements[i] = XArray.resize(elements[i],
0661:                                        colCount);
0662:                            }
0663:                        }
0664:                        if (colCount != oldColCount) {
0665:                            fireTableStructureChanged();
0666:                        } else if (rowCount > oldRowCount) {
0667:                            fireTableRowsInserted(oldRowCount, rowCount - 1);
0668:                        } else if (rowCount < oldRowCount) {
0669:                            fireTableRowsDeleted(rowCount, oldRowCount - 1);
0670:                        }
0671:                        widthSelector.setValue(new Integer(colCount));
0672:                        heightSelector.setValue(new Integer(rowCount));
0673:                    }
0674:                }
0675:
0676:                /**
0677:                 * Returns the index of the specified kernel name in the specified category,
0678:                 * or -1 if it was not found.   This method is invoked by {@link #addKernel}
0679:                 * and {@link #removeKernel} in order to determine the range of index values
0680:                 * to give to {@link ListDataEvent}.
0681:                 *
0682:                 * @param category The kernel category. Only kernels in this category will
0683:                 *        be taken in account. This argument is usually provided by
0684:                 *        {@link KernelEditor#getKernelCategory}. {@code null}
0685:                 *        is a special value taking all categories in account.
0686:                 * @param toSearch The name of the kernel to search.
0687:                 */
0688:                private int indexOf(final String category, final String toSearch) {
0689:                    int index = 0;
0690:                    for (final Iterator it = categories.entrySet().iterator(); it
0691:                            .hasNext();) {
0692:                        final Map.Entry entry = (Map.Entry) it.next();
0693:                        final String name = (String) entry.getKey();
0694:                        if (category == null
0695:                                || category.equals(entry.getValue())) {
0696:                            // A kernel of the required category has been found.
0697:                            if (toSearch.equals(name)) {
0698:                                // Found the kernel we are looking for.
0699:                                assert !sorted
0700:                                        || Arrays.binarySearch(
0701:                                                getKernelNames(), toSearch) == index;
0702:                                return index;
0703:                            }
0704:                            // Right category, but wrong kernel.
0705:                            index++;
0706:                        }
0707:                        if (sorted && name.compareTo(toSearch) >= 0) {
0708:                            // Since kernel names are sorted, there is no
0709:                            // need to continue the iteration past this point.
0710:                            break;
0711:                        }
0712:                    }
0713:                    assert !sorted
0714:                            || Arrays.binarySearch(getKernelNames(), toSearch) < 0;
0715:                    return -1;
0716:                }
0717:
0718:                /**
0719:                 * Adds a kernel to the list of available kernels. Each kernel can belong to an optional
0720:                 * category. Example of categories includes "Error filters" and "Gradient masks".
0721:                 *
0722:                 * @param category The kernel's category name, which <strong>must not</strong> be
0723:                 *        {@code null}. The public method in {@link KernelEditor} is responsible
0724:                 *        for substituing a string (usually "Others" or "Personalized") in place of the
0725:                 *        null value.
0726:                 * @param name The kernel name. Kernels will be displayed in alphabetic order.
0727:                 * @param kernel The kernel. If an other kernel was registered with the same
0728:                 *        name, the previous kernel will be discarted.
0729:                 *
0730:                 * @see KernelEditor#addKernel
0731:                 */
0732:                public void addKernel(final String category, final String name,
0733:                        final KernelJAI kernel) {
0734:                    sorted = false;
0735:                    if (!category.equals(categories.put(name, category))) {
0736:                        // The category doesn't already exists.
0737:                        addCategory(category);
0738:                    }
0739:                    if (kernels.put(name, kernel) != null) {
0740:                        // The new kernel replace an existing one.
0741:                        findKernelName();
0742:                    } else {
0743:                        // The kernel must be added to existing ones.
0744:                        final String cc = getKernelCategory();
0745:                        if (cc == null || category.equals(cc)) {
0746:                            names = null; // Must be before 'indexOf'
0747:                            final int index = indexOf(cc, name);
0748:                            assert index >= 0 : name;
0749:                            fireListChanged(ListDataEvent.INTERVAL_ADDED,
0750:                                    index, index);
0751:                        }
0752:                    }
0753:                    assert kernels.size() == categories.size();
0754:                }
0755:
0756:                /**
0757:                 * Removes a kernel. If the kernel was the only one in
0758:                 * its category, the category is removed as well.
0759:                 *
0760:                 * @see KernelEditor#removeKernel
0761:                 */
0762:                public void removeKernel(final KernelJAI kernel) {
0763:                    final String cc = getKernelCategory();
0764:                    for (final Iterator it = kernels.entrySet().iterator(); it
0765:                            .hasNext();) {
0766:                        final Map.Entry entry = (Map.Entry) it.next();
0767:                        if (kernel.equals(entry.getValue())) {
0768:                            // Found the kernel to remove.
0769:                            final String name = (String) entry.getKey();
0770:                            final int index = indexOf(cc, name); // Must be before any remove.
0771:                            final String category = (String) categories
0772:                                    .remove(name);
0773:                            if (!categories.values().contains(category)) {
0774:                                // No other kernel in this category.
0775:                                categorySelector.removeItem(category);
0776:                            }
0777:                            it.remove();
0778:                            if (index >= 0) {
0779:                                names = null; // Must be after 'it.remove'
0780:                                fireListChanged(ListDataEvent.INTERVAL_REMOVED,
0781:                                        index, index);
0782:                            }
0783:                        }
0784:                    }
0785:                    assert kernels.size() == categories.size();
0786:                }
0787:
0788:                /**
0789:                 * Removes all kernels and categories.
0790:                 *
0791:                 * @see KernelEditor#removeAllKernels
0792:                 */
0793:                public void removeAllKernels() {
0794:                    final int size = kernels.size();
0795:                    kernels.clear();
0796:                    categories.clear();
0797:                    names = null;
0798:                    fireListChanged(ListDataEvent.INTERVAL_REMOVED, 0, size - 1);
0799:                    categorySelector.removeAllItems();
0800:                    categorySelector.addItem(getResources().getString(
0801:                            VocabularyKeys.ALL));
0802:                }
0803:
0804:                /**
0805:                 * Returns a kernel by its name.
0806:                 *
0807:                 * @param  name The kernel name.
0808:                 * @return The kernel, or {@code null} if there is no kernel for the specified name.
0809:                 */
0810:                public KernelJAI getKernel(final String name) {
0811:                    return (KernelJAI) kernels.get(name);
0812:                }
0813:
0814:                /**
0815:                 * Returns the array of kernel names. <strong>This method
0816:                 * returns the array by reference; do not modify!</strong>.
0817:                 *
0818:                 * @see KernelEditor#getKernelNames
0819:                 */
0820:                public String[] getKernelNames() {
0821:                    if (names == null) {
0822:                        int count = 0;
0823:                        names = new String[kernels.size() + 1];
0824:                        final String category = getKernelCategory();
0825:                        for (final Iterator it = categories.entrySet()
0826:                                .iterator(); it.hasNext();) {
0827:                            final Map.Entry entry = (Map.Entry) it.next();
0828:                            if (category == null
0829:                                    || category.equals(entry.getValue())) {
0830:                                names[count++] = (String) entry.getKey();
0831:                            }
0832:                        }
0833:                        names[count++] = getString(VocabularyKeys.PERSONALIZED);
0834:                        names = (String[]) XArray.resize(names, count);
0835:                    }
0836:                    return names;
0837:                }
0838:
0839:                /**
0840:                 * Find the name for the current kernel. If such a name is
0841:                 * found, it will be given to the combo-box. Otherwise,
0842:                 * nothing is done.
0843:                 */
0844:                protected void findKernelName() {
0845:                    String newName = null; // "Personalized"
0846:                    final int rowCount = elements.length;
0847:                    final int colCount = rowCount != 0 ? elements[0].length : 0;
0848:                    iter: for (final Iterator it = kernels.entrySet()
0849:                            .iterator(); it.hasNext();) {
0850:                        final Map.Entry entry = (Map.Entry) it.next();
0851:                        final KernelJAI kernel = (KernelJAI) entry.getValue();
0852:                        if (rowCount == kernel.getHeight()
0853:                                && colCount == kernel.getWidth()) {
0854:                            for (int j = 0; j < rowCount; j++) {
0855:                                for (int i = 0; i < colCount; i++) {
0856:                                    if (elements[j][i] != kernel.getElement(i,
0857:                                            j)) {
0858:                                        continue iter;
0859:                                    }
0860:                                }
0861:                            }
0862:                            newName = (String) entry.getKey();
0863:                        }
0864:                    }
0865:                    if (newName == null) {
0866:                        newName = getString(VocabularyKeys.PERSONALIZED);
0867:                    }
0868:                    if (!newName.equals(name)) {
0869:                        // Set the name now in order to avoid that
0870:                        // setSelectedItem invokes setKernel again.
0871:                        this .name = newName;
0872:                        categorySelector.setSelectedItem(categories
0873:                                .get(newName));
0874:                        kernelSelector.setSelectedItem(newName);
0875:                        kernelSelector.repaint(); // JComboBox doesn't seems to repaint by itself.
0876:                    }
0877:                }
0878:
0879:                /**
0880:                 * Sorts all kernel names according the specified comparator.
0881:                 *
0882:                 * @param comparator The comparator, or {@code null} for the natural ordering.
0883:                 *
0884:                 * @see KernelEditor#sortKernelNames
0885:                 */
0886:                public void sortKernelNames(final Comparator comparator) {
0887:                    final Map sorted = new TreeMap(comparator);
0888:                    sorted.putAll(categories);
0889:                    categories.clear();
0890:                    categories.putAll(sorted);
0891:                    names = null;
0892:                    this .sorted = (comparator == null);
0893:                    fireListChanged(ListDataEvent.CONTENTS_CHANGED, 0,
0894:                            categories.size() - 1);
0895:                }
0896:
0897:                /**
0898:                 * Invoked when a {@link JSpinner} has changed its state.
0899:                 * This method reset the matrix size according the new
0900:                 * spinner value.
0901:                 */
0902:                public void stateChanged(final ChangeEvent event) {
0903:                    final int rowCount = ((Number) heightSelector.getValue())
0904:                            .intValue();
0905:                    final int colCount = ((Number) widthSelector.getValue())
0906:                            .intValue();
0907:                    setKernelSize(rowCount, colCount);
0908:                    findKernelName();
0909:                }
0910:
0911:                /**
0912:                 * Invoked when the user selected a new kernel category.
0913:                 * The kernel list must be cleared and reconstructed.
0914:                 */
0915:                public void itemStateChanged(final ItemEvent event) {
0916:                    if (event.getStateChange() == ItemEvent.SELECTED) {
0917:                        names = null;
0918:                        fireListChanged(ListDataEvent.CONTENTS_CHANGED, 0,
0919:                                categories.size());
0920:                    }
0921:                }
0922:
0923:                /**
0924:                 * Convenience method returning a string for the specified resource keys.
0925:                 */
0926:                private String getString(final int key) {
0927:                    return getResources().getString(key);
0928:                }
0929:
0930:                /**
0931:                 * Adds a listener to the list that's notified
0932:                 * each time a change to the data model occurs.
0933:                 */
0934:                public void addListDataListener(final ListDataListener listener) {
0935:                    listenerList.add(ListDataListener.class, listener);
0936:                }
0937:
0938:                /**
0939:                 * Removes a listener from the list that's notified
0940:                 * each time a change to the data model occurs.
0941:                 */
0942:                public void removeListDataListener(
0943:                        final ListDataListener listener) {
0944:                    listenerList.remove(ListDataListener.class, listener);
0945:                }
0946:
0947:                /**
0948:                 * Invoked after one or more kernels are added to the model.
0949:                 *
0950:                 * @param type Must be one of {@link ListDataEvent#CONTENTS_CHANGED},
0951:                 *        {@link ListDataEvent#INTERVAL_ADDED} or {@link ListDataEvent#INTERVAL_REMOVED}.
0952:                 * @param index0 Lower index, inclusive.
0953:                 * @param index1 Upper index, <strong>inclusive</strong>.
0954:                 */
0955:                private void fireListChanged(final int type, final int index0,
0956:                        final int index1) {
0957:                    ListDataEvent event = null;
0958:                    final Object[] listeners = listenerList.getListenerList();
0959:                    for (int i = listeners.length; (i -= 2) >= 0;) {
0960:                        if (listeners[i] == ListDataListener.class) {
0961:                            if (event == null) {
0962:                                event = new ListDataEvent(this , type, index0,
0963:                                        index1);
0964:                            }
0965:                            final ListDataListener listener = (ListDataListener) listeners[i + 1];
0966:                            switch (type) {
0967:                            case ListDataEvent.CONTENTS_CHANGED:
0968:                                listener.contentsChanged(event);
0969:                                break;
0970:                            case ListDataEvent.INTERVAL_ADDED:
0971:                                listener.intervalAdded(event);
0972:                                break;
0973:                            case ListDataEvent.INTERVAL_REMOVED:
0974:                                listener.intervalRemoved(event);
0975:                                break;
0976:                            }
0977:                        }
0978:                    }
0979:                }
0980:            }
0981:
0982:            /**
0983:             * Shows a dialog box requesting input from the user. If {@code owner} is contained into a
0984:             * {@link javax.swing.JDesktopPane}, the dialog box will appears as an internal frame. This
0985:             * method can be invoked from any thread (may or may not be the <cite>Swing</cite> thread).
0986:             *
0987:             * @param  owner The parent component for the dialog box, or {@code null} if there is no parent.
0988:             * @param  title The dialog box title.
0989:             * @return {@code true} if user pressed the "Ok" button, or {@code false} otherwise
0990:             *         (e.g. pressing "Cancel" or closing the dialog box from the title bar).
0991:             */
0992:            public boolean showDialog(final Component owner, final String title) {
0993:                return SwingUtilities.showOptionDialog(owner, this , title);
0994:            }
0995:
0996:            /**
0997:             * Show the dialog box. This method is provided only as an easy
0998:             * way to test the dialog appearance from the command line.
0999:             */
1000:            public static void main(final String[] args) {
1001:                final KernelEditor editor = new KernelEditor();
1002:                editor.addDefaultKernels();
1003:                editor.showDialog(null, Utilities.getShortClassName(editor));
1004:            }
1005:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.