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