diff options
author | Reinier Zwitserloot <reinier@tipit.to> | 2009-07-05 21:47:24 +0200 |
---|---|---|
committer | Reinier Zwitserloot <reinier@tipit.to> | 2009-07-05 21:48:24 +0200 |
commit | a9fe617303f9726794451eaf2c517a8ec57f3faf (patch) | |
tree | 86444b4e19a7f79e66fd13b0371d349a806af41f | |
parent | 1f8a907187cbdeacc0947d3cc00d251640882a54 (diff) | |
download | lombok-a9fe617303f9726794451eaf2c517a8ec57f3faf.tar.gz lombok-a9fe617303f9726794451eaf2c517a8ec57f3faf.tar.bz2 lombok-a9fe617303f9726794451eaf2c517a8ec57f3faf.zip |
Final touches on the installer:
- some bug fixes for linux
- renamed InstallerWindow to Installer
- Apple-specific prettification added (dock icon, app name)
- more documentation.
Also, I started added an open source licence to all files.
-rw-r--r-- | LICENCE | 19 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | build.xml | 23 | ||||
-rw-r--r-- | src/lombok/installer/AppleNativeLook.java | 41 | ||||
-rw-r--r-- | src/lombok/installer/EclipseFinder.java | 132 | ||||
-rw-r--r-- | src/lombok/installer/EclipseLocation.java | 116 | ||||
-rw-r--r-- | src/lombok/installer/Installer.java (renamed from src/lombok/installer/InstallerWindow.java) | 176 | ||||
-rw-r--r-- | src/lombok/installer/lombok.svg | 5 | ||||
-rw-r--r-- | src/lombok/installer/package-info.java | 28 |
9 files changed, 466 insertions, 76 deletions
diff --git a/LICENCE b/LICENCE new file mode 100644 index 00000000..c370acef --- /dev/null +++ b/LICENCE @@ -0,0 +1,19 @@ +Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. @@ -2,7 +2,7 @@ projectlombok makes java a spicier language by adding 'handlers' that know how t Using lombok is made as simple as possible, and aims to work on all major java IDEs as well as javac itself. -projectlombok is open source under the Creative Commons - free to share, free to remix, provided you attribute the authors licence, as shown here: http://creativecommons.org/licenses/by/3.0/us/ +See LICENCE for the project lombok licence. Project Authors: @@ -1,3 +1,24 @@ +<!-- + Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +--> <project name="lombok" default="dist"> <property name="build.compiler" value="javac1.6" /> <path id="lombok.deps.path"> @@ -98,7 +119,7 @@ <fileset dir="dist" includes="lombok.eclipse.agent.jar" /> <manifest> - <attribute name="Main-Class" value="lombok.installer.InstallerWindow" /> + <attribute name="Main-Class" value="lombok.installer.Installer" /> </manifest> </jar> <copy file="dist/lombok-${lombok.version}.jar" tofile="dist/lombok.jar" /> diff --git a/src/lombok/installer/AppleNativeLook.java b/src/lombok/installer/AppleNativeLook.java new file mode 100644 index 00000000..1d3cfff7 --- /dev/null +++ b/src/lombok/installer/AppleNativeLook.java @@ -0,0 +1,41 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.installer; + +import java.io.IOException; + +import javax.imageio.ImageIO; + +import com.apple.eawt.Application; + +/** + * Mac OS X specific code to gussy up the GUI a little bit, mostly with a nice dock icon. Well, nicer than + * the standard icon, at any rate. + */ +class AppleNativeLook { + public static void go() throws IOException { + Application app = Application.getApplication(); + app.removeAboutMenuItem(); + app.removePreferencesMenuItem(); + app.setDockIconImage(ImageIO.read(AppleNativeLook.class.getResource("lombokIcon.png"))); + } +} diff --git a/src/lombok/installer/EclipseFinder.java b/src/lombok/installer/EclipseFinder.java index 1ca82440..3c966359 100644 --- a/src/lombok/installer/EclipseFinder.java +++ b/src/lombok/installer/EclipseFinder.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.installer; import static java.util.Arrays.asList; @@ -18,8 +39,17 @@ import java.util.regex.Pattern; import lombok.Lombok; -public class EclipseFinder { - public static File findOurJar() { +/** Utility class for doing various OS-specific operations related to finding eclipse installations. */ +class EclipseFinder { + private EclipseFinder() { + //Prevent instantiation. + } + + /** + * Returns a File object pointing to our own jar file. Will obviously fail if the installer was started via + * a jar that wasn't accessed via the file-system, or if its started via e.g. unpacking the jar. + */ + static File findOurJar() { try { URI uri = EclipseFinder.class.getResource("/" + EclipseFinder.class.getName().replace('.', '/') + ".class").toURI(); Pattern p = Pattern.compile("^jar:file:([^\\!]+)\\!.*\\.class$"); @@ -33,7 +63,15 @@ public class EclipseFinder { } } - public static List<String> getDrivesOnWindows() throws IOException { + /** + * Returns all drive letters on windows, regardless of what kind of drive is represented. + * + * Relies on the 'fsutil.exe' program. I have no idea if you can call it without triggering a gazillion + * security warnings on Vista. I did a cursory test on an out-of-the-box Windows XP and that seems to work. + * + * @return A List of drive letters, such as ["A", "C", "D", "X"]. + */ + static List<String> getDrivesOnWindows() throws IOException { ProcessBuilder builder = new ProcessBuilder("c:\\windows\\system32\\fsutil.exe", "fsinfo", "drives"); builder.redirectErrorStream(true); Process process = builder.start(); @@ -58,7 +96,12 @@ public class EclipseFinder { return drives; } - public static boolean isLocalDriveOnWindows(String driveLetter) { + /** + * @return true if the letter represents a local fixed disk, false if its a disk drive, optical drive, + * USB stick, network drive, or any other kind of drive. Substed (virtual) drives that are an alias to + * a directory on a local disk cause a 'return true', but this is intentional. + */ + static boolean isLocalDriveOnWindows(String driveLetter) { if ( driveLetter == null || driveLetter.length() == 0 ) return false; try { ProcessBuilder builder = new ProcessBuilder("c:\\windows\\system32\\fsutil.exe", "fsinfo", "drivetype", driveLetter + ":"); @@ -78,7 +121,19 @@ public class EclipseFinder { } } - public static List<String> findEclipseOnWindows() { + /** + * Returns a list of paths of eclipse installations. + * Eclipse installations are found by checking for the existence of 'eclipse.exe' in the following locations: + * + * X:\*Program Files*\*Eclipse* + * X:\*Eclipse* + * + * Where 'X' is tried for all local disk drives, unless there's a problem calling fsutil, in which case only + * C: is tried. + * + * @return A List of directories that contain 'eclipse.exe'. + */ + static List<String> findEclipseOnWindows() { List<String> eclipses = new ArrayList<String>(); List<String> driveLetters = asList("C"); @@ -109,34 +164,71 @@ public class EclipseFinder { return eclipses; } + /** Checks if the provided directory contains 'eclipse.exe', and if so, returns the directory, otherwise null. */ private static String findEclipseOnWindows1(File dir) { - if ( new File(dir, "eclipse.exe").isFile() ) return dir.toString(); + if ( new File(dir, "eclipse.exe").isFile() ) return dir.getAbsolutePath(); return null; } - public static void main(String[] args) throws Exception { - System.out.println(findEclipses()); + /** + * Calls the OS-dependent 'find eclipse' routine. If the local OS doesn't have a routine written for it, + * null is returned. + * + * @return List of directories that contain the eclipse executable. + */ + static List<String> findEclipses() { + switch ( getOS() ) { + case WINDOWS: + return findEclipseOnWindows(); + case MAC_OS_X: + return findEclipseOnMac(); + default: + case UNIX: + return null; + } } - public static List<String> findEclipses() { - String prop = System.getProperty("os.name", ""); - if ( prop.equalsIgnoreCase("Mac OS X") ) return findEclipseOnMac(); - if ( prop.equalsIgnoreCase("Windows XP") ) return findEclipseOnWindows(); - - return null; + static enum OS { + MAC_OS_X, WINDOWS, UNIX; } - public static String getEclipseExecutableName() { - String prop = System.getProperty("os.name", ""); - if ( prop.equalsIgnoreCase("Mac OS X") ) return "Eclipse.app"; - if ( prop.equalsIgnoreCase("Windows XP") ) return "eclipse.exe"; + static OS getOS() { + String prop = System.getProperty("os.name", "").toLowerCase(); + if ( prop.matches("^.*\\bmac\\b.*$") ) return OS.MAC_OS_X; + if ( prop.matches("^.*\\bwin(dows)\\b.*$") ) return OS.WINDOWS; - return "eclipse"; + return OS.UNIX; } - public static List<String> findEclipseOnMac() { + /** + * Returns the proper name of the executable for the local OS. + * + * @return 'Eclipse.app' on OS X, 'eclipse.exe' on Windows, and 'eclipse' on other OSes. + */ + static String getEclipseExecutableName() { + switch ( getOS() ) { + case WINDOWS: + return "eclipse.exe"; + case MAC_OS_X: + return "Eclipse.app"; + default: + case UNIX: + return "eclipse"; + } + } + + /** + * Scans /Applications for any folder named 'Eclipse' + */ + static List<String> findEclipseOnMac() { List<String> eclipses = new ArrayList<String>(); for ( File dir : new File("/Applications").listFiles() ) { + if ( !dir.isDirectory() ) continue; + if ( dir.getName().toLowerCase().equals("eclipse.app") ) { + //This would be kind of an unorthodox eclipse installation, but if eclipse ever + //moves to this more maclike installation concept, our installer can still handle it. + eclipses.add("/Applications"); + } if ( dir.getName().toLowerCase().contains("eclipse") ) { if ( new File(dir, "Eclipse.app").exists() ) eclipses.add(dir.toString()); } diff --git a/src/lombok/installer/EclipseLocation.java b/src/lombok/installer/EclipseLocation.java index 400b5606..66bba5b8 100644 --- a/src/lombok/installer/EclipseLocation.java +++ b/src/lombok/installer/EclipseLocation.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.installer; import java.io.BufferedReader; @@ -7,6 +28,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.jar.JarFile; @@ -17,6 +39,11 @@ import java.util.zip.ZipEntry; import javax.swing.JFrame; import javax.swing.JOptionPane; +/** + * Represents an eclipse installation. + * An instance can figure out if an eclipse installation has been lombok-ified, and can + * install and uninstall lombok from the eclipse installation. + */ final class EclipseLocation { private static final String OS_NEWLINE; @@ -30,8 +57,14 @@ final class EclipseLocation { private final File path; private volatile boolean hasLombok; + + /** Toggling the 'selected' checkbox in the GUI is tracked via this boolean */ boolean selected = true; + /** + * Thrown when creating a new EclipseLocation with a path object that doesn't, in fact, + * point at an eclipse installation. + */ final class NotAnEclipseException extends Exception { private static final long serialVersionUID = 1L; @@ -39,11 +72,19 @@ final class EclipseLocation { super(message, cause); } - public void showDialog(JFrame appWindow) { + /** + * Renders a message dialog with information about what went wrong. + */ + void showDialog(JFrame appWindow) { JOptionPane.showMessageDialog(appWindow, getMessage(), "Cannot configure eclipse installation", JOptionPane.WARNING_MESSAGE); } } + /** + * Create a new EclipseLocation by pointing at either the directory contain the eclipse executable, or the executable itself. + * + * @throws NotAnEclipseException If this isn't an eclipse executable or a directory with an eclipse executable. + */ EclipseLocation(String path) throws NotAnEclipseException { if ( path == null ) throw new NullPointerException("path"); File p = new File(path); @@ -59,6 +100,10 @@ final class EclipseLocation { } } + if ( !p.exists() || !p.getName().equalsIgnoreCase(execName) ) { + throw new NotAnEclipseException("This path does not appear to contain an eclipse installation: " + p, null); + } + this.path = p; try { this.hasLombok = checkForLombok(); @@ -69,23 +114,35 @@ final class EclipseLocation { } } - public int hashCode() { + @Override public int hashCode() { return path.hashCode(); } - public boolean equals(Object o) { + @Override public boolean equals(Object o) { if ( !(o instanceof EclipseLocation) ) return false; return ((EclipseLocation)o).path.equals(path); } - public String getPath() { + /** + * Returns the absolute path to the eclipse executable. + * + * Executables: "eclipse.exe" (Windows), "Eclipse.app" (Mac OS X), "eclipse" (Linux and other unixes). + */ + String getPath() { return path.getAbsolutePath(); } - public boolean hasLombok() { + /** + * @return true if the eclipse installation has been instrumented with lombok. + */ + boolean hasLombok() { return hasLombok; } + /** + * Returns the various directories that can contain the 'eclipse.ini' file. + * Returns multiple directories because there are a few different ways eclipse is packaged. + */ private List<File> getTargetDirs() { return Arrays.asList(path.getParentFile(), new File(new File(path, "Contents"), "MacOS")); } @@ -121,7 +178,8 @@ final class EclipseLocation { } } - public class UninstallException extends Exception { + /** Thrown when uninstalling lombok fails. */ + class UninstallException extends Exception { private static final long serialVersionUID = 1L; public UninstallException(String message, Throwable cause) { @@ -129,7 +187,15 @@ final class EclipseLocation { } } - public void uninstall() throws UninstallException { + /** + * Uninstalls lombok from this location. + * It's a no-op if lombok wasn't there in the first place, + * and it will remove a half-succeeded lombok installation as well. + * + * @throws UninstallException If there's an obvious I/O problem that is preventing installation. + * bugs in the uninstall code will probably throw other exceptions; this is intentional. + */ + void uninstall() throws UninstallException { for ( File dir : getTargetDirs() ) { File lombokJar = new File(dir, "lombok.jar"); if ( lombokJar.exists() ) { @@ -194,7 +260,8 @@ final class EclipseLocation { } } - public class InstallException extends Exception { + /** Thrown when installing lombok fails. */ + class InstallException extends Exception { private static final long serialVersionUID = 1L; public InstallException(String message, Throwable cause) { @@ -202,18 +269,31 @@ final class EclipseLocation { } } - public void install() throws InstallException { + /** + * Install lombok into the eclipse at this location. + * If lombok is already there, it is overwritten neatly (upgrade mode). + * + * @throws InstallException If there's an obvious I/O problem that is preventing installation. + * bugs in the install code will probably throw other exceptions; this is intentional. + */ + void install() throws InstallException { + List<File> failedDirs = new ArrayList<File>(); + + boolean installSucceeded = false; for ( File dir : getTargetDirs() ) { File iniFile = new File(dir, "eclipse.ini"); StringBuilder newContents = new StringBuilder(); - if ( iniFile.exists() ) { + if ( !iniFile.exists() ) failedDirs.add(dir); + else { + //If 'installSucceeded' is true here, something very weird is going on, but instrumenting all of them + //is no less bad than aborting, and this situation should be rare to the point of non-existence. + File lombokJar = new File(iniFile.getParentFile(), "lombok.jar"); File agentJar = new File(iniFile.getParentFile(), "lombok.eclipse.agent.jar"); File ourJar = EclipseFinder.findOurJar(); byte[] b = new byte[524288]; boolean readSucceeded = false; - boolean installSucceeded = false; try { JarFile jar = new JarFile(ourJar); @@ -297,7 +377,6 @@ final class EclipseLocation { fos.close(); } installSucceeded = true; - } catch ( IOException e ) { throw new InstallException("Cannot install lombok at " + path.getAbsolutePath() + " probably because this installer does not have the access rights to do so.", e); @@ -309,5 +388,18 @@ final class EclipseLocation { } } } + + if ( !installSucceeded ) { + throw new InstallException("I can't find the eclipse.ini file. Is this a real eclipse installation?", null); + } + + for ( File dir : failedDirs ) { + //If we're updating the old installation might have worked by putting the lombok jars in a different place. + //We'll delete these old files. + try { + new File(dir, "lombok.jar").delete(); + new File(dir, "lombok.eclipse.agent.jar").delete(); + } catch ( Throwable ignore ) {} + } } } diff --git a/src/lombok/installer/InstallerWindow.java b/src/lombok/installer/Installer.java index a0911c26..5d644868 100644 --- a/src/lombok/installer/InstallerWindow.java +++ b/src/lombok/installer/Installer.java @@ -1,3 +1,24 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package lombok.installer; import java.awt.Color; @@ -5,6 +26,7 @@ import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; +import java.awt.FileDialog; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridBagConstraints; @@ -16,6 +38,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.font.TextAttribute; import java.io.File; +import java.io.FilenameFilter; import java.io.IOException; import java.net.URI; import java.util.ArrayList; @@ -37,14 +60,22 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.Scrollable; import javax.swing.SwingUtilities; +import javax.swing.UIManager; import javax.swing.filechooser.FileFilter; import lombok.core.Version; +import lombok.installer.EclipseFinder.OS; import lombok.installer.EclipseLocation.InstallException; import lombok.installer.EclipseLocation.NotAnEclipseException; import lombok.installer.EclipseLocation.UninstallException; -public class InstallerWindow { +/** + * The lombok installer proper. + * Uses swing to show a simple GUI that can add and remove the java agent to eclipse installations. + * Also offers info on what this installer does in case people want to instrument their eclipse manually, + * and looks in some common places on Mac OS X and Windows. + */ +public class Installer { private static final URI ABOUT_LOMBOK_URL = URI.create("http://projectlombok.org"); private JFrame appWindow; @@ -57,15 +88,26 @@ public class InstallerWindow { private Component howIWorkArea; private Box uninstallBox; - private List<EclipseLocation> toUninstall; + private JHyperLink uninstallButton; + private JButton installButton; + public static void main(String[] args) { + if ( EclipseFinder.getOS() == OS.MAC_OS_X ) { + System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Lombok Installer"); + System.setProperty("com.apple.macos.use-file-dialog-packages", "true"); + } + try { SwingUtilities.invokeLater(new Runnable() { public void run() { try { - new InstallerWindow().show(); + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch ( Exception ignore ) {} + + new Installer().show(); } catch ( HeadlessException e ) { printHeadlessInfo(); } @@ -76,6 +118,11 @@ public class InstallerWindow { } } + /** + * If run in headless mode, the installer can't show its fancy GUI. There's little point in running + * the installer without a GUI environment, as eclipse doesn't run in headless mode either, so + * we'll make do with showing some basic info on Lombok as well as instructions for using lombok with javac. + */ private static void printHeadlessInfo() { System.out.printf("About lombok v%s\n" + "Lombok makes java better by providing very spicy additions to the Java programming language," + @@ -87,7 +134,11 @@ public class InstallerWindow { " java -cp lombok.jar MyCode.java", Version.getVersion(), ABOUT_LOMBOK_URL); } - public InstallerWindow() { + /** + * Creates a new installer that starts out invisible. + * Call the {@see #show()} method on a freshly created installer to render it. + */ + public Installer() { appWindow = new JFrame(String.format("Project Lombok v%s - Installer", Version.getVersion())); appWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -111,6 +162,7 @@ public class InstallerWindow { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JOptionPane.showMessageDialog(appWindow, "There was a problem during the installation process:\n" + t, "Uh Oh!", JOptionPane.ERROR_MESSAGE); + t.printStackTrace(); System.exit(1); } }); @@ -250,7 +302,7 @@ public class InstallerWindow { constraints.gridy = 2; loadingExpl = Box.createHorizontalBox(); - loadingExpl.add(new JLabel(new ImageIcon(InstallerWindow.class.getResource("/lombok/installer/loading.gif")))); + loadingExpl.add(new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/loading.gif")))); loadingExpl.add(new JLabel(ECLIPSE_LOADING_EXPLANATION)); container.add(loadingExpl, constraints); @@ -270,10 +322,12 @@ public class InstallerWindow { final List<EclipseLocation> locations = new ArrayList<EclipseLocation>(); final List<NotAnEclipseException> problems = new ArrayList<NotAnEclipseException>(); - for ( String eclipse : eclipses ) try { - locations.add(new EclipseLocation(eclipse)); - } catch ( NotAnEclipseException e ) { - problems.add(e); + if ( eclipses != null ) { + for ( String eclipse : eclipses ) try { + locations.add(new EclipseLocation(eclipse)); + } catch ( NotAnEclipseException e ) { + problems.add(e); + } } SwingUtilities.invokeLater(new Runnable() { @@ -291,6 +345,13 @@ public class InstallerWindow { } loadingExpl.setVisible(false); + + if ( eclipses == null ) { + JOptionPane.showMessageDialog(appWindow, + "I don't know how to automatically find eclipse installations on this platform.\n" + + "Please use the 'Specify Eclipse Location...' button to manually point out the\n" + + "location of your eclipse installation to me. Thanks!", "Can't find eclipse", JOptionPane.INFORMATION_MESSAGE); + } } }); } catch ( Throwable t ) { @@ -306,38 +367,59 @@ public class InstallerWindow { buttonBar.add(specifyEclipseLocationButton); specifyEclipseLocationButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { - JFileChooser chooser = new JFileChooser(); + final String name = EclipseFinder.getEclipseExecutableName(); + String file = null; - chooser.setAcceptAllFileFilterUsed(false); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - chooser.setFileFilter(new FileFilter() { - private final String name = EclipseFinder.getEclipseExecutableName(); - @Override public boolean accept(File f) { - if ( f.getName().equalsIgnoreCase(name) ) return true; - if ( f.isDirectory() ) return true; + if ( EclipseFinder.getOS() == OS.MAC_OS_X ) { + FileDialog chooser = new FileDialog(appWindow); + chooser.setMode(FileDialog.LOAD); + chooser.setFilenameFilter(new FilenameFilter() { + @Override public boolean accept(File dir, String name) { + if ( name.equalsIgnoreCase(name) ) return true; + if ( new File(dir, name).isDirectory() ) return true; + + return false; + } + }); + + chooser.setVisible(true); + file = new File(chooser.getDirectory(), chooser.getFile()).getAbsolutePath(); + } else { + JFileChooser chooser = new JFileChooser(); + + chooser.setAcceptAllFileFilterUsed(false); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + chooser.setFileFilter(new FileFilter() { + @Override public boolean accept(File f) { + if ( f.getName().equalsIgnoreCase(name) ) return true; + if ( f.isDirectory() ) return true; + + return false; + } - return false; - } + @Override public String getDescription() { + return "Eclipse Installation"; + } + }); - @Override public String getDescription() { - return "Eclipse Installation"; + switch ( chooser.showDialog(appWindow, "Select") ) { + case JFileChooser.APPROVE_OPTION: + file = chooser.getSelectedFile().getAbsolutePath(); } - }); + } - switch ( chooser.showDialog(appWindow, "Select") ) { - case JFileChooser.APPROVE_OPTION: + if ( file != null ) { try { - try { - eclipsesList.addEclipse(new EclipseLocation(chooser.getSelectedFile().getAbsolutePath())); - } catch ( NotAnEclipseException e ) { - e.showDialog(appWindow); - } + eclipsesList.addEclipse(new EclipseLocation(file)); + } catch ( NotAnEclipseException e ) { + e.showDialog(appWindow); } catch ( Throwable t ) { handleException(t); } } } }); + buttonBar.add(Box.createHorizontalGlue()); installButton = new JButton("Install / Update"); buttonBar.add(installButton); @@ -420,7 +502,7 @@ public class InstallerWindow { JPanel spinner = new JPanel(); spinner.setOpaque(true); spinner.setLayout(new FlowLayout()); - spinner.add(new JLabel(new ImageIcon(InstallerWindow.class.getResource("/lombok/installer/loading.gif")))); + spinner.add(new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/loading.gif")))); appWindow.setContentPane(spinner); final AtomicReference<Boolean> success = new AtomicReference<Boolean>(true); @@ -461,7 +543,7 @@ public class InstallerWindow { JPanel spinner = new JPanel(); spinner.setOpaque(true); spinner.setLayout(new FlowLayout()); - spinner.add(new JLabel(new ImageIcon(InstallerWindow.class.getResource("/lombok/installer/loading.gif")))); + spinner.add(new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/loading.gif")))); appWindow.setContentPane(spinner); @@ -562,7 +644,7 @@ public class InstallerWindow { }); if ( location.hasLombok() ) { - box.add(new JLabel(new ImageIcon(InstallerWindow.class.getResource("/lombok/installer/lombokIcon.png")))); + box.add(new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/lombokIcon.png")))); } box.add(Box.createHorizontalGlue()); locations.add(location); @@ -593,8 +675,8 @@ public class InstallerWindow { }; private void buildChrome(Container appWindowContainer) { - JLabel leftGraphic = new JLabel(new ImageIcon(InstallerWindow.class.getResource("/lombok/installer/lombok.png"))); - JLabel topGraphic = new JLabel(new ImageIcon(InstallerWindow.class.getResource("/lombok/installer/lombokText.png"))); + JLabel leftGraphic = new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/lombok.png"))); + JLabel topGraphic = new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/lombokText.png"))); GridBagConstraints constraints = new GridBagConstraints(); @@ -656,20 +738,24 @@ public class InstallerWindow { Object desktop = Class.forName("java.awt.Desktop").getMethod("getDesktop").invoke(null); Class.forName("java.awt.Desktop").getMethod("browse", URI.class).invoke(desktop, ABOUT_LOMBOK_URL); } catch ( Exception e ) { - String os = System.getProperty("os.name").toLowerCase(); Runtime rt = Runtime.getRuntime(); try { - if ( os.indexOf( "win" ) > -1 ) { + switch ( EclipseFinder.getOS() ) { + case WINDOWS: String[] cmd = new String[4]; cmd[0] = "cmd.exe"; cmd[1] = "/C"; cmd[2] = "start"; cmd[3] = ABOUT_LOMBOK_URL.toString(); rt.exec(cmd); - } else if ( os.indexOf( "mac" ) >= 0 ) { + break; + case MAC_OS_X: rt.exec( "open " + ABOUT_LOMBOK_URL.toString()); - } else { + break; + default: + case UNIX: rt.exec("firefox " + ABOUT_LOMBOK_URL.toString()); + break; } } catch ( Exception e2 ) { JOptionPane.showMessageDialog(appWindow, @@ -690,8 +776,18 @@ public class InstallerWindow { appWindow.add(buttonBar, constraints); } + /** + * Makes the installer window visible. + */ public void show() { appWindow.setVisible(true); + if ( EclipseFinder.getOS() == OS.MAC_OS_X ) { + try { + AppleNativeLook.go(); + } catch ( Throwable ignore ) { + //We're just prettying up the app. If it fails, meh. + } + } } private static final String ECLIPSE_TITLE = @@ -733,8 +829,4 @@ public class InstallerWindow { "<br>" + "That's all there is to it. Note that on Mac OS X, eclipse.ini is hidden in<br>" + "<code>Eclipse.app/Contents/MacOS</code> so that's where I place the jar files.</html>"; - - private JHyperLink uninstallButton; - - private JButton installButton; } diff --git a/src/lombok/installer/lombok.svg b/src/lombok/installer/lombok.svg index b28e1cbe..0d561aea 100644 --- a/src/lombok/installer/lombok.svg +++ b/src/lombok/installer/lombok.svg @@ -1,4 +1,9 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- +This vector art image is part of the public domain. It has been updated from: +http://www.clker.com/clipart-pepper.html +--> + <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" diff --git a/src/lombok/installer/package-info.java b/src/lombok/installer/package-info.java new file mode 100644 index 00000000..a40330e5 --- /dev/null +++ b/src/lombok/installer/package-info.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * This package contains the lombok installer. It explains to any user that double-clicks the lombok.jar what + * lombok is about, and has the ability to instrument (or remove existing Lombok instrumentation) from any + * eclipse installation. This package also contains the graphics uses in the installer in SVG format. + */ +package lombok.installer; |