/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* Oracle and Java are registered trademarks of Oracle and/or its affiliates.
* Other names may be trademarks of their respective owners.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun
* Microsystems, Inc. All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*/
package org.netbeans.modules.ruby.platform;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.plaf.UIResource;
import org.netbeans.api.ruby.platform.RubyPlatform;
import org.netbeans.api.ruby.platform.RubyPlatformManager;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
public final class PlatformComponentFactory {
/** Generally usable in conjuction with {@link #createComboWaitModel}. */
private static final String DETECTING_VALUE =
NbBundle.getMessage(PlatformComponentFactory.class, "PlatformComponentFactory.detetctingPlatforms");
private static final Logger LOGGER = Logger.getLogger(PlatformComponentFactory.class.getName());
public static final Color INVALID_PLAF_COLOR = UIManager.getColor("nb.errorForeground"); // NOI18N
private PlatformComponentFactory() {
// don't allow instances
}
/**
* Returns <code>JComboBox</code> initialized with {@link
* RubyPlatformListModel} which contains all Ruby platform.
*/
public static JComboBox getRubyPlatformsComboxBox() {
final JComboBox plafComboBox = new JComboBox();
plafComboBox.setRenderer(new RubyPlatformListRenderer());
if (RubyPreferences.isFirstPlatformTouch()) {
plafComboBox.setModel(createComboWaitModel());
plafComboBox.setEnabled(false);
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
RubyPlatformManager.performPlatformDetection();
EventQueue.invokeLater(new Runnable() {
public void run() {
plafComboBox.setModel(new RubyPlatformListModel());
plafComboBox.setEnabled(true);
}
});
}
});
} else {
plafComboBox.setModel(new RubyPlatformListModel());
}
return plafComboBox;
}
public static RubyPlatform getPlatform(final JComboBox platforms) {
Object value = platforms.getModel().getSelectedItem();
return (value == DETECTING_VALUE) ? null : (RubyPlatform) value;
}
public static boolean isLoadingPlatforms(JComboBox platforms) {
Object value = platforms.getModel().getSelectedItem();
return value == DETECTING_VALUE;
}
/**
* Returns <code>JList</code> initialized with {@link RubyPlatformListModel}
* which contains all Ruby platform.
*/
public static JList getRubyPlatformsList() {
final JList plafList = new JList(createComboWaitModel());
plafList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
plafList.setCellRenderer(new RubyPlatformListRenderer());
if (RubyPreferences.isFirstPlatformTouch()) {
plafList.setModel(createListWaitModel());
plafList.setEnabled(false);
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
RubyPlatformManager.performPlatformDetection();
EventQueue.invokeLater(new Runnable() {
public void run() {
plafList.setModel(new RubyPlatformListModel());
plafList.setEnabled(true);
}
});
}
});
} else {
plafList.setModel(new RubyPlatformListModel());
}
return plafList;
}
/**
* Use this model in situation when you need to populate combo in the
* background. The only item in this model is {@link #DETECTING_VALUE}.
*/
public static ComboBoxModel createComboWaitModel() {
return new DefaultComboBoxModel(new Object[]{ DETECTING_VALUE });
}
/**
* Use this model in situation when you need to populate list in the
* background. The only item in this model is {@link #DETECTING_VALUE}.
*/
public static ListModel createListWaitModel() {
DefaultListModel listModel = new DefaultListModel();
listModel.addElement(DETECTING_VALUE);
return listModel;
}
public static void addPlatformChangeListener(final JComboBox platforms, final PlatformChangeListener pcl) {
platforms.addItemListener(pcl);
platforms.addPropertyChangeListener(pcl);
}
public static void removePlatformChangeListener(final JComboBox platforms, final PlatformChangeListener pcl) {
platforms.removeItemListener(pcl);
platforms.removePropertyChangeListener(pcl);
}
public static abstract class PlatformChangeListener implements ItemListener, PropertyChangeListener {
public abstract void platformChanged();
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
platformChanged();
}
}
public void propertyChange(PropertyChangeEvent evt) {
// when the model has changed from "Detectin platform" to valid
// platform model itemStateChanged is not fired(??)
if (evt.getPropertyName().equals("model")) { // NOI18N
platformChanged();
}
}
}
/**
* Returns model containing all <em>currently</em> registered RubyPlatforms.
* See also {@link RubyPlatform#getPlatforms}.
* <p>Use in conjuction with {@link RubyPlatformListRenderer}</p>
*/
public static class RubyPlatformListModel extends AbstractListModel
implements ComboBoxModel {
private static RubyPlatform[] getSortedPlatforms() {
Set<? extends RubyPlatform> platforms = RubyPlatformManager.getSortedPlatforms();
return platforms.toArray(new RubyPlatform[platforms.size()]);
}
private RubyPlatform[] nbPlafs;
private Object selectedPlaf;
public RubyPlatformListModel() {
nbPlafs = getSortedPlatforms();
if (nbPlafs.length > 0) {
selectedPlaf = nbPlafs[0];
}
}
public int getSize() {
return nbPlafs.length;
}
public Object getElementAt(int index) {
return index < nbPlafs.length ? nbPlafs[index] : null;
}
public void setSelectedItem(Object plaf) {
assert plaf == null || plaf instanceof RubyPlatform;
if (selectedPlaf != plaf) {
selectedPlaf = plaf;
fireContentsChanged(this, -1, -1);
}
}
public Object getSelectedItem() {
return selectedPlaf;
}
void removePlatform(RubyPlatform plaf) {
try {
RubyPlatformManager.removePlatform(plaf);
nbPlafs = getSortedPlatforms(); // refresh
fireContentsChanged(this, 0, nbPlafs.length - 1);
} catch (IOException e) {
// tell the user that something goes wrong
LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
}
}
RubyPlatform addPlatform(final File interpreter) {
try {
RubyPlatform platform = RubyPlatformManager.addPlatform(interpreter);
if (platform != null) {
nbPlafs = getSortedPlatforms(); // refresh
fireContentsChanged(this, 0, nbPlafs.length - 1);
}
return platform;
} catch (IOException e) {
// tell the user that something goes wrong
LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
}
return null;
}
}
/**
* Render {@link RubyPlatform}.
* <p>Use in conjuction with {@link RubyPlatformListModel}</p>
*/
private static class RubyPlatformListRenderer extends JLabel implements ListCellRenderer, UIResource {
public RubyPlatformListRenderer() {
setOpaque(true);
}
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
// #93658: GTK needs name to render cell renderer "natively"
setName("ComboBox.listRenderer"); // NOI18N
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
String label;
if (value instanceof String) {
label = (String) value;
} else {
RubyPlatform plaf = ((RubyPlatform) value);
if (plaf == null || !plaf.isValid()) {
label = plaf != null ? plaf.getLabel()
: NbBundle.getMessage(PlatformComponentFactory.class, "PlatformComponentFactory.invalid.platform");
setForeground(INVALID_PLAF_COLOR);
} else {
label = plaf.getLabel();
}
}
setText(label);
return this;
}
// #93658: GTK needs name to render cell renderer "natively"
public @Override String getName() {
String name = super.getName();
return name == null ? "ComboBox.renderer" : name; // NOI18N
}
}
}