001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2008 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027 028package org.opends.guitools.controlpanel.ui.components; 029 030import static org.opends.messages.AdminToolMessages.*; 031 032import java.awt.GridBagConstraints; 033import java.awt.GridBagLayout; 034import java.awt.event.ActionListener; 035import java.awt.event.KeyEvent; 036import java.text.ParseException; 037 038import org.forgerock.i18n.LocalizableMessage; 039import org.forgerock.i18n.slf4j.LocalizedLogger; 040 041import javax.swing.Box; 042import javax.swing.Icon; 043import javax.swing.ImageIcon; 044import javax.swing.JButton; 045import javax.swing.JLabel; 046import javax.swing.JPanel; 047import javax.swing.KeyStroke; 048 049import org.opends.guitools.controlpanel.browser.IconPool; 050import org.opends.guitools.controlpanel.datamodel.BinaryValue; 051import org.opends.guitools.controlpanel.ui.ColorAndFontConstants; 052import org.opends.guitools.controlpanel.util.Utilities; 053 054/** 055 * A simple panel used in the LDAP entry viewers to display a binary value. 056 * It does not allow to edit the binary value. It is used for instance in the 057 * tables. 058 * 059 */ 060public class BinaryCellPanel extends JPanel 061{ 062 private static final long serialVersionUID = 6607973945986559802L; 063 private JButton iconButton; 064 private JLabel label; 065 private CellEditorButton editButton; 066 private CellEditorButton deleteButton; 067 private boolean displayDelete; 068 private JLabel lockLabel = Utilities.createDefaultLabel(); 069 070 private ImageIcon lockIcon = 071 Utilities.createImageIcon(IconPool.IMAGE_PATH+"/field-locked.png"); 072 073 private Object value; 074 075 private static final int THUMBNAIL_HEIGHT = 50; 076 077 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 078 079 /** 080 * Default constructor. 081 * 082 */ 083 public BinaryCellPanel() 084 { 085 super(new GridBagLayout()); 086 setOpaque(false); 087 GridBagConstraints gbc = new GridBagConstraints(); 088 gbc.fill = GridBagConstraints.HORIZONTAL; 089 gbc.gridx = 0; 090 gbc.gridy = 0; 091 iconButton = Utilities.createButton(LocalizableMessage.EMPTY); 092 label = Utilities.createDefaultLabel( 093 INFO_CTRL_PANEL_NO_VALUE_SPECIFIED.get()); 094 add(iconButton); 095 iconButton.setVisible(false); 096 gbc.weightx = 1.0; 097 gbc.gridx ++; 098 add(label, gbc); 099 add(Box.createHorizontalGlue(), gbc); 100 gbc.gridx ++; 101 editButton = new CellEditorButton(INFO_CTRL_PANEL_EDIT_BUTTON_LABEL.get()); 102 editButton.setForeground(ColorAndFontConstants.buttonForeground); 103 editButton.setOpaque(false); 104 gbc.insets.left = 5; 105 gbc.weightx = 0.0; 106 add(editButton, gbc); 107 108 gbc.gridx ++; 109 deleteButton = 110 new CellEditorButton(INFO_CTRL_PANEL_DELETE_BUTTON_LABEL.get()); 111 deleteButton.setForeground(ColorAndFontConstants.buttonForeground); 112 deleteButton.setOpaque(false); 113 deleteButton.setVisible(isDisplayDelete()); 114 add(deleteButton, gbc); 115 116 gbc.insets.left = 5; 117 gbc.gridx ++; 118 add(lockLabel, gbc); 119 lockLabel.setVisible(false); 120 } 121 122 /** 123 * Returns the message describing the provided array of bytes. 124 * @param value the array of bytes. 125 * @param isImage whether the array of bytes represents an image or not. 126 * @return the message describing the provided array of bytes. 127 */ 128 public LocalizableMessage getString(byte[] value, boolean isImage) 129 { 130 if (value == null) 131 { 132 return INFO_CTRL_PANEL_NO_VALUE_SPECIFIED.get(); 133 } 134 else if (isImage) 135 { 136 return LocalizableMessage.EMPTY; 137 } 138 else 139 { 140 return INFO_CTRL_PANEL_BINARY_VALUE.get(); 141 } 142 } 143 144 /** 145 * Updates the visibility of the lock icon. 146 * @param visible whether the lock icon is visible or not. 147 */ 148 public void setLockIconVisible(boolean visible) 149 { 150 if (visible) 151 { 152 lockLabel.setIcon(lockIcon); 153 lockLabel.setVisible(true); 154 } 155 else 156 { 157 lockLabel.setIcon(null); 158 lockLabel.setVisible(false); 159 } 160 } 161 162 /** 163 * Sets the text of the edit button (for instance if this panel is displaying 164 * a read-only value, the user might set a value of 'View...' that launches 165 * a viewer). 166 * @param text the text of the button. 167 */ 168 public void setEditButtonText(LocalizableMessage text) 169 { 170 editButton.setText(text.toString()); 171 } 172 173 /** 174 * Returns the message describing the provided binary value. 175 * @param value the binary value. 176 * @param isImage whether the binary value represents an image or not. 177 * @return the message describing the provided binary value. 178 */ 179 public LocalizableMessage getMessage(BinaryValue value, boolean isImage) 180 { 181 LocalizableMessage returnValue; 182 if (value == null) 183 { 184 returnValue = INFO_CTRL_PANEL_NO_VALUE_SPECIFIED.get(); 185 } 186 else if (isImage) 187 { 188 returnValue = LocalizableMessage.EMPTY; 189 } 190 else if (value.getType() == BinaryValue.Type.BASE64_STRING) 191 { 192 returnValue = INFO_CTRL_PANEL_BINARY_VALUE.get(); 193 } 194 else 195 { 196 returnValue = INFO_CTRL_PANEL_CONTENTS_OF_FILE.get(value.getFile()); 197 } 198 return returnValue; 199 } 200 201 /** 202 * Sets the value to be displayed by this panel. 203 * @param value the binary value as an array of bytes. 204 * @param isImage whether the binary value represents an image or not. 205 */ 206 public void setValue(byte[] value, boolean isImage) 207 { 208 label.setText(getString(value, isImage).toString()); 209 deleteButton.setVisible(value != null && isDisplayDelete()); 210 this.value = value; 211 if (!isImage) 212 { 213 label.setIcon(null); 214 label.setVisible(true); 215 iconButton.setVisible(false); 216 } 217 else 218 { 219 updateIcon(value); 220 } 221 } 222 223 /** 224 * Sets the value to be displayed by this panel. 225 * @param value the binary value as a BinaryValue object. 226 * @param isImage whether the binary value represents an image or not. 227 */ 228 public void setValue(BinaryValue value, boolean isImage) 229 { 230 label.setText(getMessage(value, isImage).toString()); 231 deleteButton.setVisible(value != null && isDisplayDelete()); 232 this.value = value; 233 if (!isImage) 234 { 235 label.setIcon(null); 236 label.setVisible(true); 237 iconButton.setVisible(false); 238 } 239 else 240 { 241 try 242 { 243 updateIcon(value.getBytes()); 244 } 245 catch (ParseException pe) 246 { 247 logger.warn(LocalizableMessage.raw("Error decoding base 64 value: "+pe, pe)); 248 Utilities.setWarningLabel(label, ERR_LOADING_IMAGE.get()); 249 } 250 } 251 } 252 253 private void updateIcon(byte[] value) 254 { 255 if (value == null) 256 { 257 label.setVisible(true); 258 iconButton.setVisible(false); 259 } 260 else 261 { 262 Icon icon = getIcon(value); 263 if (icon == null || icon.getIconHeight() <= 0) 264 { 265 Utilities.setWarningLabel(label, ERR_LOADING_IMAGE.get()); 266 label.setVisible(true); 267 iconButton.setVisible(false); 268 } 269 else 270 { 271 iconButton.setVisible(true); 272 iconButton.setIcon(icon); 273 label.setVisible(false); 274 } 275 } 276 } 277 278 /** 279 * Returns the object represented by this panel. 280 * @return the object represented by this panel. 281 */ 282 public Object getValue() 283 { 284 return value; 285 } 286 287 /** 288 * Explicitly request the focus for the edit button of this panel. 289 * 290 */ 291 public void requestFocusForButton() 292 { 293 editButton.requestFocusInWindow(); 294 } 295 296 /** 297 * Adds an action listener to this panel. The action listener will be 298 * invoked when the user clicks on the 'Edit' button or the icon. 299 * @param listener the action listener. 300 */ 301 public void addEditActionListener(ActionListener listener) 302 { 303 editButton.addActionListener(listener); 304 iconButton.addActionListener(listener); 305 } 306 307 /** 308 * Removes an action listener previously added with the method 309 * addEditActionListener. 310 * @param listener the action listener. 311 */ 312 public void removeEditActionListener(ActionListener listener) 313 { 314 editButton.removeActionListener(listener); 315 iconButton.removeActionListener(listener); 316 } 317 318 /** 319 * Adds an action listener to this panel. The action listener will be 320 * invoked when the user clicks on the 'Delete'. 321 * @param listener the action listener. 322 */ 323 public void addDeleteActionListener(ActionListener listener) 324 { 325 deleteButton.addActionListener(listener); 326 } 327 328 /** 329 * Removes an action listener previously added with the method 330 * addDeleteActionListener. 331 * @param listener the action listener. 332 */ 333 public void removeDeleteActionListener(ActionListener listener) 334 { 335 deleteButton.removeActionListener(listener); 336 } 337 338 /** {@inheritDoc} */ 339 protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, 340 int condition, boolean pressed) 341 { 342 // This method is used to transfer the key events to the button. 343 return editButton.processKeyBinding(ks, e, condition, pressed); 344 } 345 346 /** 347 * Tells whether the 'Delete' button is displayed or not. 348 * @return <CODE>true</CODE> if the 'Delete' button is visible and 349 * <CODE>false</CODE> otherwise. 350 */ 351 public boolean isDisplayDelete() 352 { 353 return displayDelete; 354 } 355 356 /** 357 * Sets whether the 'Delete' button must be displayed or not. 358 * @param displayDelete whether the 'Delete' button must be displayed or not. 359 */ 360 public void setDisplayDelete(boolean displayDelete) 361 { 362 this.displayDelete = displayDelete; 363 } 364 365 private Icon getIcon(byte[] bytes) 366 { 367 return Utilities.createImageIcon(bytes, THUMBNAIL_HEIGHT, 368 INFO_CTRL_PANEL_THUMBNAIL_DESCRIPTION.get(), 369 true); 370 } 371}