├── .gitignore
├── .idea
├── .gitignore
├── artifacts
│ └── CodeLite_jar.xml
├── encodings.xml
├── misc.xml
├── uiDesigner.xml
└── vcs.xml
├── README.md
├── pom.xml
└── src
└── main
├── java
├── App.java
├── CustomNode.java
├── EditorView.java
├── ProjectView.java
└── WelcomeView.java
└── resources
├── META-INF
└── MANIFEST.MF
├── icons
├── folder_icon.png
└── folder_icon_24.png
└── themes
├── blue.xml
├── eclipse.xml
├── monokai.xml
├── night.xml
├── purple.xml
└── red.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/artifacts/CodeLite_jar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | $PROJECT_DIR$/out/artifacts/CodeLite_jar
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CodeLite
2 |
3 | A minimalistic code editor built using Java swing, flatlaf and RSyntaxTextArea.
4 | This project is meant for learning and experimental purposes, by no means this is a production-ready code editor, but rather a fun attempt to learn and create my own code editor
5 |
6 | 
7 |
8 | # Features
9 | * Syntax highlighting
10 | * Auto save
11 | * adding, deleting or renaming files
12 | * open native terminal
13 | * language support for Java, python, C, C++ and Javascript (more to be added soon)
14 | * Dark and light theme
15 | * various color schemes, including Monokai and Eclipse themes.
16 |
17 | # Snapshots
18 |
19 | 
20 |
21 | 
22 |
23 | 
24 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | CodeLite
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 21
13 | 21
14 | UTF-8
15 |
16 |
17 |
18 |
19 | com.formdev
20 | flatlaf
21 | 3.5.1
22 |
23 |
24 | com.formdev
25 | flatlaf-extras
26 | 3.5.1
27 |
28 |
29 | com.formdev
30 | flatlaf-fonts-jetbrains-mono
31 | 2.304
32 |
33 |
34 | com.fifesoft
35 | rsyntaxtextarea
36 | 3.5.1
37 |
38 |
39 | com.formdev
40 | flatlaf-fonts-inter
41 | 4.0
42 |
43 |
44 | com.fifesoft
45 | autocomplete
46 | 3.3.1
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/main/java/App.java:
--------------------------------------------------------------------------------
1 |
2 | import com.formdev.flatlaf.fonts.inter.FlatInterFont;
3 | import com.formdev.flatlaf.fonts.jetbrains_mono.FlatJetBrainsMonoFont;
4 | import com.formdev.flatlaf.themes.FlatMacDarkLaf;
5 | import com.formdev.flatlaf.themes.FlatMacLightLaf;
6 | import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
7 |
8 | import javax.swing.*;
9 | import java.awt.*;
10 | import java.io.File;
11 | import java.io.IOException;
12 |
13 | public class App extends JFrame {
14 |
15 | public WelcomeView welcomeView;
16 | public JSplitPane rootPanel;
17 | public ProjectView projectView;
18 | public EditorView editorView;
19 |
20 | public JPanel rightSplitPanel;
21 | public JPanel toolPanel;
22 |
23 | public JButton openTerminalButton;
24 | public JButton saveFileButton;
25 |
26 | public String os = System.getProperty("os.name").toLowerCase();
27 | public String currentFileParentPath;
28 | public ProcessBuilder pb;
29 |
30 | public JMenuBar menuBar;
31 | public JMenu settingsMenu, themeItem, colorSchemeItem, languageItem;
32 | public JMenuItem closeProjectItem, newProjectItem,
33 | darkThemeItem, lightThemeItem,
34 | monokaiItem, eclipseItem, nightItem, redItem, blueItem, purpleItem,
35 | javaItem, pythonItem, cItem, jsItem,
36 | autoSaveItem, projectViewItem,
37 | exitItem;
38 |
39 | public boolean autoSave = false;
40 | public boolean projectViewEnabled = true;
41 | public Timer autoSaveTimer;
42 |
43 | public boolean darkTheme = true;
44 | public Font editorFont;
45 |
46 | public App() {
47 | setSize(800, 500);
48 | setTitle("CodeLite");
49 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
50 | setLayout(new BorderLayout());
51 | setLocationRelativeTo(null);
52 | }
53 |
54 | public void init() {
55 | editorFont = new Font(FlatJetBrainsMonoFont.FAMILY, Font.PLAIN, 18);
56 |
57 | welcomeView = new WelcomeView(this);
58 |
59 | projectView = new ProjectView(this);
60 | projectView.setMinimumSize(new Dimension(200, 0));
61 | projectView.init();
62 | projectView.initActionListeners();
63 |
64 | editorView = new EditorView(this);
65 |
66 | rightSplitPanel = new JPanel();
67 |
68 | toolPanel = new JPanel();
69 | rootPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, projectView, rightSplitPanel);
70 |
71 | rightSplitPanel.setLayout(new BorderLayout());
72 | toolPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
73 |
74 | rightSplitPanel.add(editorView.getContentPanel(), BorderLayout.CENTER);
75 | rightSplitPanel.add(toolPanel, BorderLayout.NORTH);
76 |
77 | saveFileButton = new JButton("Save");
78 | saveFileButton.setEnabled(false);
79 | saveFileButton.setFont(new Font(FlatJetBrainsMonoFont.FAMILY, Font.PLAIN, 14));
80 | saveFileButton.setBackground(new Color(67, 175, 21));
81 | saveFileButton.addActionListener(e -> projectView.saveFile());
82 |
83 |
84 | currentFileParentPath = projectView.projectPath;
85 |
86 | openTerminalButton = new JButton("Open Terminal");
87 | openTerminalButton.setFont(new Font(FlatJetBrainsMonoFont.FAMILY, Font.PLAIN, 14));
88 | openTerminalButton.setBackground(new Color(30, 126, 248));
89 | openTerminalButton.addActionListener(e -> {
90 | try {
91 |
92 | if (os.contains("win")) {
93 | pb = new ProcessBuilder("cmd" , "/c" , "start" , "powershell.exe");
94 | } else if (os.contains("mac")) {
95 | pb = new ProcessBuilder("open", "-a", "Terminal");
96 | } else if (os.contains("nix") || os.contains("nux") || os.contains("bsd")) {
97 | pb = new ProcessBuilder("x-terminal-emulator");
98 | } else
99 | JOptionPane.showMessageDialog(null, "Unsupported Operating System", "Error", JOptionPane.ERROR_MESSAGE);
100 |
101 |
102 | if (!projectView.getSelectedCustomNode().getParent().isLeaf()) {
103 | pb.directory(new File(projectView.projectPath));
104 | } else {
105 | pb.directory(new File(currentFileParentPath));
106 | }
107 | pb.start();
108 |
109 | } catch (IOException ex) {
110 | System.err.println("Failed to open terminal: " + ex.getMessage());
111 | } catch (UnsupportedOperationException ex) {
112 | System.err.println(ex.getMessage());
113 | } catch (NullPointerException ex) {
114 | JOptionPane.showMessageDialog(null, "Select a file to open the terminal", "Error", JOptionPane.ERROR_MESSAGE);
115 | }
116 | });
117 |
118 | menuBar = new JMenuBar();
119 | settingsMenu = new JMenu("Settings", true);
120 |
121 | newProjectItem = new JMenuItem("Open new Project");
122 | closeProjectItem = new JMenuItem("Close project");
123 |
124 | themeItem = new JMenu("Theme");
125 | darkThemeItem = new JMenuItem("Dark");
126 | lightThemeItem = new JMenuItem("Light");
127 |
128 | colorSchemeItem = new JMenu("Color scheme");
129 | monokaiItem = new JMenuItem("Monokai");
130 | eclipseItem = new JMenuItem("Eclipse");
131 | nightItem = new JMenuItem("Night");
132 | redItem = new JMenuItem("Reversal Red");
133 | blueItem = new JMenuItem("Amplified Blue");
134 | purpleItem = new JMenuItem("Hollow Purple");
135 |
136 | languageItem = new JMenu("Language support");
137 | javaItem = new JMenuItem("Java");
138 | pythonItem = new JMenuItem("Python");
139 | cItem = new JMenuItem("C/C++");
140 | jsItem = new JMenuItem("Javascript");
141 |
142 | autoSaveItem = new JMenuItem("Auto save : Off");
143 | projectViewItem = new JMenuItem("Project view : Enabled");
144 | exitItem = new JMenuItem("Exit CodeLite");
145 |
146 | newProjectItem.addActionListener(e -> {
147 | projectView.getProjectTree().removeAll();
148 | projectView.root.removeAllChildren();
149 | projectView.openProject();
150 | });
151 |
152 | closeProjectItem.addActionListener(e -> {
153 | projectView.getProjectTree().removeAll();
154 | projectView.root.removeAllChildren();
155 | projectView.projectFiles.clear();
156 |
157 | setContentPane(welcomeView);
158 | this.setSize(800, 500);
159 | this.setLocationRelativeTo(null);
160 | });
161 |
162 | darkThemeItem.addActionListener(e -> {
163 | try {
164 | darkTheme = true;
165 | UIManager.setLookAndFeel(new FlatMacDarkLaf());
166 | welcomeView.openProjectButton.setBackground(new Color(20, 125, 241));
167 |
168 | SwingUtilities.updateComponentTreeUI(this);
169 | editorView.setFont(editorFont);
170 | projectView.refreshTree();
171 | } catch (UnsupportedLookAndFeelException ex) {
172 | throw new RuntimeException(ex);
173 | }
174 | });
175 |
176 | lightThemeItem.addActionListener(e -> {
177 | try {
178 | darkTheme = false;
179 | UIManager.setLookAndFeel(new FlatMacLightLaf());
180 | welcomeView.openProjectButton.setBackground(new Color(12, 182, 41));
181 | SwingUtilities.updateComponentTreeUI(this);
182 | editorView.setFont(editorFont);
183 | projectView.refreshTree();
184 | } catch (UnsupportedLookAndFeelException ex) {
185 | throw new RuntimeException(ex);
186 | }
187 | });
188 |
189 | monokaiItem.addActionListener(e -> editorView.setColorScheme("Monokai"));
190 | eclipseItem.addActionListener(e -> editorView.setColorScheme("Eclipse"));
191 | nightItem.addActionListener(e -> editorView.setColorScheme("Night"));
192 | redItem.addActionListener(e -> editorView.setColorScheme("Red"));
193 | blueItem.addActionListener(e -> editorView.setColorScheme("Blue"));
194 | purpleItem.addActionListener(e -> editorView.setColorScheme("Purple"));
195 | javaItem.addActionListener(e -> editorView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA));
196 | pythonItem.addActionListener(e -> editorView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_PYTHON));
197 | cItem.addActionListener(e -> editorView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_C));
198 | jsItem.addActionListener(e -> editorView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT));
199 | autoSaveItem.addActionListener(e -> {
200 | if (autoSave) {
201 | autoSave = false;
202 | autoSaveItem.setText("Auto save : Off");
203 | saveFileButton.setVisible(true);
204 | autoSaveTimer.stop();
205 | }
206 | else {
207 | autoSave = true;
208 | autoSaveItem.setText("Auto save : On");
209 | saveFileButton.setVisible(false);
210 | autoSaveTimer.start();
211 | }
212 | });
213 | projectViewItem.addActionListener(e -> {
214 | if (projectViewEnabled) {
215 | projectViewEnabled = false;
216 | projectView.setVisible(false);
217 | rootPanel.setDividerLocation(0);
218 | projectViewItem.setText("Project view : Disabled");
219 | } else {
220 | projectViewEnabled = true;
221 | projectView.setVisible(true);
222 |
223 | rootPanel.setDividerLocation(200);
224 | projectViewItem.setText("Project view : Enabled");
225 |
226 | revalidate();
227 | repaint();
228 | }
229 | });
230 | exitItem.addActionListener(e -> System.exit(0));
231 | }
232 | public void addComponent() {
233 | projectView.addComponent();
234 |
235 | menuBar.add(settingsMenu);
236 | settingsMenu.add(newProjectItem);
237 | settingsMenu.add(closeProjectItem);
238 |
239 | settingsMenu.addSeparator();
240 | settingsMenu.add(themeItem);
241 | settingsMenu.add(colorSchemeItem);
242 | settingsMenu.addSeparator();
243 | settingsMenu.add(languageItem);
244 | settingsMenu.add(autoSaveItem);
245 | settingsMenu.add(projectViewItem);
246 | settingsMenu.addSeparator();
247 |
248 | themeItem.add(darkThemeItem);
249 | themeItem.add(lightThemeItem);
250 |
251 | colorSchemeItem.add(monokaiItem);
252 | colorSchemeItem.add(eclipseItem);
253 | colorSchemeItem.add(nightItem);
254 | colorSchemeItem.add(redItem);
255 | colorSchemeItem.add(blueItem);
256 | colorSchemeItem.add(purpleItem);
257 |
258 | languageItem.add(javaItem);
259 | languageItem.add(pythonItem);
260 | languageItem.add(cItem);
261 | languageItem.add(jsItem);
262 |
263 | settingsMenu.add(exitItem);
264 |
265 | toolPanel.add(openTerminalButton);
266 | toolPanel.add(saveFileButton);
267 |
268 | this.add(rootPanel, BorderLayout.CENTER);
269 | this.add(welcomeView);
270 | setJMenuBar(menuBar);
271 |
272 | revalidate();
273 | repaint();
274 |
275 | setVisible(true);
276 | }
277 |
278 | public void launch() {
279 | setContentPane(rootPanel);
280 |
281 | this.setExtendedState(MAXIMIZED_BOTH);
282 | editorView.setColorScheme("Monokai");
283 | }
284 |
285 | public static void main(String[] args){
286 | FlatMacDarkLaf.setup();
287 | FlatJetBrainsMonoFont.install();
288 | FlatInterFont.install();
289 |
290 | UIManager.put("defaultFont", new Font(FlatInterFont.FAMILY, Font.PLAIN, 13));
291 |
292 | SwingUtilities.invokeLater(() -> {
293 |
294 | App app = new App();
295 | app.init();
296 | app.addComponent();
297 | });
298 | }
299 |
300 |
301 | }
302 |
--------------------------------------------------------------------------------
/src/main/java/CustomNode.java:
--------------------------------------------------------------------------------
1 | import javax.swing.tree.DefaultMutableTreeNode;
2 |
3 | public class CustomNode extends DefaultMutableTreeNode{
4 |
5 | private String nodeName, content, path;
6 | public boolean isDirectory;
7 |
8 | public CustomNode(String name, String content, String path) {
9 | super(name);
10 | this.nodeName = name;
11 | this.content = content;
12 | this.path = path;
13 | }
14 |
15 | public String getNodeName() {
16 | return nodeName;
17 | }
18 |
19 | public String getContent() {
20 | return content;
21 | }
22 |
23 | public String getFilePath() {
24 | return path;
25 | }
26 |
27 | public void setFilePath(String newPath) {
28 | this.path = newPath;
29 | }
30 |
31 | public void setContent(String newContent){
32 | content = newContent;
33 | }
34 |
35 | public void setNodeName(String newName) {
36 | this.nodeName = newName;
37 | this.setUserObject(newName);
38 | }
39 |
40 |
41 |
42 | }
--------------------------------------------------------------------------------
/src/main/java/EditorView.java:
--------------------------------------------------------------------------------
1 | import com.formdev.flatlaf.fonts.jetbrains_mono.FlatJetBrainsMonoFont;
2 | import org.fife.ui.rsyntaxtextarea.*;
3 | import org.fife.ui.rtextarea.RTextScrollPane;
4 |
5 | import javax.swing.*;
6 | import java.awt.*;
7 | import java.awt.event.*;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 |
11 |
12 | public class EditorView extends RSyntaxTextArea implements KeyListener{
13 |
14 | private final RTextScrollPane editorScrollPane;
15 |
16 | InputStream monokaiStream, eclipseStream, nightStream, redStream, blueStream, purpleStream;
17 | Theme monokaiTheme, eclipseTheme, nightTheme, redTheme, blueTheme, purpleTheme;
18 | private final App app;
19 |
20 | public EditorView(App app) {
21 | super();
22 | this.app = app;
23 | this.addKeyListener(this);
24 |
25 | monokaiStream = EditorView.class.getResourceAsStream("/themes/monokai.xml");
26 | eclipseStream = EditorView.class.getResourceAsStream("/themes/eclipse.xml");
27 | nightStream = EditorView.class.getResourceAsStream("/themes/night.xml");
28 | redStream = EditorView.class.getResourceAsStream("/themes/red.xml");
29 | blueStream = EditorView.class.getResourceAsStream("/themes/blue.xml");
30 | purpleStream = EditorView.class.getResourceAsStream("/themes/purple.xml");
31 |
32 | try {
33 | monokaiTheme = Theme.load(monokaiStream);
34 | eclipseTheme = Theme.load(eclipseStream);
35 | nightTheme = Theme.load(nightStream);
36 | redTheme = Theme.load(redStream);
37 | blueTheme = Theme.load(blueStream);
38 | purpleTheme = Theme.load(purpleStream);
39 | } catch (IOException e) {
40 | throw new RuntimeException(e);
41 | }
42 |
43 | this.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
44 | this.setCodeFoldingEnabled(true);
45 | this.setRoundedSelectionEdges(true);
46 |
47 | editorScrollPane = new RTextScrollPane(this);
48 | }
49 |
50 | public void setColorScheme(String colorScheme) {
51 | switch (colorScheme) {
52 | case "Monokai" : monokaiTheme.apply(this);
53 | break;
54 | case "Eclipse" : eclipseTheme.apply(this);
55 | break;
56 | case "Night" : nightTheme.apply(this);
57 | break;
58 | case "Red" : redTheme.apply(this);
59 | break;
60 | case "Blue" : blueTheme.apply(this);
61 | break;
62 | case "Purple" : purpleTheme.apply(this);
63 | break;
64 | }
65 | this.setFont(app.editorFont);
66 | }
67 |
68 |
69 | public JScrollPane getContentPanel() {
70 | return editorScrollPane;
71 | }
72 |
73 | private int fontSize = 12;
74 | private static final int MIN_FONT_SIZE = 8;
75 | private static final int MAX_FONT_SIZE = 72;
76 |
77 | @Override
78 | public void keyTyped(KeyEvent e) {}
79 |
80 | @Override
81 | public void keyPressed(KeyEvent e) {
82 | if (e.isControlDown()) {
83 | if (e.getKeyCode() == KeyEvent.VK_PLUS || e.getKeyCode() == KeyEvent.VK_EQUALS) {
84 | if (fontSize < MAX_FONT_SIZE) {
85 | fontSize++;
86 | }
87 | } else if (e.getKeyCode() == KeyEvent.VK_MINUS) {
88 | if (fontSize > MIN_FONT_SIZE) {
89 | fontSize--;
90 | }
91 | }
92 | this.setFont(new Font(FlatJetBrainsMonoFont.FAMILY, Font.PLAIN, fontSize));
93 | }
94 | }
95 |
96 | @Override
97 | public void keyReleased(KeyEvent e) {}
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/ProjectView.java:
--------------------------------------------------------------------------------
1 | import com.formdev.flatlaf.fonts.inter.FlatInterFont;
2 |
3 | import javax.swing.*;
4 | import javax.swing.tree.DefaultMutableTreeNode;
5 | import javax.swing.tree.DefaultTreeCellRenderer;
6 | import javax.swing.tree.DefaultTreeModel;
7 | import java.awt.*;
8 | import java.awt.event.MouseAdapter;
9 | import java.awt.event.MouseEvent;
10 | import java.io.File;
11 | import java.io.FileNotFoundException;
12 | import java.io.FileWriter;
13 | import java.io.IOException;
14 | import java.util.ArrayList;
15 | import java.util.Objects;
16 | import java.util.Scanner;
17 |
18 | public class ProjectView extends JPanel {
19 |
20 | private final App app;
21 |
22 | public CustomNode root;
23 | private JTree projectTree;
24 | private JScrollPane projectScrollPane;
25 | public String directoryPath;
26 |
27 | public ArrayList projectFiles = new ArrayList<>();
28 | public String projectPath = null;
29 |
30 | private static Icon folderIcon;
31 |
32 | private JPopupMenu popupMenu;
33 |
34 | public ProjectView(App app) {
35 | this.app = app;
36 | this.setPreferredSize(new Dimension(300, 1200));
37 |
38 | setLayout(new BorderLayout());
39 | }
40 |
41 | public void init() {
42 | root = new CustomNode("Project", null, projectPath);
43 | projectTree = new JTree(root);
44 | projectTree.setFont(new Font(FlatInterFont.FAMILY, Font.PLAIN, 16));
45 | projectScrollPane = new JScrollPane(projectTree);
46 |
47 | folderIcon = new ImageIcon(Objects.requireNonNull
48 | (ProjectView.class.getResource("/icons/folder_icon_24.png")));
49 | refreshTree();
50 | createPopupMenu();
51 | }
52 |
53 | public void initActionListeners() {
54 | projectTree.addMouseListener(new MouseAdapter() {
55 | @Override
56 | public void mouseClicked(MouseEvent e) {
57 | super.mouseClicked(e);
58 | try {
59 | CustomNode node = (CustomNode) projectTree.getLastSelectedPathComponent();
60 | if (!node.isDirectory) {
61 | setEditorContent(app.editorView, node);
62 | app.saveFileButton.setEnabled(true);
63 | CustomNode parentNode = (CustomNode) node.getParent();
64 | app.currentFileParentPath = parentNode.getFilePath();
65 |
66 | } else {
67 | app.saveFileButton.setEnabled(false);
68 | }
69 | } catch (NullPointerException pointerException) {
70 | System.out.println("No File Selected");
71 | } catch (ClassCastException classCastException) {
72 | System.out.println("Exception");
73 | }
74 | }
75 | @Override
76 | public void mouseReleased(MouseEvent e) {
77 | if (e.isPopupTrigger()) {
78 | int row = projectTree.getClosestRowForLocation(e.getX(), e.getY());
79 | projectTree.setSelectionRow(row);
80 | popupMenu.show(e.getComponent(), e.getX(), e.getY());
81 | }
82 | }
83 |
84 | });
85 |
86 | }
87 |
88 | public void setEditorContent(EditorView editorView, CustomNode node) {
89 | editorView.setText(node.getContent());
90 | app.setTitle("CodeLite - " + node.getNodeName());
91 | }
92 |
93 | public void addComponent() {
94 | this.add(projectScrollPane, BorderLayout.CENTER);
95 | }
96 |
97 | public void openProject() {
98 | JFileChooser chooser = new JFileChooser();
99 | chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
100 |
101 | int result = chooser.showOpenDialog(null);
102 | File file = chooser.getSelectedFile();
103 | directoryPath = file.getAbsolutePath();
104 |
105 | if (result == JFileChooser.APPROVE_OPTION) {
106 | projectPath = file.getAbsolutePath();
107 | openDirectory(file);
108 | }
109 | }
110 |
111 | public void openDirectory(File inputFile) {
112 | openDirectoryRecursive(inputFile, root);
113 | DefaultTreeModel treeModel = (DefaultTreeModel) projectTree.getModel();
114 | treeModel.reload();
115 | }
116 |
117 | private void openDirectoryRecursive(File inputFile, DefaultMutableTreeNode parentNode) {
118 | File[] files = inputFile.listFiles();
119 | if (files != null) {
120 | for (File file : files) {
121 | CustomNode node;
122 | if (file.isDirectory()) {
123 | node = new CustomNode(file.getName(), "", file.getAbsolutePath());
124 | node.isDirectory = true;
125 | openDirectoryRecursive(file, node);
126 | } else {
127 | try {
128 | Scanner scanner = new Scanner(file);
129 | StringBuilder data = new StringBuilder();
130 | while (scanner.hasNextLine()) {
131 | data.append(scanner.nextLine()).append("\n");
132 | }
133 | scanner.close();
134 | node = new CustomNode(file.getName(), data.toString(), file.getAbsolutePath());
135 | node.isDirectory = false;
136 | projectFiles.add(node);
137 |
138 | } catch (FileNotFoundException e) {
139 | System.err.println("File not found: " + file.getAbsolutePath());
140 | continue;
141 | }
142 | }
143 | parentNode.add(node);
144 | }
145 | }
146 |
147 | }
148 |
149 | public void saveFile() {
150 | CustomNode node = (CustomNode) projectTree.getLastSelectedPathComponent();
151 | if (node == null) {
152 | JOptionPane.showMessageDialog(null, "No file selected.", "Error", JOptionPane.ERROR_MESSAGE);
153 | return;
154 | }
155 |
156 | node.setContent(app.editorView.getText());
157 |
158 | File savedFile = new File(node.getFilePath());
159 | try (FileWriter writer = new FileWriter(savedFile)) {
160 | writer.write(node.getContent());
161 | } catch (IOException e) {
162 | JOptionPane.showMessageDialog(this,
163 | "Error saving file: " + savedFile.getName() + "\n" + e.getMessage(),
164 | "Save Error",
165 | JOptionPane.ERROR_MESSAGE);
166 | }
167 | }
168 |
169 | private void createPopupMenu() {
170 | popupMenu = new JPopupMenu();
171 |
172 | JMenuItem addFileItem = new JMenuItem("New File");
173 | JMenuItem addFolderItem = new JMenuItem("New Folder");
174 | JMenuItem deleteItem = new JMenuItem("Delete");
175 | JMenuItem renameItem = new JMenuItem("Rename");
176 |
177 | addFileItem.addActionListener(e -> createFile(false));
178 | addFolderItem.addActionListener(e -> createFile(true));
179 | deleteItem.addActionListener(e -> deleteFile());
180 | renameItem.addActionListener(e -> renameFile());
181 |
182 | popupMenu.add(addFileItem);
183 | popupMenu.add(addFolderItem);
184 | popupMenu.add(deleteItem);
185 | popupMenu.add(renameItem);
186 | }
187 |
188 | private void createFile(boolean isDirectory) {
189 | CustomNode selectedNode = (CustomNode) projectTree.getLastSelectedPathComponent();
190 | File parentFile;
191 | CustomNode newNode;
192 |
193 | if (!isDirectory) {
194 | String fileName = JOptionPane.showInputDialog(null, "Enter file name");
195 | try {
196 | parentFile = new File(selectedNode.getFilePath());
197 | } catch (NullPointerException e) {
198 | parentFile = new File(projectPath);
199 | }
200 |
201 | File newFile = new File(parentFile.getAbsolutePath(), fileName);
202 | newNode = new CustomNode(fileName, "", newFile.getAbsolutePath());
203 |
204 | if (parentFile.isDirectory()) selectedNode.add(newNode);
205 | else root.add(newNode);
206 | } else {
207 | String folderName = JOptionPane.showInputDialog(null, "Enter folder name");
208 | try {
209 | parentFile = new File(selectedNode.getFilePath());
210 | } catch (NullPointerException e) {
211 | parentFile = new File(projectPath);
212 | }
213 |
214 | File newFolder = new File(parentFile.getAbsolutePath(), folderName);
215 | boolean folderCreated = newFolder.mkdir();
216 | if (!folderCreated) JOptionPane.showMessageDialog(null, "Unable to create folder",
217 | "Error", JOptionPane.ERROR_MESSAGE);
218 | else {
219 | newNode = new CustomNode(folderName, null, newFolder.getAbsolutePath());
220 |
221 | if (parentFile.isDirectory()) selectedNode.add(newNode);
222 | else root.add(newNode);
223 | }
224 | }
225 | refreshTree();
226 | }
227 |
228 | private void deleteFile() {
229 | CustomNode selectedNode = (CustomNode) projectTree.getLastSelectedPathComponent();
230 | try {
231 | File selectedFile = new File(selectedNode.getFilePath());
232 | if (selectedFile.exists()) {
233 | boolean deleted;
234 | if (selectedFile.isDirectory()) deleted = deleteDirectory(selectedFile);
235 | else deleted = selectedFile.delete();
236 |
237 |
238 | if (deleted) {
239 | DefaultTreeModel model = (DefaultTreeModel) projectTree.getModel();
240 | model.removeNodeFromParent(selectedNode);
241 | model.reload();
242 | } else {
243 | JOptionPane.showMessageDialog(null,
244 | "Could not delete the file/folder",
245 | "Error",
246 | JOptionPane.ERROR_MESSAGE);
247 | }
248 | }
249 | } catch (NullPointerException e) {
250 | JOptionPane.showMessageDialog(null, "Cannot delete opened project", "Error", JOptionPane.ERROR_MESSAGE);
251 | }
252 |
253 | }
254 |
255 | private boolean deleteDirectory(File directory) {
256 | File[] files = directory.listFiles();
257 | if (files != null) {
258 | for (File file : files) {
259 | if (file.isDirectory()) {
260 | deleteDirectory(file);
261 | } else {
262 | file.delete();
263 | }
264 | }
265 | }
266 | return directory.delete();
267 | }
268 |
269 | private void renameFile() {
270 | CustomNode selectedNode = (CustomNode) projectTree.getLastSelectedPathComponent();
271 |
272 | if (selectedNode.isDirectory) JOptionPane.showMessageDialog(null, "Cannot rename folders", "Error", JOptionPane.ERROR_MESSAGE);
273 | else {
274 |
275 | String newName = JOptionPane.showInputDialog(null, "Enter new name", selectedNode.getNodeName());
276 | if (newName == null || newName.trim().isEmpty()) {
277 | return;
278 | }
279 |
280 | File currentFile = new File(selectedNode.getFilePath());
281 | File parentFile = currentFile.getParentFile();
282 | File newFile = new File(parentFile, newName);
283 |
284 | if (currentFile.renameTo(newFile)) {
285 |
286 | selectedNode.setNodeName(newName);
287 | selectedNode.setFilePath(newFile.getAbsolutePath());
288 |
289 |
290 | DefaultTreeModel model = (DefaultTreeModel) projectTree.getModel();
291 | model.nodeChanged(selectedNode);
292 |
293 | refreshTree();
294 | } else {
295 | JOptionPane.showMessageDialog(null,
296 | "Could not rename the file",
297 | "Rename Error",
298 | JOptionPane.ERROR_MESSAGE);
299 | }
300 | }
301 | }
302 |
303 | public void refreshTree() {
304 | DefaultTreeModel model = (DefaultTreeModel) projectTree.getModel();
305 | DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) projectTree.getCellRenderer();
306 | renderer.setClosedIcon(folderIcon);
307 | renderer.setOpenIcon(folderIcon);
308 | model.reload();
309 | }
310 |
311 | public JTree getProjectTree() {
312 | return projectTree;
313 | }
314 |
315 | public CustomNode getSelectedCustomNode() {
316 | return (CustomNode) projectTree.getLastSelectedPathComponent();
317 | }
318 |
319 | }
320 |
--------------------------------------------------------------------------------
/src/main/java/WelcomeView.java:
--------------------------------------------------------------------------------
1 | import com.formdev.flatlaf.fonts.jetbrains_mono.FlatJetBrainsMonoFont;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 | import java.awt.event.ComponentEvent;
6 | import java.awt.event.ComponentListener;
7 |
8 | public class WelcomeView extends JPanel implements ComponentListener {
9 |
10 | private final App app;
11 |
12 | private final JLabel titleLabel;
13 | private final JLabel mottoLabel;
14 | public JButton openProjectButton;
15 |
16 | GradientPaint gradient;
17 |
18 | int titleWidth = 400, titleHeight = 200, mottoWidth = 400, mottoHeight = 100;
19 |
20 | public WelcomeView(App app) {
21 | this.app = app;
22 | this.addComponentListener(this);
23 | this.setBounds(0, 0, app.getWidth(), app.getHeight());
24 | this.setLayout(null);
25 | this.setOpaque(false);
26 |
27 | titleLabel = new JLabel("{CodeLite}");
28 | titleLabel.setFont(new Font(FlatJetBrainsMonoFont.FAMILY, Font.BOLD, 52));
29 | titleLabel.setForeground(Color.WHITE);
30 | titleLabel.setHorizontalAlignment(SwingConstants.CENTER);
31 |
32 | mottoLabel = new JLabel("Code editing simplified");
33 | mottoLabel.setFont(new Font(FlatJetBrainsMonoFont.FAMILY, Font.PLAIN, 24));
34 | mottoLabel.setForeground(Color.WHITE);
35 | mottoLabel.setHorizontalAlignment(SwingConstants.CENTER);
36 |
37 | openProjectButton = new JButton("Open Project");
38 | openProjectButton.setForeground(Color.WHITE);
39 | openProjectButton.setFont(new Font(FlatJetBrainsMonoFont.FAMILY, Font.PLAIN, 18));
40 |
41 | openProjectButton.setBackground(new Color(12, 100, 181));
42 |
43 | openProjectButton.addActionListener(e -> {
44 | app.projectView.openProject();
45 | app.launch();
46 | });
47 |
48 | this.add(titleLabel);
49 | this.add(mottoLabel);
50 | this.add(openProjectButton);
51 | }
52 | @Override
53 | public void paintComponent(Graphics g) {
54 | super.paintComponent(g);
55 | Graphics2D g2D = (Graphics2D) g;
56 |
57 | if (app.darkTheme) {
58 | gradient = new GradientPaint(0, 0, new Color(32, 32, 32), getWidth(), getHeight(), new Color(40, 40, 40));
59 | } else {
60 | gradient = new GradientPaint(0, 0, new Color(6, 74, 181), getWidth(), getHeight(), new Color(84, 166, 251));
61 | }
62 | g2D.setPaint(gradient);
63 | g2D.fillRect(0, 0, getWidth(), getHeight());
64 | }
65 |
66 | @Override
67 | public void componentResized(ComponentEvent e) {
68 | if (titleLabel != null && mottoLabel!=null && openProjectButton!= null) {
69 | titleLabel.setBounds(getWidth() / 2 - titleWidth / 2,
70 | (getHeight() / 2 - titleHeight / 2) - 50,
71 | titleWidth, titleHeight);
72 | mottoLabel.setBounds(getWidth() / 2 - mottoWidth / 2,
73 | titleLabel.getY() + titleHeight / 2,
74 | mottoWidth, mottoHeight);
75 | openProjectButton.setBounds(getWidth() / 2 - titleWidth / 4,
76 | mottoLabel.getY() + mottoHeight,
77 | titleWidth / 2, mottoHeight / 2);
78 | }
79 | }
80 |
81 | @Override
82 | public void componentMoved(ComponentEvent e) {
83 |
84 | }
85 |
86 | @Override
87 | public void componentShown(ComponentEvent e) {
88 |
89 | }
90 |
91 | @Override
92 | public void componentHidden(ComponentEvent e) {
93 |
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Main-Class: App
3 |
4 |
--------------------------------------------------------------------------------
/src/main/resources/icons/folder_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gufranthakur/CodeLite/31202dd9420bb93564dbdbdbacfbecd256178879/src/main/resources/icons/folder_icon.png
--------------------------------------------------------------------------------
/src/main/resources/icons/folder_icon_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gufranthakur/CodeLite/31202dd9420bb93564dbdbdbacfbecd256178879/src/main/resources/icons/folder_icon_24.png
--------------------------------------------------------------------------------
/src/main/resources/themes/blue.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/main/resources/themes/eclipse.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/src/main/resources/themes/monokai.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/main/resources/themes/night.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/main/resources/themes/purple.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/main/resources/themes/red.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------