/* * Apocalypse Laboratories * Open Source License * * Source code can be used for any purpose, as long as: * - Compiled binaries are rebranded and trademarks are not * visible by the end user at any time, except to give * credit to Apocalypse Laboratories, such as by showing * "Based on by Apocalypse Laboratories" or a * similar notice; * - You do not use the code for evil; * - Rebranded compiled applications have significant * differences in functionality; * - and you provide your modified source code for download, * under the terms of the GNU LGPL v3 or a comparable * license. * * Compiled binaries cannot be redistributed or mirrored, * unless: * - You have written permission from Apocalypse Laboratories; * - Downloads are not available from Apocalypse Laboratories, * not even behind a paywall or other blocking mechanism; * - or you have received a multi-computer license, in which * case you should take measures to prevent unauthorized * downloads, such as preventing download access from the * Internet. */ package net.apocalypselabs.symat; import java.awt.Font; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.text.AttributeSet; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; import javax.swing.text.TabSet; import javax.swing.text.TabStop; /** * * @author Skylar */ public class CodeEditor extends javax.swing.JInternalFrame { private final JFileChooser fc = new JFileChooser(); private boolean isSaved = false; private final JTextPane codeBox = new JTextPane(); private final TextLineNumber tln; private String lastSaved = ""; /** * Creates new form CodeEditor */ public CodeEditor() { initComponents(); FileFilter filter = new FileNameExtensionFilter("SyMAT script (.symt)", "symt"); fc.setFileFilter(filter); fc.addChoosableFileFilter(filter); filter = new FileNameExtensionFilter("JavaScript file (.js)", "js"); fc.addChoosableFileFilter(filter); filter = new FileNameExtensionFilter("MeetLeeb script (.mls)", "mls"); fc.addChoosableFileFilter(filter); int font_size = 12; try { font_size = Integer.valueOf(PrefStorage.getSetting("editor-fontsize")); } catch (Exception ex) { } codeBox.setFont(new Font(Font.MONOSPACED, Font.PLAIN, font_size)); TabStop[] tabs = new TabStop[30]; for (int i = 0; i < tabs.length; i++) { tabs[i] = new TabStop(15 * i, TabStop.ALIGN_RIGHT, TabStop.LEAD_NONE); } TabSet tabset = new TabSet(tabs); StyleContext sc = StyleContext.getDefaultStyleContext(); AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.TabSet, tabset); codeBox.setParagraphAttributes(aset, false); tln = new TextLineNumber(codeBox); scrollPane.setRowHeaderView(tln); codeBox.setVisible(true); tln.setVisible(true); codeBox.requestFocus(); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { jMenuItem4 = new javax.swing.JMenuItem(); jMenuBar2 = new javax.swing.JMenuBar(); jMenu3 = new javax.swing.JMenu(); jMenu4 = new javax.swing.JMenu(); jPanel1 = new javax.swing.JPanel(); jSplitPane1 = new javax.swing.JSplitPane(); scrollPane = new JScrollPane(codeBox); jPanel2 = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); outputPane = new javax.swing.JTextArea(); jMenuBar1 = new javax.swing.JMenuBar(); jMenu1 = new javax.swing.JMenu(); jMenuItem1 = new javax.swing.JMenuItem(); jMenuItem2 = new javax.swing.JMenuItem(); jMenuItem3 = new javax.swing.JMenuItem(); jMenuItem8 = new javax.swing.JMenuItem(); jMenu5 = new javax.swing.JMenu(); jMenuItem6 = new javax.swing.JMenuItem(); jMenuItem7 = new javax.swing.JMenuItem(); jMenu2 = new javax.swing.JMenu(); jMenuItem5 = new javax.swing.JMenuItem(); jMenuItem4.setText("jMenuItem4"); jMenu3.setText("File"); jMenuBar2.add(jMenu3); jMenu4.setText("Edit"); jMenuBar2.add(jMenu4); setClosable(true); setIconifiable(true); setMaximizable(true); setResizable(true); setTitle("Editor"); setFrameIcon(new javax.swing.ImageIcon(getClass().getResource("/net/apocalypselabs/symat/icons/editor.png"))); // NOI18N jSplitPane1.setDividerLocation(275); jSplitPane1.setDividerSize(3); jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); jSplitPane1.setResizeWeight(0.7); scrollPane.setRequestFocusEnabled(false); jSplitPane1.setTopComponent(scrollPane); jLabel1.setText("Output:"); outputPane.setEditable(false); outputPane.setColumns(20); outputPane.setRows(5); jScrollPane1.setViewportView(outputPane); javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); jPanel2.setLayout(jPanel2Layout); jPanel2Layout.setHorizontalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel2Layout.createSequentialGroup() .addComponent(jLabel1) .addGap(0, 0, Short.MAX_VALUE)) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 524, Short.MAX_VALUE) ); jPanel2Layout.setVerticalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel2Layout.createSequentialGroup() .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 72, Short.MAX_VALUE)) ); jSplitPane1.setRightComponent(jPanel2); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jSplitPane1) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 359, Short.MAX_VALUE) ); jMenu1.setText("File"); jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK)); jMenuItem1.setText("Open..."); jMenuItem1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItem1ActionPerformed(evt); } }); jMenu1.add(jMenuItem1); jMenuItem2.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK)); jMenuItem2.setText("Save..."); jMenuItem2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItem2ActionPerformed(evt); } }); jMenu1.add(jMenuItem2); jMenuItem3.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK)); jMenuItem3.setText("Save as..."); jMenuItem3.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItem3ActionPerformed(evt); } }); jMenu1.add(jMenuItem3); jMenuItem8.setText("Export..."); jMenuItem8.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItem8ActionPerformed(evt); } }); jMenu1.add(jMenuItem8); jMenuBar1.add(jMenu1); jMenu5.setText("Edit"); jMenuItem6.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_W, java.awt.event.InputEvent.CTRL_MASK)); jMenuItem6.setText("Clear output"); jMenuItem6.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItem6ActionPerformed(evt); } }); jMenu5.add(jMenuItem6); jMenuItem7.setText("Font size..."); jMenuItem7.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItem7ActionPerformed(evt); } }); jMenu5.add(jMenuItem7); jMenuBar1.add(jMenu5); jMenu2.setText("Run"); jMenu2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenu2ActionPerformed(evt); } }); jMenuItem5.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F5, 0)); jMenuItem5.setText("Run code"); jMenuItem5.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMenuItem5ActionPerformed(evt); } }); jMenu2.add(jMenuItem5); jMenuBar1.add(jMenu2); setJMenuBar(jMenuBar1); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); pack(); }// //GEN-END:initComponents private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed int r = fc.showOpenDialog(this); if (r == JFileChooser.APPROVE_OPTION) { try { File f = fc.getSelectedFile(); codeBox.setText(readFile(f.toString(), StandardCharsets.UTF_8)); isSaved = true; lastSaved = codeBox.getText(); setTitle("Editor - " + f.getName()); } catch (IOException ex) { JOptionPane.showInternalMessageDialog(this, "Error: Cannot load file: " + ex.getMessage()); } } codeBox.setCaretPosition(0); }//GEN-LAST:event_jMenuItem1ActionPerformed public void openFileFromString(String file) { try { File f = new File(file); codeBox.setText(readFile(f.toString(), StandardCharsets.UTF_8)); isSaved = true; lastSaved = codeBox.getText(); setTitle("Editor - " + f.getName()); } catch (IOException ex) { JOptionPane.showInternalMessageDialog(this, "Error: Cannot load file: " + ex.getMessage()); } } private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed if (!isSaved) { int r = fc.showSaveDialog(this); if (r == JFileChooser.APPROVE_OPTION) { try { saveFile(codeBox.getText(), addSaveExt(fc.getSelectedFile().toString())); } catch (IOException ex) { JOptionPane.showInternalMessageDialog(this, "Error: Cannot save file: " + ex.getMessage()); } } } else { try { saveFile(codeBox.getText(), addSaveExt(fc.getSelectedFile().toString())); } catch (IOException ex) { JOptionPane.showInternalMessageDialog(this, "Error: Cannot save file: " + ex.getMessage()); } } }//GEN-LAST:event_jMenuItem2ActionPerformed private String addSaveExt(String path) { if (!path.matches(".*\\.(js|mls|symt)")) { path += ".symt"; } return path; } private void jMenuItem3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem3ActionPerformed isSaved = false; // Reset saved status, force dialog jMenuItem2ActionPerformed(evt); }//GEN-LAST:event_jMenuItem3ActionPerformed private void jMenu2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenu2ActionPerformed }//GEN-LAST:event_jMenu2ActionPerformed private void jMenuItem5ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem5ActionPerformed CodeRunner cr = new CodeRunner(); Object result = cr.evalString(codeBox.getText()); try { outputPane.append(result.toString() + "\n"); } catch (NullPointerException ex) { } }//GEN-LAST:event_jMenuItem5ActionPerformed private void jMenuItem6ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem6ActionPerformed outputPane.setText(""); }//GEN-LAST:event_jMenuItem6ActionPerformed private void jMenuItem7ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem7ActionPerformed try { int size = Integer.parseInt(JOptionPane.showInternalInputDialog(this, "New font size (8-36):", "Font Size", JOptionPane.QUESTION_MESSAGE)); if (size >= 8 && size <= 36) { codeBox.setFont(new Font(Font.MONOSPACED, Font.PLAIN, size)); PrefStorage.saveSetting("editor-fontsize", size + ""); } } catch (Exception ex) { } }//GEN-LAST:event_jMenuItem7ActionPerformed private void jMenuItem8ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem8ActionPerformed CodeExport ce = new CodeExport(codeBox.getText()); MainGUI.loadFrame(ce); }//GEN-LAST:event_jMenuItem8ActionPerformed private void saveFile(String content, String path) throws IOException { try (PrintStream out = new PrintStream(new FileOutputStream(path))) { out.print(content); } setTitle("Editor - " + (new File(path)).getName()); lastSaved = content; isSaved = true; } @Override public void doDefaultCloseAction() { if (lastSaved.equals(codeBox.getText())) { dispose(); } else { int p = JOptionPane.showInternalConfirmDialog(this, "Are you sure you want to exit without saving this file?", "Unsaved Changes", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (p == JOptionPane.YES_OPTION) { dispose(); } else { jMenuItem3ActionPerformed(null); } } } private static String readFile(String path, Charset encoding) throws IOException { byte[] encoded = Files.readAllBytes(Paths.get(path)); return new String(encoded, encoding); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel jLabel1; private javax.swing.JMenu jMenu1; private javax.swing.JMenu jMenu2; private javax.swing.JMenu jMenu3; private javax.swing.JMenu jMenu4; private javax.swing.JMenu jMenu5; private javax.swing.JMenuBar jMenuBar1; private javax.swing.JMenuBar jMenuBar2; private javax.swing.JMenuItem jMenuItem1; private javax.swing.JMenuItem jMenuItem2; private javax.swing.JMenuItem jMenuItem3; private javax.swing.JMenuItem jMenuItem4; private javax.swing.JMenuItem jMenuItem5; private javax.swing.JMenuItem jMenuItem6; private javax.swing.JMenuItem jMenuItem7; private javax.swing.JMenuItem jMenuItem8; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JTextArea outputPane; private javax.swing.JScrollPane scrollPane; // End of variables declaration//GEN-END:variables }