├── resources ├── react.png └── sublime.png ├── src └── com │ └── elsea │ ├── sublimelauncher │ ├── Template.java │ ├── FileListCellRenderer.java │ ├── ProjectContainer.java │ ├── SublimeContainer.java │ ├── SublimeLocation.java │ ├── FileUtilities.java │ ├── Program.java │ ├── ViewAddExisting.java │ ├── FileSystem.java │ ├── Project.java │ ├── ViewLaunch.java │ └── ViewAddNew.java │ └── stone │ └── groups │ ├── Property.java │ ├── Group.java │ ├── GroupSearch.java │ ├── Element.java │ └── Groups.java ├── README.md └── .gitignore /resources/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Connorelsea/SublimeLauncher/HEAD/resources/react.png -------------------------------------------------------------------------------- /resources/sublime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Connorelsea/SublimeLauncher/HEAD/resources/sublime.png -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/Template.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.io.File; 4 | 5 | public class Template { 6 | 7 | private String name; 8 | private File location; 9 | 10 | public Template(String name, String path) { 11 | this.name = name; 12 | this.location = new File(path); 13 | } 14 | 15 | public File getLocation() { 16 | return location; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/FileListCellRenderer.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.awt.Component; 4 | import javax.swing.JList; 5 | import javax.swing.ListCellRenderer; 6 | 7 | public class FileListCellRenderer implements ListCellRenderer { 8 | 9 | @Override 10 | public Component getListCellRendererComponent( 11 | JList list, 12 | Object value, 13 | int index, 14 | boolean selected, 15 | boolean focused 16 | ) { 17 | 18 | Project project = (Project) value; 19 | project.processUIState(selected); 20 | return project.getPanel(); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /src/com/elsea/stone/groups/Property.java: -------------------------------------------------------------------------------- 1 | package com.elsea.stone.groups; 2 | 3 | public class Property extends Element 4 | { 5 | 6 | public Property(String name, String value, Group parent) 7 | { 8 | super(name, value, parent); 9 | } 10 | 11 | public Property(String name, String curVal, String defVal, Group parent) 12 | { 13 | super(name, curVal, parent); 14 | defaultValue(defVal); 15 | } 16 | 17 | /** 18 | * Sets the current value of this property. 19 | * 20 | * @param currentValue The new current value of this property. 21 | */ 22 | public void value(String currentValue) 23 | { 24 | currentValue(currentValue); 25 | } 26 | 27 | /** 28 | * Sets the current and default values of this property. 29 | * 30 | * @param currentValue The new current value of this property. 31 | * @param defaultValue The new default value fo this property. 32 | */ 33 | public void value(String currentValue, String defaultValue) 34 | { 35 | currentValue(currentValue); 36 | defaultValue(defaultValue); 37 | } 38 | 39 | /** 40 | * Sets the ID of the current property and returns the parent group. 41 | * 42 | * @param id The ID of the current property. 43 | * @return The parent group 44 | */ 45 | public Group id(String id) 46 | { 47 | setID(id); 48 | return getParent(); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Sublime Launcher 2 | ##### [Download Latest Release (Sublime Launcher 1.1.2)](https://github.com/Connorelsea/SublimeLauncher/releases/tag/v1.1.2) 3 | 4 | ### A multi-platform, fully-featured, project launcher for Sublime Text 5 | 6 | Programs like Eclipse, IntelliJ, WebStorm, and other IDEs have convienient project launchers that allow you to quickly choose the project on startup. Frequently switching projects in Sublime Text is fairly slow. Sublime Launcher aims to remedy this. 7 | 8 | - Create new projects easily 9 | - Easily load existing projects into Sublime Launcher 10 | - Fill new projects with content using templates 11 | - Create your own templates easily 12 | - Sublime Launcher adds absolutely no metadata/files in the project directory 13 | 14 | Pin to your taskbar, start menu, or dock to use easily. 15 | 16 | For this to work you must add the following to your Sublime User Settings. 17 | 18 | "remember_open_files": false, 19 | "hot_exit": false 20 | 21 | ![Sublime Launcher Main Window Picture](http://i.imgur.com/ufavMqh.png) 22 | 23 | ## Build 24 | 25 | Current build: 1.1.2 26 | Download: [Download Sublime Launcher 1.0](https://github.com/Connorelsea/SublimeLauncher/releases/tag/v1.1.2) 27 | 28 | ## Contributing 29 | 30 | Browsing the Issues list or looking for things that could be fixed or added is a good way to begin contributing to Sublime Launcher -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/ProjectContainer.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.util.ArrayList; 4 | import javax.swing.DefaultListModel; 5 | import com.elsea.stone.groups.Group; 6 | 7 | public class ProjectContainer { 8 | 9 | private ArrayList projects; 10 | private DefaultListModel model; 11 | 12 | public ProjectContainer() { 13 | projects = new ArrayList<>(); 14 | model = new DefaultListModel<>(); 15 | } 16 | 17 | public Group generateGroup() { 18 | 19 | Group g = new Group("projects"); 20 | 21 | for (Project project : projects) { 22 | 23 | String name = project.getName(); 24 | String property = project.getLocation().getAbsolutePath() + "#<#>#"; 25 | 26 | if (project.hasIcon()) property += project.getIcon().getAbsolutePath(); 27 | else property += "None"; 28 | 29 | g.property(name, property); 30 | } 31 | 32 | g.end(); 33 | 34 | return g; 35 | } 36 | 37 | public void add(Project p) { 38 | 39 | projects.add(p); 40 | model.addElement(p); 41 | } 42 | 43 | public void remove(Project p) { 44 | projects.remove(p); 45 | model.removeElement(p); 46 | } 47 | 48 | public ArrayList getProjects() { 49 | return projects; 50 | } 51 | 52 | public Project getProject(int index) { 53 | return projects.get(index); 54 | } 55 | 56 | public DefaultListModel getModel() { 57 | return model; 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/SublimeContainer.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | 6 | import com.elsea.stone.groups.Group; 7 | 8 | /** 9 | * SublimeContainer 10 | * 11 | * Finds and contains all instances and versions of Sublime Text 12 | * on the user's computer. 13 | */ 14 | public class SublimeContainer { 15 | 16 | private ArrayList locations; 17 | private ArrayList possibleLocations; 18 | 19 | public Group generateGroup() { 20 | 21 | Group g = new Group("sublimes"); 22 | 23 | for (SublimeLocation location: locations) { 24 | g.property(location.getName(), location.getFile().getAbsolutePath()); 25 | } 26 | 27 | g.end(); 28 | 29 | return g; 30 | } 31 | 32 | /** 33 | * Locates all occurences and versions of the Sublime Text program 34 | * on the user's computer and stores them into an Array List. 35 | */ 36 | public void findSublime() { 37 | 38 | locations = new ArrayList<>(); 39 | possibleLocations = new ArrayList<>(); 40 | 41 | possibleLocations.add("C:\\Program Files\\Sublime Text 3\\subl.exe"); 42 | possibleLocations.add("C:\\Program Files\\Sublime Text 2\\sublime_text.exe"); 43 | 44 | for (String loc : possibleLocations) { 45 | File file = new File(loc); 46 | if (file.exists()) locations.add(new SublimeLocation(file)); 47 | } 48 | 49 | } 50 | 51 | public SublimeLocation getLocation(int index) { 52 | return locations.get(index); 53 | } 54 | 55 | public ArrayList getLocations() { 56 | return locations; 57 | } 58 | 59 | public void addLocation(File file) { 60 | locations.add(new SublimeLocation(file)); 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/SublimeLocation.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | /** 7 | * A container that holds the location of a Sublime Text 8 | * program on the user's computer. Can create a process 9 | * and execute said program. 10 | */ 11 | public class SublimeLocation { 12 | 13 | private String name; 14 | private File file; 15 | 16 | /** 17 | * Creates a container that holds the location of a Sublime 18 | * Text program on the user's computer. 19 | * 20 | * @param file The location of the sublime executable 21 | */ 22 | public SublimeLocation(File file) { 23 | this.file = file; 24 | } 25 | 26 | /** 27 | * Loads the Sublime Text program that this container holds 28 | * and loads a specific folder or file into said program. 29 | * 30 | * @param locationToOpen Location of the folder or file to load 31 | * @return Whether or not the location was loaded successfully 32 | */ 33 | public boolean load(String locationToOpen) { 34 | 35 | System.out.println("OPENING: " + locationToOpen); 36 | 37 | try { 38 | new ProcessBuilder(file.getAbsolutePath(), locationToOpen).start(); 39 | return true; 40 | } catch (IOException e) { 41 | e.printStackTrace(); 42 | return false; 43 | } 44 | } 45 | 46 | /** 47 | * Loads the Sublime Text program that this container holds 48 | * and loads a specific folder or file into said program. 49 | * 50 | * @param p The project to load 51 | * @return Whether or not the project was loaded successfully 52 | */ 53 | public boolean load(Project p) { 54 | return load(p.getLocation().getAbsolutePath()); 55 | } 56 | 57 | public File getFile() { 58 | return file; 59 | } 60 | 61 | public String getName() { 62 | return name; 63 | } 64 | 65 | public void setName(String name) { 66 | this.name = name; 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/FileUtilities.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.nio.channels.FileChannel; 8 | 9 | public class FileUtilities { 10 | 11 | private FileUtilities() {} 12 | 13 | public static final void copy( File source, File destination ) throws IOException { 14 | if( source.isDirectory() ) { 15 | copyDirectory( source, destination ); 16 | } else { 17 | copyFile( source, destination ); 18 | } 19 | } 20 | 21 | public static final void copyDirectory( File source, File destination ) throws IOException { 22 | if( !source.isDirectory() ) { 23 | throw new IllegalArgumentException( "Source (" + source.getPath() + ") must be a directory." ); 24 | } 25 | 26 | if( !source.exists() ) { 27 | throw new IllegalArgumentException( "Source directory (" + source.getPath() + ") doesn't exist." ); 28 | } 29 | 30 | if( destination.exists() ) { 31 | throw new IllegalArgumentException( "Destination (" + destination.getPath() + ") exists." ); 32 | } 33 | 34 | destination.mkdirs(); 35 | File[] files = source.listFiles(); 36 | 37 | for( File file : files ) { 38 | if( file.isDirectory() ) { 39 | copyDirectory( file, new File( destination, file.getName() ) ); 40 | } else { 41 | copyFile( file, new File( destination, file.getName() ) ); 42 | } 43 | } 44 | } 45 | 46 | public static final void copyFile( File source, File destination ) throws IOException { 47 | FileChannel sourceChannel = new FileInputStream( source ).getChannel(); 48 | FileChannel targetChannel = new FileOutputStream( destination ).getChannel(); 49 | sourceChannel.transferTo(0, sourceChannel.size(), targetChannel); 50 | sourceChannel.close(); 51 | targetChannel.close(); 52 | } 53 | } -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/Program.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.awt.EventQueue; 4 | 5 | public class Program { 6 | 7 | private ProjectContainer projects; 8 | private SublimeContainer sublimes; 9 | private FileSystem fileSystem; 10 | 11 | public static void main(String[] args) { 12 | new Program(); 13 | } 14 | 15 | public Program() { 16 | 17 | long timeStart = System.currentTimeMillis(); 18 | 19 | System.out.println("PROGRAM: Running program"); 20 | 21 | System.out.println("PROGRAM: Creating sublime container"); 22 | 23 | sublimes = new SublimeContainer(); 24 | sublimes.findSublime(); 25 | 26 | System.out.println("PROGRAM: Creating project container"); 27 | 28 | projects = new ProjectContainer(); 29 | 30 | long timeFileSystem = System.currentTimeMillis(); 31 | 32 | System.out.println("PROGRAM: Loading file system"); 33 | 34 | fileSystem = FileSystem.createInstance(sublimes, projects); 35 | 36 | if (!fileSystem.load()) { 37 | System.err.println("Unable to load Sublime Launcher"); 38 | } 39 | 40 | System.out.println("File System done"); 41 | 42 | long timeViewLaunch = System.currentTimeMillis(); 43 | 44 | System.out.println("PROGRAM: Creating new ViewLaunch"); 45 | 46 | EventQueue.invokeLater(new Runnable() { 47 | public void run() { 48 | ViewLaunch view = new ViewLaunch(projects, sublimes, fileSystem); 49 | view.setVisible(true); 50 | } 51 | }); 52 | 53 | System.out.println("Took " + (timeFileSystem - timeStart) + " for Program -> Program Done"); 54 | System.out.println("Took " + (timeViewLaunch - timeFileSystem) + " for FileSystem -> FileSystem Done"); 55 | 56 | // for (Project project : projects) { 57 | // System.out.println(project.getLocation().toString()); 58 | // } 59 | // 60 | // for (SublimeLocation sl : sublimes.getLocations()) { 61 | // System.out.println(sl.getFile().toString()); 62 | // } 63 | 64 | //sublimes.getLocation(0).load("C:\\Users\\connorelsea\\OneDrive\\Programming"); 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io 2 | 3 | ### Eclipse ### 4 | *.pydevproject 5 | .metadata 6 | .gradle 7 | bin/ 8 | tmp/ 9 | *.tmp 10 | *.bak 11 | *.swp 12 | *~.nib 13 | local.properties 14 | .settings/ 15 | .loadpath 16 | 17 | # Eclipse Core 18 | .project 19 | 20 | # External tool builders 21 | .externalToolBuilders/ 22 | 23 | # Locally stored "Eclipse launch configurations" 24 | *.launch 25 | 26 | # CDT-specific 27 | .cproject 28 | 29 | # JDT-specific (Eclipse Java Development Tools) 30 | .classpath 31 | 32 | # PDT-specific 33 | .buildpath 34 | 35 | # sbteclipse plugin 36 | .target 37 | 38 | # TeXlipse plugin 39 | .texlipse 40 | 41 | 42 | ### Intellij ### 43 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 44 | 45 | *.iml 46 | 47 | ## Directory-based project format: 48 | .idea/ 49 | # if you remove the above rule, at least ignore the following: 50 | 51 | # User-specific stuff: 52 | # .idea/workspace.xml 53 | # .idea/tasks.xml 54 | # .idea/dictionaries 55 | 56 | # Sensitive or high-churn files: 57 | # .idea/dataSources.ids 58 | # .idea/dataSources.xml 59 | # .idea/sqlDataSources.xml 60 | # .idea/dynamic.xml 61 | # .idea/uiDesigner.xml 62 | 63 | # Gradle: 64 | # .idea/gradle.xml 65 | # .idea/libraries 66 | 67 | # Mongo Explorer plugin: 68 | # .idea/mongoSettings.xml 69 | 70 | ## File-based project format: 71 | *.ipr 72 | *.iws 73 | 74 | ## Plugin-specific files: 75 | 76 | # IntelliJ 77 | /out/ 78 | 79 | # mpeltonen/sbt-idea plugin 80 | .idea_modules/ 81 | 82 | # JIRA plugin 83 | atlassian-ide-plugin.xml 84 | 85 | # Crashlytics plugin (for Android Studio and IntelliJ) 86 | com_crashlytics_export_strings.xml 87 | crashlytics.properties 88 | crashlytics-build.properties 89 | 90 | 91 | ### NetBeans ### 92 | nbproject/private/ 93 | build/ 94 | nbbuild/ 95 | dist/ 96 | nbdist/ 97 | nbactions.xml 98 | nb-configuration.xml 99 | .nb-gradle/ 100 | 101 | 102 | ### OSX ### 103 | .DS_Store 104 | .AppleDouble 105 | .LSOverride 106 | 107 | # Icon must end with two \r 108 | Icon 109 | 110 | 111 | # Thumbnails 112 | ._* 113 | 114 | # Files that might appear in the root of a volume 115 | .DocumentRevisions-V100 116 | .fseventsd 117 | .Spotlight-V100 118 | .TemporaryItems 119 | .Trashes 120 | .VolumeIcon.icns 121 | 122 | # Directories potentially created on remote AFP share 123 | .AppleDB 124 | .AppleDesktop 125 | Network Trash Folder 126 | Temporary Items 127 | .apdisk 128 | -------------------------------------------------------------------------------- /src/com/elsea/stone/groups/Group.java: -------------------------------------------------------------------------------- 1 | package com.elsea.stone.groups; 2 | 3 | public class Group extends Element 4 | { 5 | private GroupSearch search; 6 | 7 | public Group(String name, Group parent) 8 | { 9 | super(name, null, parent); 10 | } 11 | 12 | public Group(String name) 13 | { 14 | super(name, null, null); 15 | } 16 | 17 | public Group() 18 | { 19 | super("parent", null, null); 20 | } 21 | 22 | /** 23 | * If this object is null, the most recently created 24 | * element was the group. If this object is not null, 25 | * the most recently created object is the current 26 | * group. This is used in identifying which element 27 | * to apply ID commands to. 28 | */ 29 | private Property recent; 30 | 31 | /** 32 | * Returns a Group Search object that allows the group 33 | * to be traversed and searched. 34 | * 35 | * @return A Group Search object 36 | */ 37 | public GroupSearch search() 38 | { 39 | return (search == null) ? (search = new GroupSearch(this)) : search; 40 | } 41 | 42 | /** 43 | * Creates a new group as a child of the current group and 44 | * returns the newly made child group, effectively switching 45 | * to the new child group during template creation. 46 | * 47 | * @param name The name of the group to create 48 | * @return The created group 49 | */ 50 | public Group group(String name) 51 | { 52 | Group group = new Group(name, this); 53 | recent = null; 54 | addChild(group); 55 | return group; 56 | } 57 | 58 | /** 59 | * Creates a new property with the given name and sets both the 60 | * current and default values as the same value. The current 61 | * parent group is returned. 62 | * 63 | * @param name The name of the new property 64 | * @param value The default and current value of the new property 65 | * @return The current parent group 66 | */ 67 | public Group property(String name, String value) 68 | { 69 | Property property = new Property(name, value, this); 70 | recent = property; 71 | addChild(property); 72 | return this; 73 | } 74 | 75 | /** 76 | * Sets the ID of the current group and returns the current group. 77 | * 78 | * @param id The ID of the current group. 79 | * @return The group 80 | */ 81 | public Group id(String id) 82 | { 83 | if (recent == null) setID(id); 84 | else recent.setID(id); 85 | 86 | return this; 87 | } 88 | 89 | /** 90 | * Returns the parent of this group, effectively ending 91 | * the possibility for the addition of children during 92 | * template creation. 93 | * 94 | * @return The parent of the current group 95 | */ 96 | public Group end() 97 | { 98 | // Recent isn't used after group is done 99 | recent = null; 100 | return getParent(); 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/ViewAddExisting.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.io.File; 4 | 5 | import javax.imageio.ImageIO; 6 | import javax.swing.JButton; 7 | import javax.swing.JFileChooser; 8 | import javax.swing.JFrame; 9 | import javax.swing.JLabel; 10 | import javax.swing.JPanel; 11 | import javax.swing.JSeparator; 12 | import javax.swing.JTextField; 13 | import javax.swing.UIManager; 14 | import javax.swing.filechooser.FileFilter; 15 | import javax.swing.filechooser.FileNameExtensionFilter; 16 | 17 | public class ViewAddExisting extends JFrame { 18 | 19 | private JPanel contentPane; 20 | private JTextField textName; 21 | private JTextField textLocation; 22 | private FileSystem fileSystem = FileSystem.getInstance(); 23 | private File file; 24 | private ViewAddExisting view = this; 25 | private JTextField textIcon; 26 | 27 | public ViewAddExisting(ProjectContainer projects) { 28 | 29 | try { 30 | UIManager.setLookAndFeel( 31 | UIManager.getSystemLookAndFeelClassName()); 32 | } catch (Exception ex) { 33 | ex.printStackTrace(); 34 | } 35 | 36 | setTitle("Add Existing Project"); 37 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 38 | setBounds(100, 100, 450, 217); 39 | contentPane = new JPanel(); 40 | contentPane.setBorder(null); 41 | setContentPane(contentPane); 42 | contentPane.setLayout(null); 43 | 44 | JLabel lblProjectName = new JLabel("Project Name"); 45 | lblProjectName.setBounds(10, 18, 98, 14); 46 | contentPane.add(lblProjectName); 47 | 48 | textName = new JTextField(); 49 | textName.setBounds(118, 11, 306, 28); 50 | contentPane.add(textName); 51 | textName.setColumns(10); 52 | 53 | JLabel lblProjectLocation = new JLabel("Project Location"); 54 | lblProjectLocation.setBounds(10, 57, 98, 14); 55 | contentPane.add(lblProjectLocation); 56 | 57 | textLocation = new JTextField(); 58 | textLocation.setColumns(10); 59 | textLocation.setBounds(118, 50, 190, 28); 60 | contentPane.add(textLocation); 61 | 62 | JButton btnFolder = new JButton("Choose Folder"); 63 | btnFolder.addActionListener(action -> { 64 | JFileChooser chooser = new JFileChooser(); 65 | chooser.setDialogTitle("Choose a Directory"); 66 | chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 67 | chooser.setAcceptAllFileFilterUsed(false); 68 | 69 | if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { 70 | file = chooser.getSelectedFile(); 71 | textLocation.setText(file.getAbsolutePath()); 72 | } 73 | }); 74 | btnFolder.setBounds(318, 50, 106, 28); 75 | contentPane.add(btnFolder); 76 | 77 | JSeparator separator = new JSeparator(); 78 | separator.setBounds(10, 128, 414, 2); 79 | contentPane.add(separator); 80 | 81 | JButton btnSave = new JButton("Save"); 82 | btnSave.addActionListener(action -> { 83 | 84 | boolean exists = new File(textIcon.getText()).exists(); 85 | 86 | if (textIcon.getText().trim().equals("") || !exists) { 87 | textIcon.setText("None"); 88 | } 89 | 90 | projects.add(new Project(textName.getText(), textLocation.getText(), textIcon.getText())); 91 | fileSystem.save(); 92 | view.dispose(); 93 | }); 94 | btnSave.setBounds(318, 141, 106, 28); 95 | contentPane.add(btnSave); 96 | 97 | JButton btnCancel = new JButton("Cancel"); 98 | btnCancel.addActionListener(action -> { 99 | view.dispose(); 100 | }); 101 | btnCancel.setBounds(10, 141, 106, 28); 102 | contentPane.add(btnCancel); 103 | 104 | JLabel lblProjectIcon = new JLabel("Project Icon (50px)"); 105 | lblProjectIcon.setBounds(10, 96, 98, 14); 106 | contentPane.add(lblProjectIcon); 107 | 108 | textIcon = new JTextField(); 109 | textIcon.setColumns(10); 110 | textIcon.setBounds(118, 89, 190, 28); 111 | contentPane.add(textIcon); 112 | 113 | JButton btnChooseIcon = new JButton("Choose Icon"); 114 | btnChooseIcon.addActionListener(action -> { 115 | 116 | FileFilter imageFilter = new FileNameExtensionFilter( 117 | "Image files", ImageIO.getReaderFileSuffixes()); 118 | 119 | final JFileChooser fc = new JFileChooser(); 120 | fc.addChoosableFileFilter(imageFilter); 121 | fc.setAcceptAllFileFilterUsed(false); 122 | int file = fc.showOpenDialog(view); 123 | 124 | textIcon.setText(fc.getSelectedFile().getAbsolutePath()); 125 | 126 | }); 127 | btnChooseIcon.setBounds(318, 89, 106, 28); 128 | contentPane.add(btnChooseIcon); 129 | 130 | setLocationRelativeTo(null); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/com/elsea/stone/groups/GroupSearch.java: -------------------------------------------------------------------------------- 1 | package com.elsea.stone.groups; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.function.Predicate; 6 | import java.util.stream.Collectors; 7 | 8 | public class GroupSearch { 9 | 10 | private Group group; 11 | 12 | public GroupSearch(Group group) 13 | { 14 | this.group = group; 15 | } 16 | 17 | /** 18 | * Returns the first group found with the given name. Ignores groups 19 | * with duplicate names and still returns the first group. If there 20 | * are no groups to be found with that name, null is returned. 21 | * 22 | * @param name The name of the group to find. 23 | * @return The first group with the specified name, or null 24 | */ 25 | public Group group(String name) 26 | { 27 | List list = filter(p -> p.getName().equals(name) && p instanceof Group); 28 | 29 | if (list != null && list.size() > 0) 30 | { 31 | if (list.size() > 1) 32 | System.out.println("Warning: Returning first of many groups with duplicate names"); 33 | 34 | return (Group) list.get(0); 35 | } 36 | else return null; 37 | } 38 | 39 | /** 40 | * Returns all groups with a certain name. 41 | * 42 | * @param name The name of the groups to find. 43 | * @return A list of the groups with the specified name. 44 | */ 45 | public List groups(String name) 46 | { 47 | return filter(p -> p.getName().equals(name) && p instanceof Group) 48 | .stream() 49 | .map(e -> (Group) e) 50 | .collect(Collectors.toList()); 51 | } 52 | 53 | /** 54 | * Returns the first property found with the given name. Ignores properties 55 | * with duplicate names and still returns the first property. If there are no 56 | * properties to be found with that name, null is returned. 57 | * 58 | * @param name The name of the property to find. 59 | * @return The first property with the specified name, or null 60 | */ 61 | public Property property(String name) 62 | { 63 | List list = filter(p -> p.getName().equals(name) && p instanceof Property); 64 | 65 | if (list != null && list.size() > 0) 66 | { 67 | if (list.size() > 1) 68 | System.out.println("Warning: Returning first of many groups with duplicate names"); 69 | 70 | return (Property) list.get(0); 71 | } 72 | else return null; 73 | } 74 | 75 | /** 76 | * Returns all properties with a certain name. 77 | * 78 | * @param name The name of the properties to find. 79 | * @return A list of the properties with the specified name. 80 | */ 81 | public List properties(String name) 82 | { 83 | return filter(p -> p.getName().equals(name) && p instanceof Property) 84 | .stream() 85 | .map(e -> (Property) e) 86 | .collect(Collectors.toList()); 87 | } 88 | 89 | /** 90 | * Returns the first group with the specified ID. Ignores groups with 91 | * duplicate IDs and returns the first group. If there are no groups 92 | * to be found with that ID, null is returned. 93 | * 94 | * @param id The id of the group to find. 95 | * @return The first group with the specified id, or null 96 | */ 97 | public Group groupid(String id) 98 | { 99 | List list = filter(p -> p instanceof Group && p.getid().equals(id)); 100 | 101 | if (list != null && list.size() > 0) 102 | { 103 | if (list.size() > 1) { 104 | System.out.println("Warning: IDs should not duplicate. You have multiple #" + id); 105 | System.out.println("Warning: Returning first of many groups with duplicate IDs"); 106 | } 107 | 108 | return (Group) list.get(0); 109 | } 110 | else return null; 111 | } 112 | 113 | /** 114 | * Returns the first property with the specified ID. Ignores properties with 115 | * duplicate IDs and returns the first property. If there are no properties 116 | * to be found with that ID, null is returned. 117 | * 118 | * @param id The id of the group to find. 119 | * @return The first group with the specified id, or null 120 | */ 121 | public Group propertyid(String id) 122 | { 123 | List list = filter(p -> p instanceof Property && p.getid().equals(id)); 124 | 125 | if (list != null && list.size() > 0) 126 | { 127 | if (list.size() > 1) { 128 | System.out.println("Warning: IDs should not duplicate. You have multiple #" + id); 129 | System.out.println("Warning: Returning first of many properties with duplicate IDs"); 130 | } 131 | 132 | return (Group) list.get(0); 133 | } 134 | else return null; 135 | } 136 | 137 | /** 138 | * Tests a predicate against each element under the specified group 139 | * 140 | * @param p The predicate to use 141 | * @return A list of elements that are true for the specified predicate 142 | */ 143 | public List filter(Predicate p) 144 | { 145 | return recursive_filter(new ArrayList(), p, group); 146 | } 147 | 148 | private List recursive_filter(List list, Predicate p, Element cur) 149 | { 150 | if (p.test(cur)) list.add(cur); 151 | 152 | if (cur.hasChildren()) 153 | for (Element e : cur.getChildren()) recursive_filter(list, p, e); 154 | 155 | return list; 156 | } 157 | 158 | } -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/FileSystem.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.awt.image.BufferedImage; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | import java.util.List; 9 | 10 | import javax.imageio.ImageIO; 11 | 12 | import com.elsea.stone.groups.Element; 13 | import com.elsea.stone.groups.Group; 14 | import com.elsea.stone.groups.Groups; 15 | 16 | public class FileSystem { 17 | 18 | private File programLocation; 19 | private File stoneFile; 20 | private File templateLocation; 21 | private File sublimeImage; 22 | private SublimeContainer sublimes; 23 | private ProjectContainer projects; 24 | 25 | private static FileSystem instance; 26 | 27 | public static FileSystem createInstance(SublimeContainer sublimes, ProjectContainer projects) { 28 | return instance = new FileSystem(sublimes, projects); 29 | } 30 | public static FileSystem getInstance() { 31 | return instance; 32 | } 33 | 34 | private FileSystem(SublimeContainer sublimes, ProjectContainer projects) { 35 | this.sublimes = sublimes; 36 | this.projects = projects; 37 | } 38 | 39 | public void determinePath() { 40 | 41 | String os = System.getProperty("os.name").toLowerCase(); 42 | String user = System.getProperty("user.name"); 43 | 44 | if (os.contains("win")) { 45 | 46 | programLocation = new File("C:\\Users\\" + user + "\\AppData\\Roaming\\Elsea\\SublimeLauncher"); 47 | templateLocation = new File(programLocation.getAbsolutePath() + "\\Templates"); 48 | stoneFile = new File(programLocation.getAbsolutePath() + "\\program.stone"); 49 | sublimeImage = new File(programLocation.getAbsolutePath() + File.separator + "sublime.png"); 50 | 51 | } else if (os.contains("osx") || os.contains("mac")) { 52 | 53 | programLocation = new File("/Library/Elsea/SublimeLauncher"); 54 | templateLocation = new File(programLocation.getAbsolutePath() + "/Templates"); 55 | stoneFile = new File(programLocation.getAbsolutePath() + "/program.stone"); 56 | sublimeImage = new File(programLocation.getAbsolutePath() + File.separator + "sublime.png"); 57 | 58 | } else { 59 | 60 | programLocation = new File(System.getProperty("user.dir") + "/Elsea/SublimeLauncher"); 61 | templateLocation = new File(programLocation.getAbsolutePath() + "/Templates"); 62 | stoneFile = new File(programLocation.getAbsolutePath() + "/program.stone"); 63 | sublimeImage = new File(programLocation.getAbsolutePath() + File.separator + "sublime.png"); 64 | } 65 | } 66 | 67 | public void checkFixPath() { 68 | 69 | if (!programLocation.exists()) { 70 | 71 | try { 72 | 73 | Files.createDirectories(Paths.get(programLocation.getAbsolutePath())); 74 | 75 | } catch (IOException e) { 76 | e.printStackTrace(); 77 | } 78 | 79 | } 80 | 81 | } 82 | 83 | public boolean save() { 84 | 85 | System.out.println("Saving Stone data file. Writing to disk."); 86 | 87 | Group g = new Group(); 88 | 89 | g.addChild(sublimes.generateGroup()); 90 | g.addChild(projects.generateGroup()); 91 | 92 | Groups.get().write(g).to(stoneFile); 93 | 94 | return true; 95 | } 96 | 97 | public boolean load() { 98 | 99 | long loadStart = System.currentTimeMillis(); 100 | System.out.println("Loading program file system"); 101 | 102 | determinePath(); 103 | checkFixPath(); 104 | 105 | // Dump image resource from inside jar to outside jar 106 | // Loading resource on render takes way too long. Better 107 | // to have long file load (from this) on first run than 108 | // long load during render every time. 109 | 110 | BufferedImage bi; 111 | 112 | if (!sublimeImage.exists()) { 113 | 114 | try { 115 | bi = ImageIO.read(ViewLaunch.class.getResource("/sublime.png")); 116 | ImageIO.write(bi, "png", new File(programLocation.getAbsolutePath() + File.separator + "sublime.png")); 117 | } catch (IOException e1) { 118 | e1.printStackTrace(); 119 | } 120 | 121 | } 122 | 123 | // Load projects 124 | 125 | if (stoneFile.exists()) { 126 | 127 | Group g = Groups.get().read(stoneFile); 128 | 129 | List elements = g.search().group("projects").getChildren(); 130 | 131 | 132 | for (Element e : elements) { 133 | 134 | long newProjStart = System.currentTimeMillis(); 135 | 136 | String name = e.getName(); 137 | String[] props = e.getCurrentValue().split("#<#>#"); 138 | String path = props[0]; 139 | String icon = props[1]; 140 | 141 | projects.add(new Project(name, path, icon)); 142 | 143 | long newProjEnd = System.currentTimeMillis(); 144 | 145 | System.out.println("PROJECT: \"" + name + "\" took " + (newProjEnd - newProjStart) + "ms"); 146 | } 147 | 148 | List sbls = g.search().group("sublimes").getChildren(); 149 | 150 | for (Element e : sbls) { 151 | sublimes.addLocation(new File(e.getCurrentValue())); 152 | } 153 | 154 | long loadEnd = System.currentTimeMillis(); 155 | System.out.println("Took " + (loadEnd - loadStart) + " for fileSystem.load()"); 156 | 157 | } 158 | 159 | return true; 160 | } 161 | 162 | public File getTemplateLocation() { 163 | return templateLocation; 164 | } 165 | 166 | public File getSublimeImageLocation() { 167 | return sublimeImage; 168 | } 169 | 170 | } -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/Project.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Color; 5 | import java.awt.Dimension; 6 | import java.awt.Font; 7 | import java.awt.Graphics; 8 | import java.awt.image.BufferedImage; 9 | import java.io.File; 10 | import java.io.IOException; 11 | 12 | import javax.imageio.ImageIO; 13 | import javax.swing.Box; 14 | import javax.swing.BoxLayout; 15 | import javax.swing.JLabel; 16 | import javax.swing.JPanel; 17 | 18 | public class Project { 19 | 20 | private String name; 21 | private File location; 22 | 23 | private BufferedImage bufferedIcon; 24 | private File icon; 25 | private boolean hasIcon; 26 | 27 | private JPanel panel; 28 | private JPanel panelTitle; 29 | private JPanel panelLeft; 30 | private JPanel panelIcon; 31 | private JPanel panelPadding; 32 | 33 | private boolean selected = false; 34 | 35 | private Color background = new Color(234, 241, 251); 36 | private Color selection = new Color(207, 220, 241); 37 | 38 | public Project(String name, String path, String iconPath) { 39 | 40 | this.name = name; 41 | this.location = new File(path); 42 | 43 | if (iconPath.equals("None")) { 44 | hasIcon = false; 45 | } else { 46 | hasIcon = true; 47 | icon = new File(iconPath); 48 | loadIcon(); 49 | } 50 | 51 | } 52 | 53 | public void loadIcon() { 54 | 55 | BufferedImage bi = null; 56 | 57 | try { 58 | bi = ImageIO.read(getIcon()); 59 | bufferedIcon = bi; 60 | } catch (IOException e) { 61 | e.printStackTrace(); 62 | } 63 | 64 | } 65 | 66 | public void processUIState(boolean selected) { 67 | 68 | if (this.selected != selected) { 69 | 70 | if (selected == false) { 71 | 72 | panelTitle.setBackground(background); 73 | if (!hasIcon()) panelPadding.setBackground(background); 74 | if (hasIcon()) panelIcon.setBackground(background); 75 | 76 | this.selected = false; 77 | 78 | } else { 79 | 80 | panelTitle.setBackground(selection); 81 | if (!hasIcon()) panelPadding.setBackground(selection); 82 | if (hasIcon()) panelIcon.setBackground(selection); 83 | 84 | this.selected = true; 85 | } 86 | 87 | } 88 | 89 | } 90 | 91 | public JPanel getPanel() { 92 | 93 | if (panel == null) { 94 | 95 | Dimension container = new Dimension(300, 60); 96 | Dimension padding = new Dimension(15 , 60); 97 | Color foreground = new Color(25, 50, 95); 98 | Font large = new Font("Sans Serif", Font.PLAIN, 17); 99 | 100 | // Container panel 101 | 102 | panel = new JPanel(); 103 | panel.setLayout(new BorderLayout()); 104 | panel.setBackground(background); 105 | panel.setPreferredSize(container); 106 | panel.setMinimumSize(container); 107 | panel.setMaximumSize(container); 108 | 109 | // Panel Title 110 | 111 | panelTitle = new JPanel(); 112 | panelTitle.setBackground(background); 113 | panelTitle.setLayout(new BoxLayout(panelTitle, BoxLayout.Y_AXIS)); 114 | 115 | JLabel labelName = new JLabel(getName()); 116 | JLabel labelPath = new JLabel(getLocation().getAbsolutePath()); 117 | 118 | labelName.setForeground(foreground); 119 | labelName.setFont(large); 120 | labelPath.setForeground(foreground); 121 | 122 | panelTitle.add(Box.createRigidArea(new Dimension(10, 10))); 123 | panelTitle.add(labelName); 124 | panelTitle.add(labelPath); 125 | 126 | panel.add(panelTitle, BorderLayout.CENTER); 127 | 128 | // Left Panel 129 | 130 | panelLeft = new JPanel(); 131 | panelLeft.setLayout(new BorderLayout()); 132 | 133 | // Icon Panel 134 | 135 | if (hasIcon()) { 136 | 137 | Dimension dimIcon = new Dimension(60, 60); 138 | 139 | panelIcon = new JPanel() { 140 | 141 | public void paint(Graphics g) { 142 | 143 | super.paint(g); 144 | 145 | int x = (60 / 2) - (50 / 2); 146 | int y = (60 / 2) - (50 / 2); 147 | g.drawImage(getBufferedIcon(), x, y, 50, 50, null); 148 | 149 | } 150 | 151 | }; 152 | 153 | panelIcon.setBackground(background); 154 | panelIcon.setPreferredSize(dimIcon); 155 | panelIcon.setMinimumSize(dimIcon); 156 | panelIcon.setMaximumSize(dimIcon); 157 | 158 | panelLeft.add(panelIcon, BorderLayout.CENTER); 159 | 160 | } else { 161 | 162 | // Padding Panel 163 | 164 | panelPadding = new JPanel(); 165 | panelPadding.setBackground(background); 166 | panelPadding.setPreferredSize(padding); 167 | panelPadding.setMinimumSize(padding); 168 | panelPadding.setMaximumSize(padding); 169 | 170 | panelLeft.add(panelPadding, BorderLayout.EAST); 171 | 172 | } 173 | 174 | // Adding Panel Left to Panel Container 175 | 176 | panel.add(panelLeft, BorderLayout.WEST); 177 | 178 | } 179 | 180 | return panel; 181 | } 182 | 183 | public BufferedImage getBufferedIcon() { 184 | return bufferedIcon; 185 | } 186 | 187 | public File getLocation() { 188 | return location; 189 | } 190 | 191 | public void setLocation(File location) { 192 | this.location = location; 193 | } 194 | 195 | public String getName() { 196 | return name; 197 | } 198 | 199 | public void setName(String name) { 200 | this.name = name; 201 | } 202 | 203 | public File getIcon() { 204 | return icon; 205 | } 206 | 207 | public void setIcon(File icon) { 208 | this.icon = icon; 209 | } 210 | 211 | public boolean hasIcon() { 212 | return hasIcon; 213 | } 214 | 215 | public void setHasIcon(boolean value) { 216 | this.hasIcon = value; 217 | } 218 | } -------------------------------------------------------------------------------- /src/com/elsea/stone/groups/Element.java: -------------------------------------------------------------------------------- 1 | package com.elsea.stone.groups; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Element 7 | { 8 | private Group parent; 9 | private List children; 10 | 11 | private String name; 12 | private String id; 13 | private String currentValue; 14 | private String defaultValue; 15 | 16 | private boolean changed = false; 17 | 18 | public Element(String name, String value, Group parent) 19 | { 20 | this.name = name; 21 | this.currentValue = value; 22 | this.defaultValue = value; 23 | this.parent = parent; 24 | } 25 | 26 | /** 27 | * Adds a child to an element. Ignores the addition if this method is 28 | * performed on a property element. Triggers change. 29 | * 30 | * @param element The element to be added as a child. 31 | */ 32 | public void addChild(Element element) 33 | { 34 | if (this instanceof Property) 35 | { 36 | System.out.println("Warning: Adding a child to a property is not allowed."); 37 | return; 38 | } 39 | 40 | if (children == null) children = new ArrayList<>(); 41 | children.add(element); 42 | changed = true; 43 | } 44 | 45 | public List getChildren() { return children; } 46 | 47 | /** 48 | * Displays the group and its children as a tree. Does not 49 | * show parent element. 50 | */ 51 | public void show() 52 | { 53 | print(0, 0); 54 | } 55 | 56 | /** 57 | * The lower level recursive method that allows the show 58 | * method to recurse through the children elements and 59 | * show each one with a different indentation. 60 | * 61 | * @param level The level of indentation to begin at 62 | */ 63 | protected void print(int level, int spaces) 64 | { 65 | spaces(level); 66 | 67 | if (this instanceof Group) 68 | { 69 | System.out.printf("|--> Group::%s ", name); 70 | 71 | if (id != null && !id.equalsIgnoreCase("null")) 72 | System.out.printf("#%s", id); 73 | 74 | System.out.println(); 75 | 76 | if (this.hasChildren()) 77 | { 78 | int longest = 0; 79 | 80 | // Determine longest child name to align equals operators 81 | 82 | for (Element e : children) 83 | { 84 | if (e.name.length() > longest) longest = e.name.length(); 85 | } 86 | 87 | // Print all children 88 | 89 | for (Element e : children) { 90 | e.print(level + 1, longest); 91 | } 92 | } 93 | } 94 | else 95 | { 96 | System.out.printf("|> Property::%s", name); 97 | 98 | int width = spaces - this.getName().length(); 99 | 100 | if (id != null && !id.equalsIgnoreCase("null")) 101 | System.out.printf("#%s", id); 102 | 103 | // Print calculated spaces to align equals operators 104 | for (int i = 0; i < width; i++) System.out.print(" "); 105 | 106 | System.out.printf(" = \"%s\" \n", currentValue, defaultValue); 107 | 108 | 109 | } 110 | 111 | } 112 | 113 | private void spaces(int level) 114 | { 115 | for (int i = 0; i < level ; i++) System.out.print(" "); 116 | } 117 | 118 | /** 119 | * Indicates whether or not this item has been changed. An item 120 | * is considered changed when the contents stored in the object 121 | * do not match the records stored on the disk. 122 | * 123 | * @return 124 | */ 125 | public boolean isChanged() { return changed; } 126 | 127 | /** 128 | * Changes the parent of this element. Triggers change. 129 | * 130 | * @param parent The new parent of this element 131 | */ 132 | protected void setParent(Group parent) { 133 | this.parent = parent; 134 | changed = true; 135 | } 136 | 137 | public Group getParent() { return parent; } 138 | 139 | /** 140 | * Changes the name of this element. Triggers change. 141 | * 142 | * @param name The new name of this element 143 | */ 144 | public Element name(String name) { 145 | this.name = name; 146 | changed = true; 147 | return this; 148 | } 149 | 150 | public String getName() { return name; } 151 | 152 | /** 153 | * Changes the id of this element. Triggers change. 154 | * 155 | * @param id The new id of this element 156 | */ 157 | protected Element setID(String id) { 158 | this.id = id; 159 | changed = true; 160 | return this; 161 | } 162 | 163 | public String getid() { return id; } 164 | 165 | /** 166 | * Changes the current value of the element and triggers a change, 167 | * but only if the element is a property element. 168 | * 169 | * @param value The new current value of this element 170 | */ 171 | protected Element currentValue(String value) 172 | { 173 | if (this instanceof Group) 174 | { 175 | System.out.println("Warning: Setting the value of a group not allowed"); 176 | return (Group) this; 177 | } 178 | 179 | this.currentValue = value; 180 | changed = true; 181 | return (Property) this; 182 | } 183 | 184 | public String getCurrentValue() { return currentValue; } 185 | 186 | /** 187 | * Changes the default value of the element and triggers a change, 188 | * but only if the element is a property element. 189 | * 190 | * @param value The new default value of this element 191 | */ 192 | protected Element defaultValue(String value) 193 | { 194 | if (this instanceof Group) 195 | { 196 | System.out.println("Warning: Setting the value of a group not allowed"); 197 | return (Group) this; 198 | } 199 | 200 | this.defaultValue = value; 201 | changed = true; 202 | return (Property) this; 203 | } 204 | 205 | public String getDefaultValue() { return defaultValue; } 206 | 207 | public boolean hasChildren() 208 | { 209 | if (children != null && children.size() > 0) return true; 210 | else return false; 211 | } 212 | } -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/ViewLaunch.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.EventQueue; 5 | 6 | import javax.imageio.ImageIO; 7 | import javax.swing.ImageIcon; 8 | import javax.swing.JFrame; 9 | import javax.swing.JList; 10 | import javax.swing.JPanel; 11 | import javax.swing.JScrollPane; 12 | import javax.swing.UIManager; 13 | import java.awt.Color; 14 | import java.awt.Dimension; 15 | 16 | import java.io.IOException; 17 | import javax.swing.JLabel; 18 | import javax.swing.Box; 19 | import javax.swing.BoxLayout; 20 | import javax.swing.JButton; 21 | import java.awt.Component; 22 | import java.awt.event.MouseAdapter; 23 | import java.awt.event.MouseEvent; 24 | 25 | public class ViewLaunch extends JFrame { 26 | private static final long serialVersionUID = 1L; 27 | 28 | private ViewLaunch view = this; 29 | private JLabel lblIcon; 30 | 31 | private JPanel contentPane; 32 | 33 | private Dimension mainDim = new Dimension(300, 300); 34 | private Dimension button = new Dimension(220, 30); 35 | private Color background = new Color(247, 247, 247); 36 | 37 | public ViewLaunch(ProjectContainer projects, SublimeContainer sublimes, FileSystem fileSystem) { 38 | 39 | long timeViewLaunch = System.currentTimeMillis(); 40 | 41 | try { 42 | UIManager.setLookAndFeel( 43 | UIManager.getSystemLookAndFeelClassName()); 44 | } catch (Exception ex) { 45 | ex.printStackTrace(); 46 | } 47 | 48 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 49 | setBounds(100, 100, 735, 433); 50 | contentPane = new JPanel(); 51 | contentPane.setBorder(null); 52 | contentPane.setLayout(new BorderLayout()); 53 | setContentPane(contentPane); 54 | 55 | JPanel panelProjects = new JPanel(); 56 | panelProjects.setLayout(new BorderLayout()); 57 | panelProjects.setBackground(Color.WHITE); 58 | contentPane.add(panelProjects, BorderLayout.WEST); 59 | 60 | JList list = new JList(projects.getModel()); 61 | list.setPreferredSize(mainDim); 62 | list.setMinimumSize(mainDim); 63 | list.setMaximumSize(mainDim); 64 | list.setCellRenderer(new FileListCellRenderer()); 65 | list.setBackground(Color.WHITE); 66 | 67 | list.addMouseListener(new MouseAdapter() { 68 | 69 | public void mouseClicked(MouseEvent e) { 70 | 71 | @SuppressWarnings("unchecked") 72 | JList source = (JList) e.getSource(); 73 | 74 | // Launch project on double click 75 | if (e.getClickCount() == 2) { 76 | int index = list.locationToIndex(e.getPoint()); 77 | Project p = source.getModel().getElementAt(index); 78 | sublimes.getLocation(0).load(p); 79 | view.dispose(); 80 | } 81 | 82 | } 83 | 84 | }); 85 | 86 | JScrollPane scrollPane = new JScrollPane(); 87 | scrollPane.setPreferredSize(mainDim); 88 | scrollPane.setMinimumSize(mainDim); 89 | scrollPane.setMaximumSize(mainDim); 90 | scrollPane.setBorder(null); 91 | scrollPane.setViewportView(list); 92 | 93 | panelProjects.add(scrollPane, BorderLayout.CENTER); 94 | 95 | JPanel panelRightBorder = new JPanel(); 96 | panelRightBorder.setBackground(new Color(236, 236, 236)); 97 | panelRightBorder.setPreferredSize(new Dimension(1, 1)); 98 | panelProjects.add(panelRightBorder, BorderLayout.EAST); 99 | 100 | JPanel panelContainer = new JPanel(); 101 | panelContainer.setBackground(background); 102 | contentPane.add(panelContainer, BorderLayout.CENTER); 103 | 104 | JPanel panelMain = new JPanel(); 105 | panelContainer.add(panelMain); 106 | panelMain.setBackground(background); 107 | panelMain.setLayout(new BoxLayout(panelMain, BoxLayout.Y_AXIS)); 108 | 109 | Component rigidArea_2 = Box.createRigidArea(new Dimension(10, 25)); 110 | panelMain.add(rigidArea_2); 111 | 112 | JPanel panelActionContainer = new JPanel(); 113 | panelActionContainer.setBackground(background); 114 | panelMain.add(panelActionContainer); 115 | panelActionContainer.setLayout(new BorderLayout(0, 0)); 116 | 117 | JPanel panelLogo = new JPanel(); 118 | panelLogo.setBackground(background); 119 | panelActionContainer.add(panelLogo, BorderLayout.NORTH); 120 | 121 | JPanel panelButtons = new JPanel(); 122 | panelButtons.setBackground(background); 123 | panelActionContainer.add(panelButtons); 124 | panelButtons.setLayout(new BoxLayout(panelButtons, BoxLayout.Y_AXIS)); 125 | 126 | Component rigidArea = Box.createRigidArea(new Dimension(10, 10)); 127 | panelButtons.add(rigidArea); 128 | 129 | JButton btn_new = new JButton("Create New Project"); 130 | btn_new.addActionListener(action -> { 131 | 132 | EventQueue.invokeLater(new Runnable() { 133 | @Override 134 | public void run() { 135 | ViewAddNew van = new ViewAddNew(projects); 136 | van.setVisible(true); 137 | } 138 | }); 139 | 140 | }); 141 | panelButtons.add(btn_new); 142 | btn_new.setPreferredSize(button); 143 | btn_new.setMinimumSize(button); 144 | btn_new.setMaximumSize(button); 145 | 146 | Component rigidArea_1 = Box.createRigidArea(new Dimension(10, 10)); 147 | panelButtons.add(rigidArea_1); 148 | 149 | JButton btn_existing = new JButton("Add Existing Project"); 150 | btn_existing.addActionListener(action -> { 151 | 152 | EventQueue.invokeLater(new Runnable() { 153 | @Override 154 | public void run() { 155 | ViewAddExisting vae = new ViewAddExisting(projects); 156 | vae.setVisible(true); 157 | } 158 | }); 159 | 160 | }); 161 | panelButtons.add(btn_existing); 162 | btn_existing.setPreferredSize(button); 163 | btn_existing.setMinimumSize(button); 164 | btn_existing.setMaximumSize(button); 165 | 166 | setLocationRelativeTo(null); 167 | 168 | lblIcon = new JLabel(); 169 | panelLogo.add(lblIcon); 170 | 171 | new Thread(new Runnable() { 172 | 173 | @Override 174 | public void run() { 175 | 176 | long imageLoadStart = System.currentTimeMillis(); 177 | 178 | try { 179 | 180 | //ImageIcon image = new ImageIcon(ImageIO.read(ViewLaunch.class.getResource("/sublime.png"))); 181 | ImageIcon image = new ImageIcon(ImageIO.read(fileSystem.getSublimeImageLocation())); 182 | 183 | EventQueue.invokeLater(new Runnable() { 184 | 185 | public void run() { 186 | lblIcon.setIcon(image); 187 | lblIcon.repaint(); 188 | setIconImage(image.getImage()); 189 | } 190 | 191 | }); 192 | 193 | } catch (IOException e) { 194 | e.printStackTrace(); 195 | } 196 | 197 | long imageLoadEnd = System.currentTimeMillis(); 198 | 199 | System.out.println("IMAGE LOAD: " + (imageLoadEnd - imageLoadStart) + "ms"); 200 | 201 | } 202 | }).start(); 203 | 204 | long timeAfterViewLaunch = System.currentTimeMillis(); 205 | System.out.println("Took " + (timeAfterViewLaunch - timeViewLaunch) + " for ViewLaunch -> ViewLaunch Done"); 206 | } 207 | 208 | } -------------------------------------------------------------------------------- /src/com/elsea/sublimelauncher/ViewAddNew.java: -------------------------------------------------------------------------------- 1 | package com.elsea.sublimelauncher; 2 | 3 | import java.awt.EventQueue; 4 | import java.io.File; 5 | import java.nio.file.Files; 6 | import java.nio.file.Paths; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | 10 | import javax.swing.JButton; 11 | import javax.swing.JFileChooser; 12 | import javax.swing.JFrame; 13 | import javax.swing.JLabel; 14 | import javax.swing.JPanel; 15 | import javax.swing.JSeparator; 16 | import javax.swing.JTextField; 17 | import javax.swing.UIManager; 18 | import javax.swing.filechooser.FileFilter; 19 | import javax.swing.filechooser.FileNameExtensionFilter; 20 | import javax.swing.JComboBox; 21 | import javax.swing.JDialog; 22 | import javax.imageio.ImageIO; 23 | import javax.swing.DefaultComboBoxModel; 24 | 25 | public class ViewAddNew extends JFrame { 26 | 27 | private JPanel contentPane; 28 | private JTextField textName; 29 | private JTextField textLocation; 30 | private JComboBox comboBox; 31 | private FileSystem fileSystem = FileSystem.getInstance(); 32 | private File file; 33 | private ViewAddNew view = this; 34 | private JTextField textIcon; 35 | 36 | public ViewAddNew(ProjectContainer projects) { 37 | 38 | // Load template information and create the 39 | // JComboBox model 40 | 41 | File templates = fileSystem.getTemplateLocation(); 42 | 43 | ArrayList children = new ArrayList<>(); 44 | 45 | // If the user has templates, catalog them 46 | if (templates.list() != null) { 47 | 48 | for (String s : templates.list()) { 49 | children.add(s); 50 | } 51 | 52 | } 53 | 54 | DefaultComboBoxModel model = new DefaultComboBoxModel<>(); 55 | ArrayList