/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.visualvm.core.ui;
import com.sun.tools.visualvm.core.datasource.DataSource;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptorFactory;
import com.sun.tools.visualvm.core.datasupport.DataRemovedListener;
import com.sun.tools.visualvm.core.datasupport.Stateful;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
/**
*
* @author Jiri Sedlacek
*/
final class DataSourceCaption<X extends DataSource> extends JComponent implements PropertyChangeListener, DataRemovedListener<DataSource> {
private static final boolean ANIMATE = Boolean.getBoolean("com.sun.tools.visualvm.core.ui.DataSourceCaption.animate"); // NOI18N
private static final int ANIMATION_RATE = Integer.getInteger("com.sun.tools.visualvm.core.ui.DataSourceCaption.animationRate", 80); // NOI18N
private static final Color DISABLED_CAPTION = new Color(128, 128, 128);
private static final String APPLICATION_PID_PREFIX = "(pid"; // NOI18N
private static final String APPLICATION_PID_SUFFIX = ")"; // NOI18N
private DataSource dataSource;
private DataSourceDescriptor<X> dataSourceDescriptor;
private boolean isAvailable;
private String name;
private String description;
private boolean finished = false;
public DataSourceCaption(X dataSource) {
initComponents();
this.dataSource = dataSource;
dataSource.addPropertyChangeListener(this);
dataSourceDescriptor = DataSourceDescriptorFactory.getDescriptor(dataSource);
dataSourceDescriptor.addPropertyChangeListener(this);
initAvailable();
name = dataSourceDescriptor.getName();
description = dataSourceDescriptor.getDescription();
updateCaption();
updateDescription();
updateAvailable();
dataSource.notifyWhenRemoved(this);
}
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if (Stateful.PROPERTY_STATE.equals(propertyName)) {
isAvailable = (Integer)evt.getNewValue() == Stateful.STATE_AVAILABLE;
updateAvailable();
updateCaption();
} else if (DataSourceDescriptor.PROPERTY_NAME.equals(propertyName)) {
name = (String)evt.getNewValue();
updateCaption();
} else if (DataSourceDescriptor.PROPERTY_DESCRIPTION.equals(propertyName)) {
description = (String)evt.getNewValue();
updateDescription();
} else if (DataSourceDescriptor.PROPERTY_ICON.equals(propertyName)) {
// Could display datasource icon instead of progress icon
// setIcon(new ImageIcon((Image)evt.getNewValue()));
}
}
public void dataRemoved(DataSource dataSource) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
finish();
isAvailable = false;
updateAvailable();
updateCaption();
}
});
}
public synchronized void finish() {
if (finished) return;
finished = true;
dataSource.removePropertyChangeListener(this);
dataSourceDescriptor.removePropertyChangeListener(this);
}
private void updateAvailable() {
if (isAvailable) {
if (ANIMATE) {
busyIconIndex = 0;
if (busyIconTimer == null) createTimer();
busyIconTimer.start();
} else {
presenter.setIcon(new ImageIcon(getClass().getResource("/com/sun/tools/visualvm/core/ui/resources/busy-icon4.png"))); // NOI18N
}
} else {
if (busyIconTimer != null) busyIconTimer.stop(); // Stop previous animation if still running
presenter.setIcon(new ImageIcon(getClass().getResource("/com/sun/tools/visualvm/core/ui/resources/idle-icon.png"))); // NOI18N
}
}
private void updateCaption() {
// TODO: mask all html-specific characters
name = name.replace(">", ">"); // NOI18N
name = name.replace("<", "<"); // NOI18N
Color textColor = isAvailable ? UIManager.getColor("Label.foreground") : DISABLED_CAPTION; // NOI18N
String textColorString = "rgb(" + textColor.getRed() + "," + textColor.getGreen() + "," + textColor.getBlue() + ")"; // NOI18N
if (name.contains(APPLICATION_PID_PREFIX) && name.contains(APPLICATION_PID_SUFFIX)) {
// Hack to customize default Application displayname containing "(pid XXX)"
int startPid = name.indexOf(APPLICATION_PID_PREFIX);
String captionBase = name.substring(0, startPid).trim();
String captionPid = name.substring(startPid).trim();
presenter.setText("<html><body style='font-size: 1.15em; color: " + textColorString + ";'><nobr>" + "<b>" + captionBase + "</b> " + captionPid + "</nobr></body></html>"); // NOI18N
} else {
presenter.setText("<html><body style='font-size: 1.15em; color: " + textColorString + ";'><nobr>" + "<b>" + name + "</b></nobr></body></html>"); // NOI18N
}
}
private void updateDescription() {
if (description == null || description.trim().length() == 0)
presenter.setToolTipText(null);
else presenter.setToolTipText(description);
}
private void createTimer() {
final Icon[] busyIcons = new Icon[15];
for (int i = 0; i < busyIcons.length; i++) busyIcons[i] = new ImageIcon(getClass().getResource("/com/sun/tools/visualvm/core/ui/resources/busy-icon" + i + ".png")); // NOI18N
busyIconTimer = new Timer(ANIMATION_RATE, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!ANIMATE) {
if (busyIconTimer != null) busyIconTimer.stop(); // Stop animation
presenter.setIcon(new ImageIcon(getClass().getResource("/com/sun/tools/visualvm/core/ui/resources/busy-icon4.png"))); // NOI18N
} else {
busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
if (!DataSourceCaption.this.isShowing()) return;
presenter.setIcon(busyIcons[busyIconIndex]);
}
}
});
}
private void initAvailable() {
if (dataSource instanceof Stateful) {
Stateful statefulDataSource = (Stateful)dataSource;
isAvailable = statefulDataSource.getState() == Stateful.STATE_AVAILABLE;
} else {
isAvailable = true;
}
}
private void initComponents() {
setLayout(new BorderLayout());
presenter = new JLabel();
presenter.setIconTextGap(6);
add(presenter, BorderLayout.CENTER);
}
private JLabel presenter;
private Timer busyIconTimer;
private int busyIconIndex;
}