001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: /*
043: * InplaceEditableLabel.java
044: *
045: * Created on June 9, 2006, 3:12 PM
046: *
047: * To change this template, choose Tools | Template Manager
048: * and open the template in the editor.
049: */
050:
051: package org.netbeans.modules.xml.schema.abe;
052:
053: import java.awt.Color;
054: import java.awt.Component;
055: import java.awt.Dimension;
056: import java.awt.Font;
057: import java.awt.FontMetrics;
058: import java.awt.Graphics;
059: import java.awt.Rectangle;
060: import java.awt.event.FocusEvent;
061: import java.awt.event.FocusListener;
062: import java.awt.event.HierarchyEvent;
063: import java.awt.event.HierarchyListener;
064: import java.awt.event.KeyAdapter;
065: import java.awt.event.KeyEvent;
066: import java.awt.event.MouseAdapter;
067: import java.awt.event.MouseEvent;
068: import javax.swing.JComponent;
069: import javax.swing.JLabel;
070: import javax.swing.JPanel;
071: import javax.swing.JScrollPane;
072: import javax.swing.JTextField;
073: import javax.swing.SwingConstants;
074: import javax.swing.SwingUtilities;
075: import org.openide.util.NbBundle;
076:
077: /**
078: *
079: * @author girix
080: */
081: public class InplaceEditableLabel extends JLabel {
082: private static final long serialVersionUID = 7526472295622776147L;
083: boolean editMode = false;
084: public static final String PROPERTY_MODE_CHANGE = "PROPERTY_MODE_CHANGE";
085:
086: public enum Mode {
087: EDIT, NORMAL
088: };
089:
090: boolean mouseOverMe = false;
091: boolean altKeyPressed = false;
092: private Color mouseOverColor;
093: private JComponent editorComponent;
094: JPanel glass;
095:
096: //NBGlassPaneAccessSupport editorSupport;
097: /** Creates a new instance of InplaceEditableLabel */
098: public InplaceEditableLabel() {
099: super ();
100: setForeground(Color.BLUE);
101: setMouseOverColor(getForeground());
102: setToolTipText(NbBundle.getMessage(InplaceEditableLabel.class,
103: "TTP_DEFAULT_INPLACE_EDIT"));
104: initialize();
105: }
106:
107: public InplaceEditableLabel(String str) {
108: this ();
109: super .setText(str);
110: }
111:
112: public JScrollPane getScrollPane() {
113: return ((ABEBaseDropPanel) this .getParent()).context
114: .getInstanceDesignerScrollPane();
115: }
116:
117: void initialize() {
118: addMouseListener(new MouseAdapter() {
119: public void mouseClicked(MouseEvent e) {
120: //add logic to handle edits
121: if (((e.isShiftDown() && (e.getClickCount() == 1)) || (e
122: .getClickCount() > 1))) {
123: //setEditMode
124: showEditor();
125: } else if (drewLine) {
126: //call the ctrl click handler
127: if (ctrlClickHandler != null)
128: ctrlClickHandler.handleCtrlClick();
129: } else {
130: InplaceEditableLabel.this .getParent()
131: .dispatchEvent(e);
132: }
133: }
134:
135: public void mouseEntered(MouseEvent e) {
136: super .mouseEntered(e);
137: /*mouseOverMe = true;
138: if(e.isControlDown()){
139: altKeyPressed = true;
140: //requestFocusInWindow();
141: }*/
142: repaint();
143: InplaceEditableLabel.this .getParent().dispatchEvent(e);
144: }
145:
146: public void mouseExited(MouseEvent e) {
147: super .mouseExited(e);
148: /*mouseOverMe = false;
149: altKeyPressed = false;
150: repaint();*/
151: InplaceEditableLabel.this .getParent().dispatchEvent(e);
152: }
153:
154: public void mouseReleased(MouseEvent e) {
155: if (!drewLine)
156: InplaceEditableLabel.this .getParent()
157: .dispatchEvent(e);
158: }
159:
160: public void mousePressed(MouseEvent e) {
161: if (!drewLine)
162: InplaceEditableLabel.this .getParent()
163: .dispatchEvent(e);
164: }
165:
166: });
167: }
168:
169: boolean drewLine = false;
170:
171: protected void paintComponent(Graphics g) {
172: drewLine = false;
173: if (mouseOverMe && altKeyPressed && (ctrlClickHandler != null)) {
174: //draw diff color and underline
175: Color origC = getForeground();
176: Font origF = getFont();
177: setForeground(getMouseOverColor());
178: //g.setFont(new Font(origF.getName(), Font.BOLD, origF.getSize()));
179: Rectangle bounds = g.getClipBounds();
180: super .paintComponent(g);
181: g.setColor(getMouseOverColor());
182: int width = SwingUtilities.computeStringWidth(
183: getFontMetrics(getFont()), getText());
184: g.drawLine(bounds.x, bounds.y + bounds.height - 1, bounds.x
185: + width, bounds.y + bounds.height - 1);
186: setForeground(origC);
187: setFont(origF);
188: drewLine = true;
189: } else {
190: super .paintComponent(g);
191: }
192: }
193:
194: public Color getMouseOverColor() {
195: return mouseOverColor;
196: }
197:
198: public void setMouseOverColor(Color mouseOverColor) {
199: this .mouseOverColor = mouseOverColor;
200: }
201:
202: public void setText(String str) {
203: super .setText(str);
204: Font font = getFont();
205: if (font != null) {
206: FontMetrics fm = getFontMetrics(font);
207: int width = SwingUtilities.computeStringWidth(fm, str);
208: setPreferredSize(new Dimension(width,
209: getPreferredSize().height));
210: }
211: if (editMode) {
212: //this case will happen if the user selected something in edit mode
213: hideEditor();
214: }
215: }
216:
217: public void showEditor() {
218: firePropertyChange(PROPERTY_MODE_CHANGE, Mode.NORMAL, Mode.EDIT);
219: if ((editorComponent == null) && (editInfoString == null))
220: return;
221:
222: editMode = true;
223:
224: //editorSupport = new NBGlassPaneAccessSupport();
225: glass = NBGlassPaneAccessSupport.getNBGlassPane(this );
226: if (glass == null)
227: return;
228: if (editorComponent != null) {
229: Rectangle rect = SwingUtilities.convertRectangle(this
230: .getParent(), this .getBounds(), glass);
231: glass.add(editorComponent);
232: rect.width = this .getMinimumSize().width * wMagFactor + 5;
233: rect.height += 7;
234: editorComponent.setBounds(rect);
235: }
236: addInfoLabel();
237: glass.setVisible(true);
238:
239: if (editorComponent != null) {
240: editorComponent.addKeyListener(new KeyAdapter() {
241: public void keyTyped(KeyEvent e) {
242: super .keyTyped(e);
243: if (e.getKeyChar() == e.VK_ESCAPE)
244: hideEditor();
245: if (e.getKeyChar() == e.VK_ENTER) {
246: if (validInput())
247: hideEditor();
248: }
249: }
250: });
251: editorComponent.addFocusListener(new FocusListener() {
252: public void focusLost(FocusEvent e) {
253: if (getParent() instanceof ABEBaseDropPanel) {
254: //if focus is lost while the DnD is not complete, ignore hide
255: ABEBaseDropPanel acp = (ABEBaseDropPanel) getParent();
256: if (acp.context.isUserInducedEventMode())
257: return;
258: }
259: hideEditor();
260: }
261:
262: public void focusGained(FocusEvent e) {
263: }
264: });
265:
266: this .addHierarchyListener(new HierarchyListener() {
267: public void hierarchyChanged(HierarchyEvent e) {
268: //remove when the inplace label is taken off
269: try {
270: hideEditor();
271: } catch (Exception ex) {
272: //ignore this
273: }
274: }
275: });
276: //dont let the user scroll when the edit mode is on
277: getScrollPane().setWheelScrollingEnabled(false);
278: editorComponent.requestFocusInWindow();
279: }
280: }
281:
282: public void hideEditor() {
283: editMode = false;
284: //restore scroll mode.
285: getScrollPane().setWheelScrollingEnabled(true);
286: NBGlassPaneAccessSupport.disposeNBGlassPane();
287: //refresh all selected components again for focus change.
288: ((ABEBaseDropPanel) this .getParent()).context
289: .getComponentSelectionManager().refreshFocus();
290: }
291:
292: public void setInlineEditorComponent(JComponent editorComponent) {
293: this .editorComponent = editorComponent;
294: }
295:
296: public Dimension getMaximumSize() {
297: return super .getMinimumSize();
298: }
299:
300: public Dimension getMinimumSize() {
301: return super .getPreferredSize();
302: }
303:
304: public Dimension getPreferredSize() {
305: return super .getMinimumSize();
306: }
307:
308: String editInfoString = null;
309: InstanceUIContext context = null;
310:
311: public void setEditInfoText(String editInfoString,
312: InstanceUIContext context) {
313: this .editInfoString = editInfoString;
314: this .context = context;
315: }
316:
317: private void addInfoLabel() {
318: if (editInfoString == null)
319: return;
320: JLabel infoLabel = new JLabel(UIUtilities
321: .getImageIcon("bulb.png"), SwingConstants.LEFT);
322: infoLabel.setText(editInfoString);
323: Component panel = this .getParent();
324: Rectangle rect = panel.getBounds();
325: rect = SwingUtilities.convertRectangle(panel.getParent(), rect,
326: glass);
327: rect.y -= 20;
328: Dimension dim = infoLabel.getPreferredSize();
329: rect.width = dim.width;
330: rect.height = dim.height;
331: glass.add(infoLabel);
332: infoLabel.setBackground(new Color(255, 255, 220));
333: infoLabel.setOpaque(true);
334: infoLabel.setBounds(rect);
335: }
336:
337: int wMagFactor = 2;
338:
339: public void setWidthMagnificationFactor(int factor) {
340: this .wMagFactor = factor;
341: }
342:
343: InputValidator inputValidator;
344: String errorMessage;
345:
346: public void setInputValidator(InputValidator iv, String errorMessage) {
347: this .inputValidator = iv;
348: this .errorMessage = errorMessage;
349: }
350:
351: private boolean validInput() {
352: if (editorComponent instanceof JTextField) {
353: String str = ((JTextField) editorComponent).getText();
354: if ((this .inputValidator != null) && (str != null)) {
355: if (!this .inputValidator.isStringValid(str)) {
356: UIUtilities
357: .showErrorMessageFor(errorMessage,
358: ((ABEBaseDropPanel) this
359: .getParent()).context,
360: glass, editorComponent);
361: return false;
362: } else {
363: UIUtilities.hideGlassMessage(false);
364: }
365: }
366: }
367: return true;
368: }
369:
370: CtrlClickHandler ctrlClickHandler;
371:
372: public void addCtrlClickHandler(CtrlClickHandler ctrlClickHandler) {
373: this .ctrlClickHandler = ctrlClickHandler;
374: }
375:
376: public interface CtrlClickHandler {
377: public void handleCtrlClick();
378: }
379: }
|