/** * * Copyright (c) 2009-2016 Freedomotic team http://freedomotic.com * * This file is part of Freedomotic * * This Program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2, or (at your option) any later version. * * This Program 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 for more * details. * * You should have received a copy of the GNU General Public License along with * Freedomotic; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. */ package com.freedomotic.jfrontend; import com.freedomotic.api.API; import com.freedomotic.app.Freedomotic; import com.freedomotic.jfrontend.utils.SpringUtilities; import com.freedomotic.marketplace.IPluginCategory; import com.freedomotic.marketplace.IPluginPackage; import com.freedomotic.marketplace.MarketPlaceService; import com.freedomotic.plugins.ClientStorage; import com.freedomotic.plugins.PluginsManager; import com.freedomotic.i18n.I18n; import com.freedomotic.settings.Info; import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.SpringLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Gabriel Pulido de Torres */ public class MarketPlaceForm extends javax.swing.JFrame { private static final Logger LOG = LoggerFactory.getLogger(MarketPlaceForm.class.getName()); ArrayList<IPluginCategory> pluginCategoryList; private static final IPlugCatComparator CatComp = new IPlugCatComparator(); private static final IPlugPackComparator PackComp = new IPlugPackComparator(); private final I18n I18n; private final ClientStorage clients; private final PluginsManager pluginsManager; /** * Creates new form MarketPlaceForm * * @param api */ public MarketPlaceForm(API api) { this.I18n = api.getI18n(); this.clients = api.getClientStorage(); this.pluginsManager = api.getPluginManager(); this.setPreferredSize(new Dimension(800, 600)); initComponents(); cmbCategory.setEnabled(false); EventQueue.invokeLater(new Runnable() { @Override public void run() { new Thread(new Runnable() { @Override public void run() { MarketPlaceService mps = MarketPlaceService.getInstance(); pluginCategoryList = mps.getCategoryList(); retrieveCategories(); } }).start(); } }); } /** * */ public final void retrieveCategories() { cmbCategory.setEnabled(false); Collections.sort(pluginCategoryList, CatComp); for (IPluginCategory pc : pluginCategoryList) { //do not use pc.retrievePluginsInfo() here //it forces to download all plugins in all categories!! cmbCategory.addItem(pc.getName()); } //add listener to category selection changes cmbCategory.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int index = cmbCategory.getSelectedIndex(); retrievePlugins(pluginCategoryList.get(index)); } }); //force to retrive plugins for first category if (!pluginCategoryList.isEmpty()) { retrievePlugins(pluginCategoryList.get(0)); } } private void politeWaitingMessage(boolean isActive) { jProgressBar1.setVisible(isActive); txtInfo.setVisible(isActive); pnlMain.setEnabled(!isActive); cmbCategory.setEnabled(!isActive); } /** * * @param category */ public final void retrievePlugins(final IPluginCategory category) { politeWaitingMessage(true); pnlMain.setLayout(new SpringLayout()); pnlMain.removeAll(); pnlMain.setBackground(Color.white); pnlMain.repaint(); EventQueue.invokeLater(new Runnable() { @Override public void run() { new Thread(new Runnable() { @Override public void run() { try { String path = Info.PATHS.PATH_RESOURCES_FOLDER.toString(); if (category.retrievePluginsInfo() == null) { return; } Collections.sort(category.retrievePluginsInfo(), PackComp); //TODO: use package images. ImageIcon pluginIcon = new ImageIcon(path + File.separatorChar + "plug.png", "Icon"); int row = 0; for (final IPluginPackage pp : category.retrievePluginsInfo()) { renderBoundle(pp, pluginIcon); row++; } SpringUtilities.makeCompactGrid(pnlMain, row, 4, //rows, cols 5, 5, //initX, initY 5, 5); //xPad, yPad politeWaitingMessage(false); pnlMain.repaint(); } catch (Exception e) { LOG.warn(Freedomotic.getStackTraceInfo(e)); } } }).start(); } }); } private void renderBoundle(final IPluginPackage pp, ImageIcon iconPlugin) { JLabel lblIcon; if (pp.getIcon() != null) { lblIcon = new JLabel(pp.getIcon()); } else { lblIcon = new JLabel(iconPlugin); } JLabel lblName = new JLabel(pp.getTitle()); JButton btnAction = null; String freedomoticVersion = Info.getMajor() + "." + Info.getMinor(); if (pp.getFilePath(freedomoticVersion) != null && !pp.getFilePath(freedomoticVersion).isEmpty() && pp.getTitle() != null) { String version = extractVersion(new File(pp.getFilePath(freedomoticVersion)).getName()); int result = clients.compareVersions(pp.getTitle(), version); //System.out.println("COMPARE VERSIONS: "+new File(pp.getFilePath()).getName().toString() + " " + version + " = "+result); if (result == -1) { //older version or not yet installed //btnAction = new JButton(pp.getTitle() + " (Install version " + version + ")"); btnAction = new JButton(I18n.msg("install")); } else { if (result == 1) { //newer version //btnAction = new JButton(pp.getTitle() + " (Update from " + version + " to " + version + ")"); btnAction = new JButton(I18n.msg("update")); } } } else { lblName = new JLabel(I18n.msg( "X_unavailable", new Object[]{ pp.getTitle() })); } if (btnAction != null) { btnAction.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { installPackage(pp); } }); } JButton btnMore = new JButton(I18n.msg("more_info")); btnMore.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { browse(new URI(pp.getURI())); } catch (URISyntaxException ex) { LOG.error(ex.getMessage()); } } }); lblIcon.setPreferredSize(new Dimension(80, 80)); lblIcon.setMaximumSize(new Dimension(80, 80)); pnlMain.add(lblIcon); pnlMain.add(lblName); pnlMain.add(btnMore); if (btnAction != null) { pnlMain.add(btnAction); } else { JButton disabled = new JButton(I18n.msg("install")); disabled.setEnabled(false); pnlMain.add(disabled); } } private String extractVersion(String filename) { //suppose filename is something like it.nicoletti.test-5.2.x-1.212.device //only 5.2.x-1.212 is needed //remove extension filename = filename.substring(0, filename.lastIndexOf(".")); String[] tokens = filename.split("-"); //3 tokens expected if (tokens.length == 3) { return tokens[1] + "-" + tokens[2]; } else { return filename; } } private void installPackage(IPluginPackage pp) { String freedomoticVersion = Info.getMajor() + "." + Info.getMinor(); if (pp.getFilePath(freedomoticVersion) == null) { JOptionPane.showMessageDialog(this, I18n.msg( "warn_plugin_X_unavailable", new Object[]{pp.getTitle(), pp.getURI()})); return; } //Custom button text Object[] options = {I18n.msg("yes_please"), I18n.msg("no_thanks")}; int n = JOptionPane.showOptionDialog(null, I18n.msg( "confirm_package_X_download", new Object[]{pp.getTitle()}), I18n.msg("title_install_package"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); if (n != 0) { return; } JOptionPane.showMessageDialog(null, I18n.msg("info_download_started"), I18n.msg("title_download_started"), JOptionPane.INFORMATION_MESSAGE); Runnable task; final String string = pp.getFilePath(freedomoticVersion); LOG.info("Download string: {}", string); task = new Runnable() { boolean done = false; @Override public void run() { try { done = pluginsManager.installBoundle(new URL(string)); } catch (MalformedURLException ex) { done = false; LOG.error(ex.getMessage()); } if (!done) { JOptionPane.showMessageDialog(null, I18n.msg("info_download_failed"), I18n.msg("title_download_failed"), JOptionPane.INFORMATION_MESSAGE); } else { JOptionPane.showMessageDialog(null, I18n.msg("info_package_install_completed"), I18n.msg("title_install_completed"), JOptionPane.INFORMATION_MESSAGE); } } }; task.run(); } private void browse(URI uri) { if (!java.awt.Desktop.isDesktopSupported()) { JOptionPane.showInputDialog( null, I18n.msg("info_point_browser_to"), I18n.msg("info"), JOptionPane.PLAIN_MESSAGE, null, null, uri.toString()); } else { try { java.awt.Desktop.getDesktop().browse(uri); } catch (Exception e) { System.err.println(e.getMessage()); } } } /** * Order plugin categories by name */ public static class IPlugCatComparator implements Comparator<IPluginCategory> { @Override public int compare(IPluginCategory m1, IPluginCategory m2) { return m1.getName().compareTo(m2.getName()); } } /** * Order plugin buoudles by name */ public static class IPlugPackComparator implements Comparator<IPluginPackage> { @Override public int compare(IPluginPackage m1, IPluginPackage m2) { return m1.getTitle().compareTo(m2.getTitle()); } } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { txtInfo = new javax.swing.JLabel(); jProgressBar1 = new javax.swing.JProgressBar(); cmbCategory = new javax.swing.JComboBox(); jScrollPane1 = new javax.swing.JScrollPane(); pnlMain = new javax.swing.JPanel(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setTitle(I18n.msg("title_marketplace")); setMinimumSize(new java.awt.Dimension(521, 370)); txtInfo.setText(I18n.msg("connecting_online_repo")); jProgressBar1.setIndeterminate(true); pnlMain.setLayout(new java.awt.BorderLayout()); jScrollPane1.setViewportView(pnlMain); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(txtInfo, javax.swing.GroupLayout.PREFERRED_SIZE, 378, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(36, 36, 36) .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 195, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(cmbCategory, javax.swing.GroupLayout.PREFERRED_SIZE, 609, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) .addComponent(jScrollPane1) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(15, 15, 15) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(txtInfo) .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(18, 18, 18) .addComponent(cmbCategory, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 468, Short.MAX_VALUE)) ); pack(); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JComboBox cmbCategory; private javax.swing.JProgressBar jProgressBar1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JPanel pnlMain; private javax.swing.JLabel txtInfo; // End of variables declaration//GEN-END:variables }