changeset 1272:104317f48096

Added desktop integration dialog
author Jiri Vanek <jvanek@redhat.com>
date Thu, 12 Nov 2015 17:19:20 +0100
parents a27404e97867
children a83c72313001
files ChangeLog netx/net/sourceforge/jnlp/controlpanel/DesktopShortcutPanel.java netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/Blinker.java netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/FreeDesktopIntegrationEditorFrame.java netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/JListUtils.java netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/Panels.java netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/PreviewSelectionJTextPane.java netx/net/sourceforge/jnlp/resources/Messages.properties netx/net/sourceforge/jnlp/security/dialogs/SecurityDialogPanel.java netx/net/sourceforge/jnlp/util/XDesktopEntry.java netx/net/sourceforge/jnlp/util/logging/ConsoleOutputPaneModel.java tests/netx/unit/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/AppTrustWarningPanelTest.java
diffstat 12 files changed, 1392 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Nov 12 15:48:22 2015 +0100
+++ b/ChangeLog	Thu Nov 12 17:19:20 2015 +0100
@@ -1,3 +1,29 @@
+2015-11-12  Jiri Vanek  <jvanek@redhat.com>
+
+	Added desktop integration dialog
+	* netx/net/sourceforge/jnlp/controlpanel/DesktopShortcutPanel.java: added linux-only
+	button to sow FreeDesktopIntegrationEditorFrame 
+	* netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/Blinker.java:
+	new class, blink colors on selected component
+	* netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/FreeDesktopIntegrationEditorFrame.java:
+	new class, window to allow managing generated icons, jnlpfiles and shortcuts
+	* netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/JListUtils.java:
+	new class, provides models, extensions, renderers and listeners for FreeDesktopIntegrationEditorFrame
+	* netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/Panels.java:
+	new class, provides various encapsulated parts of FreeDesktopIntegrationEditorFrame
+	* netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/PreviewSelectionJTextPane.java:
+	new class, impelmetation of preview for FreeDesktopIntegrationEditorFrame
+	* netx/net/sourceforge/jnlp/resources/Messages.properties: added  Control 
+	Panel - desktop integration manager DIM family
+	* netx/net/sourceforge/jnlp/security/dialogs/SecurityDialogPanel.java: htmlWrap
+	made public
+	* netx/net/sourceforge/jnlp/util/XDesktopEntry.java: findFreedesktopOrgDesktopPathCatch
+	made public
+	* netx/net/sourceforge/jnlp/util/logging/ConsoleOutputPaneModel.java:  replacing of chars by html
+	entities extracted to new method escapeHtmlForJTextPane
+	* tests/netx/unit/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/AppTrustWarningPanelTest.java:
+	htmlwrap moved to use SecurityDialogPanel's implementation
+
 2015-11-12  Jiri Vanek  <jvanek@redhat.com>
 
 	fixed build and runtime with jdk9
