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-2006 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: package org.netbeans.modules.progress.ui;
043:
044: import java.awt.Color;
045: import java.awt.Component;
046: import java.awt.Cursor;
047: import java.awt.Dimension;
048: import java.awt.Font;
049: import java.awt.Image;
050: import java.awt.LayoutManager;
051: import java.awt.event.ActionEvent;
052: import java.awt.event.FocusListener;
053: import java.awt.event.KeyEvent;
054: import java.awt.event.MouseAdapter;
055: import java.awt.event.MouseEvent;
056: import javax.swing.AbstractAction;
057: import javax.swing.Action;
058: import javax.swing.BorderFactory;
059: import javax.swing.ImageIcon;
060: import javax.swing.JButton;
061: import javax.swing.JLabel;
062: import javax.swing.JPanel;
063: import javax.swing.JPopupMenu;
064: import javax.swing.KeyStroke;
065: import javax.swing.UIManager;
066: import org.netbeans.progress.spi.InternalHandle;
067: import org.netbeans.progress.spi.ProgressEvent;
068: import org.openide.DialogDisplayer;
069: import org.openide.NotifyDescriptor;
070: import org.openide.util.NbBundle;
071: import org.openide.util.Utilities;
072:
073: /**
074: *
075: * @author mkleint
076: */
077: public class ListComponent extends JPanel {
078: private NbProgressBar bar;
079: private JLabel mainLabel;
080: private JLabel dynaLabel;
081: private JButton closeButton;
082: private InternalHandle handle;
083: private boolean watched;
084: private Action cancelAction;
085: private Color selectBgColor;
086: private Color selectFgColor;
087: private Color bgColor;
088: private Color fgColor;
089: // private Color dynaFgColor;
090: private int mainHeight;
091: private int dynaHeight;
092:
093: /** Creates a new instance of ListComponent */
094: public ListComponent(InternalHandle hndl) {
095: setFocusable(true);
096: setRequestFocusEnabled(true);
097: // setVerifyInputWhenFocusTarget(false);
098: mainLabel = new JLabel();
099: dynaLabel = new JLabel();
100: // in gtk, the panel is non-opague, meaning we cannot color background
101: // #59419
102: setOpaque(true);
103: dynaLabel.setFont(dynaLabel.getFont().deriveFont(
104: (float) (dynaLabel.getFont().getSize() - 2)));
105: bar = new NbProgressBar();
106: handle = hndl;
107: Color bg = UIManager
108: .getColor("nbProgressBar.popupText.background");
109: if (bg != null) {
110: setBackground(bg);
111: mainLabel.setBackground(bg);
112: dynaLabel.setBackground(bg);
113: }
114: bgColor = getBackground();
115: Color dynaFg = UIManager
116: .getColor("nbProgressBar.popupDynaText.foreground");
117: if (dynaFg != null) {
118: dynaLabel.setForeground(dynaFg);
119: }
120: // dynaFgColor = dynaLabel.getForeground();
121: fgColor = UIManager
122: .getColor("nbProgressBar.popupText.foreground");
123: if (fgColor != null) {
124: mainLabel.setForeground(fgColor);
125: }
126: fgColor = mainLabel.getForeground();
127: selectBgColor = UIManager
128: .getColor("nbProgressBar.popupText.selectBackground");
129: if (selectBgColor == null) {
130: selectBgColor = UIManager
131: .getColor("List.selectionBackground");
132: }
133: selectFgColor = UIManager
134: .getColor("nbProgressBar.popupText.selectForeground");
135: if (selectFgColor == null) {
136: selectFgColor = UIManager
137: .getColor("List.selectionForeground");
138: }
139: bar.setToolTipText(NbBundle.getMessage(ListComponent.class,
140: "ListComponent.bar.tooltip"));
141: bar.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
142: //start figure out height
143: mainLabel.setText("XYZ");
144: dynaLabel.setText("XYZ");
145: mainHeight = mainLabel.getPreferredSize().height;
146: dynaHeight = dynaLabel.getPreferredSize().height;
147: mainLabel.setText(null);
148: dynaLabel.setText(null);
149: //end figure out height
150:
151: setLayout(new CustomLayout());
152: add(mainLabel);
153: add(bar);
154: MListener list = new MListener();
155: if (handle.isAllowCancel()) {
156: cancelAction = new CancelAction(false);
157: closeButton = new JButton(cancelAction);
158: closeButton.setBorderPainted(false);
159: closeButton.setBorder(BorderFactory.createEmptyBorder());
160: closeButton.setOpaque(false);
161: closeButton.setContentAreaFilled(false);
162: closeButton.setFocusable(false);
163:
164: Image img = (Image) UIManager
165: .get("nb.progress.cancel.icon");
166: if (null != img) {
167: closeButton.setIcon(new ImageIcon(img));
168: }
169: img = (Image) UIManager
170: .get("nb.progress.cancel.icon.mouseover");
171: if (null != img) {
172: closeButton.setRolloverEnabled(true);
173: closeButton.setRolloverIcon(new ImageIcon(img));
174: }
175: img = (Image) UIManager
176: .get("nb.progress.cancel.icon.pressed");
177: if (null != img) {
178: closeButton.setPressedIcon(new ImageIcon(img));
179: }
180:
181: closeButton.setToolTipText(NbBundle.getMessage(
182: ListComponent.class,
183: "ListComponent.btnClose.tooltip"));
184: add(closeButton);
185: if (handle.getState() != InternalHandle.STATE_RUNNING) {
186: closeButton.setEnabled(false);
187: }
188: }
189: add(dynaLabel);
190: setBorder(BorderFactory.createEmptyBorder());
191: addMouseListener(list);
192: bar.addMouseListener(list);
193: mainLabel.addMouseListener(list);
194: dynaLabel.addMouseListener(list);
195: if (handle.isAllowCancel()) {
196: closeButton.addMouseListener(list);
197: }
198:
199: mainLabel.setText(handle.getDisplayName());
200: NbProgressBar.setupBar(handle, bar);
201: addFocusListener(new FocusListener() {
202: public void focusGained(java.awt.event.FocusEvent e) {
203: if (!e.isTemporary()) {
204: setBackground(selectBgColor);
205: mainLabel.setBackground(selectBgColor);
206: dynaLabel.setBackground(selectBgColor);
207: mainLabel.setForeground(selectFgColor);
208: // TODO assuming now that dynalabel has always the same foreground color
209: // seems to be the case according to the spec
210: scrollRectToVisible(getBounds());
211: }
212: }
213:
214: public void focusLost(java.awt.event.FocusEvent e) {
215: if (!e.isTemporary()) {
216: setBackground(bgColor);
217: mainLabel.setBackground(bgColor);
218: dynaLabel.setBackground(bgColor);
219: mainLabel.setForeground(fgColor);
220: // TODO assuming now that dynalabel has always the same foreground color
221: // seems to be the case according to the spec
222:
223: }
224: }
225:
226: });
227:
228: }
229:
230: Action getCancelAction() {
231: return cancelAction;
232: }
233:
234: InternalHandle getHandle() {
235: return handle;
236: }
237:
238: void processProgressEvent(ProgressEvent event) {
239: if (event.getType() == ProgressEvent.TYPE_PROGRESS
240: || event.getType() == ProgressEvent.TYPE_SWITCH
241: || event.getType() == ProgressEvent.TYPE_SILENT) {
242: if (event.getSource() != handle) {
243: throw new IllegalStateException();
244: }
245: if (event.isSwitched()) {
246: NbProgressBar.setupBar(event.getSource(), bar);
247: }
248: if (event.getWorkunitsDone() > 0) {
249: bar.setValue(event.getWorkunitsDone());
250: }
251: bar.setString(StatusLineComponent.getBarString(event
252: .getPercentageDone(), event
253: .getEstimatedCompletion()));
254: if (event.getMessage() != null) {
255: dynaLabel.setText(event.getMessage());
256: }
257: if (event.getSource().getState() == InternalHandle.STATE_REQUEST_STOP) {
258: closeButton.setEnabled(false);
259: }
260: if (event.getDisplayName() != null) {
261: mainLabel.setText(event.getDisplayName());
262: }
263: } else {
264: throw new IllegalStateException();
265: }
266: }
267:
268: void markAsActive(boolean sel) {
269: if (sel == watched) {
270: return;
271: }
272: watched = sel;
273: if (sel) {
274: mainLabel
275: .setFont(mainLabel.getFont().deriveFont(Font.BOLD));
276: } else {
277: mainLabel.setFont(mainLabel.getFont()
278: .deriveFont(Font.PLAIN));
279: }
280: if (mainLabel.isVisible()) {
281: mainLabel.repaint();
282: }
283: }
284:
285: private class MListener extends MouseAdapter {
286: public void mouseClicked(MouseEvent e) {
287: if (e.getSource() == bar) {
288: handle.requestExplicitSelection();
289: // markAsSelected(true);
290: }
291: if (e.getClickCount() > 1
292: && (e.getSource() == mainLabel || e.getSource() == dynaLabel)) {
293: handle.requestView();
294: }
295: if (e.getButton() != e.BUTTON1) {
296: showMenu(e);
297: } else {
298: ListComponent.this .requestFocus();
299: }
300:
301: // System.out.println("list component requesting focus..");
302: }
303: }
304:
305: private void showMenu(MouseEvent e) {
306: JPopupMenu popup = new JPopupMenu();
307: //mark teh popup for the status line awt listener
308: popup.setName("progresspopup");
309: popup.add(new ViewAction());
310: popup.add(new WatchAction());
311: popup.add(new CancelAction(true));
312: popup.show((Component) e.getSource(), e.getX(), e.getY());
313: }
314:
315: private class CancelAction extends AbstractAction {
316: CancelAction(boolean text) {
317: if (text) {
318: putValue(Action.NAME, NbBundle.getMessage(
319: ListComponent.class,
320: "StatusLineComponent.Cancel"));
321: putValue(Action.ACCELERATOR_KEY, KeyStroke
322: .getKeyStroke(KeyEvent.VK_DELETE, 0));
323: } else {
324: Image icon = (Image) UIManager
325: .get("nb.progress.cancel.icon");
326: if (icon == null) {
327: // for custom L&F?
328: icon = Utilities
329: .loadImage("org/netbeans/progress/module/resources/buton.png");
330: }
331: putValue(Action.SMALL_ICON, new ImageIcon(icon));
332: }
333: setEnabled(handle == null ? false : handle.isAllowCancel());
334: }
335:
336: public void actionPerformed(ActionEvent actionEvent) {
337: if (handle.getState() == InternalHandle.STATE_RUNNING) {
338: String message = NbBundle.getMessage(
339: ListComponent.class, "Cancel_Question", handle
340: .getDisplayName());
341: String title = NbBundle.getMessage(ListComponent.class,
342: "Cancel_Question_Title");
343: NotifyDescriptor dd = new NotifyDescriptor(message,
344: title, NotifyDescriptor.YES_NO_OPTION,
345: NotifyDescriptor.QUESTION_MESSAGE, null, null);
346: Object retType = DialogDisplayer.getDefault()
347: .notify(dd);
348: if (retType == NotifyDescriptor.YES_OPTION) {
349: handle.requestCancel();
350: }
351: }
352: }
353: }
354:
355: private class ViewAction extends AbstractAction {
356: public ViewAction() {
357: putValue(Action.NAME, NbBundle.getMessage(
358: ListComponent.class, "StatusLineComponent.View"));
359: setEnabled(handle == null ? false : handle.isAllowView());
360: putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
361: KeyEvent.VK_ENTER, 0));
362: }
363:
364: public void actionPerformed(ActionEvent actionEvent) {
365: if (handle != null) {
366: handle.requestView();
367: }
368: }
369: }
370:
371: private class WatchAction extends AbstractAction {
372: public WatchAction() {
373: putValue(Action.NAME, NbBundle.getMessage(
374: ListComponent.class, "ListComponent.Watch"));
375: putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
376: KeyEvent.VK_SPACE, 0));
377: setEnabled(true);
378: }
379:
380: public void actionPerformed(ActionEvent actionEvent) {
381: if (handle != null) {
382: handle.requestExplicitSelection();
383: }
384: }
385: }
386:
387: private static final int UPPERMARGIN = 3;
388: private static final int LEFTMARGIN = 2;
389: private static final int BOTTOMMARGIN = 2;
390: private static final int BETWEENTEXTMARGIN = 3;
391:
392: static final int ITEM_WIDTH = 400;
393:
394: private class CustomLayout implements LayoutManager {
395:
396: /**
397: * If the layout manager uses a per-component string,
398: * adds the component <code>comp</code> to the layout,
399: * associating it
400: * with the string specified by <code>name</code>.
401: *
402: * @param name the string to be associated with the component
403: * @param comp the component to be added
404: */
405: public void addLayoutComponent(String name,
406: java.awt.Component comp) {
407: }
408:
409: /**
410: * Calculates the preferred size dimensions for the specified
411: * container, given the components it contains.
412: * @param parent the container to be laid out
413: *
414: * @see #minimumLayoutSize
415: */
416: public Dimension preferredLayoutSize(java.awt.Container parent) {
417: int height = UPPERMARGIN + mainHeight + BETWEENTEXTMARGIN
418: + dynaHeight + BOTTOMMARGIN;
419: return new Dimension(ITEM_WIDTH, height);
420: }
421:
422: /**
423: *
424: * Lays out the specified container.
425: * @param parent the container to be laid out
426: */
427: public void layoutContainer(java.awt.Container parent) {
428: int parentWidth = parent.getWidth();
429: int parentHeight = parent.getHeight();
430: int offset = parentWidth - 18;
431: if (closeButton != null) {
432: closeButton.setBounds(offset, UPPERMARGIN, 18,
433: mainHeight);
434: }
435: // have the bar approx 30 percent of the width
436: int barOffset = offset - (ITEM_WIDTH / 3);
437: bar.setBounds(barOffset, UPPERMARGIN, offset - barOffset,
438: mainHeight);
439: mainLabel.setBounds(LEFTMARGIN, UPPERMARGIN, barOffset
440: - LEFTMARGIN, mainHeight);
441: dynaLabel.setBounds(LEFTMARGIN, mainHeight + UPPERMARGIN
442: + BETWEENTEXTMARGIN, parentWidth - LEFTMARGIN,
443: dynaHeight);
444: }
445:
446: /**
447: *
448: * Calculates the minimum size dimensions for the specified
449: * container, given the components it contains.
450: * @param parent the component to be laid out
451: * @see #preferredLayoutSize
452: */
453: public Dimension minimumLayoutSize(java.awt.Container parent) {
454: return preferredLayoutSize(parent);
455: }
456:
457: /**
458: * Removes the specified component from the layout.
459: * @param comp the component to be removed
460: */
461: public void removeLayoutComponent(java.awt.Component comp) {
462: }
463:
464: }
465: }
|