/* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores * CA 94065 USA or visit www.oracle.com if you need additional information or * have any questions. */ package com.sun.lwuit.resources.editor; import com.sun.lwuit.resources.editor.editors.CustomComponent; import com.sun.lwuit.Display; import com.sun.lwuit.Form; import com.sun.lwuit.impl.swing.SwingImplementation; import com.sun.lwuit.plaf.Accessor; import com.sun.lwuit.uidemo.Main; import com.sun.lwuit.util.EditableResources; import com.sun.lwuit.util.UIBuilderOverride; import java.io.IOException; import java.util.jar.Attributes.Name; import javax.microedition.midlet.MIDletAccessor; import javax.microedition.midlet.MIDlet; import java.awt.BorderLayout; import java.awt.Component; import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import java.util.Vector; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.prefs.Preferences; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; /** * UI and logic allowing us to pick the MIDlet which will appear in the preview * pane * * @author Shai Almog */ public class PickMIDlet extends javax.swing.JPanel { private static CustomComponent[] customComponents; /** Creates new form PickMIDlet */ public PickMIDlet() { initComponents(); midletPicker.setRenderer(new DefaultListCellRenderer() { public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if(value == null) { value = ""; } else { String s = (String)value; value = s.substring(0, s.indexOf(',')); } return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); } }); Preferences pref = Preferences.userNodeForPackage(ResourceEditorView.class); jarFile.setText(pref.get("jar", "")); updateMIDletList(); midletPicker.setSelectedItem(pref.get("midlet", null)); customComponents = null; } public static void showPickMIDletDialog(JComponent parent) { JDialog dlg = new JDialog((JFrame)SwingUtilities.getWindowAncestor(parent)); dlg.setTitle("Pick MIDlet"); dlg.getContentPane().setLayout(new BorderLayout()); dlg.getContentPane().add(BorderLayout.CENTER, new PickMIDlet()); dlg.setLocationByPlatform(true); dlg.pack(); dlg.setVisible(true); } public static CustomComponent[] getCustomComponents() { if(customComponents == null) { Preferences pref = Preferences.userNodeForPackage(ResourceEditorView.class); String jar = pref.get("jar", null); if(jar != null) { try { File jarFile = new File(jar); URLClassLoader cl = URLClassLoader.newInstance(new URL[]{jarFile.toURI().toURL()}, PickMIDlet.class.getClassLoader()); JarFile zip = new JarFile(jarFile); Enumeration<JarEntry> en = zip.entries(); List<CustomComponent> customList = new ArrayList<CustomComponent>(); while(en.hasMoreElements()) { JarEntry e = en.nextElement(); String className = e.getName().replace("/", "."); if(className.endsWith(".class") && !className.startsWith("com.sun.lwuit.") && className.indexOf('$') < 0) { className = className.substring(0, className.length() - 6); try { CustomComponent current = new CustomComponent(); current.setCls(cl.loadClass(className)); if(!current.getCls().getName().startsWith("com.sun.lwuit")) { // check that it has a default constructor com.sun.lwuit.Component cmp = (com.sun.lwuit.Component)current.getCls().newInstance(); current.setClassName(current.getCls().getName()); current.setLwuitBaseClass(current.getCls().getName()); current.setType(cmp.getUIID()); customList.add(current); UIBuilderOverride.registerCustomComponent(cmp.getUIID(), current.getCls()); } } catch (Throwable ex) { } } } customComponents = new CustomComponent[customList.size()]; customList.toArray(customComponents); } catch (IOException ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(JFrame.getFrames()[0], "IO Error when accessing MIDlet JAR File: " + ex, "IO Error", JOptionPane.ERROR_MESSAGE); } } } return customComponents; } public static void resetSettings() { Preferences pref = Preferences.userNodeForPackage(ResourceEditorView.class); pref.remove("jar"); pref.remove("midlet"); } public static void startMIDlet(Hashtable themeHash) { Accessor.setTheme(themeHash); Preferences pref = Preferences.userNodeForPackage(ResourceEditorView.class); String jar = pref.get("jar", null); String midlet = pref.get("midlet", null); if(jar != null && midlet != null) { File jarFile = new File(jar); if(jarFile.exists()) { try { URLClassLoader cl = URLClassLoader.newInstance(new URL[]{jarFile.toURI().toURL()}, PickMIDlet.class.getClassLoader()); StringTokenizer tokenizer = new StringTokenizer((String) midlet, " ,"); String s = tokenizer.nextToken(); while(tokenizer.hasMoreTokens()) { s = tokenizer.nextToken(); } Class cls = cl.loadClass(s); SwingImplementation.setClassLoader(cls); EditableResources.setResourcesClassLoader(cls); Accessor.setTheme(themeHash); MIDlet app = (MIDlet) cls.newInstance(); JarFile zip = new JarFile(jarFile); Attributes m = zip.getManifest().getMainAttributes(); Set set = m.keySet(); Iterator iter = set.iterator(); while(iter.hasNext()){ Attributes.Name name = (Name) iter.next(); app.putAppProperty(name.toString(), m.getValue(name)); } MIDletAccessor.start(app); // there might be an ongoing transition and the form.show() method is serial Display.getInstance().callSerially(new Runnable() { public void run() { if(Display.getInstance().getCurrent() != null) { Display.getInstance().getCurrent().refreshTheme(); return; } else { new Thread() { public void run() { try { sleep(100); } catch (InterruptedException ex) { ex.printStackTrace(); } Display.getInstance().callSerially(this); } }.start(); } } }); return; } catch (Exception ex) { ex.printStackTrace(); } } } SwingImplementation.setClassLoader(PickMIDlet.class); MIDletAccessor.start(new Main()); Accessor.setTheme(themeHash); Form current = Display.getInstance().getCurrent(); if(current != null) { current.refreshTheme(); } } /** 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() { jLabel2 = new javax.swing.JLabel(); jarFile = new javax.swing.JTextField(); pickJarFile = new javax.swing.JButton(); jLabel3 = new javax.swing.JLabel(); midletPicker = new javax.swing.JComboBox(); okButton = new javax.swing.JButton(); cancelButton = new javax.swing.JButton(); jScrollPane1 = new javax.swing.JScrollPane(); jTextPane1 = new javax.swing.JTextPane(); FormListener formListener = new FormListener(); setName("Form"); // NOI18N jLabel2.setText("JAR File"); jLabel2.setName("jLabel2"); // NOI18N jarFile.setEditable(false); jarFile.setName("jarFile"); // NOI18N pickJarFile.setText("..."); pickJarFile.setName("pickJarFile"); // NOI18N pickJarFile.addActionListener(formListener); jLabel3.setText("MIDlet"); jLabel3.setName("jLabel3"); // NOI18N midletPicker.setName("midletPicker"); // NOI18N okButton.setText("OK"); okButton.setEnabled(false); okButton.setName("okButton"); // NOI18N okButton.addActionListener(formListener); cancelButton.setText("Cancel"); cancelButton.setName("cancelButton"); // NOI18N cancelButton.addActionListener(formListener); jScrollPane1.setName("jScrollPane1"); // NOI18N jTextPane1.setContentType("text/html"); jTextPane1.setEditable(false); jTextPane1.setText("<html>\r\n <head>\r\n\r\n </head>\r\n <body>\r\n <p style=\"margin-top: 0\">\r\n Allows selecting a MIDlet to execute within the preview window of the theme view when\ncreating a theme for a specific MIDlet. The preview might not reflect thefull set of changes \nfrom the theme but would provide a good estimate for a designer. This MIDlet can also expose\nadditional custom components to the GUI designer view simply by creating valid LWUIT component\nsubclasses with default constructors.\r\n </p>\r\n <p>\n The picked MIDlet MUST NOT be obfuscated, this allows the resource editor to replace the \nMIDlet's LWUIT version with its own. It can use the GCF (generic connection framework) and\nMMAPI but cannot expect them to work (mostly these API's return null or do nothing).\n </p>\n <p>\n To debug pick MIDlet run the resource editor with a console or from command line and look at the\nerrors printed out when picking a MIDlet.\n </p>\n </body>\r\n</html>\r\n"); // NOI18N jTextPane1.setName("jTextPane1"); // NOI18N jScrollPane1.setViewportView(jTextPane1); org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .addContainerGap() .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jLabel2) .add(jLabel3)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(midletPicker, 0, 274, Short.MAX_VALUE) .add(jarFile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE) .add(layout.createSequentialGroup() .add(okButton) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(cancelButton))) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(pickJarFile) .addContainerGap()) .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 387, Short.MAX_VALUE) ); layout.linkSize(new java.awt.Component[] {cancelButton, okButton}, org.jdesktop.layout.GroupLayout.HORIZONTAL); layout.setVerticalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .addContainerGap() .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel2) .add(jarFile, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(pickJarFile)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(jLabel3) .add(midletPicker, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(okButton) .add(cancelButton)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 247, Short.MAX_VALUE)) ); } // Code for dispatching events from components to event handlers. private class FormListener implements java.awt.event.ActionListener { FormListener() {} public void actionPerformed(java.awt.event.ActionEvent evt) { if (evt.getSource() == pickJarFile) { PickMIDlet.this.pickJarFileActionPerformed(evt); } else if (evt.getSource() == okButton) { PickMIDlet.this.okButtonActionPerformed(evt); } else if (evt.getSource() == cancelButton) { PickMIDlet.this.cancelButtonActionPerformed(evt); } } }// </editor-fold>//GEN-END:initComponents private void updateMIDletList() { String j = jarFile.getText(); if(j != null && j.length() > 0) { File file = new File(j); if(file.exists() && file.isFile()) { try { JarFile zip = new JarFile(file); Attributes m = zip.getManifest().getMainAttributes(); Vector v = new Vector(); for (int i = 1 ; m.getValue("MIDlet-" + i) != null ; i++) { v.addElement(m.getValue("MIDlet-" + i)); } midletPicker.setModel(new DefaultComboBoxModel(v)); } catch (IOException ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(this, "An IO Error occured while accessing\n" + "the MIDlet JAR:\n" + ex.getMessage(), "IO Error", JOptionPane.ERROR_MESSAGE); } } } } private void selectFile(JTextField field, String type) { JFileChooser c = ResourceEditorView.createFileChooser("*" + type, type); if(JFileChooser.APPROVE_OPTION == c.showDialog(this, "Select")) { File f = c.getSelectedFile(); field.setText(f.getAbsolutePath()); Preferences.userNodeForPackage(ResourceEditorView.class).put("lastDir", f.getParentFile().getAbsolutePath()); } updateMIDletList(); if(midletPicker.getModel().getSize() > 0) { midletPicker.setSelectedIndex(0); } updateOKEnabled(); } private void updateOKEnabled() { if(new File(jarFile.getText()).exists()) { okButton.setEnabled(true); } } private void pickJarFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pickJarFileActionPerformed selectFile(jarFile, ".jar"); }//GEN-LAST:event_pickJarFileActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed SwingUtilities.windowForComponent(this).dispose(); Preferences pref = Preferences.userNodeForPackage(ResourceEditorView.class); pref.put("jar", jarFile.getText()); pref.put("midlet", (String)midletPicker.getSelectedItem()); }//GEN-LAST:event_okButtonActionPerformed private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed SwingUtilities.windowForComponent(this).dispose(); }//GEN-LAST:event_cancelButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton cancelButton; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextPane jTextPane1; private javax.swing.JTextField jarFile; private javax.swing.JComboBox midletPicker; private javax.swing.JButton okButton; private javax.swing.JButton pickJarFile; // End of variables declaration//GEN-END:variables }