--- a/netx/net/sourceforge/jnlp/controlpanel/DesktopShortcutPanel.java	Thu Nov 12 15:48:22 2015 +0100
+++ b/netx/net/sourceforge/jnlp/controlpanel/DesktopShortcutPanel.java	Thu Nov 12 17:19:20 2015 +0100
@@ -1,5 +1,5 @@
 /* DesktopShortcutPanel.java -- Display option for adding desktop shortcut.
-Copyright (C) 2010 Red Hat
+Copyright (C) 2015 Red Hat
 
 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
@@ -15,40 +15,42 @@
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-
 package net.sourceforge.jnlp.controlpanel;
 
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 
 import javax.swing.Box;
+import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JLabel;
+import javax.swing.SwingUtilities;
 import net.sourceforge.jnlp.ShortcutDesc;
 
 import net.sourceforge.jnlp.config.DeploymentConfiguration;
+import net.sourceforge.jnlp.controlpanel.desktopintegrationeditor.FreeDesktopIntegrationEditorFrame;
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
 import net.sourceforge.jnlp.runtime.Translator;
 
 /**
  * This class provides the panel that allows the user to set whether they want
  * to create a desktop shortcut for javaws.
- * 
- * @author Andrew Su (asu@redhat.com, andrew.su@utoronto.ca)
- * 
  */
 public class DesktopShortcutPanel extends NamedBorderPanel implements ItemListener {
 
     private final DeploymentConfiguration config;
+    private FreeDesktopIntegrationEditorFrame integrationManagment;
 
     /**
      * Create a new instance of the desktop shortcut settings panel.
-     * 
-     * @param config
-     *            Loaded DeploymentConfiguration file.
+     *
+     * @param config Loaded DeploymentConfiguration file.
      */
     public DesktopShortcutPanel(DeploymentConfiguration config) {
         super(Translator.R("CPHeadDesktopIntegration"), new GridBagLayout());
@@ -57,7 +59,6 @@
         addComponents();
     }
 
-
     public static ComboItem deploymentJavawsShortcutToComboItem(String i) {
         return new ComboItem(ShortcutDesc.deploymentJavawsShortcutToString(i), i);
     }
@@ -69,6 +70,27 @@
         GridBagConstraints c = new GridBagConstraints();
         JLabel description = new JLabel("<html>" + Translator.R("CPDesktopIntegrationDescription") + "<hr /></html>");
         JComboBox<ComboItem> shortcutComboOptions = new JComboBox<>();
+        JButton manageIntegrationsButton = new JButton(Translator.R("CPDesktopIntegrationShowIntegrations"));
+        if (JNLPRuntime.isWindows()) {
+            manageIntegrationsButton.setToolTipText(Translator.R("CPDesktopIntegrationLinuxOnly"));
+            manageIntegrationsButton.setEnabled(false);
+        }
+        manageIntegrationsButton.addActionListener(new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                SwingUtilities.invokeLater(new Runnable() {
+
+                    @Override
+                    public void run() {
+                        if (integrationManagment == null) {
+                            integrationManagment = new FreeDesktopIntegrationEditorFrame();
+                        }
+                        integrationManagment.setVisible(true);
+                    }
+                });
+            }
+        });
         ComboItem[] items = {deploymentJavawsShortcutToComboItem(ShortcutDesc.CREATE_NEVER),
             deploymentJavawsShortcutToComboItem(ShortcutDesc.CREATE_ALWAYS),
             deploymentJavawsShortcutToComboItem(ShortcutDesc.CREATE_ASK_USER),
@@ -92,6 +114,8 @@
         add(description, c);
         c.gridy = 1;
         add(shortcutComboOptions, c);
+        c.gridy = 2;
+        add(manageIntegrationsButton, c);
 
         // This is to keep it from expanding vertically if resized.
         Component filler = Box.createRigidArea(new Dimension(1, 1));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/Blinker.java	Thu Nov 12 17:19:20 2015 +0100
@@ -0,0 +1,103 @@
+/*   Copyright (C) 2015 Red Hat, Inc.
+
+ This file is part of IcedTea.
+
+ IcedTea 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, version 2.
+
+ IcedTea 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 IcedTea; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version.
+ */
+package net.sourceforge.jnlp.controlpanel.desktopintegrationeditor;
+
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+
+public class Blinker {
+
+    private boolean blinking;
+    private final JComponent compToBlink;
+
+    public Blinker(JComponent compToBlink) {
+        this.compToBlink = compToBlink;
+    }
+
+    public void blink() {
+        if (blinking) {
+            return;
+        }
+        blinking = true;
+        Timer t = new Timer(100, new BlinkBody());
+        t.setInitialDelay(0);
+        t.start();
+    }
+
+    class BlinkBody implements ActionListener {
+
+        int counter = 0;
+        Color base;
+        Color invert;
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            counter++;
+            if (counter == 1) {
+                base = compToBlink.getBackground();
+                invert = new Color(Math.min(255, base.getRed() * 2), Math.max(0, base.getGreen() / 2), 255 - base.getBlue());
+            }
+            if (counter == 5) {
+                ((Timer) e.getSource()).stop();
+                SwingUtilities.invokeLater(new Runnable() {
+
+                    @Override
+                    public void run() {
+                        compToBlink.setBackground(base);
+                        blinking = false;
+                    }
+                });
+                return;
+            }
+            SwingUtilities.invokeLater(new Runnable() {
+
+                @Override
+                public void run() {
+                    if (compToBlink.getBackground().equals(base)) {
+                        compToBlink.setBackground(invert);
+                    } else {
+                        compToBlink.setBackground(base);
+                    }
+                }
+            });
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/FreeDesktopIntegrationEditorFrame.java	Thu Nov 12 17:19:20 2015 +0100
@@ -0,0 +1,509 @@
+/*   Copyright (C) 2015 Red Hat, Inc.
+
+ This file is part of IcedTea.
+
+ IcedTea 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, version 2.
+
+ IcedTea 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 IcedTea; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version.
+ */
+package net.sourceforge.jnlp.controlpanel.desktopintegrationeditor;
+
+import java.awt.BorderLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextPane;
+import javax.swing.ListModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import net.sourceforge.jnlp.config.PathsAndFiles;
+import net.sourceforge.jnlp.security.dialogs.SecurityDialogPanel;
+import net.sourceforge.jnlp.util.XDesktopEntry;
+import net.sourceforge.jnlp.util.logging.ConsoleOutputPaneModel;
+
+import static net.sourceforge.jnlp.runtime.Translator.R;
+
+public class FreeDesktopIntegrationEditorFrame extends JFrame {
+
+    //gui
+    private final javax.swing.JLabel title = new JLabel();
+    private final javax.swing.JCheckBox selectRelativeRecordsFromOtherColumns = new JCheckBox();
+    private final javax.swing.JButton removeSelectedButton = new JButton();
+    private final javax.swing.JButton cleanAll = new JButton();
+    private final javax.swing.JButton closeButton = new JButton();
+    private final javax.swing.JButton reloadsListButton = new JButton();
+    private final javax.swing.JButton selectAll = new JButton();
+
+    //important ones
+    private final javax.swing.JList menuList = new JListUtils.CustomRendererJList();
+    private final javax.swing.JList desktopList = new JListUtils.CustomValidatingRendererJList();
+    private final javax.swing.JList generatedList = new JListUtils.CustomRendererJList();
+    private final javax.swing.JList iconsList = new JListUtils.CustomRendererWithIconJList();
+
+    PreviewSelectionJTextPane previewPane = new PreviewSelectionJTextPane(iconsList, menuList, desktopList, generatedList);
+    //gui end
+
+    private final Blinker blinker;
+
+    private void setListeners() {
+        removeSelectedButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                FreeDesktopIntegrationEditorFrame.this.removeSelected();
+            }
+        });
+
+        closeButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                dispose();
+            }
+        });
+
+        reloadsListButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                populateLists();
+            }
+        });
+
+        selectAll.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                selectAll();
+            }
+        });
+
+        cleanAll.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                cleanAll();
+            }
+        });
+
+    }
+
+    private void setTexts() {
+        this.setTitle(R("DIMtitle"));
+        closeButton.setText(R("ButClose"));
+        removeSelectedButton.setText(R("DIMremoveSelected"));
+        selectRelativeRecordsFromOtherColumns.setText(R("DIMselectRelativeRecordsFromOtherColumns"));
+        reloadsListButton.setText(R("DIMreloadLists"));
+        selectAll.setText(R("DIMselectAll"));
+        cleanAll.setText(R("DIMclearSelection"));
+        title.setText(SecurityDialogPanel.htmlWrap("<p>" + R("DIMdescription") + "</p>"));
+    }
+
+    private JPanel createMainControls() {
+        JPanel mainControls = new JPanel(new GridLayout(1, 2));
+        mainControls.add(closeButton);
+        mainControls.add(removeSelectedButton);
+        return mainControls;
+    }
+
+    private JPanel createMiddleToolBox() {
+        JPanel middleToolBox = new JPanel(new GridLayout(1, 2));
+        middleToolBox.add(selectRelativeRecordsFromOtherColumns);
+        middleToolBox.add(reloadsListButton);
+        middleToolBox.add(selectAll);
+        middleToolBox.add(cleanAll);
+        return middleToolBox;
+    }
+
+    private JPanel createPreviewPanel(JTextPane previewPane) {
+        JPanel previewPanel = new JPanel(new BorderLayout());
+        JScrollPane jScrollPane2 = new JScrollPane();
+        jScrollPane2.setViewportView(previewPane);
+        previewPanel.add(jScrollPane2, BorderLayout.CENTER);
+        createMiddleToolBox();
+        previewPanel.add(createMiddleToolBox(), BorderLayout.PAGE_START);
+        return previewPanel;
+    }
+
+    private JSplitPane createListsLayout() {
+        JPanel menusPanel = Panels.createMenuPanel(menuList, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                selectSomeRelatives(menuList.getSelectedValuesList(), iconsList);
+            }
+        }, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                selectSomeRelatives(menuList.getSelectedValuesList(), generatedList);
+            }
+        }
+        );
+        JPanel desktopsPanel = Panels.createDesktopPanel(desktopList, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                selectSomeRelatives(desktopList.getSelectedValuesList(), iconsList);
+            }
+        }, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                selectSomeRelatives(desktopList.getSelectedValuesList(), generatedList);
+            }
+        }
+        );
+        JPanel iconsPanel = Panels.createIconsPanel(iconsList, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                findOrphans(iconsList, allItemsAsFiles(menuList), allItemsAsFiles(desktopList));
+            }
+        });
+        JPanel generatedsPanel = Panels.createGeneratedPanel(generatedList, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                findOrphans(generatedList, allItemsAsFiles(menuList), allItemsAsFiles(desktopList));
+            }
+        });
+        return Panels.createQuadroSplit(expectedWidth, menusPanel, desktopsPanel, iconsPanel, generatedsPanel);
+    }
+
+    private void setLayout() {
+        createMainControls();
+        getContentPane().add(createMainControls(), BorderLayout.PAGE_END);
+        JSplitPane splitListsAndPreview = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+        splitListsAndPreview.setLeftComponent(createListsLayout());
+        splitListsAndPreview.setRightComponent(createPreviewPanel(previewPane));
+        getContentPane().add(splitListsAndPreview, BorderLayout.CENTER);
+        getContentPane().add(title, BorderLayout.PAGE_START);
+        splitListsAndPreview.setDividerLocation(expectedHeight / 2);
+    }
+
+    public static void main(String args[]) {
+
+        java.awt.EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                new FreeDesktopIntegrationEditorFrame().setVisible(true);
+            }
+        });
+    }
+
+    private boolean selecting = false;
+    private final int expectedWidth = 800;
+    private final int expectedHeight = 600;
+
+    public FreeDesktopIntegrationEditorFrame() {
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        this.setSize(expectedWidth, expectedHeight);
+        populateLists();
+        setTexts();
+        setListeners();
+        setLayout();
+        selectRelativeRecordsFromOtherColumns.setSelected(true);
+
+        ListSelectionListener generatePreviewListener = new GeneratePreviewListener();
+
+        iconsList.addListSelectionListener(generatePreviewListener);
+        desktopList.addListSelectionListener(generatePreviewListener);
+        menuList.addListSelectionListener(generatePreviewListener);
+        generatedList.addListSelectionListener(generatePreviewListener);
+        blinker = new Blinker(selectRelativeRecordsFromOtherColumns);
+
+    }
+
+    private void populateLists() {
+        menuList.setModel(new JListUtils.InfrastructureFileDescriptorListingBasedJListModel(PathsAndFiles.MENUS_DIR));
+        desktopList.setModel(new JListUtils.FileListBasedJListModel(new File(XDesktopEntry.findFreedesktopOrgDesktopPathCatch()), "(?i)^.*\\.desktop$") {
+
+            @Override
+            public String toString() {
+                return R("DIMguessedDesktop");
+            }
+        });
+        iconsList.setModel(new JListUtils.InfrastructureFileDescriptorListingBasedJListModel(PathsAndFiles.ICONS_DIR));
+        generatedList.setModel(new JListUtils.InfrastructureFileDescriptorListingBasedJListModel(PathsAndFiles.GEN_JNLPS_DIR));
+    }
+
+    private void cleanAll() {
+        selecting = true;
+        try {
+            clearAll();
+        } finally {
+            selecting = false;
+        }
+    }
+
+    private void clearAll() {
+        desktopList.clearSelection();
+        menuList.clearSelection();
+        generatedList.clearSelection();
+        iconsList.clearSelection();
+        previewPane.setText(R("DIMselectionPreview"));
+    }
+
+    private void removeSelected() {
+        int a = getTotal(
+                objectListToFileList(iconsList.getSelectedValuesList()),
+                objectListToFileList(menuList.getSelectedValuesList()),
+                objectListToFileList(desktopList.getSelectedValuesList()),
+                objectListToFileList(generatedList.getSelectedValuesList())
+        );
+        if (a <= 0) {
+            return;
+        }
+        int x = JOptionPane.showConfirmDialog(this, R("DIMaskBeforeDelete", a));
+        if (x == JOptionPane.OK_OPTION || x == JOptionPane.YES_OPTION) {
+            removeSelected(
+                    objectListToFileList(iconsList.getSelectedValuesList()),
+                    objectListToFileList(menuList.getSelectedValuesList()),
+                    objectListToFileList(desktopList.getSelectedValuesList()),
+                    objectListToFileList(generatedList.getSelectedValuesList())
+            );
+            populateLists();
+        }
+    }
+
+    private void selectAll() {
+        selecting = true;
+        try {
+            selectAll(menuList);
+            selectAll(desktopList);
+            selectAll(iconsList);
+            selectAll(generatedList);
+        } finally {
+            selecting = false;
+        }
+        previewPane.generatePreview();
+    }
+
+    public List<File> allItemsAsFiles(JList l) {
+        return allItemsAsFiles(l.getModel());
+    }
+
+    public List<File> allItemsAsFiles(ListModel l) {
+        List<File> r = new ArrayList<>(l.getSize());
+        for (int i = 0; i < l.getSize(); i++) {
+            r.add((File) l.getElementAt(i));
+
+        }
+        return r;
+    }
+
+    private List<File> objectListToFileList(List l) {
+        List<File> r = new ArrayList(l.size());
+        for (Object l1 : l) {
+            r.add((File) l1);
+        }
+        return r;
+    }
+
+    private void removeSelected(List<File>... a) {
+        for (List<File> list : a) {
+            for (File file : list) {
+                file.delete();
+
+            }
+        }
+    }
+
+    private int getTotal(List<File>... a) {
+        int i = 0;
+        for (List<File> list : a) {
+            i+=list.size();
+        }
+        return i;
+    }
+
+    private void findOrphans(JList possibleOrphans, List<File>... whereItCanBe) {
+        selecting = true;
+        if (selectRelativeRecordsFromOtherColumns.isSelected()) {
+            clearAll();
+            blinker.blink();
+        }
+        try {
+            possibleOrphans.clearSelection();
+            List<File> l = allItemsAsFiles(possibleOrphans);
+            for (int i = 0; i < l.size(); i++) {
+                File file = l.get(i);
+                boolean found = false;
+                for (List<File> lf : whereItCanBe) {
+                    if (found) {
+                        break;
+                    }
+                    for (File f : lf) {
+                        String s = fileToString(f, false);
+                        if (s.contains(file.getAbsolutePath())) {
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+                if (!found) {
+                   possibleOrphans.addSelectionInterval(i, i);
+                }
+            }
+        } finally {
+            selecting = false;
+        }
+        previewPane.generatePreview();
+    }
+
+    private void selectSomeRelatives(List selected, JList target) {
+        selecting = true;
+        try {
+            selectFileFromShortcuts(selected, target);
+        } finally {
+            selecting = false;
+        }
+        previewPane.generatePreview();
+    }
+
+    private void selectAll(JList list) {
+        int start = 0;
+        int end = list.getModel().getSize() - 1;
+        if (end >= 0) {
+            list.setSelectionInterval(start, end);
+        }
+    }
+
+    private class GeneratePreviewListener implements ListSelectionListener {
+
+        public GeneratePreviewListener() {
+        }
+
+        @Override
+        public void valueChanged(ListSelectionEvent e) {
+            if (selecting) {
+                return;
+            }
+            try {
+                selecting = true;
+                if (selectRelativeRecordsFromOtherColumns.isSelected()) {
+                    blinker.blink();
+                    selectRelatives(e.getSource());
+
+                }
+            } finally {
+                selecting = false;
+            }
+
+            previewPane.generatePreview();
+        }
+    }
+
+    private void selectRelatives(Object source) {
+        if (source instanceof JList) {
+            int[] indexes = ((JList) (source)).getSelectedIndices();
+            clearAll();
+            ((JList) (source)).setSelectedIndices(indexes);
+        }
+
+        for (int x = 1; x <= 3; x++) {
+            //we dont wont recurse, so sending copies in
+            selectShortcutsByFiles(
+                    objectListToFileList(iconsList.getSelectedValuesList()),
+                    objectListToFileList(generatedList.getSelectedValuesList())
+            );
+            selectFilesByShortcuts(
+                    objectListToFileList(menuList.getSelectedValuesList()),
+                    objectListToFileList(desktopList.getSelectedValuesList())
+            );
+        }
+    }
+
+    static String fileToString(File f, boolean escape) {
+        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(f))) {
+
+            StringBuilder sb = new StringBuilder();
+
+            while (true) {
+                String line = bufferedReader.readLine();
+                if (line == null) {
+                    return sb.toString();
+                }
+                if (escape) {
+                    line = ConsoleOutputPaneModel.escapeHtmlForJTextPane(line);
+                }
+                sb.append(line).append("\n");
+            }
+
+        } catch (Exception ex) {
+            return ex.toString();
+        }
+    }
+
+    private void selectShortcutsByFiles(List<File> icons, List<File> jnlps) {
+        selectShortcutsWithFiles(icons, desktopList);
+        selectShortcutsWithFiles(icons, menuList);
+        selectShortcutsWithFiles(jnlps, desktopList);
+        selectShortcutsWithFiles(jnlps, menuList);
+    }
+
+    private void selectFilesByShortcuts(List<File> menu, List<File> desktop) {
+        selectFileFromShortcuts(desktop, iconsList);
+        selectFileFromShortcuts(desktop, generatedList);
+        selectFileFromShortcuts(menu, iconsList);
+        selectFileFromShortcuts(menu, generatedList);
+    }
+
+    private void selectShortcutsWithFiles(List<File> icons, JList list) {
+        for (int i = 0; i < list.getModel().getSize(); i++) {
+            File item = (File) list.getModel().getElementAt(i);
+            String s = fileToString(item, false);
+            for (File icon : icons) {
+                if (s.contains(icon.getAbsolutePath())) {
+                    list.addSelectionInterval(i, i);
+                }
+            }
+
+        }
+    }
+
+    private void selectFileFromShortcuts(List<File> shortcuts, JList files) {
+        for (File shortcut : shortcuts) {
+            String s = fileToString(shortcut, false);
+            for (int i = 0; i < files.getModel().getSize(); i++) {
+                File item = (File) files.getModel().getElementAt(i);
+                if (s.contains(item.getAbsolutePath())) {
+                    files.addSelectionInterval(i, i);
+                }
+
+            }
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/JListUtils.java	Thu Nov 12 17:19:20 2015 +0100
@@ -0,0 +1,367 @@
+/*   Copyright (C) 2015 Red Hat, Inc.
+
+ This file is part of IcedTea.
+
+ IcedTea 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, version 2.
+
+ IcedTea 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 IcedTea; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version.
+ */
+package net.sourceforge.jnlp.controlpanel.desktopintegrationeditor;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+import javax.imageio.ImageIO;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JList;
+
+import javax.swing.ListModel;
+import javax.swing.event.ListDataListener;
+import net.sourceforge.jnlp.config.InfrastructureFileDescriptor;
+import net.sourceforge.jnlp.util.XDesktopEntry;
+
+public class JListUtils {
+
+    private static Map<File, Icon> iconCache = new HashMap<>();
+    private static Map<File, String> textFilesCache = new HashMap<>();
+    private static Map<File, Long> stamps = new HashMap<>();
+
+    public static class InfrastructureFileDescriptorListingBasedJListModel extends FileListBasedJListModel {
+
+        private final InfrastructureFileDescriptor source;
+
+        public InfrastructureFileDescriptorListingBasedJListModel(InfrastructureFileDescriptor source, String mask) {
+            super(source.getFile(), mask);
+            this.source = source;
+        }
+
+        public InfrastructureFileDescriptorListingBasedJListModel(InfrastructureFileDescriptor source) {
+            super(source.getFile());
+            this.source = source;
+        }
+
+        public InfrastructureFileDescriptor getSource() {
+            return source;
+        }
+
+        @Override
+        protected File getFile() {
+            return source.getFile();
+        }
+
+        @Override
+        public String toString() {
+            return source.toString();
+        }
+
+    }
+
+    public static class FileListBasedJListModel implements ListModel {
+
+        private final File directory;
+        private File[] list;
+        private final Pattern mask;
+
+        /**
+         * Construct list containing all files from given directory
+         *
+         * @param dir
+         */
+        public FileListBasedJListModel(File dir) {
+            //calling constructor with regex matching every file
+            this(dir, ".*");
+        }
+
+        /**
+         * Construct list containing files from given directory matching regex of given mask, 
+         *
+         * @param dir directory to list
+         * @param mask regex to match files to display
+         */
+        public FileListBasedJListModel(File dir, final String mask) {
+            directory = dir;
+            this.mask = Pattern.compile(mask);
+        }
+
+        protected File getFile() {
+            return directory;
+        }
+
+        @Override
+        public String toString() {
+            return getFile().getAbsolutePath();
+        }
+
+        private File[] populateList() {
+            list = getFile().listFiles(new FilenameFilter() {
+
+                @Override
+                public boolean accept(File dir, String name) {
+                    return mask.matcher(name).matches();
+                }
+            });
+            return list;
+        }
+
+        @Override
+        public int getSize() {
+            if (list == null) {
+                populateList();
+            }
+            return list.length;
+        }
+
+        @Override
+        public Object getElementAt(int index) {
+            if (list == null) {
+                populateList();
+            }
+            return list[index];
+        }
+
+        @Override
+        public void addListDataListener(ListDataListener l) {
+
+        }
+
+        @Override
+        public void removeListDataListener(ListDataListener l) {
+
+        }
+
+    }
+
+    public static class CustomRendererJList extends JList<File> {
+
+        public CustomRendererJList() {
+            this.setCellRenderer(new FileCellRenderer());
+        }
+
+    }
+
+    public static class CustomValidatingRendererJList extends JList<File> {
+
+        public CustomValidatingRendererJList() {
+            this.setCellRenderer(new ValidatingFileCellRenderer());
+        }
+
+    }
+
+    public static class CustomRendererWithIconJList extends JList<File> {
+
+        public CustomRendererWithIconJList() {
+            setCellRenderer(new IconisedCellRenderer());
+        }
+
+    }
+
+    private static class FileCellRenderer extends DefaultListCellRenderer {
+
+        @Override
+        public Component getListCellRendererComponent(
+                JList list, Object value, int index,
+                boolean isSelected, boolean cellHasFocus) {
+
+            File f = (File) value;
+            JLabel label = (JLabel) super.getListCellRendererComponent(
+                    list, value, index, isSelected, cellHasFocus);
+            label.setText(f.getName());
+            return label;
+        }
+    }
+
+    private static class ValidatingFileCellRenderer extends FileCellRenderer {
+
+        @Override
+        public Component getListCellRendererComponent(
+                JList list, Object value, int index,
+                boolean isSelected, boolean cellHasFocus) {
+            JLabel l = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+            File f = (File) value;
+            String s = processTextFilesCache(f);
+            if (!isSelected) {
+                if (isJavaws(s)) {
+                    l.setBackground(new Color(0, 200, 0));
+
+                } else if (isBrowser(s)) {
+                    l.setBackground(new Color(100, 150, 0));
+                } else {
+                    l.setBackground(new Color(255, 200, 200));
+                }
+            } else {
+                if (isJavaws(s)) {
+                    l.setForeground(new Color(0, 200, 0));
+
+                } else if (isBrowser(s)) {
+                    l.setForeground(new Color(100, 150, 0));
+                } else {
+                    l.setForeground(new Color(255, 200, 200));
+                }
+            }
+            return l;
+        }
+
+        private boolean isJavaws(String s) {
+            return haveString(s, "javaws");
+        }
+
+        private boolean isBrowser(String s) {
+            String[] browsers = XDesktopEntry.BROWSERS;
+            for (String browser : browsers) {
+                if (haveString(s, browser)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private boolean haveString(String s, String i) {
+            return s.matches("(?sm).*^.*Exec.*=.*" + i + ".*$.*");
+        }
+    }
+
+    private static class IconisedCellRenderer extends DefaultListCellRenderer {
+
+        @Override
+        public Component getListCellRendererComponent(
+                JList list, Object value, int index,
+                boolean isSelected, boolean cellHasFocus) {
+
+            File f = (File) value;
+            JLabel label = (JLabel) super.getListCellRendererComponent(
+                    list, value, index, isSelected, cellHasFocus);
+            label.setIcon(processIconCache(f));
+            label.setText(f.getName());
+            label.setHorizontalTextPosition(JLabel.RIGHT);
+            return label;
+        }
+
+    }
+
+    /**
+     * This method looks to cache whether file F was already read as image.
+     * If not, file is loaded, put to cache and returned
+     * If so, it also check whether it was modified. If so, it is reloaded, replaced in cache and returned.
+     * 
+     * @param f
+     * @return 
+     */
+    private static Icon processIconCache(File f) {
+        Icon i = iconCache.get(f);
+        if (i == null) {
+            i = updateIconCache(f, i);
+        } else {
+            if (f.lastModified() != stamps.get(f)) {
+                i = updateIconCache(f, i);
+            }
+        }
+        return i;
+    }
+
+     /**
+     * This method load Icon from file.
+     * Once file is loaded, it is stored also to cache
+     * Also the time stamp of last modification is stored to cache to allow reloading when changed.
+     * 
+     * @param f file to load, and to provide timestamp of last modification
+     * @return loaded icon or null
+     */
+    private static Icon updateIconCache(File f, Icon i) {
+        i = createImageIcon(f, f.getAbsolutePath());
+        if (i != null) {
+            iconCache.put(f, i);
+            stamps.put(f, f.lastModified());
+        }
+        return i;
+    }
+
+     /**
+     * This method looks to cache whether file F was already read as text file.
+     * If not, file is loaded, and its content is put to cache and returned as String
+     * If so, it also check whether it was modified. If so, it is reloaded, replaced in cache and returned.
+     * 
+     * @param f
+     * @return 
+     */
+    private static String processTextFilesCache(File f) {
+        String s = textFilesCache.get(f);
+        if (s == null) {
+            s = updateTextCache(f, s);
+        } else {
+            if (f.lastModified() != stamps.get(f)) {
+                s = updateTextCache(f, s);
+            }
+        }
+        return s;
+    }
+
+    /**
+     * This method load Text from file.
+     * Once file is loaded, it is stored also to cache
+     * Also the time stamp of last modification is stored to cache to allow reloading when changed.
+     * 
+     * @param f file to load, and to provide timestamp of last modification
+     * @return loaded Text, error message or null
+     */
+    private static String updateTextCache(File f, String s) {
+        s = FreeDesktopIntegrationEditorFrame.fileToString(f, false);
+        if (s != null) {
+            textFilesCache.put(f, s);
+            stamps.put(f, f.lastModified());
+        }
+        return s;
+    }
+
+    /**
+     * Load BufferedImage form file, scale it and converts to icon.
+     * 
+     * @param f file to be loaded
+     * @param description description to be provided
+     * @return icon from file or null if something went wrong
+     */
+    private static ImageIcon createImageIcon(File f, String description) {
+        try {
+            BufferedImage i = ImageIO.read(f);
+            return new ImageIcon(i.getScaledInstance(50, 50, Image.SCALE_SMOOTH));
+        } catch (Exception ex) {
+            //not worthy to log it. No image is there and so be it.
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/Panels.java	Thu Nov 12 17:19:20 2015 +0100
@@ -0,0 +1,152 @@
+/*   Copyright (C) 2015 Red Hat, Inc.
+
+ This file is part of IcedTea.
+
+ IcedTea 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, version 2.
+
+ IcedTea 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 IcedTea; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version.
+ */
+package net.sourceforge.jnlp.controlpanel.desktopintegrationeditor;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionListener;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import net.sourceforge.jnlp.security.dialogs.SecurityDialogPanel;
+
+import static net.sourceforge.jnlp.runtime.Translator.R;
+
+public class Panels {
+
+    public static JPanel createGeneratedPanel(JList list, ActionListener findOrphans) {
+        return createIconsOrGeneratedPanel(list, findOrphans, R("DIMgeneratedJnlps"), bold(R("DIMgeneratedJnlpsTooltip")));
+    }
+
+    public static JPanel createIconsPanel(JList list, ActionListener findOrphans) {
+        return createIconsOrGeneratedPanel(list, findOrphans, R("DIMicons"), bold(R("DIMiconsTooltip")));
+    }
+
+    private static JPanel createIconsOrGeneratedPanel(JList list, ActionListener findOrphans, String title, String tooltip) {
+        JPanel iconsPanel = new JPanel(new BorderLayout());
+        JLabel l = new JLabel(title);
+        l.setToolTipText(createToolTip(tooltip, list));
+        iconsPanel.add(l, BorderLayout.PAGE_START);
+        JScrollPane scrollIcons = new JScrollPane();
+        scrollIcons.setViewportView(list);
+        iconsPanel.add(scrollIcons, BorderLayout.CENTER);
+        JPanel iconsToolPanel = new JPanel(new BorderLayout());
+        JButton findOrphansButton = new JButton(R("DIMorphans"));
+        findOrphansButton.addActionListener(findOrphans);
+        findOrphansButton.setToolTipText(R("DIMorphansTooltip"));
+        iconsToolPanel.add(findOrphansButton, BorderLayout.CENTER);
+        iconsPanel.add(iconsToolPanel, BorderLayout.PAGE_END);
+        return iconsPanel;
+    }
+
+    public static JPanel createMenuPanel(JList list, ActionListener findIcons, ActionListener findGenerated) {
+        return createDesktopOrMenuPanel(list, findIcons, findGenerated, R("DIMmenuItems"), bold(R("DIMmenuItemsTooltip")));
+    }
+
+    public static JPanel createDesktopPanel(JList list, ActionListener findIcons, ActionListener findGenerated) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(R("DIMdesktopItemsTooltipL1")).append("<br>")
+                .append(R("DIMdesktopItemsTooltipL2")).append(":" + "<ul>" + "<li>")
+                .append(R("DIMdesktopItemsTooltipL3")).append("</li>" + "<li>")
+                .append(R("DIMdesktopItemsTooltipL4")).append("</li>" + "<li>")
+                .append(R("DIMdesktopItemsTooltipL5")).append("</li>" + "</ul>")
+                .append(bold(R("DIMdesktopItemsTooltipL6")));
+        return createDesktopOrMenuPanel(list, findIcons, findGenerated, R("DIMdesktopItems"), sb.toString());
+    }
+
+    private static JPanel createDesktopOrMenuPanel(JList list, ActionListener findIcons, ActionListener findGenerated, String title, String tooltip) {
+        JPanel desktopPanel = new JPanel(new BorderLayout());
+        JLabel l = new JLabel(title);
+        l.setToolTipText(createToolTip(tooltip, list));
+        desktopPanel.add(l, BorderLayout.PAGE_START);
+        JScrollPane scrollDesktop = new JScrollPane();
+        scrollDesktop.setViewportView(list);
+        desktopPanel.add(scrollDesktop, BorderLayout.CENTER);
+        JPanel desktopToolPanel = createDesktopOrMenuToolBox(findIcons, findGenerated);
+        desktopPanel.add(desktopToolPanel, BorderLayout.PAGE_END);
+        return desktopPanel;
+    }
+
+    private static String createToolTip(String tooltip, JList list) {
+        if (tooltip != null) {
+            JListUtils.FileListBasedJListModel model = (JListUtils.FileListBasedJListModel) (list.getModel());
+            StringBuilder sb = new StringBuilder();
+            sb.append("<ul><li>")
+                    .append(model.getFile()).append("</li><br>" + "<li>")
+                    .append(model.toString()).append("</li><br>" + "<li>")
+                    .append(tooltip).append("</ul>");
+            String tt = SecurityDialogPanel.htmlWrap(sb.toString());
+            return tt;
+        }
+        return null;
+    }
+
+    private static JPanel createDesktopOrMenuToolBox(ActionListener findIcons, ActionListener findGenerated) {
+        JPanel desktopToolPanel = new JPanel(new BorderLayout());
+        JButton desktopFindGeneratedButton = new JButton(R("DIMgeneratedButton"));
+        desktopFindGeneratedButton.setToolTipText(R("DIMgeneratedButtonTooltip"));
+        desktopFindGeneratedButton.addActionListener(findGenerated);
+        JButton desktopFindIconsButton = new JButton(R("DIMiconsButton"));
+        desktopFindIconsButton.setToolTipText(R("DIMiconsButtonTooltip"));
+        desktopFindIconsButton.addActionListener(findIcons);
+        desktopToolPanel.add(desktopFindGeneratedButton, BorderLayout.LINE_END);
+        desktopToolPanel.add(desktopFindIconsButton, BorderLayout.LINE_START);
+        return desktopToolPanel;
+    }
+
+    static JSplitPane createQuadroSplit(int width, JPanel menusPanel, JPanel desktopsPanel, JPanel iconsPanel, JPanel generatedsPanel) {
+        JSplitPane splitAllAndGenerated = new JSplitPane();
+        JSplitPane splitIconsAndLists = new JSplitPane();
+        JSplitPane splitLists = new JSplitPane();
+        splitLists.setLeftComponent(menusPanel);
+        splitLists.setRightComponent(desktopsPanel);
+        splitIconsAndLists.setRightComponent(splitLists);
+        splitIconsAndLists.setLeftComponent(iconsPanel);
+        splitAllAndGenerated.setLeftComponent(splitIconsAndLists);
+        splitAllAndGenerated.setRightComponent(generatedsPanel);
+        splitAllAndGenerated.setDividerLocation(width / 5 * 4);
+        splitIconsAndLists.setDividerLocation(width / 4);
+        splitLists.setDividerLocation(width / 4);
+        return splitAllAndGenerated;
+    }
+
+    private static String bold(String s) {
+        return "<b>" + s + "</b>";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/controlpanel/desktopintegrationeditor/PreviewSelectionJTextPane.java	Thu Nov 12 17:19:20 2015 +0100
@@ -0,0 +1,155 @@
+/*   Copyright (C) 2015 Red Hat, Inc.
+
+ This file is part of IcedTea.
+
+ IcedTea 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, version 2.
+
+ IcedTea 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 IcedTea; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version.
+ */
+package net.sourceforge.jnlp.controlpanel.desktopintegrationeditor;
+
+import java.io.File;
+import java.util.List;
+import javax.swing.JList;
+import javax.swing.JTextPane;
+import javax.swing.text.html.HTMLEditorKit;
+import net.sourceforge.jnlp.util.logging.OutputController;
+
+import static net.sourceforge.jnlp.runtime.Translator.R;
+
+public class PreviewSelectionJTextPane extends JTextPane {
+
+    private final JList iconsList;
+    private final JList menuList;
+    private final JList desktopList;
+    private final JList generatedList;
+
+    public PreviewSelectionJTextPane(JList iconsList, JList menuList, JList desktopList, JList generatedList) {
+        this.iconsList = iconsList;
+        this.menuList = menuList;
+        this.desktopList = desktopList;
+        this.generatedList = generatedList;
+        this.setEditorKit(new HTMLEditorKit());
+        this.setEditable(false);
+    }
+
+    private StringBuilder getMenus() {
+        return getTextFiles(menuList.getSelectedValuesList());
+    }
+
+    private StringBuilder getDesktops() {
+        return getTextFiles(desktopList.getSelectedValuesList());
+    }
+
+    private StringBuilder getGenerated() {
+        return getTextFiles(generatedList.getSelectedValuesList());
+    }
+
+    private StringBuilder getHeader(boolean i, boolean d, boolean m, boolean g) {
+        StringBuilder sb = new StringBuilder();
+        if (i || d || m || g) {
+            sb.append("<tr>");
+        }
+        if (i) {
+            sb.append("<th>").append(R("DIMicons")).append(":</th>");
+        }
+        if (d) {
+            sb.append("<th>").append(R("DIMdesktopItems")).append(":</th>");
+        }
+        if (m) {
+            sb.append("<th>").append(R("DIMmenuItems")).append(":</th>");
+        }
+        if (g) {
+            sb.append("<th>").append(R("DIMgeneratedJnlps")).append(":</th>");
+        }
+
+        if (i || d || m || g) {
+            sb.append("</tr>");
+        }
+        return sb;
+    }
+
+    public void generatePreview() {
+        try {
+            StringBuilder sb = new StringBuilder("<html><table>");
+            sb.append(getHeader(iconsList.getSelectedIndices().length > 0,
+                    menuList.getSelectedIndices().length > 0,
+                    desktopList.getSelectedIndices().length > 0,
+                    generatedList.getSelectedIndices().length > 0)).append("<tr>");
+            if (iconsList.getSelectedIndices().length > 0) {
+                sb.append("<td>").append(getIcons()).append("</td>");
+            }
+            if (menuList.getSelectedIndices().length > 0) {
+                sb.append("<td>").append(getMenus()).append("</td>");
+            }
+            if (desktopList.getSelectedIndices().length > 0) {
+                sb.append("<td>").append(getDesktops()).append("</td>");
+            }
+            if (generatedList.getSelectedIndices().length > 0) {
+                sb.append("<td>").append(getGenerated()).append("</td>");
+            }
+            sb.append("</tr></table></html>");
+            this.setText(sb.toString());
+
+        } catch (Exception ex) {
+            OutputController.getLogger().log(ex);
+        }
+
+    }
+
+    private StringBuilder getIcons() {
+        StringBuilder s = new StringBuilder();
+        try {
+            List l = iconsList.getSelectedValuesList();
+            for (Object l1 : l) {
+                File f = (File) l1;
+                s.append("<small>").append(f.getAbsolutePath()).append("</small><br>");
+                s.append("<img src='").append(f.toURI().toURL()).append("'></img><br>");
+
+            }
+        } catch (Exception ex) {
+            OutputController.getLogger().log(ex);
+        }
+        return s;
+    }
+
+    private StringBuilder getTextFiles(List selectedValuesList) {
+        StringBuilder s = new StringBuilder();
+        for (Object i : selectedValuesList) {
+            File f = (File) i;
+            s.append("<small>").append(f.getAbsolutePath()).append("</small><br>");
+            s.append("<pre>").append(FreeDesktopIntegrationEditorFrame.fileToString(f, true)).append("</pre><br>");
+
+        }
+        return s;
+
+    }
+
+}
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties	Thu Nov 12 15:48:22 2015 +0100
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties	Thu Nov 12 17:19:20 2015 +0100
@@ -559,6 +559,8 @@
 CPSecurityDescription=Use this to configure security settings.
 CPDebuggingDescription=Enable options here to help with debugging
 CPDesktopIntegrationDescription=Set whether or not to allow creation of desktop shortcut.
+CPDesktopIntegrationShowIntegrations=Show desktop and menu integrations window
+CPDesktopIntegrationLinuxOnly=Desktop integration manager available only for Linux. Sorry
 CPJVMPluginArguments=Set JVM arguments for plugin.
 CPJVMitwExec=Set JVM for IcedTea-Web \u2014 working best with OpenJDK
 CPJVMitwExecValidation=Validate JVM for IcedTea-Web
@@ -971,6 +973,37 @@
 CVCPColPath=Path
 CVCPColName=Name
 
+# Control Panel - desktop integration manager
+DIMtitle=IcedTea-Web Shortcut Manager
+DIMremoveSelected=Remove selected
+DIMselectRelativeRecordsFromOtherColumns=Select related records
+DIMreloadLists=Reload
+DIMselectAll=Select all
+DIMclearSelection=Deselect all
+DIMdescription=Manage the shorctuts and resources (cached images, etc) IcedTea-Web created for desktop integration
+DIMguessedDesktop=Desktop folder as well guessed as possible.
+DIMselectionPreview=Selection preview
+DIMaskBeforeDelete=Are you sure you want to delete {0} files?
+DIMgeneratedJnlps=Generated JNLPs
+DIMgeneratedJnlpsTooltip=All files in this list should be generated by IcedTea-Web!
+DIMicons=Icons
+DIMiconsTooltip=All files in this list should be icons cached by IcedTea-Web!
+DIMorphans=orphans
+DIMorphansTooltip=Will select all items which are not listed in any shortcut.
+DIMmenuItems=Menu Items
+DIMmenuItemsTooltip=All shortcuts in this list should be generated by IcedTea-Web!
+DIMdesktopItems=Desktop Items
+DIMdesktopItemsTooltipL1=Not all your shortcuts on your Desktop were generated by IcedTea-Web!
+DIMdesktopItemsTooltipL2=For your convenience:
+DIMdesktopItemsTooltipL3=red items were probably not generated by IcedTea-Web
+DIMdesktopItemsTooltipL4=dark green items are browser shortcuts, so they were probably generated by IcedTea-Web
+DIMdesktopItemsTooltipL5=green items are javaws shortcuts, so they were very likely generated by IcedTea-Web
+DIMdesktopItemsTooltipL6=In all cases, be careful what you delete, and verify connections with `select related records` mode
+DIMgeneratedButton=generated
+DIMgeneratedButtonTooltip=Will select related generated stuff.
+DIMiconsButton=icons
+DIMiconsButtonTooltip=Will select related cached icons.
+
 # Control Panel - Misc.
 CPJRESupport=IcedTea-Web currently does not support the use of multiple JREs.
 CPInvalidPort=Invalid port number given.\n[Valid port numbers are 1-65535]
--- a/netx/net/sourceforge/jnlp/security/dialogs/SecurityDialogPanel.java	Thu Nov 12 15:48:22 2015 +0100
+++ b/netx/net/sourceforge/jnlp/security/dialogs/SecurityDialogPanel.java	Thu Nov 12 17:19:20 2015 +0100
@@ -71,7 +71,7 @@
     /**
      * Needed to get word wrap working in JLabels.
      */
-    protected String htmlWrap(String s) {
+    public  static String htmlWrap(String s) {
         return "<html>" + s + "</html>";
     }
 
--- a/netx/net/sourceforge/jnlp/util/XDesktopEntry.java	Thu Nov 12 15:48:22 2015 +0100
+++ b/netx/net/sourceforge/jnlp/util/XDesktopEntry.java	Thu Nov 12 17:19:20 2015 +0100
@@ -531,7 +531,7 @@
         return fPath;
     }
 
-    private static String findFreedesktopOrgDesktopPathCatch() {
+    public static String findFreedesktopOrgDesktopPathCatch() {
         try {
             return findFreedesktopOrgDesktopPath();
         } catch (Exception ex) {
--- a/netx/net/sourceforge/jnlp/util/logging/ConsoleOutputPaneModel.java	Thu Nov 12 15:48:22 2015 +0100
+++ b/netx/net/sourceforge/jnlp/util/logging/ConsoleOutputPaneModel.java	Thu Nov 12 17:19:20 2015 +0100
@@ -205,11 +205,7 @@
             }
             String line = (createLine(messageWithHeader));
             if (mark) {
-                line = line.replaceAll("<", "&lt;");
-                line = line.replaceAll(">", "&gt;");
-                line = line.replaceAll("\n", "<br/>\n");
-                line = line.replaceAll("  ", "&nbsp; ");//small trick, html is reducting row of spaces to single space. This handles it and stimm allow line wrap
-                line = line.replaceAll("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
+                line = escapeHtmlForJTextPane(line);
             }
             sb.append(line);
             if (mark) {
@@ -229,6 +225,15 @@
 
     }
 
+    public static String escapeHtmlForJTextPane(String line) {
+        line = line.replaceAll("<", "&lt;")
+                .replaceAll(">", "&gt;")
+                .replaceAll("\n", "<br/>\n")
+                .replaceAll("  ", "&nbsp; ")//small trick, html is reducting row of spaces to single space. This handles it and stimm allow line wrap
+                .replaceAll("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
+        return line;
+    }
+
     String createLine(MessageWithHeader m) {
         StringBuilder sb = new StringBuilder();
         if (showHeaders) {
--- a/tests/netx/unit/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/AppTrustWarningPanelTest.java	Thu Nov 12 15:48:22 2015 +0100
+++ b/tests/netx/unit/net/sourceforge/jnlp/security/dialogs/apptrustwarningpanel/AppTrustWarningPanelTest.java	Thu Nov 12 17:19:20 2015 +0100
@@ -14,6 +14,7 @@
 import net.sourceforge.jnlp.PluginParameters;
 import net.sourceforge.jnlp.browsertesting.browsers.firefox.FirefoxProfilesOperator;
 import net.sourceforge.jnlp.config.PathsAndFiles;
+import net.sourceforge.jnlp.security.dialogs.SecurityDialogPanel;
 import org.junit.AfterClass;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -138,7 +139,7 @@
     public void testHtmlWrap() throws Exception {
         final String testText = "This is some text";
         final String expectedResult = "<html>This is some text</html>";
-        final String actualResult = UnsignedAppletTrustWarningPanel.htmlWrap(testText);
+        final String actualResult = SecurityDialogPanel.htmlWrap(testText);
         assertEquals("htmlWrap should properly wrap text with HTML tags", expectedResult, actualResult);
     }