0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU General
0007: * Public License Version 2 only ("GPL") or the Common Development and Distribution
0008: * License("CDDL") (collectively, the "License"). You may not use this file except in
0009: * compliance with the License. You can obtain a copy of the License at
0010: * http://www.netbeans.org/cddl-gplv2.html or nbbuild/licenses/CDDL-GPL-2-CP. See the
0011: * License for the specific language governing permissions and limitations under the
0012: * License. When distributing the software, include this License Header Notice in
0013: * each file and include the License file at nbbuild/licenses/CDDL-GPL-2-CP. Sun
0014: * designates this particular file as subject to the "Classpath" exception as
0015: * provided by Sun in the GPL Version 2 section of the License file that
0016: * accompanied this code. If applicable, add the following below the License Header,
0017: * with the fields enclosed by brackets [] replaced by your own identifying
0018: * information: "Portions Copyrighted [year] [name of copyright owner]"
0019: *
0020: * Contributor(s):
0021: *
0022: * The Original Software is NetBeans. The Initial Developer of the Original Software
0023: * is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun Microsystems, Inc. All
0024: * Rights Reserved.
0025: *
0026: * If you wish your version of this file to be governed by only the CDDL or only the
0027: * GPL Version 2, indicate your decision by adding "[Contributor] elects to include
0028: * this software in this distribution under the [CDDL or GPL Version 2] license." If
0029: * you do not indicate a single choice of license, a recipient has the option to
0030: * distribute your version of this file under either the CDDL, the GPL Version 2 or
0031: * to extend the choice of license to its licensees as provided above. However, if
0032: * you add GPL Version 2 code and therefore, elected the GPL Version 2 license, then
0033: * the option applies only if the new code is made subject to such option by the
0034: * copyright holder.
0035: */
0036:
0037: package org.netbeans.installer.wizard.components.panels;
0038:
0039: import java.awt.Color;
0040: import java.awt.Component;
0041: import java.awt.GridBagConstraints;
0042: import java.awt.GridBagLayout;
0043: import java.awt.Insets;
0044: import java.awt.event.ActionEvent;
0045: import java.awt.event.ActionListener;
0046: import java.awt.event.KeyEvent;
0047: import java.awt.event.MouseAdapter;
0048: import java.awt.event.MouseEvent;
0049: import java.io.File;
0050: import java.util.EventObject;
0051: import java.util.LinkedList;
0052: import java.util.List;
0053: import javax.swing.AbstractAction;
0054: import javax.swing.JCheckBox;
0055: import javax.swing.JComponent;
0056: import javax.swing.JTree;
0057: import javax.swing.KeyStroke;
0058: import javax.swing.UIManager;
0059: import javax.swing.border.EmptyBorder;
0060: import javax.swing.border.TitledBorder;
0061: import javax.swing.event.CellEditorListener;
0062: import javax.swing.event.ChangeEvent;
0063: import javax.swing.event.TreeModelEvent;
0064: import javax.swing.event.TreeModelListener;
0065: import javax.swing.event.TreeSelectionEvent;
0066: import javax.swing.event.TreeSelectionListener;
0067: import javax.swing.tree.TreeCellEditor;
0068: import javax.swing.tree.TreeCellRenderer;
0069: import javax.swing.tree.TreeModel;
0070: import javax.swing.tree.TreePath;
0071: import javax.swing.tree.TreeSelectionModel;
0072: import org.netbeans.installer.Installer;
0073: import org.netbeans.installer.product.RegistryType;
0074: import org.netbeans.installer.product.components.Product;
0075: import org.netbeans.installer.product.Registry;
0076: import org.netbeans.installer.product.RegistryNode;
0077: import org.netbeans.installer.product.components.Group;
0078: import org.netbeans.installer.product.dependencies.Conflict;
0079: import org.netbeans.installer.product.dependencies.Requirement;
0080: import org.netbeans.installer.utils.ErrorManager;
0081: import org.netbeans.installer.utils.helper.Dependency;
0082: import org.netbeans.installer.utils.helper.Status;
0083: import org.netbeans.installer.utils.ResourceUtils;
0084: import org.netbeans.installer.utils.StringUtils;
0085: import org.netbeans.installer.utils.SystemUtils;
0086: import org.netbeans.installer.utils.exceptions.NativeException;
0087: import org.netbeans.installer.utils.helper.Version;
0088: import org.netbeans.installer.utils.helper.swing.NbiCheckBox;
0089: import org.netbeans.installer.utils.helper.swing.NbiLabel;
0090: import org.netbeans.installer.utils.helper.swing.NbiPanel;
0091: import org.netbeans.installer.utils.helper.swing.NbiScrollPane;
0092: import org.netbeans.installer.utils.helper.swing.NbiTextPane;
0093: import org.netbeans.installer.utils.helper.swing.NbiTree;
0094: import org.netbeans.installer.wizard.ui.SwingUi;
0095: import org.netbeans.installer.wizard.ui.WizardUi;
0096: import org.netbeans.installer.wizard.containers.SwingContainer;
0097:
0098: /**
0099: *
0100: * @author Kirill Sorokin
0101: */
0102: public class ComponentsSelectionPanel extends ErrorMessagePanel {
0103: /////////////////////////////////////////////////////////////////////////////////
0104: // Instance
0105: public ComponentsSelectionPanel() {
0106: setProperty(TITLE_PROPERTY, DEFAULT_TITLE);
0107: setProperty(DESCRIPTION_PROPERTY, DEFAULT_DESCRIPTION);
0108: setProperty(DESCRIPTION_INSTALL_PROPERTY,
0109: DEFAULT_DESCRIPTION_INSTALL);
0110: setProperty(DESCRIPTION_UNINSTALL_PROPERTY,
0111: DEFAULT_DESCRIPTION_UNINSTALL);
0112: setProperty(FEATURE_DESCRIPTION_TITLE_PROPERTY,
0113: DEFAULT_FEATURE_DESCRIPTION_TITLE);
0114:
0115: setProperty(COMPONENT_DESCRIPTION_TEXT_PROPERTY,
0116: DEFAULT_COMPONENT_DESCRIPTION_TEXT);
0117: setProperty(COMPONENT_DESCRIPTION_CONTENT_TYPE_PROPERTY,
0118: DEFAULT_COMPONENT_DESCRIPTION_CONTENT_TYPE);
0119: setProperty(SIZES_LABEL_TEXT_PROPERTY, DEFAULT_SIZES_LABEL_TEXT);
0120: setProperty(SIZES_LABEL_TEXT_NO_DOWNLOAD_PROPERTY,
0121: DEFAULT_SIZES_LABEL_TEXT_NO_DOWNLOAD);
0122:
0123: setProperty(DEFAULT_INSTALLATION_SIZE_PROPERTY,
0124: DEFAULT_INSTALLATION_SIZE);
0125: setProperty(DEFAULT_DOWNLOAD_SIZE_PROPERTY,
0126: DEFAULT_DOWNLOAD_SIZE);
0127:
0128: setProperty(ERROR_NO_CHANGES_PROPERTY, DEFAULT_ERROR_NO_CHANGES);
0129: setProperty(ERROR_NO_CHANGES_INSTALL_ONLY_PROPERTY,
0130: DEFAULT_ERROR_NO_CHANGES_INSTALL_ONLY);
0131: setProperty(ERROR_NO_CHANGES_UNINSTALL_ONLY_PROPERTY,
0132: DEFAULT_ERROR_NO_CHANGES_UNINSTALL_ONLY);
0133: setProperty(ERROR_REQUIREMENT_INSTALL_PROPERTY,
0134: DEFAULT_ERROR_REQUIREMENT_INSTALL);
0135: setProperty(ERROR_CONFLICT_INSTALL_PROPERTY,
0136: DEFAULT_ERROR_CONFLICT_INSTALL);
0137: setProperty(ERROR_REQUIREMENT_UNINSTALL_PROPERTY,
0138: DEFAULT_ERROR_REQUIREMENT_UNINSTALL);
0139: setProperty(ERROR_NO_ENOUGH_SPACE_TO_DOWNLOAD_PROPERTY,
0140: DEFAULT_ERROR_NO_ENOUGH_SPACE_TO_DOWNLOAD);
0141: setProperty(ERROR_NO_ENOUGH_SPACE_TO_EXTRACT_PROPERTY,
0142: DEFAULT_ERROR_NO_ENOUGH_SPACE_TO_EXTRACT);
0143: setProperty(ERROR_CANNOT_CHECK_SPACE_PROPERTY,
0144: DEFAULT_ERROR_CANNOT_CHECK_SPACE);
0145: }
0146:
0147: @Override
0148: public WizardUi getWizardUi() {
0149: if (wizardUi == null) {
0150: wizardUi = new ComponentsSelectionPanelUi(this );
0151: }
0152:
0153: return wizardUi;
0154: }
0155:
0156: @Override
0157: public boolean canExecuteForward() {
0158: return canExecute();
0159: }
0160:
0161: @Override
0162: public boolean canExecuteBackward() {
0163: return canExecute();
0164: }
0165:
0166: @Override
0167: public void initialize() {
0168: if (!isThereAnythingVisibleToInstall()) {
0169: setProperty(DESCRIPTION_PROPERTY,
0170: getProperty(DESCRIPTION_UNINSTALL_PROPERTY));
0171: }
0172: if (!isThereAnythingVisibleToUninstall()) {
0173: setProperty(DESCRIPTION_PROPERTY,
0174: getProperty(DESCRIPTION_INSTALL_PROPERTY));
0175: }
0176: }
0177:
0178: // private //////////////////////////////////////////////////////////////////////
0179: private boolean canExecute() {
0180: return !(Boolean.getBoolean(Registry.FORCE_INSTALL_PROPERTY) || Boolean
0181: .getBoolean(Registry.FORCE_UNINSTALL_PROPERTY));
0182: }
0183:
0184: private boolean isThereAnythingVisibleToInstall() {
0185: final Registry registry = Registry.getInstance();
0186:
0187: final List<Product> toInstall = new LinkedList<Product>();
0188: toInstall.addAll(registry.getProducts(Status.NOT_INSTALLED));
0189: toInstall.addAll(registry.getProducts(Status.TO_BE_INSTALLED));
0190:
0191: for (Product product : toInstall) {
0192: if (product.isVisible()) {
0193: return true;
0194: }
0195: }
0196:
0197: return false;
0198: }
0199:
0200: private boolean isThereAnythingVisibleToUninstall() {
0201: final Registry registry = Registry.getInstance();
0202:
0203: final List<Product> toUninstall = new LinkedList<Product>();
0204: toUninstall.addAll(registry.getProducts(Status.INSTALLED));
0205: toUninstall.addAll(registry
0206: .getProducts(Status.TO_BE_UNINSTALLED));
0207:
0208: for (Product product : toUninstall) {
0209: if (product.isVisible()) {
0210: return true;
0211: }
0212: }
0213:
0214: return false;
0215: }
0216:
0217: /////////////////////////////////////////////////////////////////////////////////
0218: // Inner Classes
0219: public static class ComponentsSelectionPanelUi extends
0220: ErrorMessagePanelUi {
0221: private ComponentsSelectionPanel panel;
0222:
0223: public ComponentsSelectionPanelUi(
0224: final ComponentsSelectionPanel panel) {
0225: super (panel);
0226:
0227: this .panel = panel;
0228: }
0229:
0230: public SwingUi getSwingUi(SwingContainer container) {
0231: if (swingUi == null) {
0232: swingUi = new ComponentsSelectionPanelSwingUi(panel,
0233: container);
0234: }
0235:
0236: return super .getSwingUi(container);
0237: }
0238: }
0239:
0240: public static class ComponentsSelectionPanelSwingUi extends
0241: ErrorMessagePanelSwingUi {
0242: /////////////////////////////////////////////////////////////////////////////
0243: // Instance
0244: private ComponentsSelectionPanel panel;
0245:
0246: private NbiTree componentsTree;
0247: private NbiScrollPane componentsScrollPane;
0248:
0249: private NbiTextPane descriptionPane;
0250: private NbiScrollPane descriptionScrollPane;
0251:
0252: private NbiLabel sizesLabel;
0253:
0254: public ComponentsSelectionPanelSwingUi(
0255: final ComponentsSelectionPanel component,
0256: final SwingContainer container) {
0257: super (component, container);
0258:
0259: this .panel = component;
0260:
0261: initComponents();
0262: }
0263:
0264: @Override
0265: protected void initialize() {
0266: descriptionPane
0267: .setContentType(panel
0268: .getProperty(COMPONENT_DESCRIPTION_CONTENT_TYPE_PROPERTY));
0269:
0270: if (!panel.isThereAnythingVisibleToInstall()) {
0271: sizesLabel.setVisible(false);
0272: }
0273:
0274: updateDescription();
0275: updateSizes();
0276:
0277: super .initialize();
0278: }
0279:
0280: @Override
0281: protected String validateInput() {
0282: final Registry registry = Registry.getInstance();
0283:
0284: final List<Product> toInstall = registry
0285: .getProducts(Status.TO_BE_INSTALLED);
0286: final List<Product> toUninstall = registry
0287: .getProducts(Status.TO_BE_UNINSTALLED);
0288:
0289: if ((toInstall.size() == 0) && (toUninstall.size() == 0)) {
0290: if (!panel.isThereAnythingVisibleToInstall()) {
0291: return panel
0292: .getProperty(ERROR_NO_CHANGES_UNINSTALL_ONLY_PROPERTY);
0293: }
0294:
0295: if (!panel.isThereAnythingVisibleToUninstall()) {
0296: return panel
0297: .getProperty(ERROR_NO_CHANGES_INSTALL_ONLY_PROPERTY);
0298: }
0299:
0300: return panel.getProperty(ERROR_NO_CHANGES_PROPERTY);
0301: }
0302:
0303: for (Product product : toInstall) {
0304: for (Dependency requirement : product
0305: .getDependencies(Requirement.class)) {
0306: final List<Product> requirees = registry
0307: .getProducts(requirement);
0308:
0309: boolean satisfied = false;
0310:
0311: for (Product requiree : requirees) {
0312: if ((requiree.getStatus() == Status.TO_BE_INSTALLED)
0313: || (requiree.getStatus() == Status.INSTALLED)) {
0314: satisfied = true;
0315: break;
0316: }
0317: }
0318:
0319: if (!satisfied) {
0320: return StringUtils
0321: .format(
0322: panel
0323: .getProperty(ERROR_REQUIREMENT_INSTALL_PROPERTY),
0324: product.getDisplayName(),
0325: requirees.get(0)
0326: .getDisplayName());
0327: }
0328: }
0329:
0330: for (Dependency conflict : product
0331: .getDependencies(Conflict.class)) {
0332: final List<Product> conflictees = registry
0333: .getProducts(conflict);
0334:
0335: boolean satisfied = true;
0336: Product unsatisfiedConflict = null;
0337:
0338: for (Product conflictee : conflictees) {
0339: if ((conflictee.getStatus() == Status.TO_BE_INSTALLED)
0340: || (conflictee.getStatus() == Status.INSTALLED)) {
0341: satisfied = false;
0342: unsatisfiedConflict = conflictee;
0343: break;
0344: }
0345: }
0346:
0347: if (!satisfied) {
0348: return StringUtils
0349: .format(
0350: panel
0351: .getProperty(ERROR_CONFLICT_INSTALL_PROPERTY),
0352: product.getDisplayName(),
0353: unsatisfiedConflict
0354: .getDisplayName());
0355: }
0356: }
0357: }
0358:
0359: for (Product product : toUninstall) {
0360: for (Product dependent : registry.getProducts()) {
0361: if ((dependent.getStatus() == Status.TO_BE_UNINSTALLED)
0362: || (dependent.getStatus() == Status.NOT_INSTALLED)) {
0363: continue;
0364: }
0365:
0366: for (Dependency requirement : dependent
0367: .getDependencies(Requirement.class)) {
0368: final List<Product> requirees = registry
0369: .getProducts(requirement);
0370:
0371: if (requirees.contains(product)) {
0372: boolean satisfied = false;
0373: for (Product requiree : requirees) {
0374: if (requiree.getStatus() == Status.INSTALLED) {
0375: satisfied = true;
0376: break;
0377: }
0378: }
0379:
0380: if (!satisfied) {
0381: return StringUtils
0382: .format(
0383: panel
0384: .getProperty(ERROR_REQUIREMENT_UNINSTALL_PROPERTY),
0385: product
0386: .getDisplayName(),
0387: dependent
0388: .getDisplayName());
0389: }
0390: }
0391: }
0392: }
0393: }
0394:
0395: // devise the error message template which should be used - "not enough
0396: // space to download..." is at least one of the components comes from
0397: // a remote registry, "not enough space to extract..." - otherwise
0398: String template = panel
0399: .getProperty(ERROR_NO_ENOUGH_SPACE_TO_EXTRACT_PROPERTY);
0400: for (Product product : toInstall) {
0401: if (product.getRegistryType() == RegistryType.REMOTE) {
0402: template = panel
0403: .getProperty(ERROR_NO_ENOUGH_SPACE_TO_DOWNLOAD_PROPERTY);
0404: break;
0405: }
0406: }
0407:
0408: // check whether the space available in the local directory (which will
0409: // be used for downloading data) is enough to keep all the installation
0410: // data and configuration logic (plus some margin for safety)
0411: try {
0412: if (!Boolean
0413: .getBoolean(SystemUtils.NO_SPACE_CHECK_PROPERTY)) {
0414:
0415: final File localDirectory = Installer.getInstance()
0416: .getLocalDirectory();
0417: final long availableSize = SystemUtils
0418: .getFreeSpace(localDirectory);
0419:
0420: long requiredSize = 0;
0421: for (Product product : toInstall) {
0422: requiredSize += product.getDownloadSize();
0423: }
0424: requiredSize += REQUIRED_SPACE_ADDITION;
0425:
0426: if (availableSize < requiredSize) {
0427: return StringUtils.format(template,
0428: localDirectory, StringUtils
0429: .formatSize(requiredSize
0430: - availableSize));
0431: }
0432: }
0433: } catch (NativeException e) {
0434: ErrorManager
0435: .notifyError(
0436: panel
0437: .getProperty(ERROR_CANNOT_CHECK_SPACE_PROPERTY),
0438: e);
0439: }
0440:
0441: return null;
0442: }
0443:
0444: @Override
0445: public JComponent getDefaultFocusOwner() {
0446: return componentsTree;
0447: }
0448:
0449: // private //////////////////////////////////////////////////////////////////
0450: private void initComponents() {
0451: // componentsTree ///////////////////////////////////////////////////////
0452: componentsTree = new NbiTree();
0453: componentsTree.setModel(new ComponentsTreeModel());
0454: componentsTree.setCellRenderer(new ComponentsTreeCell());
0455: componentsTree.setEditable(true);
0456: componentsTree.setCellEditor(new ComponentsTreeCell());
0457: componentsTree.setShowsRootHandles(true);
0458: componentsTree.setRootVisible(false);
0459: componentsTree.setBorder(new EmptyBorder(5, 5, 5, 5));
0460: componentsTree.setRowHeight(new JCheckBox()
0461: .getPreferredSize().height);
0462: componentsTree.getSelectionModel().setSelectionMode(
0463: TreeSelectionModel.SINGLE_TREE_SELECTION);
0464: componentsTree.getSelectionModel()
0465: .addTreeSelectionListener(
0466: new TreeSelectionListener() {
0467: public void valueChanged(
0468: TreeSelectionEvent event) {
0469: updateDescription();
0470: }
0471: });
0472: componentsTree.getModel().addTreeModelListener(
0473: new TreeModelListener() {
0474: public void treeNodesChanged(
0475: TreeModelEvent event) {
0476: updateSizes();
0477: updateErrorMessage();
0478: }
0479:
0480: public void treeNodesInserted(
0481: TreeModelEvent event) {
0482: // does nothing
0483: }
0484:
0485: public void treeNodesRemoved(
0486: TreeModelEvent event) {
0487: // does nothing
0488: }
0489:
0490: public void treeStructureChanged(
0491: TreeModelEvent event) {
0492: // does nothing
0493: }
0494: });
0495: componentsTree.getActionMap().put("checkbox.update",
0496: new AbstractAction("checkbox.update") {
0497: public void actionPerformed(ActionEvent event) {
0498: final TreePath path = componentsTree
0499: .getSelectionPath();
0500:
0501: if (path != null) {
0502: componentsTree
0503: .getModel()
0504: .valueForPathChanged(path, null);
0505: }
0506: }
0507: });
0508: componentsTree.getInputMap()
0509: .put(
0510: KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,
0511: 0, false), "checkbox.update");
0512:
0513: // componentsScrollPane /////////////////////////////////////////////////
0514: componentsScrollPane = new NbiScrollPane(componentsTree);
0515:
0516: // descriptionPane //////////////////////////////////////////////////////
0517: descriptionPane = new NbiTextPane();
0518: descriptionPane.setBorder(new EmptyBorder(5, 5, 5, 5));
0519:
0520: // descriptionScrollPane ////////////////////////////////////////////////
0521: descriptionScrollPane = new NbiScrollPane(descriptionPane);
0522: descriptionScrollPane
0523: .setVerticalScrollBarPolicy(NbiScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
0524: descriptionScrollPane.setBorder(new TitledBorder(panel
0525: .getProperty(FEATURE_DESCRIPTION_TITLE_PROPERTY)));
0526:
0527: // sizesLabel ///////////////////////////////////////////////////////////
0528: sizesLabel = new NbiLabel();
0529: sizesLabel.setFocusable(true);
0530:
0531: // this /////////////////////////////////////////////////////////////////
0532: add(componentsScrollPane, new GridBagConstraints(0, 0, // x, y
0533: 1, 1, // width, height
0534: 0.7, 1.0, // weight-x, weight-y
0535: GridBagConstraints.PAGE_START, // anchor
0536: GridBagConstraints.BOTH, // fill
0537: new Insets(11, 11, 0, 0), // padding
0538: 0, 0)); // padx, pady - ???
0539: add(descriptionScrollPane, new GridBagConstraints(1, 0, // x, y
0540: 1, 1, // width, height
0541: 0.3, 1.0, // weight-x, weight-y
0542: GridBagConstraints.PAGE_START, // anchor
0543: GridBagConstraints.BOTH, // fill
0544: new Insets(11, 6, 0, 11), // padding
0545: 0, 0)); // padx, pady - ???
0546: add(sizesLabel, new GridBagConstraints(0, 1, // x, y
0547: 2, 1, // width, height
0548: 1.0, 0.0, // weight-x, weight-y
0549: GridBagConstraints.LINE_START, // anchor
0550: GridBagConstraints.HORIZONTAL, // fill
0551: new Insets(6, 11, 0, 11), // padding
0552: 0, 0)); // padx, pady - ???
0553:
0554: // run through all nodes and expand those that have the expand flag set
0555: // to true
0556: for (RegistryNode node : Registry.getInstance().getNodes()) {
0557: if (node.getExpand()) {
0558: componentsTree.expandPath(node.getTreePath());
0559: }
0560: }
0561:
0562: // l&f-specific tweaks
0563: if (UIManager.getLookAndFeel().getID().equals("GTK")) {
0564: descriptionPane.setOpaque(true);
0565: }
0566: }
0567:
0568: private void updateDescription() {
0569: final TreePath path = componentsTree.getSelectionPath();
0570:
0571: if (path != null) {
0572: final RegistryNode node = (RegistryNode) path
0573: .getLastPathComponent();
0574: descriptionPane.setText(node.getDescription());
0575: } else {
0576: descriptionPane.clearText();
0577: }
0578:
0579: descriptionPane.setCaretPosition(0);
0580: }
0581:
0582: private void updateSizes() {
0583: final Registry registry = Registry.getInstance();
0584:
0585: long installationSize = 0;
0586: long downloadSize = 0;
0587: for (Product product : registry.getProductsToInstall()) {
0588: installationSize += product.getRequiredDiskSpace();
0589: downloadSize += product.getDownloadSize();
0590: }
0591:
0592: String template = panel
0593: .getProperty(SIZES_LABEL_TEXT_NO_DOWNLOAD_PROPERTY);
0594: for (RegistryNode remoteNode : registry
0595: .getNodes(RegistryType.REMOTE)) {
0596: if (remoteNode.isVisible()) {
0597: template = panel
0598: .getProperty(SIZES_LABEL_TEXT_PROPERTY);
0599: }
0600: }
0601:
0602: if (installationSize == 0) {
0603: sizesLabel
0604: .setText(StringUtils
0605: .format(
0606: template,
0607: panel
0608: .getProperty(DEFAULT_INSTALLATION_SIZE_PROPERTY),
0609: panel
0610: .getProperty(DEFAULT_DOWNLOAD_SIZE_PROPERTY)));
0611: } else {
0612: sizesLabel.setText(StringUtils.format(template,
0613: StringUtils.formatSize(installationSize),
0614: StringUtils.formatSize(downloadSize)));
0615: }
0616: }
0617: }
0618:
0619: public static class ComponentsTreeModel implements TreeModel {
0620: private List<TreeModelListener> listeners = new LinkedList<TreeModelListener>();
0621:
0622: public Object getRoot() {
0623: return Registry.getInstance().getRegistryRoot();
0624: }
0625:
0626: public Object getChild(final Object node, final int index) {
0627: return ((RegistryNode) node).getVisibleChildren()
0628: .get(index);
0629: }
0630:
0631: public int getChildCount(final Object node) {
0632: return ((RegistryNode) node).getVisibleChildren().size();
0633: }
0634:
0635: public boolean isLeaf(final Object node) {
0636: return ((RegistryNode) node).getVisibleChildren().size() == 0;
0637: }
0638:
0639: public void valueForPathChanged(final TreePath path,
0640: final Object value) {
0641: if (path.getLastPathComponent() instanceof Product) {
0642: final Product product = (Product) path
0643: .getLastPathComponent();
0644:
0645: switch (product.getStatus()) {
0646: case NOT_INSTALLED:
0647: product.setStatus(Status.TO_BE_INSTALLED);
0648: updateRequirements(product);
0649: break;
0650: case TO_BE_INSTALLED:
0651: product.setStatus(Status.NOT_INSTALLED);
0652: break;
0653: case INSTALLED:
0654: product.setStatus(Status.TO_BE_UNINSTALLED);
0655: break;
0656: case TO_BE_UNINSTALLED:
0657: product.setStatus(Status.INSTALLED);
0658: break;
0659: }
0660: }
0661:
0662: final TreeModelListener[] clone;
0663: synchronized (listeners) {
0664: clone = listeners.toArray(new TreeModelListener[0]);
0665: }
0666:
0667: final TreeModelEvent event = new TreeModelEvent(this , path);
0668: for (TreeModelListener listener : clone) {
0669: listener.treeNodesChanged(event);
0670: }
0671: }
0672:
0673: public int getIndexOfChild(final Object node, final Object child) {
0674: return ((RegistryNode) node).getVisibleChildren().indexOf(
0675: child);
0676: }
0677:
0678: public void addTreeModelListener(
0679: final TreeModelListener listener) {
0680: synchronized (listeners) {
0681: listeners.add(listener);
0682: }
0683: }
0684:
0685: public void removeTreeModelListener(
0686: final TreeModelListener listener) {
0687: synchronized (listeners) {
0688: listeners.remove(listener);
0689: }
0690: }
0691:
0692: // private //////////////////////////////////////////////////////////////////
0693: private void updateRequirements(final Product product) {
0694: // check whether the requirements are satisfied and if there
0695: // is an unsatisfied requirement - pick an appropriate
0696: // product and select it
0697: for (Dependency requirement : product
0698: .getDependencies(Requirement.class)) {
0699: final List<Product> requirees = Registry.getInstance()
0700: .getProducts(requirement);
0701:
0702: boolean requireesNeedUpdate = true;
0703: Product correctRequiree = null;
0704: for (Product requiree : requirees) {
0705: final Version version = requiree.getVersion();
0706:
0707: if ((requiree.getStatus() == Status.INSTALLED)
0708: || (requiree.getStatus() == Status.TO_BE_INSTALLED)) {
0709: requireesNeedUpdate = false;
0710: break;
0711: }
0712: if ((correctRequiree == null)
0713: || correctRequiree.getVersion().olderThan(
0714: version)) {
0715: correctRequiree = requiree;
0716: }
0717: }
0718:
0719: if (requireesNeedUpdate && !requirees.isEmpty()) {
0720: valueForPathChanged(correctRequiree.getTreePath(),
0721: null);
0722: }
0723: }
0724: }
0725: }
0726:
0727: public static class ComponentsTreeCell implements TreeCellRenderer,
0728: TreeCellEditor {
0729: private List<CellEditorListener> listeners = new LinkedList<CellEditorListener>();
0730:
0731: private NbiPanel panel;
0732: private NbiCheckBox checkBox;
0733: private NbiLabel iconLabel;
0734: private NbiLabel titleLabel;
0735: private NbiLabel statusLabel;
0736:
0737: private Color foreground;
0738: private Color background;
0739:
0740: private Color selectionForeground;
0741: private Color selectionBackground;
0742:
0743: public ComponentsTreeCell() {
0744: foreground = UIManager.getColor("Tree.textForeground");
0745: background = UIManager.getColor("Tree.textBackground");
0746:
0747: selectionForeground = UIManager
0748: .getColor("Tree.selectionForeground");
0749: selectionBackground = UIManager
0750: .getColor("Tree.selectionBackground");
0751:
0752: initComponents();
0753: }
0754:
0755: public Component getTreeCellRendererComponent(final JTree tree,
0756: final Object value, final boolean selected,
0757: final boolean expanded, final boolean leaf,
0758: final int row, final boolean focus) {
0759: return getComponent(tree, value, selected, expanded, leaf,
0760: row, focus);
0761: }
0762:
0763: public Component getTreeCellEditorComponent(final JTree tree,
0764: final Object value, final boolean selected,
0765: final boolean expanded, final boolean leaf,
0766: final int row) {
0767: return getComponent(tree, value, selected, expanded, leaf,
0768: row, true);
0769: }
0770:
0771: public Object getCellEditorValue() {
0772: return null;
0773: }
0774:
0775: public boolean isCellEditable(final EventObject event) {
0776: return true;
0777: }
0778:
0779: public boolean shouldSelectCell(final EventObject event) {
0780: return true;
0781: }
0782:
0783: public boolean stopCellEditing() {
0784: fireEditingStopped();
0785: return true;
0786: }
0787:
0788: public void cancelCellEditing() {
0789: fireEditingCanceled();
0790: }
0791:
0792: public void addCellEditorListener(
0793: final CellEditorListener listener) {
0794: synchronized (listeners) {
0795: listeners.add(listener);
0796: }
0797: }
0798:
0799: public void removeCellEditorListener(
0800: final CellEditorListener listener) {
0801: synchronized (listeners) {
0802: listeners.remove(listener);
0803: }
0804: }
0805:
0806: // private //////////////////////////////////////////////////////////////////
0807: private void initComponents() {
0808: // panel ////////////////////////////////////////////////////////////////
0809: panel = new NbiPanel();
0810: panel.setLayout(new GridBagLayout());
0811: panel.setOpaque(false);
0812:
0813: // checkBox /////////////////////////////////////////////////////////////
0814: checkBox = new NbiCheckBox();
0815: checkBox.setOpaque(false);
0816: checkBox.setFocusable(false);
0817: checkBox.addActionListener(new ActionListener() {
0818: public void actionPerformed(final ActionEvent event) {
0819: stopCellEditing();
0820: }
0821: });
0822:
0823: // iconLabel ////////////////////////////////////////////////////////////
0824: iconLabel = new NbiLabel();
0825: iconLabel.setFocusable(false);
0826: iconLabel.addMouseListener(new MouseAdapter() {
0827: public void mouseClicked(final MouseEvent event) {
0828: cancelCellEditing();
0829: }
0830:
0831: public void mousePressed(final MouseEvent event) {
0832: cancelCellEditing();
0833: }
0834:
0835: public void mouseReleased(final MouseEvent event) {
0836: cancelCellEditing();
0837: }
0838: });
0839:
0840: // titleLabel ///////////////////////////////////////////////////////////
0841: titleLabel = new NbiLabel();
0842: titleLabel.setFocusable(false);
0843: titleLabel.addMouseListener(new MouseAdapter() {
0844: public void mouseClicked(final MouseEvent event) {
0845: cancelCellEditing();
0846: }
0847:
0848: public void mousePressed(final MouseEvent event) {
0849: cancelCellEditing();
0850: }
0851:
0852: public void mouseReleased(final MouseEvent event) {
0853: cancelCellEditing();
0854: }
0855: });
0856:
0857: // statusLabel //////////////////////////////////////////////////////////
0858: statusLabel = new NbiLabel();
0859: statusLabel.setForeground(Color.GRAY);
0860: statusLabel.setFocusable(false);
0861: statusLabel.addMouseListener(new MouseAdapter() {
0862: public void mouseClicked(final MouseEvent event) {
0863: cancelCellEditing();
0864: }
0865:
0866: public void mousePressed(final MouseEvent event) {
0867: cancelCellEditing();
0868: }
0869:
0870: public void mouseReleased(final MouseEvent event) {
0871: cancelCellEditing();
0872: }
0873: });
0874:
0875: // this /////////////////////////////////////////////////////////////////
0876: panel.add(checkBox, new GridBagConstraints(0, 0, // x, y
0877: 1, 1, // width, height
0878: 0.0, 0.0, // weight-x, weight-y
0879: GridBagConstraints.CENTER, // anchor
0880: GridBagConstraints.BOTH, // fill
0881: new Insets(0, 0, 0, 0), // padding
0882: 0, 0)); // padx, pady - ???);
0883: panel.add(iconLabel, new GridBagConstraints(1, 0, // x, y
0884: 1, 1, // width, height
0885: 0.0, 0.0, // weight-x, weight-y
0886: GridBagConstraints.CENTER, // anchor
0887: GridBagConstraints.BOTH, // fill
0888: new Insets(0, 0, 0, 0), // padding
0889: 0, 0)); // padx, pady - ???);
0890: panel.add(titleLabel, new GridBagConstraints(2, 0, // x, y
0891: 1, 1, // width, height
0892: 1.0, 0.0, // weight-x, weight-y
0893: GridBagConstraints.CENTER, // anchor
0894: GridBagConstraints.BOTH, // fill
0895: new Insets(0, 0, 0, 0), // padding
0896: 0, 0)); // padx, pady - ???);
0897: panel.add(statusLabel, new GridBagConstraints(3, 0, // x, y
0898: 1, 1, // width, height
0899: 0.0, 0.0, // weight-x, weight-y
0900: GridBagConstraints.CENTER, // anchor
0901: GridBagConstraints.BOTH, // fill
0902: new Insets(0, 0, 0, 0), // padding
0903: 0, 0)); // padx, pady - ???);
0904: }
0905:
0906: private void fireEditingStopped() {
0907: final CellEditorListener[] clone;
0908: synchronized (listeners) {
0909: clone = listeners.toArray(new CellEditorListener[0]);
0910: }
0911:
0912: final ChangeEvent event = new ChangeEvent(this );
0913: for (CellEditorListener listener : clone) {
0914: listener.editingStopped(event);
0915: }
0916: }
0917:
0918: private void fireEditingCanceled() {
0919: final CellEditorListener[] clone;
0920: synchronized (listeners) {
0921: clone = listeners.toArray(new CellEditorListener[0]);
0922: }
0923:
0924: final ChangeEvent event = new ChangeEvent(this );
0925: for (CellEditorListener listener : clone) {
0926: listener.editingCanceled(event);
0927: }
0928: }
0929:
0930: private JComponent getComponent(final JTree tree,
0931: final Object value, final boolean selected,
0932: final boolean expanded, final boolean leaf,
0933: final int row, final boolean focus) {
0934: if (selected) {
0935: titleLabel.setOpaque(true);
0936:
0937: titleLabel.setForeground(selectionForeground);
0938: titleLabel.setBackground(selectionBackground);
0939: } else {
0940: titleLabel.setOpaque(false);
0941:
0942: titleLabel.setForeground(foreground);
0943: titleLabel.setBackground(background);
0944: }
0945:
0946: if (value instanceof Product) {
0947: final Product product = (Product) value;
0948:
0949: final String title = " " + product.getDisplayName()
0950: + " ";
0951: final String status = " ["
0952: + product.getStatus().getDisplayName() + "]";
0953: final String tooltip = title + status;
0954:
0955: iconLabel.setIcon(product.getIcon());
0956: iconLabel.setToolTipText(tooltip);
0957:
0958: titleLabel.setText(title);
0959: titleLabel.setToolTipText(tooltip);
0960:
0961: statusLabel.setText(status);
0962: statusLabel.setToolTipText(tooltip);
0963:
0964: checkBox.setVisible(true);
0965: checkBox.setToolTipText(tooltip);
0966:
0967: if ((product.getStatus() == Status.INSTALLED)
0968: || (product.getStatus() == Status.TO_BE_INSTALLED)) {
0969: checkBox.setSelected(true);
0970: } else {
0971: checkBox.setSelected(false);
0972: }
0973: } else if (value instanceof Group) {
0974: final Group group = (Group) value;
0975:
0976: final String title = " " + group.getDisplayName() + " ";
0977: final String status = "";
0978: final String tooltip = title + status;
0979:
0980: iconLabel.setIcon(group.getIcon());
0981: iconLabel.setToolTipText(tooltip);
0982:
0983: titleLabel.setText(title);
0984: titleLabel.setToolTipText(tooltip);
0985:
0986: statusLabel.setText(status);
0987: statusLabel.setToolTipText(tooltip);
0988:
0989: checkBox.setVisible(false);
0990: }
0991:
0992: // l&f-specific tweaks
0993: if (UIManager.getLookAndFeel().getID().equals("GTK")) {
0994: panel.setOpaque(false);
0995: }
0996:
0997: return panel;
0998: }
0999: }
1000:
1001: /////////////////////////////////////////////////////////////////////////////////
1002: // Constants
1003: public static final String DESCRIPTION_INSTALL_PROPERTY = "description.install"; // NOI18N
1004: public static final String DESCRIPTION_UNINSTALL_PROPERTY = "description.uninstall"; // NOI18N
1005: public static final String FEATURE_DESCRIPTION_TITLE_PROPERTY = "feature.description.title";
1006:
1007: public static final String DEFAULT_TITLE = ResourceUtils.getString(
1008: ComponentsSelectionPanel.class, "CSP.title"); // NOI18N
1009: public static final String DEFAULT_DESCRIPTION = ResourceUtils
1010: .getString(ComponentsSelectionPanel.class,
1011: "CSP.description.both"); // NOI18N
1012: public static final String DEFAULT_DESCRIPTION_INSTALL = ResourceUtils
1013: .getString(ComponentsSelectionPanel.class,
1014: "CSP.description.install"); // NOI18N
1015: public static final String DEFAULT_DESCRIPTION_UNINSTALL = ResourceUtils
1016: .getString(ComponentsSelectionPanel.class,
1017: "CSP.description.uninstall"); // NOI18N
1018: public static final String DEFAULT_FEATURE_DESCRIPTION_TITLE = ResourceUtils
1019: .getString(ComponentsSelectionPanel.class,
1020: "CSP.feature.description.title");// NOI18N
1021: public static final String COMPONENT_DESCRIPTION_TEXT_PROPERTY = "component.description.text"; // NOI18N
1022: public static final String COMPONENT_DESCRIPTION_CONTENT_TYPE_PROPERTY = "component.description.content.type"; // NOI18N
1023: public static final String SIZES_LABEL_TEXT_PROPERTY = "sizes.label.text"; // NOI18N
1024: public static final String SIZES_LABEL_TEXT_NO_DOWNLOAD_PROPERTY = "sizes.label.text.no.download"; // NOI18N
1025: public static final String DEFAULT_INSTALLATION_SIZE_PROPERTY = "default.installation.size"; // NOI18N
1026: public static final String DEFAULT_DOWNLOAD_SIZE_PROPERTY = "default.download.size"; // NOI18N
1027:
1028: public static final String DEFAULT_COMPONENT_DESCRIPTION_TEXT = ResourceUtils
1029: .getString(ComponentsSelectionPanel.class,
1030: "CSP.component.description.text"); // NOI18N
1031: public static final String DEFAULT_COMPONENT_DESCRIPTION_CONTENT_TYPE = ResourceUtils
1032: .getString(ComponentsSelectionPanel.class,
1033: "CSP.component.description.content.type"); // NOI18N
1034: public static final String DEFAULT_SIZES_LABEL_TEXT = ResourceUtils
1035: .getString(ComponentsSelectionPanel.class,
1036: "CSP.sizes.label.text"); // NOI18N
1037: public static final String DEFAULT_SIZES_LABEL_TEXT_NO_DOWNLOAD = ResourceUtils
1038: .getString(ComponentsSelectionPanel.class,
1039: "CSP.sizes.label.text.no.download"); // NOI18N
1040: public static final String DEFAULT_INSTALLATION_SIZE = ResourceUtils
1041: .getString(ComponentsSelectionPanel.class,
1042: "CSP.default.installation.size"); // NOI18N
1043: public static final String DEFAULT_DOWNLOAD_SIZE = ResourceUtils
1044: .getString(ComponentsSelectionPanel.class,
1045: "CSP.default.download.size"); // NOI18N
1046:
1047: public static final String ERROR_NO_CHANGES_PROPERTY = "error.no.changes.both"; // NOI18N
1048: public static final String ERROR_NO_CHANGES_INSTALL_ONLY_PROPERTY = "error.no.changes.install"; // NOI18N
1049: public static final String ERROR_NO_CHANGES_UNINSTALL_ONLY_PROPERTY = "error.no.changes.uninstall"; // NOI18N
1050: public static final String ERROR_REQUIREMENT_INSTALL_PROPERTY = "error.requirement.install"; // NOI18N
1051: public static final String ERROR_CONFLICT_INSTALL_PROPERTY = "error.conflict.install"; // NOI18N
1052: public static final String ERROR_REQUIREMENT_UNINSTALL_PROPERTY = "error.requirement.uninstall"; // NOI18N
1053: public static final String ERROR_NO_ENOUGH_SPACE_TO_DOWNLOAD_PROPERTY = "error.not.enough.space.to.download"; // NOI18N
1054: public static final String ERROR_NO_ENOUGH_SPACE_TO_EXTRACT_PROPERTY = "error.not.enough.space.to.extract"; // NOI18N
1055: public static final String ERROR_CANNOT_CHECK_SPACE_PROPERTY = "error.cannot.check.space"; // NOI18N
1056:
1057: public static final String DEFAULT_ERROR_NO_CHANGES = ResourceUtils
1058: .getString(ComponentsSelectionPanel.class,
1059: "CSP.error.no.changes.both"); // NOI18N
1060: public static final String DEFAULT_ERROR_NO_CHANGES_INSTALL_ONLY = ResourceUtils
1061: .getString(ComponentsSelectionPanel.class,
1062: "CSP.error.no.changes.install"); // NOI18N
1063: public static final String DEFAULT_ERROR_NO_CHANGES_UNINSTALL_ONLY = ResourceUtils
1064: .getString(ComponentsSelectionPanel.class,
1065: "CSP.error.no.changes.uninstall"); // NOI18N
1066: public static final String DEFAULT_ERROR_REQUIREMENT_INSTALL = ResourceUtils
1067: .getString(ComponentsSelectionPanel.class,
1068: "CSP.error.requirement.install"); // NOI18N
1069: public static final String DEFAULT_ERROR_CONFLICT_INSTALL = ResourceUtils
1070: .getString(ComponentsSelectionPanel.class,
1071: "CSP.error.conflict.install"); // NOI18N
1072: public static final String DEFAULT_ERROR_REQUIREMENT_UNINSTALL = ResourceUtils
1073: .getString(ComponentsSelectionPanel.class,
1074: "CSP.error.requirement.uninstall"); // NOI18N
1075: public static final String DEFAULT_ERROR_NO_ENOUGH_SPACE_TO_DOWNLOAD = ResourceUtils
1076: .getString(ComponentsSelectionPanel.class,
1077: "CSP.error.not.enough.space.to.download"); // NOI18N
1078: public static final String DEFAULT_ERROR_NO_ENOUGH_SPACE_TO_EXTRACT = ResourceUtils
1079: .getString(ComponentsSelectionPanel.class,
1080: "CSP.error.not.enough.space.to.extract"); // NOI18N
1081: public static final String DEFAULT_ERROR_CANNOT_CHECK_SPACE = ResourceUtils
1082: .getString(ComponentsSelectionPanel.class,
1083: "CSP.error.cannot.check.space"); // NOI18N
1084:
1085: public static final long REQUIRED_SPACE_ADDITION = 10L * 1024L * 1024L; // 10MB
1086: }
|