| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| IIOMetadataPanel |
|
| 3.8;3,8 | ||||
| IIOMetadataPanel$Controller |
|
| 3.8;3,8 |
| 1 | /* | |
| 2 | * Geotoolkit.org - An Open Source Java GIS Toolkit | |
| 3 | * http://www.geotoolkit.org | |
| 4 | * | |
| 5 | * (C) 2009-2012, Open Source Geospatial Foundation (OSGeo) | |
| 6 | * (C) 2009-2012, Geomatys | |
| 7 | * | |
| 8 | * This library is free software; you can redistribute it and/or | |
| 9 | * modify it under the terms of the GNU Lesser General Public | |
| 10 | * License as published by the Free Software Foundation; | |
| 11 | * version 2.1 of the License. | |
| 12 | * | |
| 13 | * This library is distributed in the hope that it will be useful, | |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 16 | * Lesser General Public License for more details. | |
| 17 | */ | |
| 18 | package org.geotoolkit.gui.swing.image; | |
| 19 | ||
| 20 | import java.util.Map; | |
| 21 | import java.util.List; | |
| 22 | import java.util.Locale; | |
| 23 | import java.util.ArrayList; | |
| 24 | import java.util.LinkedHashMap; | |
| 25 | import java.util.IdentityHashMap; | |
| 26 | import java.awt.*; | |
| 27 | import java.awt.event.ActionEvent; | |
| 28 | import java.awt.event.ActionListener; | |
| 29 | import javax.swing.*; | |
| 30 | import javax.swing.tree.TreePath; | |
| 31 | import javax.swing.event.TreeSelectionEvent; | |
| 32 | import javax.swing.event.TreeSelectionListener; | |
| 33 | import javax.imageio.metadata.IIOMetadata; | |
| 34 | import javax.imageio.metadata.IIOMetadataFormat; | |
| 35 | import javax.imageio.metadata.IIOMetadataFormatImpl; | |
| 36 | ||
| 37 | import org.jdesktop.swingx.JXTreeTable; | |
| 38 | ||
| 39 | import org.geotoolkit.resources.Vocabulary; | |
| 40 | import org.geotoolkit.util.NumberRange; | |
| 41 | import org.geotoolkit.util.converter.Classes; | |
| 42 | import org.geotoolkit.image.io.metadata.MetadataTreeNode; | |
| 43 | import org.geotoolkit.image.io.metadata.MetadataTreeTable; | |
| 44 | import org.geotoolkit.image.io.metadata.SpatialMetadataFormat; | |
| 45 | import org.geotoolkit.internal.swing.ComboBoxRenderer; | |
| 46 | ||
| 47 | ||
| 48 | /** | |
| 49 | * A panel showing the content of an {@link IIOMetadata} instance. This panel contains three parts: | |
| 50 | * <p> | |
| 51 | * <ul> | |
| 52 | * <li>At the top, a field allowing to select which metadata to display: | |
| 53 | * <ul> | |
| 54 | * <li>The metadata format, typically | |
| 55 | * {@value org.geotoolkit.image.io.metadata.SpatialMetadataFormat#FORMAT_NAME} or | |
| 56 | * {@value javax.imageio.metadata.IIOMetadataFormatImpl#standardMetadataFormatName}. | |
| 57 | * </li> | |
| 58 | * <li>The metadata part to display: <cite>stream</cite> metadata or one of the | |
| 59 | * <cite>image</cite> metadata.</li> | |
| 60 | * </ul> | |
| 61 | * </li> | |
| 62 | * <li>At the center, the metadata as a {@linkplain JXTreeTable tree table}. | |
| 63 | * The columns are documented in {@link MetadataTreeTable} javadoc.</li> | |
| 64 | * <li>At the bottom, a description of the currently selected metadata node.</li> | |
| 65 | * </ul> | |
| 66 | * <p> | |
| 67 | * Most columns are hiden by default. The initial view shows only (<var>name</var>, <var>value</var>) pairs in | |
| 68 | * the {@link IIOMetadata} case, or (<var>name</var>, <var>type</var>) pairs in the {@link IIOMetadataFormat} | |
| 69 | * case. Users can make additional columns visible by clicking on the icon in the upper-right corner. | |
| 70 | * <p> | |
| 71 | * This class can be used in two ways (choose only one): | |
| 72 | * <p> | |
| 73 | * <ul> | |
| 74 | * <li>For displaying the structure of {@link IIOMetadataFormat} instances without data, | |
| 75 | * invoke {@link #addMetadataFormat addMetadataFormat(...)}.</li> | |
| 76 | * | |
| 77 | * <li>For displaying the actual content of {@link IIOMetadata} instances, invoke | |
| 78 | * {@link #addMetadata addMetadata(...)}.</li> | |
| 79 | * </ul> | |
| 80 | * | |
| 81 | * <table cellspacing="24" cellpadding="12" align="center"><tr valign="top"> | |
| 82 | * <td width="500" bgcolor="lightblue"> | |
| 83 | * {@section Demo} | |
| 84 | * To try this component in your browser, see the | |
| 85 | * <a href="http://www.geotoolkit.org/demos/geotk-simples/applet/IIOMetadataPanel.html">demonstration applet</a>. | |
| 86 | * </td></tr></table> | |
| 87 | * | |
| 88 | * @author Martin Desruisseaux (Geomatys) | |
| 89 | * @version 3.12 | |
| 90 | * | |
| 91 | * @see MetadataTreeTable | |
| 92 | * | |
| 93 | * @since 3.05 | |
| 94 | * @module | |
| 95 | */ | |
| 96 | @SuppressWarnings("serial") | |
| 97 | public class IIOMetadataPanel extends JComponent { | |
| 98 | /** | |
| 99 | * The choices of metadata format. Typical choices are | |
| 100 | * {@value org.geotoolkit.image.io.metadata.SpatialMetadataFormat#FORMAT_NAME} and | |
| 101 | * {@value javax.imageio.metadata.IIOMetadataFormatImpl#standardMetadataFormatName}. | |
| 102 | */ | |
| 103 | private final DefaultComboBoxModel formatChoices; | |
| 104 | ||
| 105 | /** | |
| 106 | * The properties of the currently selected metadata node. | |
| 107 | */ | |
| 108 | private final JLabel description, validValues; | |
| 109 | ||
| 110 | /** | |
| 111 | * The unique instance of the set of listeners which is associated to this panel. | |
| 112 | */ | |
| 113 | private final Controller controller; | |
| 114 | ||
| 115 | /** | |
| 116 | * The name of images for each index. This is an undocumented feature for now. | |
| 117 | */ | |
| 118 | transient List<String> imageNames; | |
| 119 | ||
| 120 | /** | |
| 121 | * Creates a panel with no initial metadata. One of the {@code addXXXMetadata} or | |
| 122 | * {@code addXXXMetadataFormat} methods should be invoked in order to display a content. | |
| 123 | */ | |
| 124 | 2 | public IIOMetadataPanel() { |
| 125 | 2 | setLayout(new BorderLayout()); |
| 126 | // If the preferred width is modified, consider updating the | |
| 127 | // preferred column width in IIOMetadataTreeTable constructor. | |
| 128 | 2 | setPreferredSize(new Dimension(500, 400)); |
| 129 | 2 | final JComponent tables = new JPanel(new CardLayout()); |
| 130 | 2 | add(tables, BorderLayout.CENTER); |
| 131 | 2 | final Vocabulary resources = Vocabulary.getResources(getLocale()); |
| 132 | /* | |
| 133 | * Add the control button on top of the metadata table. | |
| 134 | */ | |
| 135 | 2 | formatChoices = new DefaultComboBoxModel(); |
| 136 | 2 | final JComboBox formats = new JComboBox(formatChoices); |
| 137 | 2 | ComboBoxRenderer.install(formats); |
| 138 | 2 | formats.setName("Formats"); |
| 139 | if (true) { | |
| 140 | 2 | final JPanel controls = new JPanel(new GridBagLayout()); |
| 141 | 2 | final GridBagConstraints c = new GridBagConstraints(); |
| 142 | 2 | final Insets ci = c.insets; |
| 143 | 2 | ci.left = 12; |
| 144 | 2 | c.gridy=0; ci.top=6; ci.bottom=0; |
| 145 | 2 | c.gridx=0; c.weightx=0; c.anchor=GridBagConstraints.WEST; |
| 146 | 2 | controls.add(label(resources, Vocabulary.Keys.FORMAT, formats), c); |
| 147 | 2 | c.insets.right = 12; c.insets.left = 0; |
| 148 | 2 | c.gridx=1; c.weightx=1; c.fill=GridBagConstraints.BOTH; |
| 149 | 2 | controls.add(formats, c); |
| 150 | 2 | add(controls, BorderLayout.NORTH); |
| 151 | 2 | controls.setOpaque(false); |
| 152 | } | |
| 153 | /* | |
| 154 | * Add the section for metadata properties. | |
| 155 | */ | |
| 156 | if (true) { | |
| 157 | 2 | final JPanel properties = new JPanel(new GridBagLayout()); |
| 158 | 2 | final GridBagConstraints c = new GridBagConstraints(); |
| 159 | 2 | final Insets ci = c.insets; |
| 160 | 2 | c.gridx=1; c.weightx=1; c.anchor=GridBagConstraints.WEST; |
| 161 | 2 | c.gridy=0; ci.top=3; ci.bottom=0; properties.add(description = new JLabel(), c); |
| 162 | 2 | c.gridy++; ci.top=0; ci.bottom=3; properties.add(validValues = new JLabel(), c); |
| 163 | 2 | ci.left = 6; |
| 164 | 2 | c.gridx=0; c.weightx=0; ci.right=9; |
| 165 | 2 | c.gridy=0; ci.top=3; ci.bottom=0; properties.add(label(resources, Vocabulary.Keys.DESCRIPTION, description), c); |
| 166 | 2 | c.gridy++; ci.top=0; ci.bottom=3; properties.add(label(resources, Vocabulary.Keys.VALID_VALUES, validValues), c); |
| 167 | 2 | add(properties, BorderLayout.SOUTH); |
| 168 | 2 | properties.setOpaque(false); |
| 169 | } | |
| 170 | /* | |
| 171 | * Plug the listeners. | |
| 172 | */ | |
| 173 | 2 | controller = new Controller(tables); |
| 174 | 2 | formats.addActionListener(controller); |
| 175 | 2 | } |
| 176 | ||
| 177 | /** | |
| 178 | * Creates a new label for the given target component. | |
| 179 | */ | |
| 180 | private static JLabel label(final Vocabulary resources, final int key, final JComponent target) { | |
| 181 | 6 | final JLabel label = new JLabel(resources.getLabel(key)); |
| 182 | 6 | label.setLabelFor(target); |
| 183 | 6 | return label; |
| 184 | } | |
| 185 | ||
| 186 | /** | |
| 187 | * Various interfaces that we need to implement. We do that in an internal class | |
| 188 | * in order to avoid exposing publicly the methods that we implement. Only one | |
| 189 | * instance of this class is created for an instance of {@code IIOMetdataPanel}. | |
| 190 | * | |
| 191 | * @author Martin Desruisseaux (Geomatys) | |
| 192 | * @version 3.08 | |
| 193 | * | |
| 194 | * @since 3.05 | |
| 195 | * @module | |
| 196 | */ | |
| 197 | private final class Controller implements ActionListener, TreeSelectionListener { | |
| 198 | /** | |
| 199 | * The component which hold every tables. This is the component that appear in the center of | |
| 200 | * this {@code IIOMetadataPanel}. Its layout manager must be an instance of {@link CardLayout}. | |
| 201 | */ | |
| 202 | private final JComponent tables; | |
| 203 | ||
| 204 | /** | |
| 205 | * The selected format, or {@code null} if none. | |
| 206 | */ | |
| 207 | private IIOMetadataChoice selectedFormat; | |
| 208 | ||
| 209 | /** | |
| 210 | * The table which is currently visible, or {@code null} if none. | |
| 211 | */ | |
| 212 | private IIOMetadataTreeTable visibleTable; | |
| 213 | ||
| 214 | /** | |
| 215 | * Creates a new instance. | |
| 216 | */ | |
| 217 | 2 | Controller(final JComponent tables) { |
| 218 | 2 | this.tables = tables; |
| 219 | 2 | } |
| 220 | ||
| 221 | /** | |
| 222 | * Resets this controller in the same state than after construction. | |
| 223 | */ | |
| 224 | final void reset() { | |
| 225 | // Do not set visibleTable to null, because we want to copy its layout | |
| 226 | // when a new table will be created even if the previous table was for | |
| 227 | // an other image. | |
| 228 | 0 | selectedFormat = null; |
| 229 | 0 | tables.removeAll(); |
| 230 | 0 | } |
| 231 | ||
| 232 | /** | |
| 233 | * Invoked when a new format has been selected in the combo box. | |
| 234 | * When a change is detected, the tree is immediately updated. | |
| 235 | */ | |
| 236 | @Override | |
| 237 | public void actionPerformed(final ActionEvent event) { | |
| 238 | 1 | final JComboBox choices = (JComboBox) event.getSource(); |
| 239 | 1 | final IIOMetadataChoice oldFormat = selectedFormat; |
| 240 | 1 | final Object selected = choices.getSelectedItem(); |
| 241 | 1 | if (!(selected instanceof IIOMetadataChoice)) { |
| 242 | /* | |
| 243 | * This happen if the user selected the separator. | |
| 244 | */ | |
| 245 | 0 | choices.setSelectedItem(oldFormat); |
| 246 | 0 | return; |
| 247 | } | |
| 248 | 1 | final IIOMetadataChoice newFormat = (IIOMetadataChoice) selected; |
| 249 | 1 | if (newFormat == null) { |
| 250 | /* | |
| 251 | * May be null if the user selected the choice which was already selected, | |
| 252 | * which have the effect of unselecting it. We want the current format to | |
| 253 | * stay selected. | |
| 254 | */ | |
| 255 | 0 | choices.setSelectedItem(oldFormat); |
| 256 | 0 | return; |
| 257 | } | |
| 258 | 1 | if (newFormat == oldFormat) { |
| 259 | 0 | return; |
| 260 | } | |
| 261 | 1 | show(newFormat); |
| 262 | 1 | } |
| 263 | ||
| 264 | /** | |
| 265 | * Shows the {@code TreeTable} associated with the given choice. | |
| 266 | * It is the caller's responsibility to ensure that the given | |
| 267 | * format is the one selected in the combo box. | |
| 268 | */ | |
| 269 | final void show(final IIOMetadataChoice newFormat) { | |
| 270 | 1 | selectedFormat = newFormat; |
| 271 | 1 | visibleTable = newFormat.show(tables, this, visibleTable); |
| 272 | 1 | showProperties(visibleTable.selectedNode); |
| 273 | 1 | } |
| 274 | ||
| 275 | /** | |
| 276 | * Invoked when a node has been selected. | |
| 277 | */ | |
| 278 | @Override | |
| 279 | public void valueChanged(final TreeSelectionEvent event) { | |
| 280 | 0 | final TreePath path = event.getNewLeadSelectionPath(); |
| 281 | 0 | if (path != null) { |
| 282 | 0 | final MetadataTreeNode node = (MetadataTreeNode) path.getLastPathComponent(); |
| 283 | 0 | visibleTable.selectedNode = node; |
| 284 | 0 | showProperties(node); |
| 285 | } | |
| 286 | 0 | } |
| 287 | } | |
| 288 | ||
| 289 | /** | |
| 290 | * Fills the "properties" section in the bottom of this {@code IIOMetadataPanel} | |
| 291 | * using the information provided by the given node. | |
| 292 | * | |
| 293 | * @param node The selected node, for which to display the information in the bottom | |
| 294 | * of this panel. Can be null. | |
| 295 | */ | |
| 296 | final void showProperties(final MetadataTreeNode node) { | |
| 297 | 1 | if (node == null) { |
| 298 | 1 | description.setText(null); |
| 299 | 1 | validValues.setText(null); |
| 300 | } else { | |
| 301 | /* | |
| 302 | * Get the description of the given node. If no description is found for that node, | |
| 303 | * search for the parent until a description is found. We do that way mostly because | |
| 304 | * when an element contains only one attribute, some format don't provide a description | |
| 305 | * for that attribute since it is redundant with the element description. | |
| 306 | */ | |
| 307 | 0 | MetadataTreeNode parent = node; |
| 308 | String text; | |
| 309 | 0 | do text = parent.getDescription(); |
| 310 | 0 | while (text == null && (parent = parent.getParent()) != null); |
| 311 | 0 | if (text == null) { |
| 312 | 0 | text = node.getLabel(); |
| 313 | } | |
| 314 | 0 | description.setText(text); |
| 315 | /* | |
| 316 | * Now get the description of valid values. If there is none, we will build | |
| 317 | * one from the data type. | |
| 318 | */ | |
| 319 | 0 | Object restriction = node.getValueRestriction(); |
| 320 | 0 | if (restriction == null) { |
| 321 | 0 | Class<?> type = node.getValueType(); |
| 322 | 0 | if (type != null) { |
| 323 | 0 | if (type.isArray()) { |
| 324 | 0 | type = type.getComponentType(); |
| 325 | } | |
| 326 | 0 | StringBuilder buffer = new StringBuilder(Classes.getShortName(type)); |
| 327 | 0 | final NumberRange<Integer> occurrences = node.getOccurrences(); |
| 328 | 0 | if (occurrences != null) { |
| 329 | 0 | final String s = occurrences.toString(); |
| 330 | 0 | if (s.startsWith("[")) { |
| 331 | 0 | buffer.append(s); |
| 332 | } else { | |
| 333 | 0 | buffer.append('[').append(s).append(']'); |
| 334 | } | |
| 335 | } | |
| 336 | 0 | restriction = buffer; |
| 337 | } | |
| 338 | } | |
| 339 | 0 | validValues.setText(restriction != null ? restriction.toString() : null); |
| 340 | } | |
| 341 | 1 | } |
| 342 | ||
| 343 | /** | |
| 344 | * Removes all metadata from this widget. After the invocation of this method, | |
| 345 | * this panel will be in the same state than after construction. | |
| 346 | */ | |
| 347 | public void clear() { | |
| 348 | 0 | formatChoices.removeAllElements(); |
| 349 | 0 | controller .reset(); |
| 350 | 0 | } |
| 351 | ||
| 352 | /** | |
| 353 | * Clears the previous metadata content and adds the values of the given <em>stream</em> and | |
| 354 | * <em>image</em> metadata. Invoking this method is equivalent to invoking {@link #clear()} | |
| 355 | * followed by {@link #addMetadata(IIOMetadata, IIOMetadata[]) addMetadata(...)}, except that | |
| 356 | * the metadata initially show will be for the same format than the one currently selected, | |
| 357 | * if this format exists in the new metadata. | |
| 358 | * | |
| 359 | * @param stream The stream metadata, or {@code null} if none. | |
| 360 | * @param image The image metadata for each image in a file. | |
| 361 | * | |
| 362 | * @since 3.09 | |
| 363 | */ | |
| 364 | public void setMetadata(final IIOMetadata stream, final IIOMetadata... image) { | |
| 365 | 0 | final Object selected = formatChoices.getSelectedItem(); |
| 366 | 0 | clear(); |
| 367 | 0 | addMetadata(stream, image); |
| 368 | 0 | final int index = formatChoices.getIndexOf(selected); |
| 369 | 0 | if (index > 0) { // Intentionnaly skip the first choice, since it is already selected. |
| 370 | 0 | final Object newFormat = formatChoices.getElementAt(index); |
| 371 | 0 | if (newFormat instanceof IIOMetadataChoice) { |
| 372 | 0 | formatChoices.setSelectedItem(newFormat); |
| 373 | 0 | controller.show((IIOMetadataChoice) newFormat); |
| 374 | } | |
| 375 | } | |
| 376 | 0 | } |
| 377 | ||
| 378 | /** | |
| 379 | * Adds to this panel the values of the given <em>stream</em> and <em>image</em> metadata. | |
| 380 | * Note that this method is typically invoked alone; there is no need to invoke | |
| 381 | * {@link #addMetadataFormat addMetadataFormat} prior this method. | |
| 382 | * | |
| 383 | * @param stream The stream metadata, or {@code null} if none. | |
| 384 | * @param image The image metadata for each image in a file. | |
| 385 | */ | |
| 386 | public void addMetadata(final IIOMetadata stream, final IIOMetadata... image) { | |
| 387 | 0 | final Map<IIOMetadata,Integer> imageIndex = new IdentityHashMap<IIOMetadata,Integer>(); |
| 388 | 0 | final Map<String, List<IIOMetadata>> metadataForNames = |
| 389 | new LinkedHashMap<String, List<IIOMetadata>>(); | |
| 390 | 0 | addFormatNames(stream, metadataForNames); |
| 391 | 0 | imageIndex.put(stream, -1); |
| 392 | 0 | if (image != null) { |
| 393 | 0 | for (int i=0; i<image.length; i++) { |
| 394 | 0 | final IIOMetadata metadata = image[i]; |
| 395 | 0 | addFormatNames(metadata, metadataForNames); |
| 396 | 0 | imageIndex.put(metadata, i); |
| 397 | } | |
| 398 | } | |
| 399 | /* | |
| 400 | * At this point, we grouped every metadata by format name and we remember the | |
| 401 | * image index for each metadata. Now process to the addition to the combo box. | |
| 402 | * If the format is already present in the combo box, insert right after the | |
| 403 | * existing format. | |
| 404 | */ | |
| 405 | 0 | final Locale locale = getLocale(); |
| 406 | 0 | for (final Map.Entry<String, List<IIOMetadata>> entry : metadataForNames.entrySet()) { |
| 407 | 0 | int insertAt = -1; // Where to insert, or -1 for adding to the end of the list. |
| 408 | 0 | final String formatName = entry.getKey(); |
| 409 | 0 | for (int i=formatChoices.getSize(); --i>=0;) { |
| 410 | 0 | final Object existing = formatChoices.getElementAt(i); |
| 411 | 0 | if (existing instanceof IIOMetadataChoice) { |
| 412 | 0 | if (formatName.equals(((IIOMetadataChoice) existing).getFormatName())) { |
| 413 | 0 | insertAt = i; |
| 414 | 0 | break; |
| 415 | } | |
| 416 | } | |
| 417 | 0 | } |
| 418 | 0 | if (insertAt < 0 && formatChoices.getSize() != 0) { |
| 419 | 0 | formatChoices.addElement(ComboBoxRenderer.SEPARATOR); |
| 420 | } | |
| 421 | 0 | final List<String> names = imageNames; |
| 422 | 0 | final int namesCount = (names != null) ? names.size() : 0; |
| 423 | 0 | for (final IIOMetadata metadata : entry.getValue()) { |
| 424 | 0 | final int index = imageIndex.get(metadata); // Should never be null. |
| 425 | 0 | final String name = (index >= 0 && index < namesCount) ? names.get(index) : null; |
| 426 | 0 | final IIOMetadataChoice choice = new IIOMetadataChoice(locale, formatName, metadata, index, name); |
| 427 | 0 | if (insertAt >= 0) { |
| 428 | 0 | formatChoices.insertElementAt(choice, ++insertAt); |
| 429 | } else { | |
| 430 | 0 | formatChoices.addElement(choice); |
| 431 | } | |
| 432 | 0 | } |
| 433 | 0 | } |
| 434 | 0 | } |
| 435 | ||
| 436 | /** | |
| 437 | * Adds the metadata format names to the keys of the given map, and the metadata | |
| 438 | * to the values. The given metadata can be {@code null} (as authorized by the | |
| 439 | * {@link #addMetadata} method contract), in which case it is ignored. | |
| 440 | */ | |
| 441 | private static void addFormatNames(final IIOMetadata metadata, | |
| 442 | final Map<String, List<IIOMetadata>> metadataForNames) | |
| 443 | { | |
| 444 | 0 | if (metadata != null) { |
| 445 | 0 | final String[] formatNames = metadata.getMetadataFormatNames(); |
| 446 | 0 | moveAtEnd(formatNames, IIOMetadataFormatImpl.standardMetadataFormatName); |
| 447 | 0 | moveAtEnd(formatNames, metadata.getNativeMetadataFormatName()); |
| 448 | 0 | for (final String formatName : formatNames) { |
| 449 | 0 | List<IIOMetadata> list = metadataForNames.get(formatName); |
| 450 | 0 | if (list == null) { |
| 451 | 0 | list = new ArrayList<IIOMetadata>(); |
| 452 | 0 | metadataForNames.put(formatName, list); |
| 453 | } | |
| 454 | 0 | list.add(metadata); |
| 455 | } | |
| 456 | } | |
| 457 | 0 | } |
| 458 | ||
| 459 | /** | |
| 460 | * If the {@code toMove} name is found in the given array, move it at the end of the array. | |
| 461 | */ | |
| 462 | private static void moveAtEnd(final String[] names, final String toMove) { | |
| 463 | 0 | if (toMove != null) { |
| 464 | 0 | for (int i=0; i<names.length; i++) { |
| 465 | 0 | final String name = names[i]; |
| 466 | 0 | if (toMove.equals(name)) { |
| 467 | 0 | System.arraycopy(names, i+1, names, i, names.length - (i+1)); |
| 468 | 0 | names[names.length - 1] = name; |
| 469 | 0 | break; |
| 470 | } | |
| 471 | } | |
| 472 | } | |
| 473 | 0 | } |
| 474 | ||
| 475 | /** | |
| 476 | * Adds to this panel the description of the given <em>stream</em> and <em>image</em> | |
| 477 | * metadata formats. The descriptions contain no metadata value, only the name of the | |
| 478 | * nodes together with a few additional information (type, valid values, <i>etc.</i>). | |
| 479 | * | |
| 480 | * @param stream The stream metadata format, or {@code null} if none. | |
| 481 | * @param image The image metadata format, or {@code null} if none. | |
| 482 | */ | |
| 483 | public void addMetadataFormat(final IIOMetadataFormat stream, final IIOMetadataFormat image) { | |
| 484 | 2 | final Locale locale = getLocale(); |
| 485 | 2 | if (stream != null) { |
| 486 | 1 | formatChoices.addElement(new IIOMetadataChoice(locale, stream, true)); |
| 487 | } | |
| 488 | 2 | if (image != null) { |
| 489 | 2 | formatChoices.addElement(new IIOMetadataChoice(locale, image, false)); |
| 490 | } | |
| 491 | 2 | } |
| 492 | ||
| 493 | /** | |
| 494 | * Adds to this panel the description of | |
| 495 | * {@value org.geotoolkit.image.io.metadata.SpatialMetadataFormat#FORMAT_NAME} and | |
| 496 | * {@value javax.imageio.metadata.IIOMetadataFormatImpl#standardMetadataFormatName} formats. | |
| 497 | * The descriptions contain no metadata value, only the name of the nodes together with a few | |
| 498 | * additional information (type, valid values, <i>etc.</i>). | |
| 499 | */ | |
| 500 | public void addDefaultMetadataFormats() { | |
| 501 | 1 | addMetadataFormat(SpatialMetadataFormat.getStreamInstance(null), |
| 502 | SpatialMetadataFormat.getImageInstance (null)); | |
| 503 | 1 | addMetadataFormat(null, IIOMetadataFormatImpl.getStandardFormatInstance()); |
| 504 | 1 | } |
| 505 | } |