You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1196 lines
46 KiB
Java

/*
* Copyright (c) 2015, Netsyms Technologies
* All rights reserved.
*
*
* CODE LICENSE ==========
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* 4. You adhere to the Media License detailed below. If you do not, this license
* is automatically revoked and you must purge all copies of the software you
* possess, in source or binary form.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* MEDIA LICENSE ==========
* All images and other graphical files ("media") included with this
* software are copyright (c) 2015 Netsyms Technologies. You may not distribute
* the graphics or any program, source code repository, or other digital storage
* media containing them without permission from Netsyms Technologies.
* This ban on distribution only applies to publicly available systems.
* A password-protected network file share, USB drive, or other storage scheme that
* cannot be easily accessed by the public is generally allowed. If in doubt,
* contact Netsyms Technologies. If Netsyms Technologies allows or denies
* you permission, that decision is considered final and binding.
*
* You may only use the media for personal,
* non-commercial, non-educational use unless:
* 1, You have paid for the software and media via the SyMAT website,
* or 2, you are using it as part of the 15-day trial period.
* Other uses are prohibited without permission.
* If any part of this license is deemed unenforcable, the remainder
* of the license remains in full effect.
*/
package net.apocalypselabs.symat;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import static java.awt.Frame.MAXIMIZED_BOTH;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JInternalFrame;
import javax.swing.JOptionPane;
import javax.swing.ListModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import net.apocalypselabs.symat.plugin.LoadPlugin;
import org.pushingpixels.flamingo.api.ribbon.*;
import org.pushingpixels.flamingo.api.ribbon.resize.*;
import org.pushingpixels.flamingo.api.common.*;
import org.pushingpixels.flamingo.api.common.icon.*;
/**
* This class is like the Force: A light theme, a dark theme, and it binds the
* app together. Also like duct tape, but that's not as cool.
*
* Contains a bunch of important variables and constants that are used all over.
*
* There is only one Main per app instance, the important things are static.
*
* @author Skylar Ittner
*/
public class Main extends JRibbonFrame {
/**
* Version name, as it should be displayed.
*/
public static final String VERSION_NAME = "2.1";
/**
* The word "SyMAT".
*/
public static final String SYMAT = "SyMAT";
/**
* Program name, with version name
*/
public static final String APP_NAME = SYMAT + " " + VERSION_NAME;
/**
* Version number, for updates and //needs in scripts
*/
public static final double APP_CODE = 24;
/**
* Base URL for building API calls
*/
public static final String API_URL = "http://apis.symatapp.com/";
/**
* Contains the filename argument passed to SyMAT, if any.
*/
public static String argfile = "";
/**
* Ubuntu font. Loaded from Ubuntu-R.ttf in the default package at runtime.
* Becomes default sans-serif if something bad happens.
*/
public static Font ubuntuRegular;
/**
*
*/
public static boolean skipPython = false; // Skip python init on start?
/**
*
*/
public static boolean skipEditor = false; // Skip editor init on start?
private static boolean recentItemsMinimized = false;
/**
*
*/
public static boolean updateAvailable = false; // Update available?
/**
*
*/
public static String updateString = "";
/**
*
*/
public static boolean licValid = false; // License valid?
/**
* Application icon, for setting frame icons. Has different sizes.
*/
public static ArrayList<Image> symatlogo = new ArrayList<>();
/**
* The http server that handles opening other instances.
*/
public static SingleInstanceServer sisrv;
/**
*
*/
public static Main maingui;
/**
*
*/
public JRibbonBand pluginband;
/**
* Creates the main app window and does some quick things that aren't
* threaded in SplashScreen.
*/
public Main() {
maingui = this;
// Set icon
setIconImages(symatlogo);
initComponents();
loadRibbon();
// Center screen
setLocationRelativeTo(null);
// Run things when app closed
addWindowListener(new ExitControl());
// Open initial windows
boolean loaded = false;
if (!argfile.equals("")) {
if (argfile.endsWith(".sytt")) {
Tasks tt = new Tasks(new File(argfile));
loadFrame(tt);
argfile = "";
} else if (argfile.endsWith(".sypl")) {
loadFrame(new InstallPlugin(new File(argfile)));
} else {
Editor ed = new Editor();
loadFrame(ed);
ed.openFileFromName(argfile);
argfile = "";
}
loaded = true;
}
if (!licValid) {
licenseRestrict(true);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
loadFrame(new License());
}
});
loaded = true;
}
// Only load shell if nothing else is going on
if (argfile.equals("") && !loaded) {
loadFrame(new Interpreter());
}
if (updateAvailable) {
loadFrame(new Update(updateString));
}
loadRecentFiles();
updateDisplay();
setVisible(true);
if (PrefStorage.getSetting("framemaxed", "no").equals("yes")) {
java.awt.EventQueue.invokeLater(() -> {
setExtendedState(MAXIMIZED_BOTH);
});
}
if (!PrefStorage.getSetting("showrecent", "").equals("")) {
recentItemsPanel.setVisible(false);
}
// Pi Day easter egg
GregorianCalendar piday = new GregorianCalendar();
if ((piday.get(Calendar.MONTH) == 2)
&& (piday.get(Calendar.DAY_OF_MONTH) == 14)) {
JOptionPane.showInternalMessageDialog(mainPane,
"Happy Pi Day from the SyMAT team!",
"3/14",
JOptionPane.PLAIN_MESSAGE);
}
}
/**
* Load plugins from disk.
*/
public void loadPlugins() {
pluginband = new JRibbonBand("Plugins", null);
installpluginbtn.setActionRichTooltip(new RichTooltip("Install Plugin",
"Install a plugin from a file and view plugin info."));
installpluginbtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new InstallPlugin());
}
});
pluginband.setResizePolicies((List) Arrays.asList(
new CoreRibbonResizePolicies.Mirror(pluginband.getControlPanel())));
pluginband.addCommandButton(installpluginbtn, RibbonElementPriority.TOP);
String fsep = System.getProperty("file.separator");
File dir = new File(System.getProperty("user.home") + fsep + ".symat" + fsep + "plugins");
dir.mkdirs();
File[] files = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".sypl");
}
});
Map<RibbonElementPriority, Integer> galleryVisibleButtonCounts = new HashMap<>();
galleryVisibleButtonCounts.put(RibbonElementPriority.LOW, 4);
galleryVisibleButtonCounts.put(RibbonElementPriority.MEDIUM, 4);
galleryVisibleButtonCounts.put(RibbonElementPriority.TOP, 4);
List<StringValuePair<List<JCommandToggleButton>>> appGalleryButtons = new ArrayList<>();
List<JCommandToggleButton> appGalleryButtonsList = new ArrayList<>();
if (files != null) {
for (File pl : files) {
LoadPlugin lp;
try {
lp = new LoadPlugin(pl);
appGalleryButtonsList.add(lp.getGalleryBtn());
} catch (Exception ex) {
Debug.stacktrace(ex);
System.err.println("Error loading plugin " + pl.getName() + ": " + ex.getMessage());
}
}
}
appGalleryButtons.add(new StringValuePair<>("Plugins",
appGalleryButtonsList));
pluginband.addRibbonGallery("Plugins", appGalleryButtons,
galleryVisibleButtonCounts, 4, 3,
RibbonElementPriority.TOP);
}
/**
* Reload the Ribbon tabs and all sub-components.
*/
public void reloadRibbon() {
getRibbon().removeAllTasks();
loadRibbon();
}
/**
* Load the ribbon in all its glory.
*/
private void loadRibbon() {
ResizableIcon appico = ImageWrapperResizableIcon.getIcon(
Main.class.getResource("32x32.png"),
new Dimension(32, 32));
setApplicationIcon(appico);
int tries = 0; // no infinite loops for us!
while (tries < 20) {
try {
Thread.sleep(10);
if (getApplicationIcon().equals(appico)) {
break;
}
setApplicationIcon(appico);
} catch (Exception ex) {
}
tries++;
}
JRibbon ribbon = getRibbon();
JRibbonBand codeband = new JRibbonBand("Code", null);
JRibbonBand toolsband = new JRibbonBand("Tools", null);
JRibbonBand webband = new JRibbonBand("Web", null);
JRibbonBand collabband = new JRibbonBand("Team", null);
try {
loadPlugins();
} catch (Exception ex) {
JOptionPane.showMessageDialog(this,
"An error occurred while loading plugins: "
+ ex.getMessage());
}
shellbtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Interpreter());
}
});
editorbtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Editor());
}
});
graphbtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Graph());
}
});
notepadbtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Notepad());
}
});
wikibtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new WebBrowser("SyMAT Wiki",
"http://wiki.symatapp.com",
WebBrowser.WIKI_LOGO));
}
});
browserbtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new WebBrowser());
}
});
padsbtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Pads());
}
});
tasksbtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Tasks());
}
});
shellbtn.setActionRichTooltip(new RichTooltip("Command Shell",
"Open a window for running interactive commands."));
editorbtn.setActionRichTooltip(new RichTooltip("Code Editor",
"Write and run JavaScript and Python scripts."));
graphbtn.setActionRichTooltip(new RichTooltip("Graph",
"Plot mathematical functions on a 2D graph."));
notepadbtn.setActionRichTooltip(new RichTooltip("Notepad",
"Write quick notes on a virtual napkin."));
wikibtn.setActionRichTooltip(new RichTooltip("SyMAT Wiki",
"View and edit online documentation and tutorials."));
browserbtn.setActionRichTooltip(new RichTooltip("Web Browser",
"Go online and browse the web."));
padsbtn.setActionRichTooltip(new RichTooltip("Code Pads",
"Collaborate over the Internet on projects."));
tasksbtn.setActionRichTooltip(new RichTooltip("Task List",
"Manage tasks and to-do lists for projects."));
codeband.addCommandButton(shellbtn, RibbonElementPriority.TOP);
codeband.addCommandButton(editorbtn, RibbonElementPriority.TOP);
toolsband.addCommandButton(graphbtn, RibbonElementPriority.MEDIUM);
toolsband.addCommandButton(notepadbtn, RibbonElementPriority.MEDIUM);
toolsband.addCommandButton(tasksbtn, RibbonElementPriority.MEDIUM);
webband.addCommandButton(padsbtn, RibbonElementPriority.TOP);
webband.addCommandButton(browserbtn, RibbonElementPriority.MEDIUM);
webband.addCommandButton(wikibtn, RibbonElementPriority.MEDIUM);
codeband.setResizePolicies((List) Arrays.asList(new CoreRibbonResizePolicies.None(codeband.getControlPanel()),
new IconRibbonBandResizePolicy(codeband.getControlPanel())));
toolsband.setResizePolicies((List) Arrays.asList(new CoreRibbonResizePolicies.None(toolsband.getControlPanel()),
new IconRibbonBandResizePolicy(toolsband.getControlPanel())));
webband.setResizePolicies((List) Arrays.asList(
new CoreRibbonResizePolicies.None(webband.getControlPanel()),
new IconRibbonBandResizePolicy(webband.getControlPanel())));
collabband.setResizePolicies((List) Arrays.asList(
new CoreRibbonResizePolicies.None(collabband.getControlPanel()),
new IconRibbonBandResizePolicy(collabband.getControlPanel())));
// getpluginband.setResizePolicies((List) Arrays.asList(
// new CoreRibbonResizePolicies.None(appsband.getControlPanel()),
// new IconRibbonBandResizePolicy(pluginband.getControlPanel())));
// pluginband.setResizePolicies((List) Arrays.asList(
// new CoreRibbonResizePolicies.None(appsband.getControlPanel()),
// new IconRibbonBandResizePolicy(pluginband.getControlPanel())));
RibbonTask hometask = new RibbonTask("Apps", codeband, toolsband, webband);
//RibbonTask webtask = new RibbonTask("Tools", webband, collabband);
RibbonTask plugintask = new RibbonTask("Plugins", pluginband);
loadRibbonMenu(null);
ribbon.addTask(hometask);
//ribbon.addTask(webtask);
ribbon.addTask(plugintask);
}
/**
*
* @param name
* @return
*/
public static ResizableIcon getRibbonIcon(String name) {
return ImageWrapperResizableIcon.getIcon(
Main.class.getResource("images/" + name + ".png"),
new Dimension(100, 76));
}
/**
*
* @param name
* @return
*/
public static ResizableIcon getTinyRibbonIcon(String name) {
int d = 32;
return ImageWrapperResizableIcon.getIcon(
Main.class.getResource("icons/" + name + ".png"),
new Dimension(d, d));
}
/**
*
* @param restricted
*/
public static void licenseRestrict(boolean restricted) {
graphbtn.setEnabled(!restricted);
padsbtn.setEnabled(!restricted);
recentFileList.setEnabled(!restricted);
}
/**
* (Re)load display settings.
*/
public static void updateDisplay() {
maingui.getRibbon().setBackground(Theme.tabColor());
recentFileList.setForeground(Theme.textColor());
recentFileList.setBackground(Theme.boxColor());
recentItemsPanel.setVisible(PrefStorage.getSetting("showrecent", "")
.equals(""));
maingui.getRibbon().setMinimized(PrefStorage.getSetting(
"miniribbon", "").equals("yes"));
mainPane.paintImmediately(0, 0,
mainPane.getWidth(), mainPane.getHeight());
}
/**
*
* @param recent
*/
public static void loadRibbonMenu(RibbonApplicationMenuEntrySecondary[] recent) {
RibbonApplicationMenuEntryPrimary helpbtn
= new RibbonApplicationMenuEntryPrimary(
getRibbonIcon("help"),
"Manual",
new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Help());
}
},
JCommandButton.CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntryPrimary cascadebtn
= new RibbonApplicationMenuEntryPrimary(
getRibbonIcon("cascade"),
"Arrange all",
new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
cascade();
}
},
JCommandButton.CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntryPrimary exitbtn
= new RibbonApplicationMenuEntryPrimary(
getRibbonIcon("closeall"),
"Exit",
new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
maingui.dispatchEvent(new WindowEvent(maingui,
WindowEvent.WINDOW_CLOSING));
}
},
JCommandButton.CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntrySecondary newjsbtn
= new RibbonApplicationMenuEntrySecondary(
getTinyRibbonIcon("jsicon"),
"JavaScript",
new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Editor(Editor.JAVASCRIPT));
}
},
JCommandButton.CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntrySecondary newpybtn
= new RibbonApplicationMenuEntrySecondary(
getTinyRibbonIcon("pyicon"),
"Python",
new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Editor(Editor.PYTHON));
}
},
JCommandButton.CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntrySecondary newjavabtn
= new RibbonApplicationMenuEntrySecondary(
getTinyRibbonIcon("jaicon"),
"Java",
new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Editor(Editor.JAVA));
}
},
JCommandButton.CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntrySecondary newtaskbtn
= new RibbonApplicationMenuEntrySecondary(
getTinyRibbonIcon("taskicon"),
"Task List",
new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Tasks());
}
},
JCommandButton.CommandButtonKind.ACTION_ONLY);
RibbonApplicationMenuEntryPrimary newbtn
= new RibbonApplicationMenuEntryPrimary(
getRibbonIcon("newfile"),
"New",
null,
JCommandButton.CommandButtonKind.POPUP_ONLY);
openbtn = new RibbonApplicationMenuEntryPrimary(
getRibbonIcon("openfile"),
"Open",
new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
JFileChooser fc = new JFileChooser();
FileFilter script
= new FileNameExtensionFilter("Script"
+ "(syjs, sypy, js, py)",
"syjs", "sypy", "js", "py");
FileFilter all
= new FileNameExtensionFilter("SyMAT File"
+ "(syjs, sypy, js, py, sytt)",
"syjs", "sypy", "js", "py", "sytt");
FileFilter tasklist
= new FileNameExtensionFilter("Task List (sytt)",
"sytt");
fc.setFileFilter(all);
fc.addChoosableFileFilter(script);
fc.addChoosableFileFilter(tasklist);
int result = fc.showOpenDialog(maingui);
if (result == JFileChooser.APPROVE_OPTION) {
File f = fc.getSelectedFile();
if (f.getName().endsWith(".sytt")) {
loadFrame(new Tasks(f));
} else {
Editor ed = new Editor();
ed.openFileFromName(f.getAbsolutePath());
loadFrame(ed);
}
}
}
},
JCommandButton.CommandButtonKind.ACTION_AND_POPUP_MAIN_ACTION);
if (recent == null) {
RibbonApplicationMenuEntrySecondary blanksubbtn
= new RibbonApplicationMenuEntrySecondary(
null, "No recent files", null,
JCommandButton.CommandButtonKind.ACTION_ONLY);
blanksubbtn.setEnabled(false);
openbtn.addSecondaryMenuGroup("Recent Files", blanksubbtn);
} else {
openbtn.addSecondaryMenuGroup("Recent Files", recent);
}
newbtn.addSecondaryMenuGroup("Code File", newjsbtn, newpybtn, newjavabtn);
newbtn.addSecondaryMenuGroup("Other", newtaskbtn);
RibbonApplicationMenuEntryFooter displaybtn
= new RibbonApplicationMenuEntryFooter(
getTinyRibbonIcon("settings"),
"Settings",
new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
loadFrame(new Settings());
}
});
RibbonApplicationMenuEntryPrimary blankbtn
= new RibbonApplicationMenuEntryPrimary(
null, "", null,
JCommandButton.CommandButtonKind.ACTION_ONLY);
blankbtn.setEnabled(false);
RibbonApplicationMenu menu = new RibbonApplicationMenu();
menu.addMenuEntry(newbtn);
menu.addMenuEntry(openbtn);
menu.addMenuSeparator();
menu.addMenuEntry(helpbtn);
menu.addMenuEntry(cascadebtn);
menu.addMenuSeparator();
menu.addMenuEntry(exitbtn);
menu.addFooterEntry(displaybtn);
menu.addMenuEntry(blankbtn);
menu.addMenuEntry(blankbtn);
menu.addMenuEntry(blankbtn);
menu.addMenuEntry(blankbtn);
maingui.getRibbon().setApplicationMenu(menu);
maingui.getRibbon().setApplicationMenuRichTooltip(
new RichTooltip("SyMAT Menu",
"Create files, open documents, "
+ "get help, and change settings")
);
}
/**
* (Re)load recent file lists from storage.
*/
public static void loadRecentFiles() {
String files = PrefStorage.getSetting("recentfiles");
if (files.equals("")) {
loadRibbonMenu(null);
recentFileList.setListData(new String[0]);
return;
}
String[] fileList = files.split("\n");
int neededLength = 0;
for (String file : fileList) {
if ((new File(file)).isFile()) {
neededLength++;
}
}
if (neededLength > 10) {
neededLength = 10;
}
KeyValListItem[] items = new KeyValListItem[neededLength];
int i = 0;
RibbonApplicationMenuEntrySecondary[] recentmenu
= new RibbonApplicationMenuEntrySecondary[fileList.length];
for (String f : fileList) {
File file = new File(f);
if (file.isFile() && i < neededLength) {
items[i] = new KeyValListItem(file.getName(), file.getPath());
recentmenu[i] = (new RibbonApplicationMenuEntrySecondary(
null,
file.getName(),
new ActionListener() {
final String path = file.getPath();
@Override
public void actionPerformed(ActionEvent evt) {
Editor edit = new Editor();
edit.openFileFromName(path);
loadFrame(edit);
}
},
JCommandButton.CommandButtonKind.ACTION_ONLY));
i++;
}
}
loadRibbonMenu(recentmenu);
recentFileList.setListData(items);
// Re-save list to remove bad entries
String list = "";
for (KeyValListItem item : items) {
list += item.getValue() + "\n";
}
PrefStorage.saveSetting("recentfiles", list);
}
/**
* Add a file to the recent files lists.
*
* @param file The file path.
*/
public static void addRecentFile(String file) {
file = (new File(file)).getAbsolutePath();
String files = PrefStorage.getSetting("recentfiles");
String[] fileList = files.split("\n");
for (int i = 0; i < fileList.length; i++) {
if (fileList[i].trim().equals(file)) {
fileList[i] = "";
}
}
files = file + "\n";
for (String f : fileList) {
if (!f.trim().equals("")) {
files += f + "\n";
}
}
PrefStorage.saveSetting("recentfiles", files);
PrefStorage.save();
loadRecentFiles();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jMenuItem1 = new javax.swing.JMenuItem();
mainPane = mainPane = new javax.swing.JDesktopPane() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Theme.windowColor());
g.fillRect(0, 0, getWidth(), getHeight());
}
}
;
jLabel2 = new javax.swing.JLabel();
recentItemsPanel = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
recentFileList = new javax.swing.JList();
recentFileBtn = new javax.swing.JButton();
recentItemsTitle = new javax.swing.JLabel();
appPanel = new javax.swing.JPanel();
jMenuItem1.setText("jMenuItem1");
setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
setTitle("SyMAT");
setMinimumSize(new java.awt.Dimension(640, 540));
addComponentListener(new java.awt.event.ComponentAdapter() {
public void componentShown(java.awt.event.ComponentEvent evt) {
formComponentShown(evt);
}
});
mainPane.setBackground(new java.awt.Color(204, 204, 204));
mainPane.setAutoscrolls(true);
mainPane.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
mainPane.setOpaque(false);
jLabel2.setFont(Main.ubuntuRegular.deriveFont(48.0F));
jLabel2.setForeground(new java.awt.Color(153, 153, 153));
jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
jLabel2.setText("SyMAT");
jLabel2.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM);
recentItemsPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
recentItemsPanel.setForeground(new java.awt.Color(153, 153, 153));
recentItemsPanel.setMaximumSize(new java.awt.Dimension(160, 273));
recentItemsPanel.setOpaque(false);
jScrollPane1.setMinimumSize(new java.awt.Dimension(23, 206));
jScrollPane1.setName(""); // NOI18N
recentFileList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
recentFileList.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
recentFileListMouseClicked(evt);
}
});
recentFileList.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseMoved(java.awt.event.MouseEvent evt) {
recentFileListMouseMoved(evt);
}
});
jScrollPane1.setViewportView(recentFileList);
recentFileBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/net/apocalypselabs/symat/icons/openfile.png"))); // NOI18N
recentFileBtn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
recentFileBtnActionPerformed(evt);
}
});
recentItemsTitle.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
recentItemsTitle.setForeground(new java.awt.Color(102, 102, 102));
recentItemsTitle.setText(" Recent Files");
recentItemsTitle.setOpaque(true);
recentItemsTitle.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
recentItemsTitleMouseClicked(evt);
}
});
javax.swing.GroupLayout recentItemsPanelLayout = new javax.swing.GroupLayout(recentItemsPanel);
recentItemsPanel.setLayout(recentItemsPanelLayout);
recentItemsPanelLayout.setHorizontalGroup(
recentItemsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(recentItemsPanelLayout.createSequentialGroup()
.addGroup(recentItemsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(recentItemsPanelLayout.createSequentialGroup()
.addGap(97, 97, 97)
.addComponent(recentFileBtn))
.addGroup(recentItemsPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 136, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(recentItemsTitle, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
recentItemsPanelLayout.setVerticalGroup(
recentItemsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(recentItemsPanelLayout.createSequentialGroup()
.addComponent(recentItemsTitle)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 357, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(recentFileBtn)
.addContainerGap())
);
appPanel.setOpaque(false);
appPanel.setLayout(new java.awt.GridBagLayout());
javax.swing.GroupLayout mainPaneLayout = new javax.swing.GroupLayout(mainPane);
mainPane.setLayout(mainPaneLayout);
mainPaneLayout.setHorizontalGroup(
mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPaneLayout.createSequentialGroup()
.addContainerGap()
.addComponent(appPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(recentItemsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
mainPaneLayout.setVerticalGroup(
mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(mainPaneLayout.createSequentialGroup()
.addContainerGap()
.addGroup(mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(appPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(mainPaneLayout.createSequentialGroup()
.addComponent(recentItemsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 84, Short.MAX_VALUE)
.addComponent(jLabel2)))
.addContainerGap())
);
mainPane.setLayer(jLabel2, javax.swing.JLayeredPane.DEFAULT_LAYER);
mainPane.setLayer(recentItemsPanel, javax.swing.JLayeredPane.DEFAULT_LAYER);
mainPane.setLayer(appPanel, javax.swing.JLayeredPane.DEFAULT_LAYER);
getContentPane().add(mainPane, java.awt.BorderLayout.CENTER);
pack();
}// </editor-fold>//GEN-END:initComponents
private void formComponentShown(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentShown
setLocationRelativeTo(null);
}//GEN-LAST:event_formComponentShown
private void recentFileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_recentFileBtnActionPerformed
if (recentFileList.getSelectedValue() == null) {
return;
}
KeyValListItem file = (KeyValListItem) recentFileList.getSelectedValue();
if (file.isEmpty()) {
return;
}
Editor edit = new Editor();
Debug.println(file.getValue());
edit.openFileFromName(file.getValue());
loadFrame(edit);
}//GEN-LAST:event_recentFileBtnActionPerformed
private void recentFileListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recentFileListMouseClicked
if (evt.getClickCount() == 2) {
recentFileBtnActionPerformed(null);
}
}//GEN-LAST:event_recentFileListMouseClicked
private void recentFileListMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recentFileListMouseMoved
try {
ListModel m = recentFileList.getModel();
int index = recentFileList.locationToIndex(evt.getPoint());
if (index > -1) {
recentFileList.setToolTipText(
((KeyValListItem) m.getElementAt(index)).getValue());
}
} catch (Exception ex) {
// This feature is optional. Just skip it if it's broken.
recentFileList.setToolTipText("");
}
}//GEN-LAST:event_recentFileListMouseMoved
private void recentItemsTitleMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recentItemsTitleMouseClicked
}//GEN-LAST:event_recentItemsTitleMouseClicked
/**
* Adds the given JInternalFrame to the mainPane. Automatically does layout
* and sets visible (if show==true).
*
* @param frame The frame
* @param show Should the frame be visible?
*/
public static void loadFrame(JInternalFrame frame, boolean show) {
int w = frame.getWidth();
int h = frame.getHeight();
int pw = mainPane.getWidth();
int ph = mainPane.getHeight();
if (frame.isResizable()) {
if (h > ph) {
h = ph;
}
if (w > pw) {
w = pw;
}
frame.setSize(w, h);
}
mainPane.add(frame);
frame.setLocation(
(pw / 2) - (w / 2),
(ph / 2) - (h / 2));
if (frame.getLocation().y < 0) {
frame.setLocation(frame.getLocation().x, 0);
}
if (show) {
frame.setVisible(true);
}
}
/**
* Adds the given JInternalFrame to the mainPane. Automatically does layout
* and sets visible.
*
* @param frame The frame
*/
public static void loadFrame(JInternalFrame frame) {
loadFrame(frame, true);
}
/**
* Cascade all the frames in a stack. Somehow reverses the order each time
* around, I have no idea why but it's a "feature" now!
*/
public static void cascade() {
JInternalFrame[] frames = mainPane.getAllFrames();
int x = 12;
int y = 24;
Debug.println("Cascading " + frames.length + " frames...");
for (int i = 0; i < frames.length; i++) {
if (frames[i].isVisible()) {
Debug.println("Frame: "
+ frames[i].getTitle()
+ ", Times: " + i
+ ", Xpos: " + x * i
+ ", Ypos: " + y * i);
frames[i].setBounds(x * i,
y * i,
frames[i].getWidth(),
frames[i].getHeight());
frames[i].toFront();
}
}
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException e) {
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, e);
}
//</editor-fold>
//</editor-fold>
//</editor-fold>
//</editor-fold>
try {
// Ubuntu font for prettifying
ubuntuRegular = Font.createFont(Font.TRUETYPE_FONT, Main.class.
getResourceAsStream("/Ubuntu-R.ttf"));
} catch (FontFormatException | IOException ex) {
ubuntuRegular = Font.getFont(Font.SANS_SERIF);
System.err.println("Error loading fonts: " + ex.getMessage());
} catch (Exception ex) {
ubuntuRegular = Font.getFont(Font.SANS_SERIF);
System.err.println("Error loading fonts: " + ex.getMessage());
}
// Set icon
String[] sizes = {"16", "24", "32", "48", "64", "96", "128", "256", "512"};
for (String s : sizes) {
symatlogo.add(new ImageIcon(
Main.class.getResource(s + "x" + s + ".png")).getImage());
}
// Command line args
for (String arg : args) {
switch (arg) {
case "skippython":
skipPython = true;
break;
case "skipeditor":
skipEditor = true;
break;
case "quickstart":
skipPython = true;
skipEditor = true;
break;
case "licensereset":
PrefStorage.saveSetting("license", "");
break;
default:
argfile = arg;
break;
}
}
SingleInstanceClient sicli = new SingleInstanceClient(argfile);
try {
new SingleInstanceServer().start();
} catch (IOException ex) {
Debug.printerr("Cannot start instance listener:\n\n");
Debug.stacktrace(ex);
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new JFXPanel(); // this will prepare JavaFX toolkit and environment
Platform.runLater(new Runnable() {
@Override
public void run() {
Platform.setImplicitExit(false);
}
});
}
});
/* Create and display the form */
java.awt.EventQueue.invokeLater(() -> {
new SplashScreen().setVisible(true);
});
}
/**
*
*/
public static JCommandButton shellbtn
= new JCommandButton("Shell", getRibbonIcon("shell"));
/**
*
*/
public static JCommandButton editorbtn
= new JCommandButton("Editor", getRibbonIcon("editor"));
/**
*
*/
public static JCommandButton graphbtn
= new JCommandButton("Graph", getRibbonIcon("graph"));
/**
*
*/
public static JCommandButton notepadbtn
= new JCommandButton("Notepad", getRibbonIcon("notepad"));
/**
*
*/
public static JCommandButton wikibtn
= new JCommandButton("Wiki", getRibbonIcon("wiki"));
/**
*
*/
public static JCommandButton browserbtn
= new JCommandButton("Browser", getRibbonIcon("browser"));
/**
*
*/
public static JCommandButton padsbtn
= new JCommandButton("Pads", getRibbonIcon("pads"));
/**
*
*/
public static JCommandButton tasksbtn
= new JCommandButton("Tasks", getRibbonIcon("tasks"));
/**
*
*/
public static JCommandButton installpluginbtn
= new JCommandButton("Install", getRibbonIcon("installplugin"));
/**
*
*/
public static RibbonApplicationMenuEntryPrimary openbtn;
// Variables declaration - do not modify//GEN-BEGIN:variables
public static javax.swing.JPanel appPanel;
public static javax.swing.JLabel jLabel2;
public static javax.swing.JMenuItem jMenuItem1;
public static javax.swing.JScrollPane jScrollPane1;
public static javax.swing.JDesktopPane mainPane;
public static javax.swing.JButton recentFileBtn;
public static javax.swing.JList recentFileList;
public static javax.swing.JPanel recentItemsPanel;
public static javax.swing.JLabel recentItemsTitle;
// End of variables declaration//GEN-END:variables
}