| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.netbeans.modules.progress.ui; |
| |
| import java.awt.AWTEvent; |
| import java.awt.Component; |
| import java.awt.Container; |
| import java.awt.Cursor; |
| import java.awt.Dimension; |
| import java.awt.FlowLayout; |
| import java.awt.Frame; |
| import java.awt.Graphics; |
| import java.awt.GraphicsEnvironment; |
| import java.awt.Image; |
| import java.awt.Point; |
| import java.awt.Rectangle; |
| import java.awt.Toolkit; |
| import java.awt.event.AWTEventListener; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ComponentAdapter; |
| import java.awt.event.ComponentEvent; |
| import java.awt.event.KeyEvent; |
| import java.awt.event.MouseAdapter; |
| import java.awt.event.MouseEvent; |
| import java.awt.event.MouseListener; |
| import java.awt.event.WindowEvent; |
| import java.awt.event.WindowStateListener; |
| import java.util.HashMap; |
| import java.util.Map; |
| import javax.swing.AbstractAction; |
| import javax.swing.Action; |
| import javax.swing.BorderFactory; |
| import javax.swing.Icon; |
| import javax.swing.ImageIcon; |
| import javax.swing.JButton; |
| import javax.swing.JComponent; |
| import javax.swing.JLabel; |
| import javax.swing.JPanel; |
| import javax.swing.JPopupMenu; |
| import javax.swing.JSeparator; |
| import javax.swing.JWindow; |
| import javax.swing.KeyStroke; |
| import javax.swing.SwingUtilities; |
| import javax.swing.UIManager; |
| import javax.swing.event.ListDataEvent; |
| import javax.swing.event.ListDataListener; |
| import javax.swing.event.ListSelectionEvent; |
| import javax.swing.event.ListSelectionListener; |
| import org.netbeans.modules.progress.spi.InternalHandle; |
| import org.netbeans.modules.progress.spi.ProgressEvent; |
| import org.netbeans.modules.progress.spi.ProgressUIWorkerWithModel; |
| import org.netbeans.modules.progress.spi.TaskModel; |
| import org.openide.DialogDisplayer; |
| import org.openide.NotifyDescriptor; |
| import org.openide.util.ImageUtilities; |
| import org.openide.util.NbBundle; |
| import org.openide.util.Utilities; |
| import org.openide.windows.WindowManager; |
| |
| /** |
| * |
| * @author Milos Kleint (mkleint@netbeans.org) |
| */ |
| public class StatusLineComponent extends JPanel implements ProgressUIWorkerWithModel { |
| private NbProgressBar bar; |
| private JLabel label; |
| private JSeparator separator; |
| private InternalHandle handle; |
| private boolean showingPopup = false; |
| private TaskModel model; |
| private MouseListener mouseListener; |
| private HideAWTListener hideListener; |
| private JWindow popupWindow; |
| private PopupPane pane; |
| private Map<InternalHandle, ListComponent> handleComponentMap; |
| private final int preferredHeight; |
| private JButton closeButton; |
| private JLabel extraLabel; |
| public StatusLineComponent() { |
| handleComponentMap = new HashMap<InternalHandle, ListComponent>(); |
| FlowLayout flay = new FlowLayout(); |
| flay.setVgap(1); |
| flay.setHgap(5); |
| setLayout(flay); |
| mouseListener = new MListener(); |
| addMouseListener(mouseListener); |
| hideListener = new HideAWTListener(); |
| |
| createLabel(); |
| createBar(); |
| // tricks to figure out correct height. |
| bar.setStringPainted(true); |
| bar.setString("@@@"); // NOI18N |
| label.setText("@@@"); // NOI18N |
| preferredHeight = Math.max(label.getPreferredSize().height, bar.getPreferredSize().height) + 3; |
| setOpaque(false); |
| discardLabel(); |
| discardBar(); |
| |
| pane = new PopupPane(); |
| pane.getActionMap().put("HidePopup", new AbstractAction() { |
| public @Override void actionPerformed(ActionEvent actionEvent) { |
| // System.out.println("escape pressed - hiding"); |
| hidePopup(); |
| } |
| }); |
| pane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "HidePopup"); |
| pane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "HidePopup"); |
| |
| |
| } |
| |
| private void createLabel() { |
| discardLabel(); |
| label = new JLabel(); |
| label.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); |
| label.addMouseListener(mouseListener); |
| } |
| |
| private void discardLabel() { |
| if (label != null) { |
| label.removeMouseListener(mouseListener); |
| label = null; |
| } |
| } |
| |
| private void createExtraLabel() { |
| discardExtraLabel(); |
| extraLabel = new JLabel(); |
| extraLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); |
| extraLabel.addMouseListener(mouseListener); |
| } |
| |
| private void discardExtraLabel() { |
| if (extraLabel != null) { |
| extraLabel.removeMouseListener(mouseListener); |
| extraLabel = null; |
| } |
| } |
| |
| private void createBar() { |
| discardBar(); |
| bar = new NbProgressBar(); |
| bar.setUseInStatusBar(true); |
| bar.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); |
| // setBorder(BorderFactory.createLineBorder(Color.BLUE, 1)); |
| // HACK - put smaller font inside the progress bar to keep |
| // the height of the progressbar constant for determinate and indeterminate bars |
| // Font fnt = UIManager.getFont("ProgressBar.font"); |
| // bar.setFont(fnt.deriveFont(fnt.getStyle(), fnt.getSize() - 3)); |
| bar.addMouseListener(mouseListener); |
| |
| } |
| |
| private void discardBar() { |
| if (bar != null) { |
| bar.removeMouseListener(mouseListener); |
| //EMI: On OSX, an animation thread is started when the progressbar is created, even if not displayed (or added to a container). |
| // The following line is needed to kill the animation thread otherwise this tends to be alive for the rest of the JVM execution |
| // pumping a lot of repaing events in the event queue (in my tests, about 50% of the CPU while idle). |
| // The culprit apple.laf.CUIAquaProgressBar$Animator was discovered with the normal Profiler, while Tim Boudreau told me about a similar |
| // problem with OSX and the pulsating button (that also has a thread for that animation). |
| // Finally, btrace and this IDEA bug report (http://www.jetbrains.net/jira/browse/IDEADEV-25376) connected the dots. |
| bar.getUI().uninstallUI(bar); |
| bar = null; |
| } |
| } |
| |
| private void createCloseButton() { |
| discardCloseButton(); |
| closeButton = new JButton(); |
| closeButton.setBorderPainted(false); |
| closeButton.setBorder(BorderFactory.createEmptyBorder()); |
| closeButton.setOpaque(false); |
| closeButton.setContentAreaFilled(false); |
| |
| Image img = (Image)UIManager.get("nb.progress.cancel.icon"); |
| if( null != img ) { |
| closeButton.setIcon( new ImageIcon( img ) ); |
| } |
| img = (Image)UIManager.get("nb.progress.cancel.icon.mouseover"); |
| if( null != img ) { |
| closeButton.setRolloverEnabled(true); |
| closeButton.setRolloverIcon( new ImageIcon( img ) ); |
| } |
| img = (Image)UIManager.get("nb.progress.cancel.icon.pressed"); |
| if( null != img ) { |
| closeButton.setPressedIcon( new ImageIcon( img ) ); |
| } |
| } |
| |
| private void setCloseButtonNameAndTooltip() { |
| closeButton.setName(NbBundle.getMessage(ListComponent.class, "ListComponent.btnClose.name")); |
| closeButton.setToolTipText(NbBundle.getMessage(ListComponent.class, "ListComponent.btnClose.tooltip")); |
| } |
| |
| private void discardCloseButton() { |
| closeButton = null; |
| } |
| |
| private void createSeparator() { |
| discardSeparator(); |
| separator = new JSeparator(JSeparator.VERTICAL); |
| // separator.setPreferredSize(new Dimension(5, prefferedHeight)); |
| separator.setBorder(BorderFactory.createEmptyBorder(1, 0, 2, 0)); |
| } |
| |
| private void discardSeparator() { |
| separator = null; |
| } |
| |
| @Override |
| public Dimension getPreferredSize() { |
| Dimension retValue; |
| retValue = super.getPreferredSize(); |
| retValue.height = preferredHeight; |
| return retValue; |
| } |
| |
| @Override |
| public Dimension getMinimumSize() { |
| Dimension retValue; |
| retValue = super.getMinimumSize(); |
| retValue.height = preferredHeight; |
| return retValue; |
| } |
| |
| @Override |
| public Dimension getMaximumSize() { |
| Dimension retValue; |
| retValue = super.getMaximumSize(); |
| retValue.height = preferredHeight; |
| return retValue; |
| } |
| |
| public @Override void setModel(TaskModel mod) { |
| model = mod; |
| model.addListDataListener(new Listener()); |
| model.addListSelectionListener(new ListSelectionListener() { |
| public @Override void valueChanged(ListSelectionEvent e) { |
| pane.updateBoldFont(model.getSelectedHandle()); |
| } |
| }); |
| } |
| |
| private void setTooltipForAll() { |
| int size = model.getSize(); |
| String key = "NbProgressBar.tooltip1"; //NOI18N |
| if (size == 1) { |
| key = "NbProgressBar.tooltip2"; //NOI18N |
| } |
| String text = NbBundle.getMessage(StatusLineComponent.class, key, size); |
| setToolTipText(text); |
| if (label != null) { |
| label.setToolTipText(text); |
| } |
| if (bar != null) { |
| bar.setToolTipText(text); |
| } |
| } |
| |
| public @Override void processProgressEvent(ProgressEvent event) { |
| if (event.getType() == ProgressEvent.TYPE_START) { |
| createListItem(event.getSource()); |
| } else if (event.getType() == ProgressEvent.TYPE_PROGRESS || |
| event.getType() == ProgressEvent.TYPE_SWITCH || |
| event.getType() == ProgressEvent.TYPE_SILENT) { |
| ListComponent comp = handleComponentMap.get(event.getSource()); |
| if (comp == null) { |
| createListItem(event.getSource()); |
| comp = handleComponentMap.get(event.getSource()); |
| } |
| comp.processProgressEvent(event); |
| } else if (event.getType() == ProgressEvent.TYPE_FINISH) { |
| removeListItem(event.getSource()); |
| if (model.getSelectedHandle() != null && handle != model.getSelectedHandle()) { |
| ProgressEvent snap = model.getSelectedHandle().requestStateSnapshot(); |
| initializeComponent(snap); |
| if (snap.getSource().isInSleepMode()) { |
| bar.setString(snap.getMessage()); |
| } |
| |
| } |
| //release handle reference if it is the last one |
| if (model.getSize() == 0 && event.getSource().equals(handle)) { |
| handle = null; |
| } |
| } |
| |
| } |
| |
| public @Override void processSelectedProgressEvent(ProgressEvent event) { |
| if (event.getType() == ProgressEvent.TYPE_START) { |
| initializeComponent(event); |
| return; |
| } else if (event.getType() == ProgressEvent.TYPE_FINISH) { |
| //happens only when there's no more handles. |
| hidePopup(); |
| removeAll(); |
| discardSeparator(); |
| discardCloseButton(); |
| discardBar(); |
| discardLabel(); |
| discardExtraLabel(); |
| //#63393, 61940 fix - removeAll() just invalidates. seems to work without revalidate/repaint on some platforms, fail on others. |
| revalidate(); |
| repaint(); |
| return; |
| } else { |
| if (event.getSource() != handle || event.isSwitched() || |
| event.getType() == ProgressEvent.TYPE_SILENT || // the following condition re-initiates the bar when going from/to sleep mode.. |
| (event.getSource().isInSleepMode() != (bar.getClientProperty(NbProgressBar.SLEEPY) != null))) { //NIO18N |
| initializeComponent(event); |
| } |
| if (bar != null) { |
| if (event.getWorkunitsDone() > 0) { |
| bar.setValue(event.getWorkunitsDone()); |
| } |
| bar.setString(getBarString(event.getPercentageDone(), event.getEstimatedCompletion())); |
| if (event.getDisplayName() != null) { |
| label.setText(event.getDisplayName()); |
| } |
| if (event.getSource().isInSleepMode()) { |
| bar.setString(event.getMessage()); |
| } |
| } |
| } |
| } |
| |
| static String formatEstimate(long estimate) { |
| long minutes = estimate / 60; |
| long seconds = estimate - (minutes * 60); |
| return "" + minutes + (seconds < 10 ? ":0" : ":") + seconds; |
| } |
| |
| static String getBarString(double percentage, long estimatedCompletion) { |
| if (estimatedCompletion != -1) { |
| return formatEstimate(estimatedCompletion); |
| } |
| if (percentage != -1) { |
| int rounded = (int) Math.round(percentage); |
| if (rounded > 100) { |
| rounded = 100; |
| } |
| return "" + rounded + "%"; //NOI18N |
| } |
| return ""; |
| } |
| |
| private void updateExtraLabel() { |
| if (extraLabel != null) { |
| if (handleComponentMap.size() > 1) { |
| extraLabel.setText(NbBundle.getMessage(StatusLineComponent.class, "StatusLineComponent.extra", handleComponentMap.size() - 1)); |
| } else { |
| extraLabel.setText(null); |
| } |
| } |
| } |
| |
| private void initializeComponent(ProgressEvent event) { |
| handle = event.getSource(); |
| boolean toShow = false; |
| if (label == null) { |
| createLabel(); |
| add(label); |
| toShow = true; |
| label.setToolTipText(getToolTipText()); |
| } |
| label.setText(handle.getDisplayName()); |
| |
| if (bar == null) { |
| createBar(); |
| add(bar); |
| toShow = true; |
| bar.setToolTipText(getToolTipText()); |
| |
| } |
| NbProgressBar.setupBar(event.getSource(), bar); |
| |
| if (closeButton == null) { |
| createCloseButton(); |
| add(closeButton); |
| toShow = true; |
| } |
| if (extraLabel == null) { |
| createExtraLabel(); |
| updateExtraLabel(); |
| add(extraLabel); |
| toShow = true; |
| } |
| if (separator == null) { |
| createSeparator(); |
| add(separator); |
| toShow = true; |
| } |
| if (handle.isAllowCancel()) { |
| closeButton.setAction(new CancelAction(false)); |
| } else { |
| closeButton.setAction(new EmptyCancelAction()); |
| } |
| |
| // #200126: tooltip property must be set following the action or it will be overwritten |
| setCloseButtonNameAndTooltip(); |
| |
| if (toShow) { |
| revalidate(); |
| repaint(); |
| } |
| } |
| |
| private class Listener implements ListDataListener { |
| public @Override void intervalAdded(ListDataEvent e) { |
| setTooltipForAll(); |
| } |
| public @Override void intervalRemoved(ListDataEvent e) { |
| setTooltipForAll(); |
| } |
| public @Override void contentsChanged(ListDataEvent e) { |
| setTooltipForAll(); |
| } |
| } |
| |
| public void hidePopup() { |
| if (GraphicsEnvironment.isHeadless()) { |
| return; |
| } |
| if (popupWindow != null) { |
| // popupWindow.getContentPane().removeAll(); |
| popupWindow.setVisible(false); |
| } |
| Toolkit.getDefaultToolkit().removeAWTEventListener(hideListener); |
| WindowManager.getDefault().getMainWindow().removeWindowStateListener(hideListener); |
| WindowManager.getDefault().getMainWindow().removeComponentListener(hideListener); |
| showingPopup = false; |
| } |
| |
| private void createListItem(InternalHandle handle) { |
| ListComponent comp; |
| if (handleComponentMap.containsKey(handle)) { |
| // happens when we click to display on popup and there is a |
| // new handle waiting in the queue. |
| comp = handleComponentMap.get(handle); |
| } else { |
| comp = new ListComponent(handle); |
| handleComponentMap.put(handle, comp); |
| } |
| pane.addListComponent(comp); |
| pane.updateBoldFont(model.getSelectedHandle()); |
| if (showingPopup) { |
| resizePopup(); |
| } |
| updateExtraLabel(); |
| } |
| |
| private void removeListItem(InternalHandle handle) { |
| ListComponent c = handleComponentMap.remove(handle); |
| pane.removeListComponent(handle); |
| pane.updateBoldFont(model.getSelectedHandle()); |
| if (showingPopup) { |
| resizePopup(); |
| } |
| if (c != null) { |
| c.clearProgressBarOSX(); |
| } |
| updateExtraLabel(); |
| } |
| |
| |
| public @Override void showPopup() { |
| if (GraphicsEnvironment.isHeadless()) { |
| return; |
| } |
| if (showingPopup) { |
| return; |
| } |
| InternalHandle[] handles = model.getHandles(); |
| if (handles.length == 0) { |
| // just in case.. |
| return; |
| } |
| showingPopup = true; |
| |
| // NOT using PopupFactory |
| // 1. on linux, creates mediumweight popup taht doesn't refresh behind visible glasspane |
| // 2. on mac, needs an owner frame otherwise hiding tooltip also hides the popup. (linux requires no owner frame to force heavyweight) |
| // 3. the created window is not focusable window |
| if (popupWindow == null) { |
| popupWindow = new JWindow(WindowManager.getDefault().getMainWindow()); |
| popupWindow.getContentPane().add(pane); |
| } |
| Toolkit.getDefaultToolkit().addAWTEventListener(hideListener, AWTEvent.MOUSE_EVENT_MASK); |
| WindowManager.getDefault().getMainWindow().addWindowStateListener(hideListener); |
| WindowManager.getDefault().getMainWindow().addComponentListener(hideListener); |
| resizePopup(); |
| popupWindow.setVisible(true); |
| pane.requestFocus(); |
| pane.repaint(); |
| // System.out.println(" window focusable=" + popupWindow.isFocusableWindow()); |
| } |
| |
| private void resizePopup() { |
| popupWindow.pack(); |
| Point point = new Point(0,0); |
| SwingUtilities.convertPointToScreen(point, this); |
| Dimension dim = popupWindow.getSize(); |
| //#63265 |
| Rectangle usableRect = Utilities.getUsableScreenBounds(); |
| int sepShift = separator != null ? separator.getSize().width : 0; |
| Point loc = new Point(point.x + this.getSize().width - dim.width - sepShift - 5 * 2 , point.y - dim.height - 5); |
| // -5 in x coordinate is becuase of the hgap between the separator and button and separator and edge |
| //#JDEV #17370036 |
| if( loc.x < usableRect.x ) |
| loc.x = Math.max( loc.x, usableRect.x ); |
| if( loc.x+dim.width > usableRect.x+usableRect.width ) |
| loc.x = usableRect.x + usableRect.width - dim.width; |
| if (! usableRect.contains(loc)) { |
| loc = new Point(loc.x, point.y + 5 + this.getSize().height); |
| } |
| // +4 here because of the width of the close button in popup, we |
| // want the progress bars to align visually.. but there's separator in status now.. |
| popupWindow.setLocation(loc); |
| // System.out.println("count=" + count); |
| // System.out.println("offset =" + offset); |
| } |
| |
| private class HideAWTListener extends ComponentAdapter implements AWTEventListener, WindowStateListener { |
| public @Override void eventDispatched(java.awt.AWTEvent aWTEvent) { |
| if (aWTEvent instanceof MouseEvent) { |
| MouseEvent mv = (MouseEvent)aWTEvent; |
| if (mv.getClickCount() > 0) { |
| //#118828 |
| if (! (aWTEvent.getSource() instanceof Component)) { |
| return; |
| } |
| Component comp = (Component)aWTEvent.getSource(); |
| Container par = SwingUtilities.getAncestorNamed("progresspopup", comp); //NOI18N |
| Container barpar = SwingUtilities.getAncestorOfClass(StatusLineComponent.class, comp); |
| if (par == null && barpar == null) { |
| hidePopup(); |
| } |
| } |
| } |
| } |
| |
| public @Override void windowStateChanged(WindowEvent windowEvent) { |
| if (showingPopup) { |
| int oldState = windowEvent.getOldState(); |
| int newState = windowEvent.getNewState(); |
| |
| if (((oldState & Frame.ICONIFIED) == 0) && |
| ((newState & Frame.ICONIFIED) == Frame.ICONIFIED)) { |
| hidePopup(); |
| // } else if (((oldState & Frame.ICONIFIED) == Frame.ICONIFIED) && |
| // ((newState & Frame.ICONIFIED) == 0 )) { |
| // //TODO remember we showed before and show again? I guess not worth the efford, not part of spec. |
| } |
| } |
| |
| } |
| |
| @Override |
| public void componentResized(ComponentEvent evt) { |
| if (showingPopup) { |
| resizePopup(); |
| } |
| } |
| |
| @Override |
| public void componentMoved(ComponentEvent evt) { |
| if (showingPopup) { |
| resizePopup(); |
| } |
| } |
| |
| } |
| |
| private class MListener extends MouseAdapter { |
| @Override |
| public void mouseClicked(java.awt.event.MouseEvent e) { |
| if (e.getButton() != MouseEvent.BUTTON1) { |
| showMenu(e); |
| } else { |
| if (showingPopup) { |
| hidePopup(); |
| } else { |
| showPopup(); |
| } |
| } |
| } |
| |
| } |
| |
| private void showMenu(MouseEvent e) { |
| JPopupMenu popup = new JPopupMenu(); |
| popup.add(new ProgressListAction(NbBundle.getMessage(StatusLineComponent.class, "StatusLineComponent.ShowProcessList"))); |
| popup.add(new ViewAction()); |
| popup.add(new CancelAction(true)); |
| popup.show((Component)e.getSource(), e.getX(), e.getY()); |
| } |
| |
| private class CancelAction extends AbstractAction { |
| public CancelAction(boolean text) { |
| if (text) { |
| putValue(Action.NAME, NbBundle.getMessage(StatusLineComponent.class, "StatusLineComponent.Cancel")); |
| } else { |
| Image icon = (Image)UIManager.get("nb.progress.cancel.icon"); |
| if (icon == null) { |
| // for custom L&F? |
| putValue(Action.SMALL_ICON, ImageUtilities.loadImageIcon("org/netbeans/progress/module/resources/buton.png", true)); |
| } else { |
| putValue(Action.SMALL_ICON, new ImageIcon(icon)); |
| } |
| } |
| setEnabled(handle == null ? false : handle.isAllowCancel()); |
| } |
| public @Override void actionPerformed(ActionEvent actionEvent) { |
| InternalHandle hndl = handle; |
| if (hndl !=null && hndl.getState() == InternalHandle.STATE_RUNNING) { |
| String message = NbBundle.getMessage(StatusLineComponent.class, "Cancel_Question", handle.getDisplayName()); |
| String title = NbBundle.getMessage(StatusLineComponent.class, "Cancel_Question_Title"); |
| NotifyDescriptor dd = new NotifyDescriptor(message, title, |
| NotifyDescriptor.YES_NO_OPTION, |
| NotifyDescriptor.QUESTION_MESSAGE, null, null); |
| Object retType = DialogDisplayer.getDefault().notify(dd); |
| if (retType == NotifyDescriptor.YES_OPTION && hndl.getState() == InternalHandle.STATE_RUNNING) { |
| hndl.requestCancel(); |
| } |
| } |
| } |
| } |
| |
| private class ViewAction extends AbstractAction { |
| public ViewAction() { |
| putValue(Action.NAME, NbBundle.getMessage(StatusLineComponent.class, "StatusLineComponent.View")); |
| setEnabled(handle == null ? false : handle.isAllowView()); |
| |
| } |
| public @Override void actionPerformed(ActionEvent actionEvent) { |
| if (handle != null) { |
| handle.requestView(); |
| } |
| } |
| } |
| |
| |
| private class EmptyCancelAction extends AbstractAction { |
| public EmptyCancelAction() { |
| setEnabled(false); |
| putValue(Action.SMALL_ICON, new Icon() { |
| public @Override int getIconHeight() { |
| return 12; |
| } |
| public @Override int getIconWidth() { |
| return 12; |
| } |
| public @Override void paintIcon(Component c, Graphics g, int x, int y) { |
| } |
| }); |
| putValue(Action.NAME, ""); |
| } |
| |
| public @Override void actionPerformed(ActionEvent e) { |
| } |
| } |
| |
| } |