summaryrefslogtreecommitdiff
path: root/jnyqide
diff options
context:
space:
mode:
Diffstat (limited to 'jnyqide')
-rw-r--r--jnyqide/BareBonesBrowserLaunch.java66
-rw-r--r--jnyqide/CodePane.java671
-rw-r--r--jnyqide/EnvelopeFrame.java1317
-rw-r--r--jnyqide/FindDialog.java118
-rw-r--r--jnyqide/InstrumentCharacteristics.java364
-rwxr-xr-xjnyqide/Jslide.java201
-rw-r--r--jnyqide/LispFileFilter.java33
-rw-r--r--jnyqide/Main.java75
-rw-r--r--jnyqide/MainFrame.java1539
-rw-r--r--jnyqide/MainFrame_AboutBox.java98
-rw-r--r--jnyqide/MiniBrowser.java66
-rw-r--r--jnyqide/NotFoundDialog.java79
-rw-r--r--jnyqide/NyqPlot.java131
-rw-r--r--jnyqide/NyquistFile.java590
-rw-r--r--jnyqide/NyquistThread.java424
-rw-r--r--jnyqide/NyquistWords.txt1520
-rw-r--r--jnyqide/Pair.java38
-rwxr-xr-xjnyqide/Piano_Roll.java1104
-rw-r--r--jnyqide/PlotFrame.java333
-rw-r--r--jnyqide/PlotMouseAdapter.java67
-rw-r--r--jnyqide/PopupListener.java46
-rw-r--r--jnyqide/PreferencesDialog.java426
-rw-r--r--jnyqide/README.txt152
-rw-r--r--jnyqide/ReplaceDialog.java167
-rw-r--r--jnyqide/SalFileFilter.java41
-rw-r--r--jnyqide/SalWordList.java57
-rw-r--r--jnyqide/SpecialMacHandler.java70
-rw-r--r--jnyqide/SpringUtilities.java194
-rw-r--r--jnyqide/TextColor.java984
-rw-r--r--jnyqide/Trie.java129
-rw-r--r--jnyqide/UPICFrame.java1425
-rw-r--r--jnyqide/WordList.java247
-rw-r--r--jnyqide/browser.java439
-rw-r--r--jnyqide/closeFile.gifbin0 -> 1154 bytes
-rw-r--r--jnyqide/help.gifbin0 -> 118 bytes
-rw-r--r--jnyqide/keywords.txt512
-rw-r--r--jnyqide/manifest.txt1
-rw-r--r--jnyqide/openFile.gifbin0 -> 1132 bytes
38 files changed, 13724 insertions, 0 deletions
diff --git a/jnyqide/BareBonesBrowserLaunch.java b/jnyqide/BareBonesBrowserLaunch.java
new file mode 100644
index 0000000..b8e9a2e
--- /dev/null
+++ b/jnyqide/BareBonesBrowserLaunch.java
@@ -0,0 +1,66 @@
+/////////////////////////////////////////////////////////
+// Bare Bones Browser Launch //
+// Version 1.5 //
+// December 10, 2005 //
+// Modified by RBD, 2008 to test for htmlview in linux//
+// Supports: Mac OS X, GNU/Linux, Unix, Windows XP //
+// Example Usage: //
+// String url = "http://www.centerkey.com/"; //
+// BareBonesBrowserLaunch.openURL(url); //
+// Public Domain Software -- Free to Use as You Like //
+/////////////////////////////////////////////////////////
+
+package jnyqide; // this line was added by RBD
+
+import java.lang.reflect.Method;
+import javax.swing.JOptionPane;
+
+public class BareBonesBrowserLaunch {
+
+ private static final String errMsg =
+ "Error attempting to launch web browser";
+
+ public static void openURL(String url) {
+ String osName = System.getProperty("os.name");
+ System.out.println("BareBonesBrowserLaunch: url=" + url +
+ " osName:" + osName);
+ try {
+ if (osName.startsWith("Mac OS")) {
+ System.out.println("BareBonesBrowserLaunch: Mac OS detected");
+ // try a new way
+ Runtime.getRuntime().exec(new String[] {"/usr/bin/open", url});
+ // here's the old way that does not handle #name suffix on url
+// Class fileMgr = Class.forName("com.apple.eio.FileManager");
+// System.out.println("fileMgr=" + fileMgr);
+// Method openURL = fileMgr.getDeclaredMethod("openURL",
+// new Class[] {String.class});
+// openURL.invoke(null, new Object[] {url});
+ System.out.println("openURL invoked with " + url);
+ } else if (osName.startsWith("Windows")) {
+ Runtime.getRuntime().exec(
+ "rundll32 url.dll, FileProtocolHandler " +
+ "\"" + url + "\""); // quote url or lose "#" suffixes
+ } else { //assume Unix or Linux
+ String[] browsers = {
+ "htmlview", "firefox", "opera", "konqueror",
+ "epiphany", "mozilla", "netscape" };
+ int count;
+ for (count = 0; count < browsers.length; count++) {
+ if (Runtime.getRuntime().exec(
+ new String[] {"which",
+ browsers[count]}).waitFor() == 0) {
+ break;
+ }
+ }
+ if (count >= browsers.length)
+ throw new Exception("Could not find web browser");
+ System.out.println("Found browser: " + browsers[count]);
+ System.out.println("sending url: " + url);
+ Runtime.getRuntime().exec(new String[] {browsers[count], url});
+ }
+ } catch (Exception e) {
+ JOptionPane.showMessageDialog(null, errMsg + ":\n" +
+ e.getLocalizedMessage());
+ }
+ }
+}
diff --git a/jnyqide/CodePane.java b/jnyqide/CodePane.java
new file mode 100644
index 0000000..e566226
--- /dev/null
+++ b/jnyqide/CodePane.java
@@ -0,0 +1,671 @@
+//
+// CodePane.java
+// nyquist
+//
+// Created by Roger Dannenberg on 12/15/07.
+// Copyright 2007 Roger B. Dannenberg. All rights reserved.
+//
+
+package jnyqide;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import javax.swing.undo.*;
+
+// CodePane subclasses a JScrollPane and initializes it to contain
+// a JTextPane which holds a DefaultStyleDocument. Syntax coloring
+// and paren balancing is performed.
+//
+// a CodePane also has a Timer -- it is used to blink a character somewhere.
+//
+public class CodePane extends JScrollPane
+ implements DocumentListener, CaretListener,
+ AdjustmentListener, KeyListener {
+ public JTextPane pane;
+ public DefaultStyledDocument doc;
+ public Timer timer;
+ public boolean evenParens; // used by MainFrame for command input
+ // (when user types return, if parens are balanced, that is, evenParens
+ // is true, then the command is sent to Nyquist)
+ // when user types a close paren, the matching one is blinked, and
+ // when user moves cursor, the matching paren is highlighted in bold
+ public int blinkLoc; // where to blink a matching paren
+ public int highlightLoc; // where to highlight a matching paren
+ public boolean blinkOn;
+ // mainFrame is a handle to access some methods, but it is also a
+ // flag to tell us if this is a command entry window:
+ public MainFrame mainFrame;
+ public boolean isSal;
+ int caretLine; // holds current line number
+ int caretColumn; // holds current column
+ int fontSize; // the font size
+ JLabel statusBar;
+
+ final int TIMER_DELAY = 1000; // ms
+
+ public CodePane(Dimension preferredSize, MainFrame mf, JLabel sb,
+ int fontSz) {
+ super();
+ blinkLoc = 0;
+ blinkOn = false; // initialize
+ fontSize = fontSz;
+ mainFrame = mf;
+ statusBar = sb;
+ isSal = false;
+ doc = new DefaultStyledDocument();
+ pane = new JTextPane(doc);
+ getViewport().add(pane);
+ setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+ setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+
+ // create timer for blinking
+ ActionListener blinkOffTask = new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ timer.stop(); // timer is just a one-shot, not periodic
+ blinkOn = false;
+ synchronousUpdate();
+ }
+ };
+ timer = new Timer(TIMER_DELAY, blinkOffTask);
+
+ doc.addDocumentListener(this);
+ pane.addCaretListener(this);
+ this.getHorizontalScrollBar().addAdjustmentListener(this);
+ this.getVerticalScrollBar().addAdjustmentListener(this);
+
+ final UndoManager undo = new UndoManager();
+ doc.addUndoableEditListener(
+ new UndoableEditListener() {
+ public void undoableEditHappened(UndoableEditEvent evt) {
+ // do not make style changes undoable -- these
+ // are fixed automatically
+ if (!evt.getEdit().getPresentationName().equals(
+ "style change")) {
+ undo.addEdit(evt.getEdit());
+ }
+ }
+ });
+
+ // Create an undo action and add it to the text component
+ pane.getActionMap().put("Undo",
+ new AbstractAction("Undo") {
+ public void actionPerformed(ActionEvent evt) {
+ try {
+ if (undo.canUndo()) {
+ undo.undo();
+ }
+ } catch (CannotUndoException e) {
+ }
+ }
+ });
+
+ // Bind the undo action to ctl-Z
+ pane.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
+
+ // Create a redo action and add it to the text component
+ pane.getActionMap().put("Redo",
+ new AbstractAction("Redo") {
+ public void actionPerformed(ActionEvent evt) {
+ try {
+ if (undo.canRedo()) {
+ undo.redo();
+ }
+ } catch (CannotRedoException e) {
+ }
+ }
+ });
+
+ // Bind the redo action to ctl-Y
+ pane.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");
+
+ // add self as a key listener
+ pane.addKeyListener(this);
+
+
+ if (preferredSize != null) setPreferredSize(preferredSize);
+
+ }
+
+
+ public void updateCaretLoc() {
+ String text;
+ try {
+ text = pane.getText();
+ } catch(Exception ex) {
+ System.out.println("exception in keyTyped");
+ return;
+ }
+ int pos = pane.getCaretPosition();
+ caretColumn = 0;
+ caretLine = 0;
+ int i = 0;
+ while (i++ < pos) {
+ if (text.charAt(i - 1) == '\n') {
+ caretColumn = 0;
+ caretLine++;
+ } else {
+ caretColumn++;
+ }
+ }
+ // the first line is 1, not 0
+ statusBar.setText(Integer.toString(caretLine + 1) + ":" +
+ Integer.toString(caretColumn));
+ }
+
+
+ public void changedUpdate(DocumentEvent e) {
+ //System.out.println("changedUpdate " + e);
+ }
+
+
+ public void removeUpdate(DocumentEvent e) {
+ synchronousUpdate();
+ }
+
+
+ public void insertUpdate(DocumentEvent e) {
+ // System.out.println("insertUpdate calls thread.update");
+ synchronousUpdate();
+ }
+
+
+ public void caretUpdate(CaretEvent e) {
+ // System.out.println("caretUpdate " + e.getDot() + " mark " +
+ // e.getMark());
+ if (e.getDot() == e.getMark()) {
+ highlightMatchingParen(e.getDot() - 1);
+ updateCaretLoc();
+ //System.out.println("caretUpdate: " + e.getDot() + " is line " +
+ // caretLine + " col " + caretColumn);
+ } else {
+ highlightMatchingParen(-1);
+ }
+ }
+
+ public void adjustmentValueChanged(AdjustmentEvent evt) {
+ // System.out.println("adjustmentValueChanged");
+ synchronousUpdate();
+ }
+
+
+ //This method can be invoked from any thread. It
+ //invokes the setText and modelToView methods, which
+ //must run in the event dispatching thread. We use
+ //invokeLater to schedule the code for execution
+ //in the event dispatching thread.
+ protected void highlightMatchingParen(final int pos) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ if (pos == -1) {
+ highlightLoc = pos;
+ } else if (charAtPos(pos) == ')') {
+ try {
+ highlightLoc = findOpenParen(
+ pane.getText(0, pos), pos);
+ } catch(BadLocationException e) {
+ System.out.println(e);
+ return;
+ }
+ if (highlightLoc == pos) highlightLoc = -1;
+ } else { // not at close paren, so turn off highlight
+ highlightLoc = -1;
+ }
+ synchronousUpdate();
+ }
+ }
+ );
+ }
+
+ char charAtPos(int pos) {
+ String text;
+ try {
+ text = doc.getText(pos, 1);
+ } catch(BadLocationException e) {
+ return 0;
+ }
+ return text.charAt(0);
+ }
+
+ // complete the KeyListener interface:
+ public void keyReleased(KeyEvent ke) { return; }
+ public void keyPressed(KeyEvent ke) { return; }
+
+ public void keyTyped(KeyEvent ke) {
+ // System.out.println("CodePane keyTyped |" +
+ // ke.getKeyChar() + "|");
+ // cases:
+ // newline
+ // mainFrame
+ // evenParens: sendCommandToNyquist
+ // !evenParens:
+ // LISP: print "paren mismatch"
+ // indent handling
+ // else
+ // indent handling
+ // otherwise
+ // process key
+ //
+ // this is where we put auto parentheses:
+ char ch = ke.getKeyChar();
+ int pos = pane.getCaretPosition();
+ if (ch == '\n') {
+ //insertIndentation(p);
+ if (mainFrame != null) {
+ if (evenParens) {
+ if (doc.getLength() == pos) {
+ // only do indentation if newline is at end of text
+ insertIndentation(pos);
+ // remove newline
+ pos = doc.getLength(); // take out newline at end
+ int newlinePos = pos - 1;
+ try {
+ while (!doc.getText(newlinePos, 1).equals("\n")) {
+ newlinePos--;
+ }
+ } catch(BadLocationException e) {
+ System.out.println(e);
+ return;
+ }
+ System.out.println("cut newline: newlinePos " + newlinePos +
+ " pos " + pos);
+ pane.setSelectionStart(newlinePos);
+ } else { // no indentation, just remove newline
+ pane.setSelectionStart(pos - 1);
+ }
+ pane.setSelectionEnd(pos);
+ pane.replaceSelection("");
+ mainFrame.sendCommandToNyquist();
+ } else {
+ if (!isSal) {
+ mainFrame.jOutputArea.append(
+ "Invalid command - paren mismatch\n");
+ }
+ insertIndentation(pos);
+ }
+ } else {
+ insertIndentation(pos);
+ }
+ } else if (ch == '\t') {
+ int spaces = TextColor.INDENT -
+ (caretColumn - 1) % TextColor.INDENT;
+ // remove tab and replace with spaces
+ pane.setSelectionStart(pos - 1);
+ pane.setSelectionEnd(pos);
+ pane.replaceSelection(" ".substring(0, spaces));
+ System.out.println("Replaced TAB by " + spaces + " spaces");
+ } else { // ordinary key handling
+ if (ke.getKeyChar() == ')') {
+ // get caret location
+ blinkParen(pos);
+ } else if (ch == '(') {
+ if (MainFrame.prefParenAutoInsert) {
+ pane.replaceSelection(")");
+ pane.setCaretPosition(pos);
+ }
+ }
+ String text;
+ int start = Math.max(pos - 100, 0);
+ try {
+ text = pane.getText(start, pos - start);
+ } catch (Exception ex) {
+ System.out.println("exception in keyTyped: start " + start +
+ " pos " + pos + " pane " + pane);
+ return;
+ }
+ // simulate typing the character unless it's a backspace
+ if (ch != '\b') text += ch;
+ else pos--;
+
+ String identifier;
+ int identLoc;
+ boolean forceExact = false; // force an exact match to complete word
+ if (isSal) { // generate completion list for SAL
+ // delimiters are "{}(),[]\n #\""
+ // look back for identifier immediately before pos
+ // if none found, look back for unbalanced paren, then search
+ // back from there
+ identifier = getSalIdentifier(text, pos - start);
+ int len = identifier.length();
+ identLoc = pos - len;
+ forceExact = (len > 0 && identifier.charAt(len - 1) == ' ');
+ if (len == 0) { // not found
+ int openParenLoc = findOpenParen(text, pos - start);
+ identifier = getSalIdentifier(text, openParenLoc);
+ identLoc = start + openParenLoc - identifier.length();
+ forceExact = true;
+ }
+ } else { // generate completion list for Lisp
+ // look back for unmatched open paren, then forward for identifier
+ // look back a maximum of 100 characters
+ int openParenLoc = findOpenParen(text, pos - start);
+ openParenLoc++;
+ identifier = getIdentifier(text, openParenLoc);
+ identLoc = start + openParenLoc;
+ int len = identifier.length();
+ forceExact = (len > 0 && identifier.charAt(len - 1) == ' ');
+ }
+ //System.out.println("keyTyped identifier is: |" + identifier + "|");
+ // put up words list
+ WordList.printList(identifier, pane, identLoc, pos + 1,
+ forceExact, isSal);
+ }
+ }
+
+
+ // get an identifier starting at pos -- if a complete identifier (terminated by something)
+ // is found, the identifier is terminated by a space character
+ static String getIdentifier(String text, int pos) {
+ int idEnd = pos; // search forward to find identifier
+ String lispIdChars = "~!@$%^&*-_+={}|:<>?/";
+ if (text.length() == 0 || pos < 0) return text; // special cases
+ while (true) {
+ if (idEnd == text.length()) {
+ text = text.substring(pos); // still typing
+ break;
+ }
+ char idChar = text.charAt(idEnd);
+ if (!Character.isLetterOrDigit(idChar) &&
+ lispIdChars.indexOf(idChar) == -1) {
+ text = text.substring(pos, idEnd) + " "; // complete
+ break; // idEnd is one past last character
+ }
+ idEnd++;
+ }
+ return text;
+ }
+
+
+ static int findColumnOf(String text, int pos) {
+ int col = 0;
+ pos--;
+ while (pos >= 0 && text.charAt(pos) != '\n') {
+ col++;
+ pos--;
+ }
+ return col;
+ }
+
+
+ private void insertIndentation(int p)
+ {
+ String text;
+ int desired = 0; // desired indentation of the previous line
+ // initialized because compiler can't figure out that it's
+ // initialized below before it is used
+ try {
+ text = pane.getText(0, p);
+ } catch (Exception e) {
+ System.out.println("exception in insertIndentation");
+ return;
+ }
+ int indent;
+ if (isSal) {
+ indent = salIndentAmount(p);
+ desired = TextColor.indentBefore;
+ } else {
+ indent = autoIndentAmount(text, p);
+ }
+ String indentation = "";
+ while (indent > 0) {
+ indentation += " ";
+ indent--;
+ }
+ // System.out.println("before replaceSelection(indentation)");
+ pane.replaceSelection(indentation);
+ // System.out.println("after replaceSelection(indentation)");
+ if (isSal) { // indent the previous line as well
+ // first find the beginning of the previous line
+ int prevStart = p - 1; // index of newline
+ // System.out.println("prevStart " + prevStart + " char |" +
+ // text.charAt(prevStart) + "|");
+ assert(text.charAt(prevStart) == '\n');
+ while (prevStart - 1 >= 0 &&
+ text.charAt(prevStart - 1) != '\n') prevStart--;
+ // System.out.println("PREV LINE BEGIN " + prevStart + " in |" +
+ // text + "|");
+ // find the actual indentation of the previous line
+ int prevIndent = 0; // search forward from prevStart for nonspace
+ while (text.charAt(prevStart + prevIndent) == ' ' ||
+ text.charAt(prevStart + prevIndent) == '\t')
+ prevIndent++;
+ // System.out.println("PREV INDENT " + prevIndent +
+ // " DESIRED " + desired);
+ // adjust the indentation
+ int delta = desired - prevIndent;
+ p = pane.getSelectionStart() + delta;
+ if (delta > 0) {
+ indentation = "";
+ while (delta > 0) {
+ indentation += " ";
+ delta--;
+ }
+ // System.out.println("INSERT " + delta +
+ // " SPACES AT " + prevStart);
+ pane.setSelectionStart(prevStart);
+ pane.setSelectionEnd(prevStart);
+ pane.replaceSelection(indentation);
+ } else if (delta < 0) {
+ // System.out.println("BACKSPACE " + -delta +
+ // " AT " + prevStart);
+ pane.setSelectionStart(prevStart);
+ pane.setSelectionEnd(prevStart - delta);
+ pane.replaceSelection("");
+ }
+ // System.out.println("MOVE CARET TO " + p);
+ pane.setSelectionStart(p);
+ pane.setSelectionEnd(p);
+ }
+ }
+
+ private int salIndentAmount(int p) {
+ // how much is the default indentation?
+ // p is position AFTER a newline, so back up one to get
+ // the index of the newline character
+ // System.out.println("salIndentAmount " + p);
+ TextColor.format(this, p - 1);
+ // System.out.println("salIndent return " + TextColor.indentAfter);
+ return TextColor.indentAfter;
+ }
+
+
+ // find auto-indent position:
+ // first, go back and find open paren that would match a close paren
+ // second search forward to find identifier
+ // if identifier is defun, defmacro, let, let*, or prog, etc.
+ // indent to paren posn + 2
+ // else indent to the first thing after the identifier
+ int autoIndentAmount(String text, int pos) {
+ int openParenLoc = findOpenParen(text, pos);
+ // System.out.println("autoIndent: openParenLoc = " + openParenLoc);
+ if (openParenLoc == -1) return 0;
+ String ident = getIdentifier(text, openParenLoc + 1);
+ if (ident.equals("defun ") || ident.equals("defmacro ") ||
+ ident.equals("let ") || ident.equals("let* ") ||
+ ident.equals("dotimes ") || ident.equals("dolist ") ||
+ ident.equals("simrep ") || ident.equals("seqrep ") ||
+ ident.equals("prog ") || ident.equals("prog* ") ||
+ ident.equals("progv ")) {
+ pos = openParenLoc + 2;
+ } else {
+ pos = openParenLoc + ident.length();
+ System.out.println("auto-indent, pos " + pos + ", ident " + ident +
+ ", length " + ident.length());
+ while (pos < text.length() && Character.isWhitespace(text.charAt(pos))) {
+ if (text.charAt(pos) == '\n') {
+ // if the end of the line looks like "(foo \n" then the tab position
+ // will be indented two from the open paren (ignore the identifier):
+ pos = openParenLoc + 2;
+ break;
+ }
+ pos++;
+ }
+ // System.out.println("pos " + pos);
+ }
+ return findColumnOf(text, pos);
+ }
+
+
+ public static boolean inComment(String text, int pos)
+ // search back to newline for ";" indicating comment
+ // assumes text[pos] is not escaped or in string
+ {
+ boolean inString = false;
+ while (pos > 0) {
+ char c = text.charAt(pos);
+ if (c == ';') return true;
+ if (c == '\n') return false;
+ pos = backup(text, pos, false);
+ }
+ return false;
+ }
+
+ static String SalIdChars = "{}(),[]\n #\"";
+
+ public static String getSalIdentifier(String docText, int pos) {
+ // System.out.println("|" + docText + "| " + pos);
+ int start = pos;
+ if (pos < 0) return ""; // special case: no place to search from
+ // allow back up over single open paren
+ if (docText.charAt(pos) == '(') start = start - 1;
+ while (start >= 0 &&
+ SalIdChars.indexOf(docText.charAt(start)) == -1) {
+ start--;
+ }
+ // protect from bogus arguments
+ if (start < -1 || pos >= docText.length()) return "";
+ // if id is terminated by open paren, substitute blank so that
+ // when we search lisp-syntax wordlist we get a more precise match.
+ // E.g. "osc(" becomes "osc " which will not match "osc-enable ..."
+ if (docText.charAt(pos) == '(')
+ return docText.substring(start + 1, pos) + " ";
+ else
+ return docText.substring(start + 1, pos + 1);
+
+
+ }
+
+
+ public static int findOpenParen(String docText, int pos) {
+ int findx = -1;
+ try {
+ boolean inString = false; // need to get it from text color
+ findx = backup(docText, pos, inString);
+ if (findx == pos - 1 && findx > 0 && docText.charAt(findx) == '\\') {
+ // escaped paren
+ return pos;
+ } else if (inComment(docText, findx)) { // in comment
+ return pos;
+ }
+ // at this point we know there is a closed paren.
+ // go back until you find the matching open paren.
+ int closed = 1;
+ while (findx >= 0 && closed > 0) {
+ char c = docText.charAt(findx);
+ if (c == '(' || c == ')') {
+ if (!inComment(docText, findx)) {
+ if (c == '(') closed--;
+ else if (c == ')') closed++;
+ }
+ }
+ if (closed > 0) // not done, back up
+ findx = backup(docText, findx, false);
+ }
+ } catch( Exception e ) {
+ // System.out.println("findOpenParen " + e);
+ }
+ // System.out.println("findOpenParen returns " + findx);
+ return findx;
+ }
+
+
+ private static int backup(String text, int pos, boolean inString)
+ // find an index in text before pos by skipping over strings
+ // and escaped characters of the form #\A, but do not consider
+ // comment lines. If findx is zero, return result is -1.
+ {
+ int findx = pos - 1;
+ while (true) {
+ if (findx < 0) {
+ return findx;
+ }
+ char c = text.charAt(findx);
+ if (inString) {
+ if (c == '"') {
+ // could it be escaped?
+ if (findx > 0) {
+ char pre = text.charAt(findx - 1);
+ if (pre == '"') findx--; // escaped as ""
+ else if (pre == '\\') findx--; // escaped as \"
+ else inString = false;
+ } else inString = false;
+ } // else keep searching for string closing
+ } else { // not inString
+ // test for escaped character
+ if (findx > 0) {
+ char pre = text.charAt(findx - 1);
+ if (pre == '\\') findx--; // escaped
+ else inString = (c == '"');
+ } // else if c == '"' then ...
+ // internal error: text begins with quote, but
+ // inString is false. Just ignore it because it
+ // may be that the coloring hasn't run yet
+ // and all will become well.
+ }
+ if (!inString || findx <= 0) {
+ return findx;
+ }
+ findx--;
+ }
+ }
+
+
+ void synchronousUpdate() {
+ // System.out.println("synchronousUpdate called");
+ final CodePane codePane = this;
+ final JViewport v = getViewport();
+ final Point pt = v.getViewPosition();
+ final Dimension e = v.getExtentSize();
+ EventQueue.invokeLater(
+ new Runnable() {
+ public void run() {
+ // System.out.println("calling TextColor");
+ codePane.evenParens = TextColor.format(codePane, 0);
+ // System.out.println("returned from TextColor");
+ codePane.updateFontSize(fontSize);
+ }
+ });
+ }
+
+ void blinkParen(int pos) {
+ try {
+ String docText = doc.getText(0, pos);
+ int openParenLoc = findOpenParen(docText, pos);
+ if (openParenLoc >= 0 && openParenLoc < pos) {
+ blink(openParenLoc);
+ }
+ } catch (Exception e) { System.out.println(e); }
+ }
+
+
+ // the blink interface: call blink(loc) to make a character blink
+ void blink(int loc) {
+ timer.start();
+ blinkOn = true;
+ blinkLoc = loc;
+ }
+
+ public void updateFontSize(int size) {
+ final MutableAttributeSet attributeSet = new SimpleAttributeSet();
+ StyleConstants.setFontSize(attributeSet, size);
+ doc.setCharacterAttributes(0, 1000000, attributeSet, false);
+ }
+
+ public void setFontSize(int size) {
+ fontSize = size;
+ updateFontSize(size);
+ }
+
+}
diff --git a/jnyqide/EnvelopeFrame.java b/jnyqide/EnvelopeFrame.java
new file mode 100644
index 0000000..9038ebb
--- /dev/null
+++ b/jnyqide/EnvelopeFrame.java
@@ -0,0 +1,1317 @@
+// Code: Chris Yealy, 5/2/06
+// Edited: Derek D'Souza 5/3/07
+// Edited: Roger Dannenberg 23Jul07
+
+// eq editor needs to do same with workspace
+
+/* Saving and Restoring:
+ * the Save button saves one envelope locally, to Nyquist, and saves the
+ * updated workspace
+ * the Load button loads all envelopes from Nyquist for editing. If no
+ * envelopes are loaded, suggests (load "workspace")
+ * selecting an envelope from the list saves the current envelope
+ * (locally, to Nyquist, and to the workspace) and switches the editor
+ * to the selected envelope
+ * delete button removes the envelope from the workspace after a confirm
+ */
+
+/*
+ Graphics organization:
+
+ myParent -- the MainFrame
+ EnvelopeFrame -- this editor, a JInternalFrame
+ mainPanel -- a JPanel
+ topPanel -- a JPanel
+ envNamePanel -- a JPanel, border "Current Envelope"
+ currEnvNameLabel -- a JLabel("Name:")
+ currEnvName -- a JTextField("ENVELOPE", 20)
+ saveEnv -- a JButtton("Save")
+ envTypeLabel - a JTextField("Type", ...)
+ envTypes - a JComboBox
+ envListPanel -- a JPanel, border "Saved Envelopes List"
+ envName -- a JComboBox
+ loadEnv -- a JButton("load")
+ deleteEnv -- a JButton("delete")
+ envPointsPanel - a JPanel, border Envelope Points
+ envTimesLabel - a JLabel("Time:")
+ envTimes - JComboBox
+ envAmplitudesLabel - a JLabel("Amplitudes:")
+ envAmplitudes - JTextField
+ addPoint - a JButton("Add Point")
+ deletePoint - a JButton("Delete Point")
+ updatePoint - a JButton("Update Point")
+ paramPanel -- a JPanel
+ rangePanel - a JPanel, border "Range Parameters"
+ maxTL - a JLabel("Stop Time")
+ maxT - a JTextField
+ minAL - a JLabel("Min. Amplitude")
+ maxAL - a JLabel("Max. Amplitude")
+ minA - a JTextField
+ maxA - a JTextField
+ update - JButton("Update Range"
+ envEditPanel -- a JPanel, border "Graphic Envelope Editor"
+ envEditButtonPanel - a JPanel
+ undo - a JButton("Undo")
+ redo - a JButton("Redo")
+ clear - a JButton("Clear")
+ dispCoord - a JButton("Coordinates")
+ output - a JButton("Output Envelope")
+ canvas - a PiecewiseCanvas (a JPanel)
+
+ to drag point:
+ on mouse pressed, set selection to index of point
+ on mouse drag, delete selection and insert new point
+
+if endpoints are specified, e.g. if times[0] is 0 or last value in times
+ matches the ending time, then use PWLV or PWEV version
+ Be careful not to drop first/last point unless the time matches the
+ begin/end time.
+
+
+ */
+
+package jnyqide;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import java.awt.image.BufferedImage;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.Enumeration;
+import java.io.File;
+import java.lang.Math.*;
+import java.text.DecimalFormat;
+import jnyqide.*;
+
+
+public class EnvelopeFrame extends JInternalFrame implements ActionListener {
+
+ double EPSILON = 0.00000001; // small number -- allow for rounding error
+ int LEFT_BORDER = 3; // inset everything by 3 pixels
+ int TOP_BORDER = 3;
+ int BOTTOM_BORDER = 5;
+ int RIGHT_BORDER = 5;
+ MainFrame myParent;
+
+ //JComponents for envelope window
+ private JComboBox envTypes;
+
+ private JPanel mainPanel;
+
+ private JTextPane jInputArea;
+ //private JPanel canvasPanel;
+ private PiecewiseCanvas canvas;
+
+ private JTextField envAmplitudes;
+ // private JTextField minT;
+ private JTextField maxT;
+ private JTextField minA;
+ private JTextField maxA;
+ private JTextField currEnvName;
+ private JComboBox envName;
+ private JComboBox envTimes;
+ private JButton dispCoord;
+ private String currentEnvName;
+ public String[] types = {"Piecewise Linear", "Piecewise Exponential"};
+ public int PWL_TYPE = 0;
+ public int PWE_TYPE = 1;
+ // when saving envelopes, we copy current envelope to the collection,
+ // but this makes the combobox think that an envelope was selected,
+ // and we get a request to save the same envelope were saving. To
+ // avoid this, the "saving" flag is used to disable the check.
+ private boolean saving = false;
+
+ //hashtable for storing envelopes
+ private Hashtable<String, String> envColl;
+
+ static double initTime=0.0;
+ static double finalTime=1.0;
+ static boolean displayCoord = false;
+ static boolean valueType=false;
+ static DecimalFormat form = new DecimalFormat("#.###");
+ private boolean modified; // tells when any aspect of envelope
+ // has changed
+ // envelope is modified by: entering a point, deleting a point, changing
+ // the end-time (update), or clearing
+ // modified is reset when envelope is loaded or saved
+
+ // Constructor
+ public EnvelopeFrame(final MainFrame parent, JTextPane inputArea) {
+ super();
+ setTitle("Untitled");
+ myParent = parent;
+ jInputArea = inputArea;
+ //canvasPanel = new JPanel();
+ //canvasPanel.setPreferredSize(new Dimension(575, 256));
+ mainPanel = (JPanel) getContentPane();
+
+ envColl = new Hashtable<String, String>();
+ setTitle("Piecewise Envelope Generator");
+ setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
+ final EnvelopeFrame envelopeFrame = this;
+ modified = false;
+ addInternalFrameListener(
+ new InternalFrameListener() {
+ public void internalFrameClosing(InternalFrameEvent e) {
+ //System.out.println("FrameClosing");
+ int r = JOptionPane.OK_OPTION;
+ if (envelopeFrame.modified) {
+ r = JOptionPane.showConfirmDialog(envelopeFrame,
+ "Really close without saving?",
+ "Alert", JOptionPane.OK_CANCEL_OPTION);
+ }
+ if (r == JOptionPane.OK_OPTION) {
+ envelopeFrame.dispose();
+ }
+ }
+ public void internalFrameOpened(InternalFrameEvent e) {
+ }
+ public void internalFrameClosed(InternalFrameEvent e) {
+ parent.disconnectEnv();
+ //System.out.println("FrameClosed");
+ }
+ public void internalFrameIconified(InternalFrameEvent e) {
+ }
+ public void internalFrameDeiconified(InternalFrameEvent e) {
+ }
+ public void internalFrameActivated(InternalFrameEvent e) {
+ }
+ public void internalFrameDeactivated(InternalFrameEvent e) {
+ }
+ }
+ );
+
+ System.out.println("EnvelopeFrame constructor 1");
+
+ JLabel currEnvNameLabel = new JLabel("Name: ");
+ currEnvName = new JTextField("envelope", 10);
+ currentEnvName = "envelope";
+
+ JButton saveEnv = new JButton("Save");
+ saveEnv.addActionListener(this);
+ saveEnv.setActionCommand("saveEnvelopes");
+
+ JLabel currEnvTypeLabel = new JLabel("Type: ");
+ envTypes = new JComboBox(types);
+ envTypes.addActionListener(this);
+ envTypes.setActionCommand("envTypeChanged");
+
+ // components for envelope list panel
+ envName = new JComboBox();
+ envName.setEditable(false);
+ envName.addActionListener(this);
+ envName.setActionCommand("envNameSelected");
+
+ JButton loadEnv = new JButton("Load");
+ loadEnv.addActionListener(this);
+ loadEnv.setActionCommand("loadEnvelope");
+
+ JButton deleteEnv = new JButton("Delete");
+ deleteEnv.addActionListener(this);
+ deleteEnv.setActionCommand("deleteEnvelope");
+
+ JPanel envNamePanel = new JPanel();
+ envNamePanel.setBorder(BorderFactory.createTitledBorder("Current Envelope"));
+ GridBagLayout layout0 = new GridBagLayout();
+ envNamePanel.setLayout(layout0);
+
+ GridBagConstraints cons0 = new GridBagConstraints();
+
+ cons0.fill = GridBagConstraints.NONE;
+ cons0.anchor = GridBagConstraints.EAST;
+ cons0.weightx = 0;
+ cons0.weighty = 0;
+ cons0.gridx = 0;
+ cons0.gridy = 0;
+ cons0.gridheight = 1;
+ cons0.gridwidth = 1;
+ envNamePanel.add(currEnvNameLabel, cons0);
+ cons0.anchor = GridBagConstraints.WEST;
+ cons0.gridx = 1;
+ envNamePanel.add(currEnvName, cons0);
+ cons0.anchor = GridBagConstraints.CENTER;
+ cons0.gridx = 2;
+ envNamePanel.add(saveEnv, cons0);
+ cons0.anchor = GridBagConstraints.EAST;
+ cons0.gridx = 0;
+ cons0.gridy = 1;
+ envNamePanel.add(currEnvTypeLabel, cons0);
+ cons0.anchor = GridBagConstraints.WEST;
+ cons0.gridx = 1;
+ cons0.gridwidth = 2;
+ envNamePanel.add(envTypes, cons0);
+
+ JPanel envListPanel = new JPanel();
+ envListPanel.setBorder(BorderFactory.createTitledBorder("Saved Envelopes List"));
+ envListPanel.add(envName);
+ envListPanel.add(loadEnv);
+ envListPanel.add(deleteEnv);
+
+ envTimes = new JComboBox();
+ envTimes.setEditable(true);
+ envTimes.addActionListener(this);
+ envTimes.setActionCommand("envTimeChange");
+ envTimes.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ System.out.println("itemStateChanged " + e);
+ }
+ });
+ JLabel envTimesLabel = new JLabel("Time: ");
+
+ envAmplitudes = new JTextField(6);
+ JLabel envAmplitudesLabel = new JLabel("Ampl: ");
+ envTimes.setPreferredSize(envAmplitudes.getPreferredSize());
+
+ JButton addPoint = new JButton("Add Point");
+ addPoint.addActionListener(this);
+ addPoint.setActionCommand("addPoint");
+
+ JButton deletePoint = new JButton("Delete Point");
+ deletePoint.addActionListener(this);
+ deletePoint.setActionCommand("deletePoint");
+
+ JButton updatePoint = new JButton("Update Point");
+ updatePoint.addActionListener(this);
+ updatePoint.setActionCommand("updatePoint");
+
+ GridBagLayout layout1 = new GridBagLayout();
+ JPanel envPointsPanel = new JPanel();
+ envPointsPanel.setBorder(BorderFactory.createTitledBorder("Envelope Points"));
+ envPointsPanel.setLayout(layout1);
+
+ GridBagConstraints cons = new GridBagConstraints();
+
+ cons.fill = GridBagConstraints.NONE;
+ cons.anchor = GridBagConstraints.EAST;
+ cons.weightx = 0;
+ cons.weighty = 0;
+ cons.gridx = 0;
+ cons.gridy = 0;
+ cons.gridheight = 1;
+ cons.gridwidth = 1;
+ envPointsPanel.add(envTimesLabel, cons);
+ cons.anchor = GridBagConstraints.WEST;
+ cons.gridx = 1;
+ envPointsPanel.add(envTimes, cons);
+ cons.anchor = GridBagConstraints.EAST;
+ cons.gridx = 0;
+ cons.gridy = 1;
+ envPointsPanel.add(envAmplitudesLabel, cons);
+ cons.anchor = GridBagConstraints.WEST;
+ cons.gridx = 1;
+ envPointsPanel.add(envAmplitudes, cons);
+ cons.anchor = GridBagConstraints.CENTER;
+ cons.gridx = 2;
+ cons.gridy = 0;
+ envPointsPanel.add(addPoint, cons);
+ cons.gridy = 1;
+ envPointsPanel.add(deletePoint, cons);
+ cons.gridy = 2;
+ envPointsPanel.add(updatePoint, cons);
+
+ // panel to contain time and amplitude parameters
+ JPanel rangePanel = new JPanel();
+ JPanel paramPanel = new JPanel();
+ paramPanel.setBorder(BorderFactory.createTitledBorder("Range"));
+ rangePanel.setLayout(new GridBagLayout());
+ paramPanel.setLayout(layout1);
+
+ // components for parameter panel
+ ActionListener stateChange = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ canvas.history.save(canvas);
+ }
+ };
+ maxT = new JTextField("1.0", 5);
+ minA = new JTextField("0.0", 5);
+ maxA = new JTextField("1.0", 5);
+
+ JLabel maxTL = new JLabel("Stop: ");
+ JLabel minAL = new JLabel("Min: ");
+ JLabel maxAL = new JLabel("Max: ");
+
+ cons.gridx = 2;
+ cons.gridy = 0;
+ rangePanel.add(maxTL, cons);
+ cons.gridx = 3;
+ cons.gridy = 0;
+ rangePanel.add(maxT, cons);
+ cons.gridx = 0;
+ cons.gridy = 1;
+ rangePanel.add(minAL, cons);
+ cons.gridx = 2;
+ rangePanel.add(maxAL, cons);
+ cons.gridx = 1;
+ rangePanel.add(minA, cons);
+ cons.gridx = 3;
+ rangePanel.add(maxA, cons);
+ JButton update = new JButton("Update Range");
+
+ update.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (getMaxT() <= 0) {
+ JOptionPane.showMessageDialog(mainPanel,
+ "Stop Time cannot be negative or zero");
+ } else if (getMinA() > getMaxA()) {
+ JOptionPane.showMessageDialog(mainPanel,
+ "Minimum Amplitude cannot be greater than Maximum Amplitude");
+ } else if ((canvas.times.size() > 0) &&
+ (getMaxT() < canvas.times.lastElement())) {
+ JOptionPane.showMessageDialog(mainPanel,
+ "Stop Time is less than the time of an existing envelope point");
+ } else {
+ modified = true;
+ canvas.history.save(canvas);
+ canvas.repaint();
+ return;
+ }
+ // an error occurred, reset the Range (using complete restore)
+ canvas.restore();
+ }
+ });
+
+ //insert components into the larger panels
+ cons.fill = GridBagConstraints.NONE;
+ cons.anchor = GridBagConstraints.WEST;
+ cons.weightx = 0;
+ cons.weighty = 0;
+ cons.gridx = 0;
+ cons.gridy = 0;
+ cons.gridheight = 1;
+ cons.gridwidth = 1;
+ //cons.insets = new Insets(5,0,0,5);
+ paramPanel.add(rangePanel, cons);
+ cons.fill = GridBagConstraints.NONE;
+ cons.anchor = GridBagConstraints.CENTER;
+ cons.weightx = 0;
+ cons.weighty = 0;
+ cons.gridx = 0;
+ cons.gridy = 1;
+ cons.gridheight = 1;
+ cons.gridwidth = 1;
+ //cons.insets = new Insets(0,0,0,5);
+ paramPanel.add(update, cons);
+
+ // components for envelope edit panel
+ JButton undo = new JButton("Undo");
+ undo.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ canvas.history.undo();
+ canvas.restore();
+ }
+ });
+ JButton redo = new JButton("Redo");
+ redo.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ canvas.history.redo();
+ canvas.restore();
+ }
+ });
+ JButton clear = new JButton("Clear");
+ clear.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ System.out.println("calling canvas.clear\n");
+ canvas.clear();
+ }
+ });
+ dispCoord = new JButton("Coordinates");
+ dispCoord.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ displayCoord = !displayCoord;
+ canvas.repaint();
+ }
+ });
+ JButton output = new JButton("Output Envelope");
+ output.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ String outputStr = canvas.getExpression();
+ jInputArea.setText(jInputArea.getText().concat(outputStr));
+ }
+ });
+
+ JPanel envEditButtonPanel = new JPanel();
+ envEditButtonPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 0));
+ envEditButtonPanel.add(undo);
+ envEditButtonPanel.add(redo);
+ envEditButtonPanel.add(clear);
+ envEditButtonPanel.add(dispCoord);
+ envEditButtonPanel.add(output);
+ JPanel topPanel = new JPanel();
+ //topPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 30, 0));
+ topPanel.setLayout(new GridBagLayout());
+ cons.anchor = GridBagConstraints.NORTHWEST;
+ cons.gridx = 0;
+ cons.gridy = 0;
+ topPanel.add(envNamePanel, cons);
+ cons.gridx = 1;
+ topPanel.add(envListPanel, cons);
+ cons.gridx = 0;
+ cons.gridy = 1;
+ topPanel.add(envPointsPanel, cons);
+ cons.gridx = 1;
+ topPanel.add(paramPanel, cons);
+
+ JPanel envEditPanel = new JPanel();
+ envEditPanel.setBorder(BorderFactory.createTitledBorder(
+ "Graphical Envelope Editor"));
+ //envEditPanel.setLayout(new BoxLayout(envEditPanel, BoxLayout.Y_AXIS));
+ envEditPanel.setLayout(new BorderLayout());
+ envEditPanel.add(BorderLayout.NORTH, envEditButtonPanel);
+ canvas = new PiecewiseCanvas();
+ //canvasPanel.add(canvas);
+ //canvasPanel.setBorder(BorderFactory.createEtchedBorder());
+ envEditPanel.add(BorderLayout.CENTER, canvas);
+
+ //insert panels into main frame and display
+ //mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+ //mainPanel.setBorder(BorderFactory.createEmptyBorder());
+ //canvasPanel.add(canvas);
+ mainPanel.add(BorderLayout.NORTH, topPanel);
+ mainPanel.add(BorderLayout.CENTER, envEditPanel);
+
+ pack();
+
+ //resize and center the window
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+
+ setLocation(100, 100);
+ setSize(650, 580);
+ // setBackground(Color.white);
+ setResizable(true);
+ setVisible(true);
+ setClosable(true);
+ setMaximizable(true);
+ setIconifiable(true);
+ System.out.println("EnvelopeFrame constructor 2 after setIcnifiable");
+ // synchronize env data by loading data from Nyquist process
+ loadEnvelopes();
+ repaint();
+ // canvas.repaint();
+ }
+
+ public void envNameSelected() {
+ if (saving) return; // ignore selection generated by "save" button
+ // If the name is different from the current envelope name, do
+ // a "save". Then switch to editing the newly selected envelope.
+ String name = (String) envName.getSelectedItem();
+ // when we load the JComboBox with new names, the contentsChanged
+ // method of JComboBox invokes a selection action, even if nothing
+ // is selected. I don't know why, but we have to handle the null
+ // selection case.
+ if (name == null) return;
+
+ String originalName = currentEnvName;
+ currentEnvName = currEnvName.getText().trim();
+ if (!originalName.equals(currentEnvName)) {
+ modified = true;
+ }
+ if (modified) {
+ Object[] options = { "OK", "CANCEL" };
+ int i = JOptionPane.showOptionDialog(mainPanel,
+ currentEnvName + " is being edited. Save it?",
+ "Warning",
+ JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
+ null, options, options[0]);
+ if (i == JOptionPane.OK_OPTION) {
+ saveEnvelopes();
+ }
+ }
+
+ // store envelope under old name
+ String edited = canvas.getExpression();
+ System.out.println("expression existed, putting " + currentEnvName +
+ " " + edited + ", changing currentEnvName to " + name);
+ if (currentEnvName.length() > 0) envColl.put(currentEnvName, edited);
+ // install name as new envelope to edit
+ String expression = envColl.get(name);
+ canvas.setEnv(expression);
+ currEnvName.setText(name);
+ // make name be the selected name
+ envName.setSelectedItem(name);
+ // }
+ currentEnvName = name;
+ }
+
+
+ //public double getMinT() { return Double.parseDouble(minT.getText().trim()); }
+ public double getMaxT() { return Double.parseDouble(maxT.getText().trim()); }
+ public double getMinA() { return Double.parseDouble(minA.getText().trim()); }
+ public double getMaxA() { return Double.parseDouble(maxA.getText().trim()); }
+ public int getEnvType() {
+ if (envTypes != null) {
+ String env = (String) envTypes.getSelectedItem();
+ if (env.matches(types[PWL_TYPE])) return PWL_TYPE;
+ return PWE_TYPE;
+ } else /* initializing */ return PWL_TYPE;
+ }
+
+ public boolean within(double x, double y, double eps) {
+ return Math.abs(x - y) < eps;
+ }
+
+ // write current envelope definition to Nyquist
+ public void saveEnvelopes() {
+ // make sure current envelope has been stored in collection
+ if (currEnvName.getText().length() == 0) {
+ JOptionPane.showMessageDialog(mainPanel, "Please Enter an Envelope Name");
+ return;
+ }
+ currentEnvName = currEnvName.getText().trim();
+
+ // now write all to Nyquist
+ saving = true;
+ boolean foundIt = false;
+ for (Enumeration keys = envColl.keys(); keys.hasMoreElements(); ) {
+ String name = (String) keys.nextElement();
+ // update envelope collection with current envelope
+ if (name.equals(currentEnvName)) {
+ envColl.remove(name);
+ //envName.removeItem(name);
+ envColl.put(currentEnvName, canvas.getExpression());
+ //envName.addItem(currentEnvName);
+ foundIt = true;
+ }
+ String expression = envColl.get(name);
+ String defn = "(define-env '" + name + " '" + expression + ")";
+ System.out.print("in saveEnvelopes: " + defn);
+ myParent.sendInputLn(defn); // send to Nyquist for evaluation
+ }
+ // if the current envelope was not in the list, add it and save it
+ if (!foundIt) {
+ String expr = canvas.getExpression();
+ envColl.put(currentEnvName, expr);
+ envName.addItem(currentEnvName);
+ String defn = "(define-env '" + currentEnvName + " '" + expr + ")";
+ System.out.print("in saveEnvelopes: " + defn);
+ myParent.sendInputLn(defn); // send to Nyquist for evaluation
+ }
+ envName.setSelectedItem(currentEnvName);
+ modified = false;
+ saving = false;
+ System.out.println("modified false in saveEnvelopes\n");
+ }
+
+
+ public void loadEnvelopes() {
+ myParent.callFunction("get-env-data", "");
+ }
+
+ public void deleteEnvelope() {
+ Object[] options = { "OK", "CANCEL" };
+ int i = JOptionPane.showOptionDialog(mainPanel,
+ "Deletion cannot be undone, click OK to continue",
+ "Warning",
+ JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
+ null, options, options[0]);
+ if (i != JOptionPane.OK_OPTION) return;
+ // it appears as though currentEnvName gets changed when you remove
+ // it from the envName comboBox, so make a local copy. Previously,
+ // we were calling DELETE-ENV after the name changed!
+ String name = currentEnvName;
+ // delete the envelope from hashtable
+ envColl.remove(name);
+ // delete the envelope from the combobox
+ envName.removeItem(name);
+ // delete the envelope from the workspace
+ myParent.sendInputLn(
+ "(delete-env '" + name + ")");
+ }
+
+
+ public void actionPerformed(ActionEvent e)
+ {
+ //System.out.println(e.getActionCommand());
+ String actionCommand = e.getActionCommand();
+
+ // File Menu options
+ if (actionCommand.equals("saveEnvelopes")) {
+ saveEnvelopes();
+ } else if (actionCommand.equals("loadEnvelope")) {
+ loadEnvelopes();
+ } else if (actionCommand.equals("deleteEnvelope")) {
+ deleteEnvelope();
+ } else if (actionCommand.equals("envNameSelected")) {
+ envNameSelected();
+ } else if (actionCommand.equals("envTypeChanged")) {
+ int type = getEnvType();
+ if (type != canvas.type) {
+ canvas.type = type;
+ canvas.history.save(canvas);
+ canvas.repaint();
+ }
+
+ //set initial amplitude and time parameters
+ if (canvas.times.size() < 1) {
+ if (type == PWE_TYPE) {
+ minA.setText("1.0");
+ maxA.setText("2.0");
+ } else {
+ minA.setText("0.0");
+ maxA.setText("1.0");
+ }
+ }
+ canvas.repaint();
+ validate();
+ setVisible(true);
+ } else if (actionCommand.equals("deletePoint")) {
+ int index = envTimes.getSelectedIndex();
+ System.out.println("at deletePoint, index " + index);
+ if (index >= 0) {
+ canvas.selection = index;
+ System.out.println("at deletePoint before deleteSelection");
+ canvas.deleteSelection();
+ index = envTimes.getSelectedIndex();
+ System.out.println("deletePoint new index " + index);
+ if (index >= 0) {
+ canvas.selection = index;
+ envAmplitudes.setText(form.format(canvas.amps.get(index)));
+ }
+ canvas.repaint();
+ }
+ } else if (actionCommand.equals("addPoint")) {
+ String text = (String) envTimes.getSelectedItem();
+ if (text.equals("")) return;
+ double time = Double.parseDouble(text.trim());
+ text = envAmplitudes.getText();
+ double amp = Double.parseDouble(text.trim());
+ canvas.insertInOrder(time, amp);
+ canvas.repaint();
+ } else if (actionCommand.equals("updatePoint")) {
+ String text = (String) envTimes.getSelectedItem();
+ if (text.equals("")) return;
+ double time = Double.parseDouble(text.trim());
+ text = envAmplitudes.getText();
+ double amp = Double.parseDouble(text.trim());
+ System.out.println("updatePoint selection " + canvas.selection);
+ canvas.deleteSelection();
+ canvas.insertInOrder(time, amp);
+ canvas.repaint();
+ } else if (actionCommand.equals("envTimeChange")) {
+ // sometimes this action gets called in the middle of
+ // doing an update and in an inconsistent state. If this
+ // happens, don't try to set amplitude text.
+ if (canvas.amps.size() != envTimes.getItemCount()) return;
+ int index = envTimes.getSelectedIndex();
+ System.out.println("envTimeChange " + index);
+ if (index >= 0) {
+ canvas.selection = index;
+ envAmplitudes.setText(form.format(canvas.amps.get(index)));
+ canvas.repaint(); // update selection marker
+ }
+ } else {
+ System.out.println("ACTION NOT HANDLED: " + actionCommand);
+ }
+ }
+
+ public void loadEnvData(String data) {
+ data = data.toLowerCase();
+ System.out.println("loadEnvData: data |" + data + "| len " + data.length());
+ envName.removeAllItems(); // clear and reload combo box
+ envTimes.removeAllItems(); // clear times
+ envAmplitudes.setText(""); // clear amplitude box
+ while (data.length() > 0) {
+ int eolx = data.indexOf("\n");
+ if (eolx < 0) return; // shouldn't happen, but bail if it does
+ String line = data.substring(0, eolx);
+ System.out.println("loadEnvData: line " + line);
+ data = data.substring(eolx + 1);
+ String name = line.substring(0, line.indexOf(' '));
+ System.out.println("loadEnvData: name " + name);
+ String env = line.substring(name.length() + 1);
+ System.out.println("loadEnvData: env " + env);
+ if (name.length() > 0) envColl.put(name, env);
+ envName.addItem(name);
+ }
+ }
+
+ private class State {
+ public int type;
+ public double maxT;
+ public double minA;
+ public double maxA;
+
+ public State(int t, double stop, double low, double hi) {
+ type = t; maxT = stop; minA = low; maxA = hi;
+ }
+ }
+
+ private class History {
+ /* consider a sequence of undo/redo to be a single edit operation -- thus
+ * the end of the versions list is set to the latest undo/redo selection
+ */
+ private boolean undoRedo = false;
+ private Vector<Vector<Double>> t_history = new Vector<Vector<Double>>();
+ private Vector<Vector<Double>> a_history = new Vector<Vector<Double>>();
+ private Vector<State> state_history = new Vector<State>();
+ private int version = -1;
+
+ public void save(PiecewiseCanvas canvas) {
+ t_history.add((Vector<Double>) (canvas.times.clone()));
+ a_history.add((Vector<Double>) (canvas.amps.clone()));
+ state_history.add(new State(canvas.type, getMaxT(),
+ getMinA(), getMaxA()));
+ version = t_history.size() - 1;
+ System.out.println("Saved version " + version);
+ undoRedo = false; /* clear flag for next undoRedo sequence */
+ }
+
+ public boolean canGet() {
+ boolean result = version >= 0 && version < t_history.size();
+ System.out.println("canGet returns " + result + " version " +
+ version);
+ return result;
+ }
+
+ public Vector<Double> getTimes() { return t_history.get(version); }
+ public Vector<Double> getAmps() { return a_history.get(version); }
+ public State getState() { return state_history.get(version); }
+
+ private void processUndoRedo() {
+ if (!undoRedo) { /* extend with copy of the version */
+ t_history.add((Vector<Double>) (t_history.get(version).clone()));
+ a_history.add((Vector<Double>) (a_history.get(version).clone()));
+ state_history.add(state_history.get(version));
+ } else { /* replace with different version */
+ t_history.set(t_history.size() - 1,
+ (Vector<Double>) (t_history.get(version).clone()));
+ a_history.set(t_history.size() - 1,
+ (Vector<Double>) (a_history.get(version).clone()));
+ state_history.set(state_history.size() - 1,
+ state_history.get(version));
+ }
+ undoRedo = true;
+ }
+
+ public void undo() {
+ if (version > 0) {
+ version--;
+ processUndoRedo();
+ }
+ }
+ public void redo() {
+ if (version < t_history.size() - 1) {
+ version++;
+ processUndoRedo();
+ }
+ }
+ }
+
+
+ // Class for the drawing area
+ //private class PiecewiseCanvas extends Canvas implements MouseListener,
+ private class PiecewiseCanvas extends JPanel implements MouseListener,
+ MouseMotionListener, KeyListener {
+ private int currentAmp;
+ private int currentTime;
+ public BufferedImage image = null;
+ public boolean selectCheck = false;
+ public int selection;
+ public History history;
+
+ private boolean mouseDown = false; // used to detect version for undo
+ private boolean changed = false; // used to detect version for undo
+
+ // Vectors to store the absolute parameters of the points in the
+ // envelope.
+ public Vector<Double> times = new Vector<Double>();
+ public Vector<Double> amps = new Vector<Double>();
+ public int type = PWL_TYPE; /* PWL_TYPE or PWE_TYPE */
+
+ // Constructor
+ public PiecewiseCanvas() {
+ setBackground(Color.white);
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ addKeyListener(this);
+ selection = -1;
+ history = new History();
+ history.save(this);
+ }
+
+ public boolean isValueType() {
+ if (times.size() == 0) return false;
+ return (times.get(0) == 0 ||
+ within(times.lastElement(), getMaxT(), EPSILON));
+ }
+
+ public boolean isImpliedFirstPoint() {
+ return (times.size() == 0) ||
+ !within(times.get(0), 0, EPSILON);
+ }
+
+ public boolean isImpliedLastPoint() {
+ return (times.size() == 0) ||
+ !within(times.lastElement(), getMaxT(), EPSILON);
+ }
+
+ // Allow JPanel to accept keyboard events
+ public boolean isFocusable() {
+ return true;
+ }
+
+ //try to make the canvas the correct size
+ public Dimension getMinimumSize() {
+ return new Dimension(0, 0);
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(575, 256);
+ }
+
+ public double impliedAmp() {
+ return (type == PWL_TYPE ? 0.0 : 1.0);
+ }
+
+
+ /*
+ public Dimension getMaximumSize() {
+ return getPreferredSize();
+ }*/
+
+ // draw the graphics inside the full canvas, so use these
+ // functions to get the size and coordinates of the drawing
+ // area that is usable
+ private int graphLeft() { return LEFT_BORDER; }
+ private int graphRight() { return getWidth() - RIGHT_BORDER; }
+ private int graphWidth() { return getWidth() -
+ (LEFT_BORDER + RIGHT_BORDER); }
+ private int graphTop() { return TOP_BORDER; }
+ private int graphBottom() { return getHeight() - BOTTOM_BORDER; }
+ private int graphHeight() { return getHeight() -
+ (TOP_BORDER + BOTTOM_BORDER); }
+ private int clipX(int x) {
+ return Math.max(LEFT_BORDER, Math.min(graphRight(), x)); }
+ private int clipY(int y) {
+ return Math.max(BOTTOM_BORDER, Math.min(graphBottom(), y)); }
+
+ public String getExpression() {
+ boolean valueType = isValueType();
+ String env;
+
+ if (type == PWL_TYPE) env = (valueType ? "pwlv" : "pwl");
+ else env = (valueType ? "pwev" : "pwe");
+
+ return outputEnv(env, valueType, 0.0, // getMinT(),
+ getMaxT(), getMinA(), getMaxA());
+ }
+
+
+ //draw the canvas image
+ public void paint(Graphics g) {
+ super.paint(g);
+ // test: g.drawLine(0, 0, 100, 100);
+
+ Graphics2D drawArea = (Graphics2D) g;
+ canvas.drawCircles(drawArea);
+ canvas.drawSelectionCircle(drawArea);
+ canvas.connectTheDots(drawArea);
+ drawArea.dispose();
+ }
+
+ //erase the canvas, then draw all of the points in the envelope
+ private void drawCircles(Graphics2D g) {
+ //erase the previous image
+ //clearCanvas(g);
+ double maxTime = getMaxT();
+
+ // is the initial point implicit?
+ if (isImpliedFirstPoint()) { // implied
+ double amp = impliedAmp();
+ int y = amp2y(amp);
+ // System.out.println("implied: amp " + amp + " y " + y);
+ drawDot(g, graphLeft(), y);
+ if (displayCoord) {
+ g.drawString("(0," + form.format(amp) + ")",
+ graphLeft(), y - 3);
+ }
+ }
+
+ // is the final point implicit?
+ if (isImpliedLastPoint()) {
+ double amp = impliedAmp();
+ int y = amp2y(amp);
+ drawDot(g, graphRight(), y);
+ if (displayCoord) {
+ g.drawString("(" + form.format(getMaxT()) + "," +
+ form.format(amp) + ")", graphWidth() - 36,
+ y - 9);
+ }
+ }
+
+ //draw points for each point in the envelope
+ for (int i = 0; i < times.size(); i++) {
+ int t = time2x(times.get(i));
+ int a = amp2y(amps.get(i));
+ if (displayCoord)
+ g.drawString("(" + form.format(times.get(i)) + "," +
+ form.format(amps.get(i)) + ")", t, a);
+ drawDot(g, t, a);
+ //System.out.println("drawDot t " + t + " a " + a + " width " +
+ // getWidth());
+ }
+ }
+
+ //given coordinates, draw a circle on the canvas
+ private void drawDot(Graphics2D g, int t, int a) {
+ //draw a black circle at the specified point
+ g.setColor(Color.black);
+ //System.out.println("drawDot: " + t + "," + a);
+ g.fillOval(t - 2, a - 2, 5, 5);
+ }
+
+ // given coordinates, draw a circle around selected envelope point
+ private void drawSelectionCircle(Graphics2D g) {
+ if (selection >= 0 && selection < times.size()) {
+ int t = time2x(times.get(selection));
+ int a = amp2y(amps.get(selection));
+ //draw a red circle around the specified point
+ g.setColor(Color.red);
+ g.drawOval(t - 4, a - 4, 9, 9);
+ }
+ }
+
+ private void draw_connect(Graphics2D g, double t1, double a1,
+ double t2, double a2) {
+ int x1 = time2x(t1);
+ int x2 = time2x(t2);
+ int y1 = amp2y(a1);
+ int y2 = amp2y(a2);
+ if (type == PWL_TYPE) {
+ g.drawLine(x1, y1, x2, y2);
+ } else {
+ // pwe type, graph is linear along a log scale
+ if (a1 <= EPSILON || a2 <= EPSILON) {
+ g.drawLine(x1, y1, x1, graphBottom());
+ g.drawLine(x1, graphBottom(), x2, graphBottom());
+ g.drawLine(x2, graphBottom(), x2, y2);
+ } else {
+ double log1 = Math.log(a1);
+ double log2 = Math.log(a2);
+ int startline = y1;
+ double logIncr = (log2 - log1) / (x2 - x1);
+ for (int j = x1 + 1; j <= x2; j++) {
+ double loga = log1 + logIncr * (j - x1);
+ int a = amp2y(Math.exp(loga));
+ g.drawLine(j - 1, startline, j, a);
+ startline = a;
+ }
+ }
+ }
+ }
+
+ //connect adjacent points in the envelope by lines (pwl, pwlv) or by an
+ // exponential curve (pwe, pwev)
+ private void connectTheDots(Graphics2D g) {
+ g.setColor(Color.blue);
+ // System.out.println("connectTheDots\n");
+ if (times.size() > 0) {
+ if (isImpliedFirstPoint()) {
+ draw_connect(g, 0, impliedAmp(),
+ times.get(0), amps.get(0));
+ }
+ if (isImpliedLastPoint()) {
+ draw_connect(g, times.lastElement(),
+ amps.lastElement(),
+ getMaxT(), impliedAmp());
+ }
+ //connect the non-endpoints in the envelope
+ double t1 = times.get(0);
+ double a1 = amps.get(0);
+ for (int i = 0; i < times.size() - 1; i++) {
+ double t2 = times.get(i + 1);
+ double a2 = amps.get(i + 1);
+ draw_connect(g, t1, a1, t2, a2);
+ t1 = t2;
+ a1 = a2;
+ }
+ } else { // size == 0, so both points are implied
+ draw_connect(g, 0, impliedAmp(), getMaxT(), impliedAmp());
+ }
+
+ }
+
+ // erase the canvas and clear the parameter vectors -
+ // completely reset the envelope
+ public void clear() {
+ if (times != null)
+ times.removeAllElements();
+ if (amps != null)
+ amps.removeAllElements();
+ envTimes.removeAllItems();
+ modified = true;
+ repaint();
+ history.save(this);
+ }
+
+ public void restore() {
+ if (history.canGet()) {
+ times = (Vector<Double>) (history.getTimes().clone());
+ amps = (Vector<Double>) (history.getAmps().clone());
+ State state = history.getState();
+ type = state.type;
+ maxT.setText(String.valueOf(state.maxT));
+ minA.setText(String.valueOf(state.minA));
+ maxA.setText(String.valueOf(state.maxA));
+ envTypes.setSelectedItem(types[type]);
+ selection = -1;
+ // put times in combo box
+ envTimes.removeAllItems();
+ for (int i = 0; i < times.size(); i++) {
+ envTimes.insertItemAt(form.format(times.get(i)), i);
+ }
+ envAmplitudes.setText("");
+ repaint();
+ }
+ }
+
+ //set time and amplitude on click by inserting the point into the vectors.
+ // if delete is checked, try to delete a point from the envelope
+ public void mousePressed(MouseEvent e) {
+ mouseDown = true;
+ System.out.println("mouseDown true\n");
+ this.requestFocus();
+ currentTime = e.getX();
+ currentAmp = e.getY();
+ selectCheck = checkSelection(currentTime, currentAmp);
+ if (selectCheck) {
+ return;
+ }
+ insertInOrder(x2time(currentTime), y2amp(currentAmp));
+ repaint();
+ }
+
+ public void mouseDragged(MouseEvent e) {
+ currentTime = clipX(e.getX());
+ currentAmp = clipY(e.getY());
+ if (currentTime <= graphRight() && currentTime >= graphLeft() &&
+ currentAmp >= graphTop() && currentAmp <= graphBottom()) {
+ deleteSelection();
+ insertInOrder(x2time(currentTime), y2amp(currentAmp));
+ repaint();
+ }
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ System.out.println("mouseReleased\n");
+ if (changed) {
+ history.save(this);
+ changed = false;
+ }
+ mouseDown = false;
+ System.out.println("mouseDown false\n");
+ }
+
+ // convert time coordinate to time in seconds
+ private double x2time(int x) {
+ return (x - graphLeft()) * getMaxT() / graphWidth();
+ }
+
+ private int time2x(double time) {
+ int x = (int) Math.round(time * graphWidth() / getMaxT()) +
+ graphLeft();
+ return x;
+ }
+
+ // convert amp coordinate to real amplitude
+ private double y2amp(int y) {
+ double maxAmp = getMaxA();
+ double aRange = maxAmp - getMinA();
+ double amp = maxAmp - ((y - graphTop()) * aRange / graphHeight());
+ return amp;
+ }
+
+ private int amp2y(double amp) {
+ double maxAmp = getMaxA();
+ double aRange = maxAmp - getMinA();
+ int y = (int) Math.round((maxAmp - amp) * graphHeight() / aRange) +
+ graphTop();
+ // System.out.println("amp2y: amp " + amp + " y " + y);
+ return y;
+ }
+
+ private void deleteSelection() {
+ if (selection < 0 || selection >= times.size()) return;
+ times.remove(selection);
+ amps.remove(selection);
+ modified = true;
+ System.out.println("deleteSelection at " + selection);
+ envTimes.removeItemAt(selection);
+ // make the Amp: box correspond to the new selection:
+ String amp = "";
+ if (times.size() > 0) {
+ int index = envTimes.getSelectedIndex();
+ if (index >= 0) amp = form.format(amps.get(index));
+ }
+ envAmplitudes.setText(amp);
+ selection = -1;
+ if (!mouseDown) history.save(this);
+ }
+
+ private void addPoint(int i, double absT, double absA) {
+ System.out.println("addPoint: " + i + " " + absT + " " + absA);
+ times.add(i, absT);
+ amps.add(i, absA);
+ envTimes.insertItemAt(form.format(absT), i);
+ System.out.println("addPoint time: " + absT + ", text " + form.format(absT));
+ envTimes.setSelectedIndex(i);
+ envAmplitudes.setText(form.format(amps.get(i)));
+ selection = i;
+ changed = true;
+ if (!mouseDown) history.save(this);
+ }
+
+ //insert the time and amplitude in the vectors in time sorted order
+ private void insertInOrder(double time, double amp) {
+ int i = 0;
+ modified = true;
+ if (times != null) {
+ while (i < times.size() && time > times.get(i)) i++;
+ }
+ addPoint(i, time, amp);
+ // System.out.println("absT: " + absT + " absA: " + absA + " i: " + i);
+ return;
+ }
+
+ // Check if mouse click corresponds to existing envelope point
+ // return index of point or -1 if no point is close
+ private int getSelection(int x, int y) {
+ int cutoff = 7;
+ int bestDist = cutoff * 2;
+ int bestIndex = -1;
+ if (times == null) return bestIndex;
+ for (int i = 0; i < times.size(); i++) {
+ int xi = time2x(times.get(i));
+ int yi = amp2y(amps.get(i));
+ int dx = Math.abs(x - xi);
+ int dy = Math.abs(y - yi);
+ if (dx < cutoff && dy < cutoff && dx + dy < bestDist) {
+ bestDist = dx + dy;
+ bestIndex = i;
+ }
+ }
+ selection = bestIndex;
+ return bestIndex;
+ }
+
+ //Check if mouse click corresponds with existing envelope point (to select point)
+ private boolean checkSelection(int time, int amp) {
+ int i = getSelection(time, amp);
+ if (i < 0) return false;
+ envTimes.setSelectedIndex(i);
+ envAmplitudes.setText(form.format(amps.get(i)));
+ repaint();
+ return true;
+ }
+
+ //output the envelope as a string
+ public String outputEnv(String envType, boolean valueType,
+ double minTime, double maxTime, double minAmp,
+ double maxAmp) {
+ String outputStr = new String();
+ int start = 0;
+
+ outputStr += ("(" + envType + " ");
+
+ if (valueType) { // insert initial value
+ if (within(times.get(0), 0.0, EPSILON)) {
+ outputStr += (form.format(amps.get(0)) + " ");
+ start = 1;
+ } else outputStr += form.format(impliedAmp()) + " ";
+ }
+
+ for (int i = start; i < amps.size(); i++) {
+ double time = times.get(i);
+ double amp = amps.get(i);
+ outputStr += form.format(time) + " " + form.format(amp) + " ";
+ }
+
+ if (valueType) { // we're already ending with a value
+ if (within(times.lastElement(), maxTime, EPSILON)) {
+ // we're done because we output at maxTime
+ } else {
+ outputStr += form.format(maxTime) + " " +
+ form.format(impliedAmp());
+ }
+ } else {
+ outputStr += form.format(maxTime);
+ }
+ outputStr += ")";
+
+ return outputStr;
+ }
+
+ // parse envelope from string and prepare to edit
+ public void setEnv(String envData) {
+
+ System.out.println("setEnv: envData " + envData);
+ if (envData == null) return; // just in case
+ //check if envelope exists in collection
+ boolean nameIsEnv = false;
+
+ // trim the open and close parens from envData
+ int startx = envData.indexOf("(") + 1;
+ // if no open paren, startx will be 0
+ int endx = envData.indexOf(")");
+ if (endx < 0) endx = envData.length();
+ envData = envData.substring(startx, endx);
+
+ System.out.println("setEnv: envData(2) " + envData);
+ StringTokenizer st = new StringTokenizer(envData);
+ String type = st.nextToken();
+ System.out.println("setEnv: type " + type);
+ envTypes.setSelectedItem(type);
+ //clear();
+
+ valueType = type.endsWith("v");
+ int limit = (valueType ? 2 : 1);
+ times.removeAllElements();
+ amps.removeAllElements();
+ int i = 0;
+ // pretend mouse is down to avoid making each point undo-able
+ boolean save = mouseDown;
+ mouseDown = false;
+ double time, amp;
+ if (valueType) { // first element is value
+ amp = new Double(st.nextToken().trim());
+ addPoint(i++, 0.0, amp);
+ }
+ while (st.countTokens() >= 2) {
+ String token1 = st.nextToken().trim();
+ time = new Double(token1);
+ String token2 = st.nextToken().trim();
+ amp = new Double(token2);
+ addPoint(i++, time, amp);
+ System.out.println("time " + token1 + " amp " + token2 +
+ " size " + times.size());
+ }
+ mouseDown = save; // restore the mouseDown state
+ if (!valueType) { // last element is time
+ maxT.setText(st.nextToken());
+ }
+ System.out.println("times " + times + " amps " + amps);
+ //calculateDraws(true);
+ modified = false;
+ repaint();
+ }
+
+ public void keyPressed(KeyEvent event) {
+ //Graphics2D drawArea = image.createGraphics();
+
+ if (event.getKeyCode() == KeyEvent.VK_DELETE) {
+ deleteSelection();
+ repaint();
+ }
+ }
+
+ //fill rest of mouse functions
+ public void mouseEntered(MouseEvent e) {}
+ public void mouseExited(MouseEvent e) {}
+ public void mouseClicked(MouseEvent e) {}
+ public void mouseMoved(MouseEvent e) {}
+ public void keyReleased(KeyEvent event) {}
+ public void keyTyped(KeyEvent event) {}
+ }
+}
diff --git a/jnyqide/FindDialog.java b/jnyqide/FindDialog.java
new file mode 100644
index 0000000..d67ec6c
--- /dev/null
+++ b/jnyqide/FindDialog.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1997 John Jensen. All rights reserved.
+ *
+ * This software is FREE FOR COMMERCIAL AND NON-COMMERCIAL USE,
+ * provided the following condition is met.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that any copy or derivative of this software or documentation
+ * retaining the name "John Jensen" also retains this condition and the
+ * following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
+ *
+ * CopyrightVersion 1.0
+ */
+
+package jnyqide;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import jnyqide.*;
+
+class FindDialog extends Dialog implements WindowListener, ActionListener
+{
+ private Button fbutton,cbutton;
+ private MainFrame mainFrame;
+ private NyquistFile nyquistFile;
+ private TextField pattern;
+ private Properties strings;
+
+ public FindDialog(NyquistFile tf, MainFrame mainFrame_)
+ {
+ super(mainFrame_, "Find", true);
+
+ setBackground(Color.lightGray);
+
+ nyquistFile = tf;
+ mainFrame = mainFrame_;
+
+ Panel p1 = new Panel();
+ p1.setLayout(new FlowLayout());
+ p1.add(new Label("Find:"));
+
+
+ pattern = new TextField();
+ pattern.setColumns(35);
+
+ if (tf.pane.getSelectedText() == null) // BWP
+ pattern.setText(mainFrame.findPattern);
+ else // BWP
+ pattern.setText(tf.pane.getSelectedText()); // BWP
+
+ p1.add(pattern);
+ p1.doLayout();
+ add("North", p1);
+
+ Panel p2 = new Panel();
+ fbutton = new Button("Find Next");
+ fbutton.addActionListener(this);
+ p2.add(fbutton);
+ cbutton = new Button("Close");
+ cbutton.addActionListener(this);
+ p2.add(cbutton);
+ add("South",p2);
+
+ Dimension size = new Dimension(400, 110);
+ setSize(size);
+ Point tfloc = tf.getLocation();
+ Point mfloc = mainFrame.getLocation();
+ setLocation(mfloc.x + tfloc.x,
+ mfloc.y + tfloc.y + 85);
+
+ addWindowListener(this);
+ setVisible(true);
+ }
+
+ public void windowDeiconified(WindowEvent event) {}
+ public void windowIconified(WindowEvent event) {}
+ public void windowActivated(WindowEvent event) {}
+ public void windowDeactivated(WindowEvent event) {}
+ public void windowOpened(WindowEvent event) {}
+ public void windowClosed(WindowEvent event) {}
+ public void windowClosing(WindowEvent event) {
+ mainFrame.findPattern = pattern.getText();
+ nyquistFile.lastFound = pattern.getText(); // BWP
+ dispose();
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ if (evt.getSource() == cbutton) {
+ mainFrame.findPattern = pattern.getText();
+ nyquistFile.lastFound = pattern.getText();
+ dispose();
+ return;
+ }
+
+ if (evt.getSource() == fbutton)
+ if (!nyquistFile.find(pattern.getText())) {
+ NotFoundDialog nf = new NotFoundDialog(mainFrame, strings,
+ getLocation());
+ nf.setVisible(true);
+ }
+ }
+
+}
diff --git a/jnyqide/InstrumentCharacteristics.java b/jnyqide/InstrumentCharacteristics.java
new file mode 100644
index 0000000..91fac84
--- /dev/null
+++ b/jnyqide/InstrumentCharacteristics.java
@@ -0,0 +1,364 @@
+package jnyqide;
+
+import java.util.ArrayList;
+import java.io.BufferedReader;
+
+/***
+** Class: InstrumentCharacteristics
+** Author: Priyanka Raghavan and Roger B. Dannenberg
+** Description: The instrument characteristics class reads from
+** the instruments.txt file and stores the
+** instrument characteristics such as the subcategory,name,library.
+** The characteristics include the implementation and parameter
+** description. The different parameters are added as an arraylist.
+*
+* Syntax for the instruments.txt file:
+* (see instruments.txt for examples, it should be clear)
+* Each sound is described by a function declaration preceded by
+* a category like this:
+* category:subcategory[function](parameters)
+* where category and subcategory determine what appears in the
+* pull-down lists in the browser, and function is the lisp
+* function to call (if omitted, then subcategory is also the
+* function name). parameters is a comma-separated list of
+* parameter declarations. Each parameter is of the form
+* type name = default (low:high)
+* where type is "int" or "float", name is the parameter name
+* (if the parameter is a keyword parameter, it is prefixed with
+* a colon), and low:high gives the range for a slider.
+* After the function declaration, there can be specifications for
+* the implementation of the function. There should be either
+* a pair of implementations for LISP and SAL, or a single
+* REQUIRE. The LISP and SAL implementation is specified as follows:
+* LISP-SOURCE
+* <any number of lines of LISP source code>
+* SAL-SOURCE
+* <any number of lines of SAL source code>
+* and the REQUIRE is specified as follows:
+* REQUIRE "path to implementation file to be loaded"
+* After the implementation specifications (if any), the
+* sound description is terminated by the following line:
+* END-SOUND
+* There may be any number of these sound specifications (instruments)
+* in the file.
+* When a user selects an instrument in the browser, the appropriate
+* implementation is constructed (using SAL-SOURCE or LISP-SOURCE if
+* present, otherwise using REQUIRE to load a file) and the function
+* is called with parameters chosen by sliders.
+*
+**/
+
+public class InstrumentCharacteristics {
+
+ private String categoryName;
+ private String subcategoryName;
+ private String functionName;
+ private ArrayList parameterList;
+ private String lispImplementation;
+ private String salImplementation;
+ private String require;
+
+ private static char buffer;
+ private static boolean bufferp;
+ private static String line;
+
+ InstrumentCharacteristics() {
+ bufferp = false;
+ parameterList = new ArrayList();
+ }
+
+ public String getCategoryName() { return categoryName; }
+
+ public void setCategoryName(String name) { categoryName = name; }
+
+ public void setSubcategoryName(String subname) {
+ subcategoryName = subname;
+ }
+
+ public String getSubcategoryName() { return subcategoryName; }
+
+ public String getFunctionName() { return functionName; }
+
+
+ public void addParameter(String name, String minValue, String maxValue,
+ String defaultValue, String type) {
+ Parameter parameter = new Parameter(name, minValue, maxValue,
+ defaultValue, type);
+ parameterList.add(parameter);
+ }
+
+ public ArrayList getParameters(){ return parameterList; }
+
+ public String getLispImplementation() { return lispImplementation; }
+
+ public String getSalImplementation() { return salImplementation; }
+
+ public String getRequire() { return require; }
+
+ public String readImplementation(BufferedReader br) throws Exception {
+ String implementation = "";
+ while ((line = br.readLine()) != null &&
+ line.indexOf("REQUIRE") != 0 &&
+ line.indexOf("LISP-SOURCE") != 0 &&
+ line.indexOf("SAL-SOURCE") != 0 &&
+ line.indexOf("END-SOUND") != 0) {
+ implementation = implementation + line + "\n";
+ }
+ return implementation;
+ }
+
+ public boolean readData(BufferedReader br) {
+ categoryName = getToken(br); // category
+ if (categoryName == null) return false;
+ if (getNonSpace(br) != ':') {
+ System.out.println("expected : after " + categoryName);
+ return false;
+ }
+ subcategoryName = getToken(br);
+ int c = getNonSpace(br);
+ functionName = subcategoryName;
+ if (c == '[') {
+ functionName = getToken(br);
+ if (getNonSpace(br) != ']') {
+ System.out.println("expected ] after " + functionName);
+ return false;
+ }
+ } else ungetChar(c);
+ if (getNonSpace(br) != '(') {
+ System.out.println("no ( after " + functionName);
+ return false;
+ }
+ while ((c = getNonSpace(br)) != ')') {
+ ungetChar(c);
+ Parameter p = readParameter(br);
+ if (p == null) {
+ System.out.println("syntax error for parameter in " +
+ subcategoryName);
+ return false;
+ }
+ parameterList.add(p);
+ }
+ // get a file to load or an implementation to execute
+ require = null;
+ lispImplementation = null;
+ salImplementation = null;
+ try {
+ // read eol after function spec
+ line = br.readLine();
+ line = ""; // force a readline on first entry to loop
+ while (true) {
+ while (line != null && line.length() < 3) {
+ // skip blank lines -- we're not checking too carefully
+ // but a char count of 3 allows only CRLF and maybe a
+ // space or tab
+ line = br.readLine();
+ }
+ if (line == null) {
+ System.out.println(
+ "expected LISP-SOURCE or SAL-SOURCE, REQUIRE or " +
+ "END-SOUND, not " + line);
+ return false;
+ }
+
+ int reqPos = line.indexOf("REQUIRE");
+ if (reqPos >= 0) {
+ reqPos += 8; // length of "REQUIRE "
+ require = line.substring(reqPos, line.length());
+ line = br.readLine();
+ } else if (line.indexOf("LISP-SOURCE") == 0) {
+ // read until LISP-END
+ lispImplementation = readImplementation(br);
+ } else if (line.indexOf("SAL-SOURCE") == 0) {
+ // read until SAL-END
+ salImplementation = readImplementation(br);
+ } else if (line.indexOf("END-SOUND") == 0) {
+ return true;
+ } else {
+ System.out.println(
+ "expected REQUIRE, LISP-SOURCE, SAL-SOURCE, or " +
+ "END-SOUND, not " + line);
+ return false;
+ }
+ }
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ private Parameter readParameter(BufferedReader br) {
+ Parameter p = new Parameter();
+ String tok = getToken(br);
+ if (tok == null) {
+ System.out.println("expected parameter type: " + tok);
+ return null;
+ }
+ p.setType(tok);
+ int param1 = getNonSpace(br);
+ if (param1 != ':') {
+ ungetChar(param1);
+ }
+ tok = getToken(br);
+ if (tok == null) {
+ System.out.println("expected parameter name: " + tok);
+ return null;
+ }
+ if (param1 == ':') tok = ":" + tok;
+ p.setName(tok);
+
+ if (getNonSpace(br) != '=') {
+ System.out.println("expected = after parameter: " + tok);
+ return null;
+ }
+
+ tok = getToken(br);
+ if (tok == null) {
+ System.out.println("expected default value: " + tok);
+ return null;
+ }
+ p.setDefaultValue(tok);
+
+ if (getNonSpace(br) != '(') {
+ System.out.println("expected ( after default value: " + tok);
+ return null;
+ }
+
+ tok = getToken(br);
+ if (tok == null) {
+ System.out.println("expected min value: " + tok);
+ return null;
+ }
+ p.setMinValue(tok);
+
+ if (getNonSpace(br) != ':') {
+ System.out.println("expected : after min value: " + tok);
+ return null;
+ }
+
+ tok = getToken(br);
+ if (tok == null) {
+ System.out.println("expected max value: " + tok);
+ return null;
+ }
+ p.setMaxValue(tok);
+
+ if (getNonSpace(br) != ')') {
+ System.out.println("expected ) after max value: " + tok);
+ return null;
+ }
+
+ int c = getNonSpace(br);
+ if (c != ',') ungetChar(c);
+
+ return p;
+ }
+
+ private int getNonSpace(BufferedReader br) {
+ int c;
+ while ((c = getChar(br)) != -1 && Character.isWhitespace(c));
+ return c;
+ }
+
+ private int getChar(BufferedReader br) {
+ if (bufferp) {
+ bufferp = false;
+ return buffer;
+ }
+ try {
+ return br.read();
+ } catch (Exception e) {
+ return -1;
+ }
+ }
+
+ private void ungetChar(int c) {
+ if (c == -1) return; // ignore EOF
+ buffer = (char) c;
+ bufferp = true;
+ }
+
+ private String getToken(BufferedReader br) {
+ int c = getNonSpace(br);
+ StringBuffer token = new StringBuffer();
+ while (c != -1 && (Character.isLetterOrDigit(c) ||
+ c == '-' || c == '.')) {
+ token.append((char) c);
+ c = getChar(br);
+ }
+ ungetChar(c);
+ String s = new String(token);
+ if (s.length() == 0) return null;
+ // System.out.println("gettoken: " + token);
+ return s;
+ }
+}
+
+
+/**
+ ** Class: Parameter
+ ** Author: Priyanka Raghavan
+ ** Description: This class is used to store parameter values like
+ ** name, minvalue, maxvalue, default value, and type (integer,string, etc.)
+ **
+ **/
+
+class Parameter{
+ String name;
+ String minValue;
+ String maxValue;
+ String defaultValue;
+ String type;
+ float value;
+
+ Parameter() { }
+
+ Parameter(String name, String minValue, String maxValue,
+ String defaultValue, String type) {
+ this.name = name;
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ this.defaultValue = defaultValue;
+ this.type=type;
+ value = 0.0f;
+ }
+
+ public void setName(String name) {
+ this.name=name;
+ }
+
+ public void setMinValue(String value) {
+ minValue = value;
+ }
+
+ public void setMaxValue(String value) {
+ maxValue = value;
+ }
+
+ public void setDefaultValue(String defaultvalue) {
+ defaultValue = defaultvalue;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getMinValue() {
+ return minValue;
+ }
+
+ public String getMaxValue() {
+ return maxValue;
+ }
+
+ public String getType() { return type; }
+
+ public void setType(String type) { this.type = type; }
+
+ public String getDefaultValue() { return defaultValue; }
+
+ public float getValue() { return value; }
+
+ public void setValue(float f) { value = f; }
+
+}
+
+
diff --git a/jnyqide/Jslide.java b/jnyqide/Jslide.java
new file mode 100755
index 0000000..fb68b12
--- /dev/null
+++ b/jnyqide/Jslide.java
@@ -0,0 +1,201 @@
+package jnyqide;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.event.*;
+import java.util.*;
+
+public class Jslide extends JFrame implements ActionListener {
+ MainFrame myParent;
+ static final int numSliders = 8;
+ static final int numEqualizers = 10;
+ /* Sliders and labels that will be used on the gui*/
+ JSlider[] js;
+ float[][] eqState;
+
+ /* Buttons that will appear on the Equalizer*/
+ JButton setEqValue = new JButton("Set");
+ JButton loadEqValue = new JButton("Load");
+ JButton restore = new JButton("Reset");
+ JComboBox eqList = new JComboBox();
+ JPanel p1 = new JPanel();
+ JPanel GraphEqPanel;
+ String extension = "";
+ // Create text fields to display slider position
+ String[] labels = {"84", "167", "330", "652", "1.3k", "2.5k", "5k", "10k"};
+ JLabel[] jlabels;
+ boolean modified = false;
+
+ public Jslide(MainFrame parent)
+ {
+ myParent = parent;
+ /*Open the file and set sliders to the default*/
+ //fileName = "eq" + extension + ".dat";
+ //setAllSliders(fileName);
+
+ /* Action listener for the restore button. This
+ * restores all slider values to zero. Right now
+ * this has no effect on the file itself.
+ */
+ js = new JSlider[numSliders];
+ eqState = new float[numEqualizers][numSliders];
+ for (int i = 0; i < numSliders; i++) {
+ js[i] = initializeSlider();
+ for (int j = 0; j < numEqualizers; j++) eqState[j][i] = 0;
+ }
+
+ setEqValue.addActionListener(this);
+ setEqValue.setActionCommand("set-eq-value");
+ loadEqValue.addActionListener(this);
+ loadEqValue.setActionCommand("load-eq-value");
+
+ restore.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ System.out.println("reset listener");
+ for (int i = 0; i < numSliders; i++) {
+ js[i].setValue(0);
+ }
+ }
+ }
+ );
+
+ /*Create individual Panels to be added to the Pane*/
+
+ /* Slider panel*/
+ p1.setBackground(Color.WHITE);
+ p1.setSize(500,300);
+ p1.setLayout(new GridLayout(1, 8));
+ /* Panel with all the labels*/
+ JPanel p2 = new JPanel();
+ p2.setBackground(Color.WHITE);
+ p2.setLayout(new GridLayout(1, 8));
+ /* add the sliders and labels */
+ jlabels = new JLabel[numSliders];
+ for (int i = 0; i < numSliders; i++) {
+ p1.add(js[i]);
+ jlabels[i] = new JLabel(labels[i]);
+ p2.add(jlabels[i]);
+ }
+ /* Combo box with a liste of numbers of equalizer values*/
+ String[] eqNums = {"0","1", "2", "3", "4","5","6","7","8","9"};
+ eqList = new JComboBox(eqNums);
+ eqList.addActionListener(this);
+ eqList.setActionCommand("eq-selection");
+
+ /*Panel the buttons, and the combo box on it*/
+ JPanel pA = new JPanel();
+ pA.setLayout(new GridLayout(1,4));
+ pA.setBackground(Color.WHITE);
+ pA.add(setEqValue);
+ pA.add(loadEqValue);
+ pA.add(restore);
+ pA.add(eqList);
+
+ pA.setSize(50,50);
+
+ GraphEqPanel = new JPanel();
+ GraphEqPanel.setLayout(new BorderLayout());
+ GraphEqPanel.setBackground(Color.WHITE);
+ GraphEqPanel.setSize(300,300);
+ GraphEqPanel.add(p1, BorderLayout.NORTH);
+ GraphEqPanel.add(p2, BorderLayout.CENTER);
+ GraphEqPanel.add(pA, BorderLayout.SOUTH);
+
+ loadEqValue();
+ } //Close constructor
+
+ public void actionPerformed(ActionEvent e) {
+ String command = e.getActionCommand();
+ if (command.equals("eq-selection")) {
+ equalizerSelected();
+ } else if (command.equals("set-eq-value")) {
+ setEqValue();
+ } else if (command.equals("load-eq-value")) {
+ loadEqValue();
+ }
+ }
+
+ public void equalizerSelected() {
+ String name = (String) eqList.getSelectedItem();
+ int index = new Integer(name);
+ // load values from state
+ for (int i = 0; i < numSliders; i++) {
+ js[i].setValue((int) eqState[index][i]);
+ }
+ }
+
+ public void setEqValue() {
+ // store slider values into state
+ String name = (String) eqList.getSelectedItem();
+ int index = new Integer(name);
+ // store value into state
+ String definition = "(define-eq " + name + " #(";
+ for (int i = 0; i < numSliders; i++) {
+ eqState[index][i] = js[i].getValue();
+ definition += (" " + eqState[index][i]);
+ }
+ definition += "))\n\n";
+ myParent.sendInput(definition);
+ }
+
+ public void loadEqValue() {
+ myParent.callFunction("get-eq-data", "");
+ }
+
+ /**
+ * Public function that returns the graphic equalizer panel
+ * @return
+ */
+ public JPanel getGraphEq() {
+ return GraphEqPanel;
+ }
+
+ /**The getter for the GUI sliders
+ * @return db value as an int
+ */
+ private int get_db_val(JSlider j){
+ return j.getValue();
+ }
+
+ /**
+ * A Private method that will initialize the sliders. This is
+ * to clean up the code and make it shorter.
+ * @param j
+ */
+ private JSlider initializeSlider() {
+ JSlider j = new JSlider(JSlider.VERTICAL, -15,15,0);
+ j.setMajorTickSpacing(10);
+ j.setMinorTickSpacing(2);
+ j.setPaintTicks(true);
+ j.setPaintLabels(true);
+ j.setForeground(Color.BLACK);
+ j.setBorder(BorderFactory.createEtchedBorder());
+ return j;
+ }
+
+ public void loadEqData(String data) {
+ System.out.println("loadEqData " + data);
+ while (true) {
+ int i = data.indexOf("\n");
+ if (i < 0) {
+ equalizerSelected(); // load sliders from eqState
+ return;
+ }
+ String line = data.substring(0, i);
+ System.out.println("loadEqData line " + line);
+ data = data.substring(i + 1);
+ // string has 9 numbers
+ StringTokenizer st = new StringTokenizer(line);
+ String name = st.nextToken();
+ int index = new Integer(name);
+ for (i = 0; i < numSliders; i++) {
+ eqState[index][i] = new Float(st.nextToken());
+ }
+ }
+ }
+}
+
+
+
diff --git a/jnyqide/LispFileFilter.java b/jnyqide/LispFileFilter.java
new file mode 100644
index 0000000..219c7af
--- /dev/null
+++ b/jnyqide/LispFileFilter.java
@@ -0,0 +1,33 @@
+package jnyqide;
+
+import javax.swing.filechooser.*;
+import java.io.File;
+
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+public class LispFileFilter extends FileFilter {
+
+ public LispFileFilter() {
+ }
+
+ public boolean accept(File f) {
+ if (f.getName().endsWith(".lsp")) return true;
+ for (int x = 0; x < f.getName().length(); x++) {
+ if ((f.getName().charAt(x) == '.'))
+ return false;
+ }
+ return true;
+ }
+
+ public String getDescription() {
+ return "Lisp files.";
+ }
+}
diff --git a/jnyqide/Main.java b/jnyqide/Main.java
new file mode 100644
index 0000000..6ff6fe9
--- /dev/null
+++ b/jnyqide/Main.java
@@ -0,0 +1,75 @@
+package jnyqide;
+
+import javax.swing.UIManager;
+import java.awt.*;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+public class Main {
+ boolean packFrame = false;
+
+ //Construct the application
+ public Main() {
+ String osName = System.getProperty("os.name");
+ System.out.println(osName);
+ if (osName.startsWith("Linux")) {
+ // motif style has some extra buttons to iconify internal frames
+ // but this obscures windows, and metal looks better anyway
+ try {
+ UIManager.setLookAndFeel(
+ "javax.swing.plaf.metal.MetalLookAndFeel");
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+ MainFrame frame = new MainFrame();
+ //Validate frames that have preset sizes
+ //Pack frames that have useful preferred size info, e.g. from their layout
+ if (packFrame) {
+ frame.pack();
+ } else {
+ frame.validate();
+ }
+ //Center the window
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension frameSize = frame.getSize();
+ // subtract 20 here because otherwise Mac OS X frames will be too tall
+ // to access resize nbutton
+ System.out.print("initial frame height ");
+ System.out.println(frameSize.height);
+ System.out.print("screen height ");
+ System.out.println(screenSize.height);
+ if (frameSize.height > screenSize.height) {
+ frameSize.height = screenSize.height - 40;
+ }
+ if (frameSize.width > screenSize.width) {
+ frameSize.width = screenSize.width;
+ }
+ System.out.print("finall frame height ");
+ System.out.println(frameSize.height);
+ frame.setSize(frameSize);
+ frame.setLocation((screenSize.width - frameSize.width) / 2,
+ (screenSize.height - frameSize.height) / 2);
+ frame.setVisible(true);
+ frame.tileCompletion();
+ }
+
+
+ //Main method
+ public static void main(String[] args) {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ new Main();
+ }
+}
diff --git a/jnyqide/MainFrame.java b/jnyqide/MainFrame.java
new file mode 100644
index 0000000..04f924d
--- /dev/null
+++ b/jnyqide/MainFrame.java
@@ -0,0 +1,1539 @@
+package jnyqide;
+
+import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.*;
+import java.beans.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.event.*;
+import javax.swing.undo.*;
+import javax.swing.text.html.*;
+// import javax.swing.JOptionPane.*;
+import javax.swing.filechooser.FileFilter;
+import java.io.*;
+import jnyqide.*;
+// this won't work on non-Mac, so use reflection tricks below
+// import com.apple.mrj.*; // import Mac menu support
+import java.lang.reflect.*; // import Constructor class
+import java.util.prefs.*;
+import java.util.Collection;
+import java.net.URL;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+class ScrollUpdate implements Runnable {
+ MainFrame frame;
+
+ ScrollUpdate(MainFrame mainframe) {
+ frame = mainframe;
+ }
+
+ public void run() {
+ frame.ScrollToEnd();
+ }
+}
+
+
+public class MainFrame extends JFrame {
+ JPanel contentPane;
+ JMenuBar jMenuBar1 = new JMenuBar();
+
+ JMenu jMenuFile = new JMenu();
+ JMenu jMenuEdit = new JMenu();
+ JMenu jMenuProcess = new JMenu();
+ JMenu jMenuWindow = new JMenu();
+ JMenu jMenuHelp = new JMenu();
+
+ JToolBar jToolBar = new JToolBar();
+ float test_value = 0.0F;
+ ImageIcon image1;
+ ImageIcon image2;
+ ImageIcon image3;
+ public JLabel statusBar = new JLabel();
+ JButton salLispButton;
+ BorderLayout borderLayout1 = new BorderLayout();
+ JDesktopPane jDesktop;
+ public CodePane jScrollPane;
+ // accessed by CodePane sometimes:
+ public JTextArea jOutputArea;
+ JTextArea jListOutputArea;
+ JScrollPane jOutputPane;
+ JScrollPane jListOutputPane;
+ JInternalFrame jOutputFrame;
+ JInternalFrame jListOutputFrame;
+ MiniBrowser miniBrowser;
+
+ NyquistThread nyquistThread;
+ JInternalFrame jFrame;
+ // used by TextColor to communicate result back to MainFrame
+ // public static boolean evenParens;
+ String currentDir = "";
+ Runnable update = new ScrollUpdate(this);
+ PlotFrame plotFrame;
+ File homeDir = new File(".");
+ public String findPattern = "";
+ public String replacePattern = "";
+ boolean packFrame = false;
+ EnvelopeFrame envelopeEditor;
+ /* BEGIN UPIC */
+ UPICFrame upicEditor;
+ /* END UPIC */
+ Jslide eqEditor;
+ public Preferences prefs;
+ public static final boolean prefStartInSalModeDefault = true;
+ public static final boolean prefSalShowLispDefault = false;
+ public static final boolean prefParenAutoInsertDefault = false;
+ public static final boolean prefEnableSoundDefault = true;
+ public static final boolean prefAutoNormDefault = true;
+
+ public static final boolean prefSalTraceBackDefault = true;
+ public static final boolean prefSalBreakDefault = false;
+ public static final boolean prefXlispBreakDefault = true;
+ public static final boolean prefXlispTraceBackDefault = false;
+
+ public static final boolean prefPrintGCDefault = false;
+ public static final boolean prefFullSearchDefault = true;
+ public static final boolean prefInternalBrowserDefault = false;
+ public static final boolean prefOnlineManualDefault = false;
+ public static final double prefCompletionListPercentDefault = 60.0;
+ public static final String prefAudioRateDefault = "44100";
+ public static final String prefControlRateDefault = "2205";
+ public static final String prefFontSizeDefault = "12";
+
+ public static boolean prefStartInSalMode = prefStartInSalModeDefault;
+ public static boolean prefSalShowLisp = prefSalShowLispDefault;
+ public static boolean prefParenAutoInsert = prefParenAutoInsertDefault;
+ public static boolean prefEnableSound = prefEnableSoundDefault;
+ public static boolean prefAutoNorm = prefAutoNormDefault;
+ public static boolean prefSalTraceBack = prefSalTraceBackDefault;
+ public static boolean prefSalBreak = prefSalBreakDefault;
+ public static boolean prefXlispBreak = prefXlispBreakDefault;
+ public static boolean prefXlispTraceBack = prefXlispTraceBackDefault;
+ public static boolean prefPrintGC = prefPrintGCDefault;
+ public static boolean prefFullSearch = prefFullSearchDefault;
+ public static boolean prefInternalBrowser = prefInternalBrowserDefault;
+ public static boolean prefOnlineManual = prefOnlineManualDefault;
+ public static double prefCompletionListPercent =
+ prefCompletionListPercentDefault;
+ public static String prefAudioRate = prefAudioRateDefault;
+ public static String prefControlRate = prefControlRateDefault;
+ public static String prefFontSize = prefFontSizeDefault;
+ public static String prefDirectory = "";
+ public static String prefSFDirectory = "";
+
+ public static boolean prefsHaveBeenSet = false;
+
+ public boolean workspaceLoaded = false;
+ public boolean workspaceSaved = false;
+
+ public static final String onlineManualURL =
+ "http://www.cs.cmu.edu/~rbd/doc/nyquist/";
+
+
+ // inputStrings allows user to type ^P to get previous entry,
+ // or ^D for next entry. This is tricky. The desired behavior is:
+ // There is a history list of everything executed in order.
+ // Typing ^P moves a cursor back in history, ^D forward. When you type
+ // Enter, a new string is placed at the front of history, and the
+ // cursor is set to the front of history as well.
+ // To implement this behavior, inputStringsX is the front of history.
+ // It wraps around when it reaches inputStringsLen. To be precise,
+ // inputStringsX is the indeX of the location where the next input
+ // string will go. inputStringsCursor is the position controlled
+ // by ^P and ^D. inputSringsCursor is set
+ // to inputStringsX when the user types Enter.
+
+ // Sending input is tricky because you could be in Lisp or SAL mode.
+ // Either way, you want to indent multi-line input by the prompt size
+ // (2 for lisp, 4 for Sal) and you want an extra return after Sal
+ // commands. You DO NOT want the last 2 returns to be followed by
+ // spaces since SAL looks at the end of input to determine when a
+ // command is complete.
+ //
+ // Use cases:
+ // calling a function like replay (R):
+ // use callFunction()
+ // user types return after code in input box:
+ // use SendInputLn
+ //
+ // Support functions:
+ // callFunction -- build expression and call SendInputLn
+ // setVariable -- build expression and call SendInputLn
+ // SendInputLn -- fix up indentation, append newline or 2, SendInput
+ // SendInput -- just send text to Nyquist
+
+ int inputStringsX = 0;
+ int inputStringsCursor = 0;
+ int inputStringsLen = 20;
+ String inputStrings[] = new String[inputStringsLen];
+
+ // some "features" for system dependent code
+ public boolean hasRightMouseButton = true;
+
+ //Construct the frame
+ public MainFrame() {
+ enableEvents(AWTEvent.WINDOW_EVENT_MASK);
+ try {
+ mainFrameInit();
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ public boolean isMac() {
+ // System.out.println("mrj.version" + System.getProperty("mrj.version"));
+ // return System.getProperty("mrj.version") != null;
+
+ // The code above seems not to work on Leopard; the following
+ // suggested by Raymond Martin:
+
+ final String strOS;
+
+ try { strOS = System.getProperty("os.name"); }
+ catch(final SecurityException e) {
+ System.out.println("In isMac: error " + e);
+ return(false);
+ }
+ System.out.println("strOS " + strOS);
+ return(strOS.indexOf("Mac OS") >= 0);
+ }
+
+ PreferencesDialog preferencesDialog;
+
+ public void disconnectPreferences() {
+ preferencesDialog = null;
+ }
+
+
+ protected void setVariable(String var, String val) {
+ String input;
+ if (jScrollPane.isSal) {
+ input = "set " + var + " = " + val;
+ } else {
+ input = "(setf " + var + " " + val + ")";
+ }
+ sendInputLn(input);
+ }
+
+
+ String tOrNil(boolean val) {
+ return (val ? "t" : "nil");
+ }
+
+
+ protected void setBoolean(String var, boolean val) {
+ setVariable(var, tOrNil(val));
+ }
+
+
+ // invoke a function call in Nyquist with 0 or 1 parameters
+ // (pass "" for 0 parameters)
+ protected void callFunction(String fn, String parameter) {
+ String input;
+ if (jScrollPane.isSal) {
+ input = "exec " + fn + "(" + parameter + ")";
+ } else {
+ input = "(" + fn + (parameter.length() > 0 ? " " : "") +
+ parameter + ")";
+ }
+ sendInputLn(input);
+ }
+
+
+ public void Prefs() {
+ // ignore if preferences is already open
+ if (preferencesDialog != null) return;
+ preferencesDialog = new PreferencesDialog(this);
+ jDesktop.add(preferencesDialog);
+ jDesktop.getDesktopManager().activateFrame(preferencesDialog);
+ }
+
+ // create a button
+ private JButton buttonInit(String name,
+ String tip, ActionListener listener) {
+ JButton button = new JButton();
+ button.setText(name);
+ button.setActionCommand(name);
+ button.setToolTipText(tip);
+ button.addActionListener(listener);
+ jToolBar.add(button);
+ return button;
+ }
+
+ private void menuAddItem(JMenu menu, String name, char mnemonic,
+ KeyStroke accelerator, ActionListener listener) {
+ JMenuItem item = new JMenuItem();
+ item.setText(name);
+ item.setActionCommand(name);
+ if (mnemonic != '\000') item.setMnemonic(mnemonic);
+ if (accelerator != null) item.setAccelerator(accelerator);
+ item.addActionListener(listener);
+ menu.add(item);
+ }
+
+ public void handlePrefs() {
+ System.out.println("handlePrefs called");
+ }
+
+ //Component initialization
+ private void mainFrameInit() throws Exception {
+ // if this is a Mac, we want some menu items on the application menu,
+ // which is accessed via some special apple code, but the apple code
+ // is not going to be installed if you are running windows or linux,
+ // so we use java reflection here to load the special code ONLY if
+ // we're on a Mac
+ //
+ // The special code ultimately calls back to the methods About(),
+ // Prefs(), and Quit() in this class. The "normal" Windows/Linux
+ // code should do the same.
+ if (isMac()) {
+ hasRightMouseButton = false;
+ try {
+ Object[] args = { this };
+ Class[] arglist = { MainFrame.class };
+
+ Class mac_class = Class.forName("jnyqide.SpecialMacHandler");
+
+ /*
+ Thread t = Thread.currentThread();
+ ClassLoader cl = t.getContextClassLoader();
+ Class mac_class = cl.loadClass("SpecialMacHandler");
+ */
+
+ System.out.println("got the class\n");
+ Constructor new_one = mac_class.getConstructor(arglist);
+ System.out.println("got the constructor\n");
+ new_one.newInstance(args);
+
+ System.out.println("isMac, so created instance of SpecialMacHandler");
+ } catch(Exception e) {
+ System.out.println(e);
+ }
+ }
+
+ prefs = Preferences.userNodeForPackage(Main.class);
+ prefStartInSalMode = prefs.getBoolean("start-with-sal",
+ prefStartInSalMode);
+ prefSalShowLisp = prefs.getBoolean("sal-show-lisp", prefSalShowLisp);
+ prefParenAutoInsert = prefs.getBoolean("paren-auto-insert",
+ prefParenAutoInsert);
+ prefEnableSound = prefs.getBoolean("sound-enable", prefEnableSound);
+ prefAutoNorm = prefs.getBoolean("auto-norm", prefAutoNorm);
+ prefSalTraceBack = prefs.getBoolean("sal-traceback", prefSalTraceBack);
+ prefSalBreak = prefs.getBoolean("sal-break", prefSalBreak);
+ prefXlispBreak = prefs.getBoolean("xlisp-break", prefXlispBreak);
+ prefXlispTraceBack = prefs.getBoolean("xlisp-traceback",
+ prefXlispTraceBack);
+ // if XlispTracBack, then we need to set XlispBreak:
+ prefXlispBreak = prefXlispBreak || prefXlispTraceBack;
+ prefPrintGC = prefs.getBoolean("print-gc", prefPrintGC);
+ prefFullSearch = prefs.getBoolean("completion-list-full-search",
+ prefFullSearch);
+ prefInternalBrowser = prefs.getBoolean("internal-browser",
+ prefInternalBrowser);
+ prefOnlineManual = prefs.getBoolean("online-manual", prefOnlineManual);
+ prefCompletionListPercent = prefs.getDouble("completion-list-percent",
+ prefCompletionListPercent);
+ prefAudioRate = prefs.get("audio-rate", prefAudioRate);
+ prefControlRate = prefs.get("control-rate", prefControlRate);
+ prefFontSize = prefs.get("font-size", prefFontSize);
+ prefDirectory = prefs.get("initial-directory", prefDirectory);
+ prefSFDirectory = prefs.get("default-sf-directory", prefSFDirectory);
+ prefsHaveBeenSet = false;
+
+ image1 = new ImageIcon("openFile.gif");
+ image2 = new ImageIcon("closeFile.gif");
+ image3 = new ImageIcon("help.gif");
+ //setIconImage(Toolkit.getDefaultToolkit().createImage(MainFrame.class.getResource("[Your Icon]")));
+ contentPane = (JPanel) this.getContentPane();
+ contentPane.setLayout(borderLayout1);
+ this.setSize(new Dimension(400, 300));
+ this.setTitle("Nyquist IDE");
+ statusBar.setText(" ");
+
+ ActionListener menuButtonListener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ menuButtonHandler(e);
+ }
+ };
+
+ // Menu Bar
+ jMenuFile.setText("File");
+ menuAddItem(jMenuFile, "New", 'n',
+ KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ menuButtonListener);
+ menuAddItem(jMenuFile, "Open", 'o',
+ KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ menuButtonListener);
+
+ if (!isMac()) { // if isMac(), Quit (not Exit) and Prefs are on the
+ // application menu
+ menuAddItem(jMenuFile, "Preferences...", '\000', null,
+ menuButtonListener);
+ menuAddItem(jMenuFile, "Exit", '\000', null, menuButtonListener);
+ }
+
+ jMenuEdit.setText("Edit");
+
+ menuAddItem(jMenuEdit, "Previous", 'p',
+ KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_P,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ menuButtonListener);
+
+ menuAddItem(jMenuEdit, "Next", 'n',
+ KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_D,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ menuButtonListener);
+
+ menuAddItem(jMenuEdit, "Select Expression", 'e',
+ KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_E,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ menuButtonListener);
+
+ jMenuHelp.setText("Help");
+ if (!isMac()) { // if isMac(), About is on the application menu
+ menuAddItem(jMenuHelp, "About", 'h', null, menuButtonListener);
+ }
+ menuAddItem(jMenuHelp, "Manual", 'm', null, menuButtonListener);
+
+ jMenuProcess.setText("Process");
+ menuAddItem(jMenuProcess, "Replay", 'r', null, menuButtonListener);
+ menuAddItem(jMenuProcess, "Plot", 'p', null, menuButtonListener);
+ menuAddItem(jMenuProcess, "Copy to Lisp", 'u',
+ KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_U,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
+ menuButtonListener);
+ menuAddItem(jMenuProcess, "Mark", 'a', null, menuButtonListener);
+
+ jMenuWindow.setText("Window");
+ menuAddItem(jMenuWindow, "Tile", 't', null, menuButtonListener);
+ menuAddItem(jMenuWindow, "Browse", 'b', null, menuButtonListener);
+ menuAddItem(jMenuWindow, "EQ", 'q', null, menuButtonListener);
+ menuAddItem(jMenuWindow, "Envelope Edit", 'e', null, menuButtonListener);
+ /* BEGIN UPIC */
+ menuAddItem(jMenuWindow, "UPIC Edit", 'u', null, menuButtonListener);
+ /* END UPIC */
+ buttonInit("Info", "Print Lisp memory status", menuButtonListener);
+ buttonInit("Break", "Break/interrupt Lisp interpreter",
+ menuButtonListener);
+ // removed "Up" and "Cont" just to make some real-estate
+ // buttonInit("Up", "Return from this break level", menuButtonListener);
+ // buttonInit("Cont", "Continue Lisp execution", menuButtonListener);
+ salLispButton = buttonInit("Sal", "Change Mode", menuButtonListener);
+ buttonInit("Top", "Exit to Lisp top-level", menuButtonListener);
+ buttonInit("Replay", "Replay the last sound", menuButtonListener);
+ int i;
+ for (i = 0; i < 11; i++) {
+ String name = "F" + (i + 2);
+ String tip = "Evaluate (" + name + ")";
+ buttonInit(name, tip, menuButtonListener);
+ }
+
+ buttonInit("Browse", "Browse Sound/Instrument/Effect Library",
+ menuButtonListener);
+ buttonInit("EQ", "Equalizer Control Panel", menuButtonListener);
+ buttonInit("EnvEdit", "Open Graphical Envelope Editor",
+ menuButtonListener);
+ // buttonNew.setIcon(image1);
+ buttonInit("New File", "New File", menuButtonListener);
+ // buttonOpen.setIcon(image1);
+ buttonInit("Open File", "Open File", menuButtonListener);
+ // buttonSave.setIcon(image3);
+ buttonInit("Save File", "Save File", menuButtonListener);
+ buttonInit("Load", "Load File into Nyquist", menuButtonListener);
+ buttonInit("Mark", "Get elapsed audio play time", menuButtonListener);
+
+ jMenuBar1.add(jMenuFile);
+ jMenuBar1.add(jMenuEdit);
+ jMenuBar1.add(jMenuProcess);
+ jMenuBar1.add(jMenuWindow);
+ jMenuBar1.add(jMenuHelp);
+ this.setJMenuBar(jMenuBar1);
+
+ //MRJApplicationUtils.registerPrefsHandler(this);
+
+ jOutputArea = new JTextArea();
+ jOutputArea.setFont(new Font("Courier", Font.PLAIN, 12));
+ jOutputArea.setLineWrap(true);
+ jOutputArea.setEditable(false);
+ jOutputPane = new JScrollPane( jOutputArea );
+ jOutputPane.setHorizontalScrollBarPolicy(
+ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+ jOutputPane.setVerticalScrollBarPolicy(
+ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+
+ jListOutputArea = new JTextArea();
+ jListOutputArea.setLineWrap(true);
+ jListOutputArea.setEditable(false);
+ // add mouse listener
+ jListOutputArea.addMouseListener(new MouseListener () {
+ public void mouseExited(MouseEvent e) { };
+ public void mouseEntered(MouseEvent e) { };
+ public void mousePressed(MouseEvent e) { };
+ public void mouseReleased(MouseEvent e) { };
+
+ public void mouseClicked(MouseEvent e) {
+ // System.out.println(e.paramString());
+ int pos = jListOutputArea.viewToModel(e.getPoint());
+ int start = 0, end = 0;
+ String line = "";
+ // System.out.println("text posn = " + pos);
+ try {
+ int lineno = jListOutputArea.getLineOfOffset(pos);
+ // System.out.println("line no = " + lineno);
+ start = jListOutputArea.getLineStartOffset(lineno);
+ end = jListOutputArea.getLineEndOffset(lineno);
+ // System.out.println("start = " + start + " end = " + end);
+ // skip newline by subtracting one from length
+ if (end > start + 1) {
+ line = jListOutputArea.getText(start, end - start - 1);
+ // WordList.replaceWithTemplate(line);
+ } // otherwise nothing selected
+ } catch (Exception ex) {
+ ex.printStackTrace(System.err);
+ }
+
+ // System.out.println("event: " + e);
+ if (SwingUtilities.isRightMouseButton(e) ||
+ // for Mac, allow option click (which java sees as alt key)
+ (e.getModifiers() & InputEvent.ALT_MASK) != 0) {
+ String ext = WordList.getlink(line);
+ System.out.println(line + " : " + ext);
+ String url, urlbase;
+
+ if (prefOnlineManual) urlbase = onlineManualURL;
+ else urlbase = findManualURL("");
+ url = urlbase + ext;
+
+ if (prefInternalBrowser) {
+ miniBrowser.setVisible(true);
+ System.out.println("URL is: " + url);
+ miniBrowser.setPage(url);
+ } else BareBonesBrowserLaunch.openURL(url);
+ } else {
+ // System.out.println(e.paramString());
+ WordList.replaceWithTemplate(line);
+ }
+ }
+ });
+ jListOutputPane = new JScrollPane( jListOutputArea );
+ jListOutputPane.setHorizontalScrollBarPolicy(
+ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+ jListOutputPane.setVerticalScrollBarPolicy(
+ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+
+ jScrollPane = new CodePane(new Dimension(400, 200), this, statusBar,
+ Integer.parseInt(prefFontSize));
+
+ // Top panel for command entry, plot, and toolbar
+ JPanel jCommands = new JPanel( new BorderLayout() );
+ JPanel jInputAndPlot = new JPanel(new BorderLayout(3, 0));
+ jInputAndPlot.add(jScrollPane, BorderLayout.WEST);
+ System.out.println("\n\n\n\n\n\n\nadded jScrollPane " + jScrollPane + " to panel\n\n\n\n\n\n");
+ jCommands.add(jToolBar, BorderLayout.SOUTH);
+ jCommands.add(jInputAndPlot, BorderLayout.CENTER);
+ jCommands.setPreferredSize(new Dimension(300, 150));
+
+ // Main desktop
+ jDesktop = new JDesktopPane();
+ jDesktop.setPreferredSize( new Dimension(300, 300) );
+
+ jOutputFrame = new JInternalFrame("Output");
+ // make this wide enough so XLISP GC messages do not wrap
+ // (it's annoying)
+ //jOutputFrame.setSize(new Dimension(500, 530 / 3));
+ jOutputFrame.setVisible(true);
+ jOutputFrame.getContentPane().add(jOutputPane);
+ jOutputFrame.setResizable( true );
+ //jOutputFrame.setLocation(0, (530 * 2) / 3);
+ jDesktop.add( jOutputFrame );
+
+
+ String clTitle = "Completion List" + (hasRightMouseButton ?
+ " - Right Click for Help" :
+ " - Option Click for Help");
+ jListOutputFrame = new JInternalFrame(clTitle);
+ //jListOutputFrame.setSize( new Dimension (500, (530 * 2) / 3));
+ jListOutputFrame.setVisible(true);
+ jListOutputFrame.getContentPane().add(jListOutputPane);
+ jListOutputFrame.setResizable(true);
+ //jListOutputFrame.setLocation(0,0);
+ jDesktop.add(jListOutputFrame);
+
+ contentPane.add( jCommands, BorderLayout.NORTH);
+ contentPane.add( jDesktop, BorderLayout.CENTER );
+ contentPane.add(statusBar, BorderLayout.SOUTH);
+ setSize( new Dimension(800, 800) );
+
+ miniBrowser = new MiniBrowser("Nyquist Manual");
+ jDesktop.add(miniBrowser);
+
+ TextColor.init();
+ WordList.init(jListOutputArea);
+ SalWordList.init();
+
+ plotFrame = new PlotFrame(jInputAndPlot);
+
+ nyquistThread = new NyquistThread();
+ nyquistThread.start(jOutputArea, update, plotFrame, this);
+
+ System.out.print("jDesktop size: ");
+ System.out.println(jDesktop.getSize().toString());
+
+ contentPane.setTransferHandler(new TransferHandler() {
+ public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
+ for (DataFlavor transferFlavor : transferFlavors) {
+ if (transferFlavor.isFlavorJavaFileListType())
+ return true;
+ }
+ return false;
+ }
+
+ public boolean importData(JComponent comp, Transferable t) {
+ try {
+ Collection<File> files = (Collection<File>)
+ t.getTransferData(DataFlavor.javaFileListFlavor);
+ for (File file : files) {
+ openFile(file);
+ }
+ return true;
+ } catch (Exception e) {
+ System.out.println("Drop failed: "+e.getMessage());
+ }
+ return false;
+ }
+ });
+ // set size and location for jOutputFrame and jListOutputFrame
+ // now this is done in Main after making desktop visible (otherwise
+ // you can't get dimensions of the desktop and layout is faulty)
+ // tileCompletion();
+ }
+
+
+ public void sendPreferenceData() {
+ // send Nyquist the preference values (assumes in Lisp mode)
+ sendInputLn(";; transferring preference data from jNyqIDE to Nyquist");
+ sendInputLn("(progn");
+ setBoolean("*sal-compiler-debug*", prefSalShowLisp);
+ callFunction(prefEnableSound ? "sound-on" : "sound-off", "");
+ callFunction(prefAutoNorm ? "autonorm-on" : "autonorm-off", "");
+ callFunction("sal-tracenable", tOrNil(prefSalTraceBack));
+ callFunction("sal-breakenable", tOrNil(prefSalBreak));
+ callFunction("xlisp-breakenable", tOrNil(prefXlispBreak));
+ callFunction("xlisp-tracenable", tOrNil(prefXlispTraceBack));
+ setBoolean("*gc-flag*", prefPrintGC);
+ callFunction("set-sound-srate", prefAudioRate);
+ callFunction("set-control-srate", prefControlRate);
+ setFontSize(Integer.parseInt(prefFontSize));
+ if (prefDirectory != null && prefDirectory.length() > 0) {
+ changeDirectory(prefDirectory);
+ }
+ if (prefSFDirectory != null && prefSFDirectory.length() > 0) {
+ String dirString = escape_backslashes(prefSFDirectory);
+ setVariable("*default-sf-dir*", "\"" + dirString + "\"");
+ } else { // no preference, suggest Java temp dir. The Java temp dir
+ // will be used as *default-sf-dir* only if *default-sf-dir*
+ // was set to "", meaning previous methods to identify a temp
+ // directory failed to produce anything.
+ String tempdir = System.getProperty("java.io.tmpdir");
+ if (!(tempdir.endsWith("/") || tempdir.endsWith("\\")))
+ tempdir = tempdir + "/";
+ // flip backslash to slash to avoid quote problems
+ tempdir = "\"" + tempdir.replaceAll("\\\\", "/") + "\"";
+ callFunction("suggest-default-sf-dir", tempdir);
+ }
+ setBoolean("*sal-secondary-prompt*", false);
+ sendInputLn(";; end preference data transfer");
+ sendInputLn(")");
+
+ if (prefStartInSalMode) {
+ callFunction("sal", "");
+ }
+ }
+
+ //File | Exit action performed
+ public void menuButtonHandler(ActionEvent e) {
+ String cmd = e.getActionCommand();
+ if (cmd == "New" || cmd == "New File") doFileNew(e);
+ else if (cmd == "Open" || cmd == "Open File") doFileOpen(e);
+ else if (cmd == "Save" || cmd == "Save File") doFileSave(e);
+ else if (cmd == "Save As...") doFileSaveAs(e);
+ else if (cmd == "Load" || cmd == "Load...") doFileLoad(e);
+ else if (cmd == "Mark") doProcessMark(e);
+ else if (cmd == "Preferences...") Prefs();
+ else if (cmd == "Exit") {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ Quit();
+ }
+ });
+ // throw new IllegalStateException("Let the quit handler do it");
+ } else if (cmd == "Find...") doEditFind(e);
+ else if (cmd == "Replace...") doEditReplace(e);
+ else if (cmd == "Previous") doEditPrevious(e);
+ else if (cmd == "Next") doEditNext(e);
+ else if (cmd == "Select Expression") doEditSelectExpression(e);
+ else if (cmd == "About") About();
+ else if (cmd == "Manual") doHelpManual(e);
+ else if (cmd == "Replay") doProcessReplay(e);
+ else if (cmd == "Plot") doProcessPlot(e);
+ else if (cmd == "Tile") doWindowTile(e);
+ else if (cmd == "Browse") doWindowBrowse(e);
+ else if (cmd == "EQ") doWindowEQ(e);
+ else if (cmd == "EnvEdit" || cmd == "Envelope Edit") doWindowEnvelope(e);
+ /* BEGIN UPIC */
+ else if (cmd == "UPIC Edit") doWindowUPIC(e);
+ /* END UPIC */
+ else if (cmd == "Info") doProcessInfo(e);
+ else if (cmd == "Break") doProcessBreak(e);
+ else if (cmd == "Up") doProcessUp(e);
+ else if (cmd == "Cont") doProcessCont(e);
+ else if (cmd == "Top") doProcessTop(e);
+ else if (cmd == "Lisp") doProcessLisp(e);
+ else if (cmd == "Sal") doProcessSal(e);
+ else if (cmd == "Copy to Lisp") doProcessCopyToLisp(e);
+ // do this last so other commands starting with "F" get handled
+ else if (cmd.charAt(0) == 'F') doProcessFn(e);
+ else System.out.println("menu or button command not expected: " + cmd);
+ }
+
+ public void Quit() {
+ System.out.println("Quit() called in MainFrame.java");
+ // close prefs?
+ int r = JOptionPane.OK_OPTION;
+ if (preferencesDialog != null) {
+ r = JOptionPane.showConfirmDialog(this,
+ "Really close without closing (saving) preferences?",
+ "alert", JOptionPane.OK_CANCEL_OPTION);
+ }
+ if (r != JOptionPane.OK_OPTION) return; // do not quit
+ if (prefsHaveBeenSet) {
+ prefs.putBoolean("start-with-sal", prefStartInSalMode);
+ prefs.putBoolean("sal-show-lisp", prefSalShowLisp);
+ prefs.putBoolean("paren-auto-insert", prefParenAutoInsert);
+ prefs.putBoolean("sound-enable", prefEnableSound);
+ prefs.putBoolean("auto-norm", prefAutoNorm);
+ prefs.putBoolean("sal-traceback", prefSalTraceBack);
+ prefs.putBoolean("sal-break", prefSalBreak);
+ prefs.putBoolean("xlisp-break", prefXlispBreak);
+ prefs.putBoolean("xlisp-traceback", prefXlispTraceBack);
+ prefs.putBoolean("print-gc", prefPrintGC);
+ prefs.putBoolean("completion-list-full-search", prefFullSearch);
+ prefs.putBoolean("internal-browser", prefInternalBrowser);
+ prefs.putBoolean("online-manual", prefOnlineManual);
+ prefs.putDouble("completion-list-percent",
+ prefCompletionListPercent);
+ prefs.put("audio-rate", prefAudioRate);
+ prefs.put("control-rate", prefControlRate);
+ prefs.put("font-size", prefFontSize);
+ prefs.put("initial-directory", prefDirectory);
+ prefs.put("default-sf-directory", prefSFDirectory);
+ prefsHaveBeenSet = false;
+ }
+ JInternalFrame[] frames = jDesktop.getAllFrames();
+ boolean flag = false;
+ int i;
+ for (i = 0; i < frames.length; i++) {
+ if (frames[i] instanceof NyquistFile) {
+ NyquistFile nyquistFile = (NyquistFile) frames[i];
+ if (nyquistFile.modified) flag = true;
+ }
+ }
+ r = JOptionPane.OK_OPTION;
+ if (flag) {
+ r = JOptionPane.showConfirmDialog(this,
+ "Really close without saving?",
+ "alert", JOptionPane.OK_CANCEL_OPTION);
+ }
+ if (r != JOptionPane.OK_OPTION) return; // do not quit
+ if (workspaceLoaded) {
+ r = JOptionPane.showConfirmDialog(this,
+ "Save workspace to current directory before exiting?",
+ "alert", JOptionPane.YES_NO_CANCEL_OPTION);
+ if (r == JOptionPane.YES_OPTION) {
+ workspaceSaved = false; // interface with NyquistThread
+ callFunction("save-workspace", "");
+ i = 0;
+ while (!workspaceSaved && i < 10000) { // allow 10s
+ try { Thread.sleep(200); }
+ catch (InterruptedException ie) { }
+ i += 200;
+ }
+ if (!workspaceSaved) {
+ r = JOptionPane.showConfirmDialog(this,
+ "Timed out waiting for workspace save.\n" +
+ "Your workspace data may not be saved.\n" +
+ "Exit anyway?",
+ "alert", JOptionPane.OK_CANCEL_OPTION);
+ }
+ }
+ if (r == JOptionPane.CANCEL_OPTION) return; // do not quit
+ }
+ System.out.println("Sending (exit) to Nyquist...");
+ // try to shut down Nyquist before it is orphaned
+ // Sal need special syntax to exit the Nyquist process:
+ if (jScrollPane.isSal) sendInputLn("exit nyquist");
+ else callFunction("exit", "");
+ try {
+ Thread.sleep(200); // does it help Nyquist's exit to stall?
+ } catch (InterruptedException ie) {
+ }
+ System.out.println("Exiting from NyquistIDE");
+ System.exit(0);
+ }
+
+
+ public void prepareNewNyquistFile(final NyquistFile file) {
+ jDesktop.add(file);
+ jDesktop.getDesktopManager().activateFrame(file);
+ jDesktop.setSelectedFrame(file);
+ file.addInternalFrameListener(
+ new InternalFrameListener() {
+ public void internalFrameClosing(InternalFrameEvent e) {
+ //System.out.println("FrameClosing");
+ int r = JOptionPane.OK_OPTION;
+ if (file.modified) {
+ r = JOptionPane.showConfirmDialog(file,
+ "Really close without saving?",
+ "alert", JOptionPane.OK_CANCEL_OPTION);
+ }
+ if (r == JOptionPane.OK_OPTION) {
+ file.dispose();
+ }
+ }
+ public void internalFrameOpened(InternalFrameEvent e) {
+ }
+ public void internalFrameClosed(InternalFrameEvent e) {
+ //System.out.println("FrameClosed");
+ }
+ public void internalFrameIconified(InternalFrameEvent e) {
+ }
+ public void internalFrameDeiconified(InternalFrameEvent e) {
+ }
+ public void internalFrameActivated(InternalFrameEvent e) {
+ }
+ public void internalFrameDeactivated(InternalFrameEvent e) {
+ }
+ }
+ );
+ }
+
+
+ public void doFileNew(ActionEvent e) {
+
+ final NyquistFile file =
+ new NyquistFile(this, Integer.parseInt(prefFontSize));
+ prepareNewNyquistFile(file);
+ }
+
+ public String fileDirectory(File file) {
+ String path = file.getAbsolutePath();
+ String name = file.getName();
+ return path.substring(0, path.length() - name.length());
+ }
+
+
+ //File | Exit action performed
+ public void doFileOpen(ActionEvent e) {
+ JFileChooser chooser = new JFileChooser();
+ LispFileFilter lispFilter = new LispFileFilter();
+ SalFileFilter salFilter = new SalFileFilter();
+ // last one seems to be the default setting for user, so set according
+ // to current mode
+ if (jScrollPane.isSal) {
+ chooser.setFileFilter(lispFilter);
+ chooser.addChoosableFileFilter(salFilter);
+ } else {
+ chooser.setFileFilter(salFilter);
+ chooser.addChoosableFileFilter(lispFilter);
+ }
+ // note if current directory setting fails on some platform,
+ // consider this code using getCanonicalPath():
+ // File f = new File(new File(".").getCanonicalPath());
+ File curdir = new File(currentDir);
+ chooser.setCurrentDirectory(curdir);
+ int returnVal = chooser.showOpenDialog(this);
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ System.out.println("You chose to open this file: " +
+ chooser.getSelectedFile().getAbsoluteFile());
+ openFile(chooser.getSelectedFile());
+ }
+ }
+
+ private void openFile(File fileToOpen) {
+ // see if file is already open
+ JInternalFrame[] frames = jDesktop.getAllFrames();
+ int i;
+ for (i = 0; i < frames.length; i++) {
+ if (frames[i] instanceof NyquistFile) {
+ NyquistFile file = (NyquistFile) frames[i];
+
+ if (file.getFile() != null &&
+ file.getFile().getAbsolutePath().equals(
+ fileToOpen.getAbsolutePath())) {
+ jDesktop.setSelectedFrame(file);
+ try {
+ file.setSelected(true);
+ }
+ catch(PropertyVetoException ve) {
+ //System.out.println("setSelected was vetoed");
+ }
+
+ JInternalFrame jInternalFrame =
+ jDesktop.getSelectedFrame();
+ if (jInternalFrame instanceof NyquistFile) {
+ NyquistFile nf = (NyquistFile) jInternalFrame;
+ //System.out.println("selected is " +
+ // nf.getAbsolutePath());
+ } else {
+ //System.out.println("selected not a NyquistFile");
+ }
+ return;
+ }
+ }
+ }
+ // Didn't find it. Open it in a new frame.
+ final NyquistFile file =
+ new NyquistFile(fileToOpen, this, Integer.parseInt(prefFontSize));
+ changeDirectory(fileDirectory(fileToOpen));
+ prepareNewNyquistFile(file);
+ }
+
+ public void doFileSave(ActionEvent e) {
+ if (jDesktop.getSelectedFrame() instanceof NyquistFile) {
+ NyquistFile file = (NyquistFile)jDesktop.getSelectedFrame();
+ if (file.save(currentDir)) {
+ changeDirectory(fileDirectory(file.getFile()));
+ }
+ }
+ }
+
+ public void doFileSaveAs(ActionEvent e) {
+ if (jDesktop.getSelectedFrame() instanceof NyquistFile) {
+ NyquistFile file = (NyquistFile)jDesktop.getSelectedFrame();
+ if (file.saveAs(currentDir)) {
+ changeDirectory(fileDirectory(file.getFile()));
+ }
+ }
+ }
+
+ public void doFileLoad(ActionEvent e) {
+ JInternalFrame frame = jDesktop.getSelectedFrame();
+ if (frame instanceof NyquistFile) {
+ NyquistFile file = (NyquistFile) frame;
+ if (file.save(currentDir)) {
+ loadFile(file.getFile());
+ }
+ }
+ }
+
+ //Edit | Find action performed
+ public void doEditFind(ActionEvent e) {
+ JInternalFrame frame = jDesktop.getSelectedFrame();
+ if (frame instanceof NyquistFile) {
+ NyquistFile file = (NyquistFile) frame;
+ FindDialog findDialog = new FindDialog(file, this);
+ }
+ }
+
+ //Edit | Replace action performed
+ public void doEditReplace(ActionEvent e) {
+ JInternalFrame frame = jDesktop.getSelectedFrame();
+ if (frame instanceof NyquistFile) {
+ NyquistFile file = (NyquistFile) frame;
+ ReplaceDialog replaceDialog = new ReplaceDialog(file, this);
+ }
+ }
+
+ public void filterCRLF(StringBuffer buf)
+ {
+ //int i = buf.toString().indexOf("\r\n"); // note: buf.indexOf() doesn't work on Mac
+ //while (i >= 0) {
+ // buf.replace(i, i + 2, "\n");
+ // i = buf.toString().indexOf("\r\n", i);
+ //}
+ buf.replace(0, buf.length(), buf.toString().replaceAll("\r\n", "\n"));
+ }
+
+ public String trimNewline(String s) {
+ int len = s.length();
+ while (len > 0 &&
+ (s.charAt(len - 1) == '\n' || s.charAt(len - 1) == '\r')) {
+ len = len - 1;
+ }
+ return s.substring(0, len);
+ }
+
+ //Edit | Previous action performed
+ public void doEditPrevious(ActionEvent e) {
+ inputStringsCursor = inputStringsCursor - 1;
+ if (inputStringsCursor < 0) inputStringsCursor = inputStringsLen - 1;
+ String text = inputStrings[inputStringsCursor];
+ if (text != null) {
+ // remove the newline at the end
+ jScrollPane.pane.setText(trimNewline(text));
+ }
+ }
+
+ //Edit | Next action performed
+ public void doEditNext(ActionEvent e) {
+ inputStringsCursor = inputStringsCursor + 1;
+ if (inputStringsCursor >= inputStringsLen) inputStringsCursor = 0;
+ String text = inputStrings[inputStringsCursor];
+ if (text != null) {
+ jScrollPane.pane.setText(trimNewline(text));
+ }
+ }
+
+ //Edit | Select Expression
+ public void doEditSelectExpression(ActionEvent e) {
+ JInternalFrame frame = jDesktop.getSelectedFrame();
+ if (frame instanceof NyquistFile) {
+ NyquistFile file = (NyquistFile) frame;
+ file.selectExpression();
+ }
+ }
+
+ //Help | About action performed
+ public void About() {
+ MainFrame_AboutBox dlg = new MainFrame_AboutBox(this);
+ Dimension dlgSize = dlg.getPreferredSize();
+ Dimension frmSize = getSize();
+ Point loc = getLocation();
+ dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x, (frmSize.height - dlgSize.height) / 2 + loc.y);
+ dlg.setModal(true);
+ dlg.setVisible(true);
+
+ Graphics g = jFrame.getContentPane().getGraphics();
+ g.setColor(Color.cyan);
+ g.fillRect(50, 50, 100, 100);
+
+ }
+
+ public String findManualURL(String ext) {
+ String url = "";
+ try {
+ url = homeDir.getCanonicalPath();
+ } catch (Exception e) {
+ System.out.println("findManualURL exception: " + e);
+ }
+ String osName = System.getProperty("os.name");
+ if (osName.startsWith("Mac OS")) {
+ // from ./NyquistIDE.app/Contents/Resources/Java to .
+ // note: I tried this using homeDir.getParentFile(), but
+ // it always returns null, so I'm string parsing instead
+ int i;
+ for (i = 0; i < 4; i++) {
+ int pos = url.lastIndexOf('/');
+ if (pos >= 0) {
+ url = url.substring(0, pos);
+ }
+ System.out.println(url);
+ }
+ url += "/nyquist";
+ } else if (osName.startsWith("Windows")) {
+ // file://C:/ does not work, file:///C:/ does work
+ url = "/" + url;
+ }
+ url = "file://" + url + "/doc/" + ext;
+ return url;
+ }
+
+ public void doHelpManual(ActionEvent e) {
+ if (prefInternalBrowser) {
+ miniBrowser.setVisible(true);
+ miniBrowser.setPage(findManualURL("title.html"));
+ } else {
+ // separate browser gets to use frames (with index) by
+ // opening home.html
+ String url = findManualURL("home.html");
+ System.out.println("Try to open: " + url);
+ BareBonesBrowserLaunch.openURL(url);
+ }
+ }
+
+ public void doProcessReplay(ActionEvent e)
+ {
+ callFunction("r", "");
+ }
+
+ public void disconnectEnv() { // no more envelopeFrame, so kill pointer
+ envelopeEditor = null;
+ }
+
+ public void disconnectEq() { // no more equalizer panel, so kill pointer
+ eqEditor = null;
+ }
+
+ /* BEGIN UPIC */
+ public void disconnectUPIC() { // no more upicFrame, so kill pointer
+ upicEditor = null;
+ }
+ /* END UPIC */
+
+ public boolean workspaceWarning(String description) { // return true if OK to proceed
+ if (workspaceLoaded) return true;
+ Object[] options = { "CANCEL", "LOAD", "SKIP" };
+ int i = JOptionPane.showOptionDialog(this,
+ "No workspace has been loaded. If you save " + description +
+ ",\nany existing workspace will be overwritten without\n" +
+ "further notice. You should probably click CANCEL,\n" +
+ "open workspace.lsp, load it into Nyquist, and then\n" +
+ "revisit this editor.\n\n" +
+ "Click SKIP to proceed at your own risk.\n" +
+ "Click LOAD to load workspace.lsp from the current directory.\n" +
+ "Click CANCEL to resume without opening a new editor window.\n\n" +
+ "(If you have no workspace to load, select SKIP.)\n",
+ "Warning",
+ JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
+ null, options, options[0]);
+ System.out.println("dialog returns " + i);
+ if (i == 2) { // skip (proceed) option
+ workspaceLoaded = true;
+ } else if (i == 1) { // load workspace
+ callFunction("load", "\"workspace\"");
+ i = 0;
+ while (!workspaceLoaded && i < 10000) { // alow 10s
+ try { Thread.sleep(200); }
+ catch (InterruptedException ie) { }
+ i += 200;
+ }
+ if (!workspaceLoaded) {
+ JOptionPane.showMessageDialog(this,
+ "Timed out waiting for workspace load.\n" +
+ "Maybe it does not exist in this directory?",
+ "alert", JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+ // otherwise OK_OPTION selected, return false meaning do not proceed
+ return workspaceLoaded;
+ }
+
+ public void doWindowEnvelope(ActionEvent e)
+ {
+ // only one editor instance allowed
+ if (envelopeEditor != null) {
+ JOptionPane.showMessageDialog(this,
+ "Envelope editor is already open.",
+ "alert", JOptionPane.INFORMATION_MESSAGE);
+ return;
+ }
+ // open an envelope window
+ if (!workspaceWarning("envelopes")) return;
+ final EnvelopeFrame envelopeFrame =
+ new EnvelopeFrame(this, jScrollPane.pane);
+ final MainFrame mainFrame = this;
+ envelopeEditor = envelopeFrame;
+ envelopeFrame.validate();
+ jDesktop.add(envelopeFrame);
+ jDesktop.getDesktopManager().activateFrame(envelopeFrame);
+ jDesktop.setSelectedFrame(envelopeFrame);
+ }
+
+ /* BEGIN UPIC */
+ public void doWindowUPIC(ActionEvent e)
+ {
+ // only one editor instance allowed
+ if (upicEditor != null) {
+ JOptionPane.showMessageDialog(this,
+ "UPIC editor is already open.",
+ "alert", JOptionPane.INFORMATION_MESSAGE);
+ return;
+ }
+ // open a UPIC window
+ final UPICFrame upicFrame =
+ new UPICFrame(this, jScrollPane.pane);
+ upicEditor = upicFrame;
+ upicFrame.validate();
+ jDesktop.add(upicFrame);
+ jDesktop.getDesktopManager().activateFrame(upicFrame);
+ jDesktop.setSelectedFrame(upicFrame);
+ }
+ /* END UPIC */
+
+ public void doWindowEQ(ActionEvent e) {
+ /* Code added by Rivera Create a slider object that is the graphic equalizer
+ * Then add that slider object to the desktop, It will display
+ * directly to the right of the output, given the outputs frame
+ * width of 500
+ */
+ if (eqEditor != null) {
+ JOptionPane.showMessageDialog(this,
+ "Equalizer editor is already open.",
+ "alert", JOptionPane.INFORMATION_MESSAGE);
+ return;
+ }
+ if (!workspaceWarning("equalizers")) return;
+ final Jslide jslide = new Jslide(this);
+ eqEditor = jslide;
+ final MainFrame mainFrame = this;
+ final JInternalFrame jEq = new JInternalFrame("Equalizer", true, true);
+ jEq.setSize(new Dimension(350, 300));
+ jEq.setLocation(500, 0);
+ jEq.setVisible(true);
+
+ jEq.getContentPane().add(jslide.getGraphEq());
+ jDesktop.add(jEq);
+
+ jEq.addInternalFrameListener(
+ new InternalFrameListener() {
+ public void internalFrameClosing(InternalFrameEvent e) {
+ //System.out.println("FrameClosing");
+ int r = JOptionPane.OK_OPTION;
+ if (jslide.modified) {
+ r = JOptionPane.showConfirmDialog(jEq,
+ "Really close without saving?",
+ "alert", JOptionPane.OK_CANCEL_OPTION);
+ }
+ if (r == JOptionPane.OK_OPTION) {
+ jEq.dispose();
+ }
+ }
+ public void internalFrameOpened(InternalFrameEvent e) {
+ }
+ public void internalFrameClosed(InternalFrameEvent e) {
+ mainFrame.disconnectEq();
+ //System.out.println("FrameClosed");
+ }
+ public void internalFrameIconified(InternalFrameEvent e) {
+ }
+ public void internalFrameDeiconified(InternalFrameEvent e) {
+ }
+ public void internalFrameActivated(InternalFrameEvent e) {
+ }
+ public void internalFrameDeactivated(InternalFrameEvent e) {
+ }
+ }
+ );
+
+ System.out.print("jOutputFrame size: ");
+ System.out.println(jOutputFrame.getSize().toString());
+ System.out.print("Available space in jDesktop: ");
+ System.out.println(jDesktop.getInsets().toString());
+ System.out.print("jDesktop size: ");
+ System.out.println(jDesktop.getSize().toString());
+ }
+
+ public void doProcessInfo(ActionEvent e)
+ {
+ callFunction("info", "");
+ }
+
+ public void doProcessBreak(ActionEvent e)
+ {
+ sendInput("\02\n");
+ }
+
+ public void doProcessCont(ActionEvent e)
+ {
+ callFunction("continue", "");
+ }
+
+ public void doProcessTop(ActionEvent e)
+ {
+ // don't use callFunction because isSal might be wrong
+ // using (top) will work in both Lisp and Sal modes
+ sendInputLn("(top)");
+ }
+
+ public void doProcessSal(ActionEvent e) {
+ callFunction("sal", "");
+ }
+
+ public void doProcessLisp(ActionEvent e) {
+ sendInputLn("exit");
+ }
+
+ public void doProcessUp(ActionEvent e)
+ {
+ callFunction("up", "");
+ }
+
+ public void doProcessMark(ActionEvent e)
+ {
+ sendInput(Character.toString('\001'), true);
+ }
+
+ /* this is an old test function to simulate a slider change...
+ public void doProcessTest(ActionEvent e)
+ {
+ sendInput(Character.toString('\016'), true); // begin message
+ sendInput("S", true); // command is "slider change"
+ test_value += 1.0;
+ sendInput("5 ", true); // which slider
+ sendInput(Float.toString(test_value), true); // new value
+ sendInput(Character.toString('\021'), true); // end message
+ }
+ */
+
+ public void doProcessFn(ActionEvent e)
+ {
+ callFunction(e.getActionCommand(), "");
+ }
+
+ // Plot command
+ public void doProcessPlot(ActionEvent e) {
+ NyqPlot.plot("points.dat", plotFrame);
+ }
+
+
+ // Process | Copy to Lisp Command
+ public void doProcessCopyToLisp(ActionEvent e) {
+ JInternalFrame frame = jDesktop.getSelectedFrame();
+ if (frame instanceof NyquistFile) {
+ NyquistFile file = (NyquistFile) frame;
+ String selection = file.currentSelection();
+ jScrollPane.pane.setText(selection);
+ sendCommandToNyquist();
+ }
+ }
+
+ // adjust completion window and output windows only
+ public void tileCompletion() {
+ // place output frame at left, full height
+ Dimension dim = jDesktop.getSize();
+ // something goes wrong at initialization, so hack in a reasonable value
+ if (dim.width == 0 || dim.height == 0) {
+ System.out.println("desktop size is zero, guessing 800 by 612");
+ dim = new Dimension(800, 612);
+ } else {
+ System.out.println("desktop size is actually " + dim);
+ }
+ //System.out.print("jDesktop size: ");
+ //System.out.println(dim.toString());
+ int loc = (int) (dim.height * prefCompletionListPercent * 0.01);
+ jOutputFrame.setLocation(0, loc);
+ jListOutputFrame.setLocation(0, 0);
+ // make output_width based on width of "desktop", which is the
+ // area that contains the output frame and all the file (editor)
+ // frames.
+ int output_width = 530;
+ if (dim.width < 600) output_width = dim.width - 100;
+ if (output_width < 100) output_width = dim.width / 2;
+ jOutputFrame.setSize(output_width, dim.height - loc);
+ jListOutputFrame.setSize(output_width, loc);
+ System.out.println("jListOutputFrame.setSize " + output_width + " " + loc + " " + dim);
+ }
+
+ // Window Tile command -- organize window placement
+ public void doWindowTile(ActionEvent e) {
+ tileCompletion();
+ // place output frame at left, full height
+ Dimension dim = jDesktop.getSize();
+ System.out.println("jDesktop.getSize(): " + dim);
+ int output_width = 530; // for now this is constant, see tileCompletion
+
+ // organize windows
+ // if there are 3 or less or width is less than 1200,
+ // use one column
+ int cols = 1;
+ JInternalFrame[] frames = jDesktop.getAllFrames();
+ int num_frames = frames.length - 2; // don't count jOutput Frame or
+ // completion frame
+ if (!miniBrowser.isVisible()) num_frames--; // don't count browser frame
+ if (num_frames <= 0) return; // nothing to tile
+ if (num_frames > 3 && dim.width >= 1200) {
+ cols = 2;
+ }
+ int frames_per_col = (num_frames + cols - 1) / cols;
+ int frame_spacing = dim.height / frames_per_col;
+ // allow overlap if necessary
+ int frame_height = Math.max(frame_spacing, 100);
+ int frame_width = (dim.width - output_width) / cols;
+ int i;
+ int col = 0;
+ int row = 0;
+ for (i = 0; i < frames.length; i++) {
+ if (frames[i] != jOutputFrame && frames[i] != jListOutputFrame &&
+ frames[i].isVisible()) {
+ //NyquistFile nyquistFile = (NyquistFile) frames[i];
+ JInternalFrame nyquistFile = (JInternalFrame) frames[i];
+ nyquistFile.setLocation(output_width + col * frame_width,
+ row * frame_spacing);
+ nyquistFile.setSize(frame_width, frame_height);
+ row = row + 1;
+ if (row >= frames_per_col) {
+ row = 0;
+ col = col + 1;
+ }
+ }
+ }
+ }
+
+ // Window Browse command -- create a browse/demo window
+ public void doWindowBrowse(ActionEvent e) {
+ // place output frame at left, full height
+ loadBrowserFrame();
+ }
+
+ //Overridden so we can exit (if confirmed) when window is closed
+ protected void processWindowEvent(WindowEvent e) {
+ // super.processWindowEvent(e);
+ if (e.getID() == WindowEvent.WINDOW_CLOSING) {
+ Quit();
+ }
+ }
+
+ // convert backslash to escaped backslash in path for nyquist
+ public String escape_backslashes(String path) {
+ String escaped = "";
+ int i = 0;
+ while (i < path.length()) {
+ char c = path.charAt(i);
+ escaped = escaped + c;
+ if (c == '\\') escaped = escaped + c;
+ i++;
+ }
+ return escaped;
+ }
+
+ // set current directory
+ public void changeDirectory(String dir) {
+ System.out.println("changeDirectory: currentDir " + currentDir +
+ " to " + dir);
+ if (!currentDir.equals(dir)) {
+ currentDir = dir;
+ String escapedDir = escape_backslashes(dir);
+ callFunction("setdir", "\"" + escapedDir + "\"");
+ }
+ }
+
+ // tell nyquist to load a file
+ public void loadFile(File file) {
+ changeDirectory(fileDirectory(file));
+ String path = escape_backslashes(file.getAbsolutePath());
+ // if we're in lisp, pop out of any debug/break prompts before loading
+ // don't do this is we're in sal because it will exit Sal - not good
+ if (jScrollPane.isSal) {
+ // callFunction would also work, but I prefer to use the "native"
+ // Sal load command
+ sendInputLn("load \"" + path + "\"");
+ } else {
+ callFunction("top", "");
+ callFunction("sal-load", "\"" + path + "\"");
+ }
+ }
+
+
+ // send data to Nyquist process after fixing indentation and appending
+ // a newline
+ public void sendInputLn(String text) {
+ // fix text with indentation if there are multiple lines
+ String newlines = (jScrollPane.isSal ? "\n\n" : "\n");
+ sendInput(
+ text.replaceAll("\n", (jScrollPane.isSal ? "\n " : "\n ")) +
+ newlines, false);
+ }
+
+ public void setSalMode(final boolean sal) {
+ jScrollPane.isSal = sal;
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ String name = (sal ? "Lisp" : "Sal");
+ salLispButton.setText(name);
+ salLispButton.setActionCommand(name);
+ salLispButton.setToolTipText(sal ? "Switch to Lisp Mode" :
+ "Switch to SAL Mode");
+ }
+ });
+ }
+
+
+ // send data to Nyquist process
+ public void sendInput(String text) {
+ sendInput(text, false);
+ }
+
+ public void sendInput(String text, boolean hide) {
+ SwingUtilities.invokeLater(update);
+ System.out.println("sendInput: " + text + "(" + hide + ")");
+ nyquistThread.sendInput(text, hide);
+ }
+
+ public void sendCommandToNyquist() {
+ StringBuffer text = new StringBuffer(jScrollPane.pane.getText());
+ inputStrings[inputStringsX] = new String(text);
+ // for some reason, text sometimes ends up
+ // with a CR LF at end. Make sure it's gone
+ // before we output to Nyquist
+ filterCRLF(text);
+ // System.out.println("text |" + text + "| pos " + pos);
+ // SAL wants newline before multiline input to make input prettier
+ //if (jScrollPane.isSal &&
+ // inputStrings[inputStringsX].indexOf("\n") >= 0)
+ // sendInput("\n");
+
+ sendInputLn(inputStrings[inputStringsX]);
+ // System.out.println("text sent to Nyquist");
+ inputStringsX++;
+ if (inputStringsX >= inputStringsLen) {
+ inputStringsX = 0;
+ }
+ inputStringsCursor = inputStringsX;
+ jScrollPane.pane.setText("");
+ }
+
+ public void ScrollToEnd() {
+ JScrollBar scroll = jOutputPane.getVerticalScrollBar();
+ scroll.setValue(scroll.getMaximum() - scroll.getVisibleAmount());
+ }
+
+ public void loadBrowserFrame() {
+ Browser frame = new Browser(this, nyquistThread);
+
+ // Validate frames that have preset sizes
+ // Pack frames that have useful preferred size info, e.g. from their layout
+ if (packFrame) {
+ frame.pack();
+ } else {
+ frame.validate();
+ }
+ jDesktop.add(frame);
+ }
+
+ public void loadEnvData(String data) {
+ if (envelopeEditor != null) {
+ envelopeEditor.loadEnvData(data);
+ }
+ /* BEGIN UPIC */
+ /* if (upicEditor != null) {
+ upicEditor.loadEnvData(data);
+ } */
+ /* END UPIC */
+ }
+
+ public void loadEqData(String data) {
+ if (eqEditor != null) {
+ eqEditor.loadEqData(data);
+ }
+ }
+
+ public void setFontSize(int s) {
+ JInternalFrame[] frames = jDesktop.getAllFrames();
+ int i;
+ for (i = 0; i < frames.length; i++) {
+ if (frames[i] instanceof NyquistFile) {
+ NyquistFile nyquistFile = (NyquistFile) frames[i];
+ CodePane pane = nyquistFile.filePane;
+ pane.setFontSize(s);
+ }
+ }
+ jScrollPane.setFontSize(s);
+ jOutputArea.setFont(new Font("Courier", Font.PLAIN, s));
+ }
+
+}
+
diff --git a/jnyqide/MainFrame_AboutBox.java b/jnyqide/MainFrame_AboutBox.java
new file mode 100644
index 0000000..6f8d89a
--- /dev/null
+++ b/jnyqide/MainFrame_AboutBox.java
@@ -0,0 +1,98 @@
+package jnyqide;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+public class MainFrame_AboutBox extends JDialog implements ActionListener {
+
+ JPanel panel1 = new JPanel();
+ JPanel panel2 = new JPanel();
+ JPanel insetsPanel1 = new JPanel();
+ JPanel insetsPanel2 = new JPanel();
+ JPanel insetsPanel3 = new JPanel();
+ JButton button1 = new JButton();
+ JLabel imageLabel = new JLabel();
+ JLabel label1 = new JLabel();
+ JLabel label2 = new JLabel();
+ JLabel label3 = new JLabel();
+ JLabel label4 = new JLabel();
+ BorderLayout borderLayout1 = new BorderLayout();
+ BorderLayout borderLayout2 = new BorderLayout();
+ FlowLayout flowLayout1 = new FlowLayout();
+ GridLayout gridLayout1 = new GridLayout();
+ String product = "jNyqIDE - Nyquist Integrated Development Environment";
+ String version = "Version 2.0";
+ String copyright = "Copyright (c) 2002-2006";
+ String comments = "Jesse Clark, David Howard, David Mowatt, David Deangelis, and Roger B. Dannenberg";
+ public MainFrame_AboutBox(Frame parent) {
+ super(parent);
+ enableEvents(AWTEvent.WINDOW_EVENT_MASK);
+ try {
+ jbInit();
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ pack();
+ }
+ //Component initialization
+ private void jbInit() throws Exception {
+ //imageLabel.setIcon(new ImageIcon(MainFrame_AboutBox.class.getResource("[Your Image]")));
+ this.setTitle("About");
+ setResizable(false);
+ panel1.setLayout(borderLayout1);
+ panel2.setLayout(borderLayout2);
+ insetsPanel1.setLayout(flowLayout1);
+ insetsPanel2.setLayout(flowLayout1);
+ insetsPanel2.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+ gridLayout1.setRows(4);
+ gridLayout1.setColumns(1);
+ label1.setText(product);
+ label2.setText(version);
+ label3.setText(copyright);
+ label4.setText(comments);
+ insetsPanel3.setLayout(gridLayout1);
+ insetsPanel3.setBorder(BorderFactory.createEmptyBorder(10, 60, 10, 10));
+ button1.setText("Ok");
+ button1.addActionListener(this);
+ insetsPanel2.add(imageLabel, null);
+ panel2.add(insetsPanel2, BorderLayout.WEST);
+ this.getContentPane().add(panel1, null);
+ insetsPanel3.add(label1, null);
+ insetsPanel3.add(label2, null);
+ insetsPanel3.add(label3, null);
+ insetsPanel3.add(label4, null);
+ panel2.add(insetsPanel3, BorderLayout.CENTER);
+ insetsPanel1.add(button1, null);
+ panel1.add(insetsPanel1, BorderLayout.SOUTH);
+ panel1.add(panel2, BorderLayout.NORTH);
+ }
+ //Overridden so we can exit when window is closed
+ protected void processWindowEvent(WindowEvent e) {
+ if (e.getID() == WindowEvent.WINDOW_CLOSING) {
+ cancel();
+ }
+ super.processWindowEvent(e);
+ }
+ //Close the dialog
+ void cancel() {
+ dispose();
+ }
+ //Close the dialog on a button event
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == button1) {
+ cancel();
+ }
+ }
+}
diff --git a/jnyqide/MiniBrowser.java b/jnyqide/MiniBrowser.java
new file mode 100644
index 0000000..69e7d9f
--- /dev/null
+++ b/jnyqide/MiniBrowser.java
@@ -0,0 +1,66 @@
+package jnyqide;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.text.html.*;
+import javax.swing.event.*;
+import java.net.URL;
+
+public class MiniBrowser extends JInternalFrame {
+ JEditorPane urlPane;
+
+ class Hyperactive implements HyperlinkListener {
+ public void hyperlinkUpdate(HyperlinkEvent e) {
+ if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+ JEditorPane pane = (JEditorPane) e.getSource();
+ if (e instanceof HTMLFrameHyperlinkEvent) {
+ HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
+ //System.out.println("Target = " + evt.getTarget());
+ HTMLDocument doc = (HTMLDocument) pane.getDocument();
+ doc.processHTMLFrameHyperlinkEvent(evt);
+ } else {
+ try {
+ urlPane.setPage(e.getURL());
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+
+ public MiniBrowser(String title) {
+ super(title);
+ urlPane = new JEditorPane();
+ urlPane.setEditable(false);
+ urlPane.addHyperlinkListener(new Hyperactive());
+ JScrollPane sp = new JScrollPane(urlPane);
+ sp.setHorizontalScrollBarPolicy(
+ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+ sp.setVerticalScrollBarPolicy(
+ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+ setVisible(false);
+ setClosable(true);
+ getContentPane().add(sp);
+ setResizable(true);
+ setPreferredSize(new Dimension(400, 400));
+ setLocation(50, 100);
+ setSize(700, 400);
+ setDefaultCloseOperation(HIDE_ON_CLOSE);
+ }
+
+ public void setPage(String url) {
+ try {
+ // hard-wired URL for testing only!:
+ // System.out.println("setPage actual input: " + url);
+ // url = "file://doc/nyquist/doc/part8.html";
+ URL u = new URL(url);
+ System.out.println("MiniBrowser.setPage: " + u);
+ urlPane.setPage(u);
+ } catch (Exception ex) {
+ System.out.println(
+ "Exception from urlPane.setPage: " + ex);
+ }
+ }
+}
diff --git a/jnyqide/NotFoundDialog.java b/jnyqide/NotFoundDialog.java
new file mode 100644
index 0000000..12a61e0
--- /dev/null
+++ b/jnyqide/NotFoundDialog.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1997 John Jensen. All rights reserved.
+ *
+ * This software is FREE FOR COMMERCIAL AND NON-COMMERCIAL USE,
+ * provided the following condition is met.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that any copy or derivative of this software or documentation
+ * retaining the name "John Jensen" also retains this condition and the
+ * following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
+ *
+ * CopyrightVersion 1.0
+ */
+
+package jnyqide;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+class NotFoundDialog extends Dialog implements WindowListener, ActionListener
+{
+ private Button okButton;
+
+ public NotFoundDialog(MainFrame mainFrame, Properties strings,
+ Point loc)
+ {
+ super(mainFrame, "", true);
+
+ Panel north = new Panel();
+ north.add(new Label("Not Found"));
+ add("North", north);
+
+ okButton = new Button("Ok");
+ okButton.addActionListener(this);
+ Panel south = new Panel();
+ south.add(okButton);
+ add("South", south);
+
+ Dimension size = new Dimension(200,110);
+ setSize(size);
+ setLocation(loc);
+ // setLocation(textFrame.getPlace(size));
+
+ addWindowListener(this);
+ }
+
+ public void windowDeiconified(WindowEvent event) {}
+ public void windowIconified(WindowEvent event) {}
+ public void windowActivated(WindowEvent event) {}
+ public void windowDeactivated(WindowEvent event) {}
+ public void windowOpened(WindowEvent event) {}
+ public void windowClosed(WindowEvent event) {}
+ public void windowClosing(WindowEvent event)
+ {
+ dispose();
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ if (evt.getSource() == okButton)
+ dispose();
+ }
+
+}
diff --git a/jnyqide/NyqPlot.java b/jnyqide/NyqPlot.java
new file mode 100644
index 0000000..4d010c7
--- /dev/null
+++ b/jnyqide/NyqPlot.java
@@ -0,0 +1,131 @@
+package jnyqide;
+
+import java.io.*;
+import java.util.*;
+import java.awt.*;
+import javax.swing.*;
+
+// Note: Modifications to move plots from a JInternalFrame to a fixed JPanel
+// are marked with //JPANEL:
+
+public class NyqPlot
+{
+ /**
+ * main method takes 1 parameter from command line
+ * @param args name of input file
+ */
+ public static void plot(String plotFilename, PlotFrame plotFrame) {
+ if (plotFrame == null) {
+ System.out.println("null plotFrame in plot");
+ return;
+ }
+ BufferedReader input = null;
+
+ try {
+ input = new BufferedReader(new FileReader(plotFilename));
+ } catch( FileNotFoundException fnfx ) {
+ System.out.println("File not found: " + plotFilename);
+ return;
+ } // End try/catch block
+
+
+ /////////////////////////////////////////////////
+ // Read File
+ /////////////////////////////////////////////////
+
+ Vector<Pair> dataPoints = new Vector<Pair>();
+ String line;
+ StringTokenizer st;
+ boolean firsttime = true;
+
+ Double num1 = new Double(0);
+
+ double innum1 = 0;
+ double innum2 = 0;
+
+ double minx = 0;
+ double miny = 0;
+ double maxx = 0;
+ double maxy = 0;
+
+ System.out.println("plot reading file");
+ try {
+ while ((line = input.readLine()) != null) {
+ //Read another line from the file
+ st = new StringTokenizer(line);
+ if (st.countTokens() != 2) {
+ System.out.println("input must have two numbers per line");
+ return;
+ }
+
+ String word1 = st.nextToken();
+ String word2 = st.nextToken();
+
+ innum1 = num1.valueOf(word1).doubleValue();
+ innum2 = num1.valueOf(word2).doubleValue();
+
+ if (firsttime == true) {
+ // initializes mins and maxes to real values
+ minx = innum1;
+ maxx = innum1;
+ miny = innum2;
+ maxy = innum2;
+ firsttime = false;
+ }
+
+ if (innum1 < minx){minx = innum1;}
+ if (innum1 > maxx){maxx = innum1;}
+ if (innum2 < miny){miny = innum2;}
+ if (innum2 > maxy){maxy = innum2;}
+
+ Pair currentPair = new Pair(innum1, innum2);
+ dataPoints.add(currentPair);
+ } //while ((line = input.readLine()) != null)
+
+ input.close(); //Close the file
+
+ } catch( IOException iox ) {
+ System.out.println(iox );
+ } // End try/catch block
+
+ // printData(dataPoints);
+
+ //System.out.println("Min X = " + minx + " Max X = " + maxx);
+ //System.out.println("Min Y = " + miny + " Max Y = " + maxy);
+
+ // Plotting stuff
+/*
+ Color [] colors = new Color [4];
+
+ colors[0] = Color.red;
+ colors[1] = Color.yellow;
+ colors[2] = Color.green;
+ colors[3] = Color.blue;
+
+
+ double [][][] graphstuff = new double [1][2][dataPoints.size()];
+
+ for(int i = 0; i < dataPoints.size(); i++){
+ graphstuff[0][0][i] = ((Pair) dataPoints.get(i)).getNum1();
+ graphstuff[0][1][i] = ((Pair) dataPoints.get(i)).getNum2();
+ }
+
+
+ GRAph myGraph = new GRAph(colors);
+ myGraph.graphit(minx,maxx,miny,maxy,graphstuff);
+*/
+
+ plotFrame.PlotData(dataPoints, minx, miny, maxx, maxy);
+ //JPANEL: JInternalFrame plotFrame = new PlotFrame(jDesktop, dataPoints, minx, miny, maxx, maxy);
+ //JPANEL: JPanel plotFrame = new PlotFrame(jDesktop, dataPoints, minx, miny, maxx, maxy);
+ //JPANEL: plotFrame.setVisible(true);
+ }
+
+ public static void printData(Vector input){
+
+ for(int i = 0; i < input.size(); i++){
+ System.out.println( ((Pair) input.get(i)).getTime() + " " +
+ ((Pair) input.get(i)).getValue());
+ }
+ }
+}
diff --git a/jnyqide/NyquistFile.java b/jnyqide/NyquistFile.java
new file mode 100644
index 0000000..a7c1ec6
--- /dev/null
+++ b/jnyqide/NyquistFile.java
@@ -0,0 +1,590 @@
+package jnyqide;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.event.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.undo.*;
+import jnyqide.*;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+
+// BWP -- added "implements ActionListener"
+public class NyquistFile extends JInternalFrame
+ implements ActionListener, ComponentListener {
+ DefaultStyledDocument doc;
+ JTextPane pane;
+ public final CodePane filePane;
+ JLabel statusBar = new JLabel();
+ UndoManager undo;
+ File file;
+ public boolean modified = false;
+ NyquistFile thisFile;
+ MainFrame myParent; //BWP
+
+ String lastFound = ""; //BWP -- BUG, shouldn't these be global?
+ //String revertTo = ""; //BWP
+
+ public File getFile() {
+ return file;
+ }
+
+
+ // BWP: Constructors now take a MainFrame object to associate
+ // the document window with the parent window for Find
+ // and Find/Replace operations
+ public NyquistFile(MainFrame parent, int fontSize) { // BWP
+ this(null, parent, fontSize); // BWP
+ modified = true;
+ setTitle(getTitle()+"*");
+ }
+
+
+ public void readFile(File file) {
+ if (file != null) {
+ try {
+ FileInputStream openFileStream = new FileInputStream(file);
+
+ byte b[] = new byte[1000]; // read 1K at a time
+ int pos = 0;
+ //System.out.println("starting to read file");
+ doc.remove(0, doc.getLength()); // clear the current content
+ while (openFileStream.available() > 0) {
+ int count = openFileStream.read(b);
+ doc.insertString(pos, new String(b, 0, count),
+ TextColor.attrNormal);
+ pos += count;
+ }
+ }
+ catch (Exception e2) { System.out.println(e2); }
+ }
+ }
+
+
+ public void determineType() {
+ String name = file.getName();
+ filePane.isSal = name.toLowerCase().endsWith(".sal");
+ }
+
+
+ public NyquistFile(File f, MainFrame parent, int fontSize) {
+ super();
+
+ setTitle(f != null ? f.getName() : "Untitled");
+ file = f;
+ thisFile = this;
+
+ myParent = parent;
+
+ int keyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+ // Menu Bar for top of Document Windows
+ JMenuBar myMenuBar = new JMenuBar();
+
+ // File Menu
+ JMenu myFileMenu = new JMenu("File");
+
+ JMenuItem myLoad = new JMenuItem("Load");
+ myLoad.setActionCommand("load");
+ myLoad.addActionListener(this);
+ myLoad.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_K, keyMask));
+
+ JMenuItem mySave = new JMenuItem("Save");
+ mySave.setActionCommand("save");
+ mySave.addActionListener(this);
+ mySave.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, keyMask));
+
+ JMenuItem mySaveAs = new JMenuItem("Save As...");
+ mySaveAs.setActionCommand("save as");
+ mySaveAs.addActionListener(this);
+ mySaveAs.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S,
+ keyMask | java.awt.event.InputEvent.SHIFT_MASK));
+
+ JMenuItem myRevert = new JMenuItem("Revert");
+ myRevert.setActionCommand("revert");
+ myRevert.addActionListener(this);
+
+ JMenuItem myClose = new JMenuItem("Close");
+ myClose.setActionCommand("close");
+ myClose.addActionListener(this);
+ myClose.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_W, keyMask));
+
+ myFileMenu.add(myLoad);
+ myFileMenu.add(mySave);
+ myFileMenu.add(mySaveAs);
+ myFileMenu.add(myRevert);
+ myFileMenu.add(myClose);
+
+ // Edit Menu
+ JMenu myEditMenu = new JMenu("Edit");
+
+ JMenuItem myCut = new JMenuItem("Cut");
+ myCut.setActionCommand("cut");
+ myCut.addActionListener(this);
+ myCut.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, keyMask));
+
+ JMenuItem myCopy = new JMenuItem("Copy");
+ myCopy.setActionCommand("copy");
+ myCopy.addActionListener(this);
+ myCopy.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, keyMask));
+
+ JMenuItem myPaste = new JMenuItem("Paste");
+ myPaste.setActionCommand("paste");
+ myPaste.addActionListener(this);
+ myPaste.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_V, keyMask));
+
+ JMenuItem myFind = new JMenuItem("Find...");
+ myFind.setActionCommand("find");
+ myFind.addActionListener(this);
+ myFind.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, keyMask));
+
+ JMenuItem myNext = new JMenuItem("Find Next");
+ myNext.setActionCommand("next");
+ myNext.addActionListener(this);
+ myNext.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_G, keyMask));
+
+ JMenuItem myReplace = new JMenuItem("Replace");
+ myReplace.setActionCommand("replace");
+ myReplace.addActionListener(this);
+ myReplace.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_R, keyMask));
+
+ JMenuItem mySelect = new JMenuItem("Select Expression");
+ mySelect.setActionCommand("select expression");
+ mySelect.addActionListener(this);
+ mySelect.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_E, keyMask));
+
+ myEditMenu.add(myCut);
+ myEditMenu.add(myCopy);
+ myEditMenu.add(myPaste);
+ myEditMenu.addSeparator();
+ myEditMenu.add(myFind);
+ myEditMenu.add(myNext);
+ myEditMenu.add(myReplace);
+ myEditMenu.add(mySelect);
+
+ // Set up Menu Bar
+ myMenuBar.add(myFileMenu);
+ myMenuBar.add(myEditMenu);
+ thisFile.setJMenuBar(myMenuBar);
+ /* BWP END */ // end menu stuff
+
+ filePane = new CodePane(null, null, statusBar, fontSize);
+ pane = filePane.pane;
+ System.out.println("NyquistFile creation, this " + this + " pane = " + pane);
+ doc = filePane.doc;
+
+ getContentPane().add(filePane);
+ statusBar.setPreferredSize(new Dimension(200, 8));
+ getContentPane().add(statusBar, java.awt.BorderLayout.SOUTH);
+ statusBar.setText("");
+
+ if (file != null) {
+ readFile(file);
+ determineType();
+ }
+
+ /////////////// BWP BEGIN
+ // Right-Click Menu for the Document Window
+ JPopupMenu myContext = new JPopupMenu();
+
+ JMenuItem contextCut = new JMenuItem("Cut");
+ contextCut.setActionCommand("context cut");
+ contextCut.setName("context cut");
+ contextCut.addActionListener(this);
+
+ JMenuItem contextCopy = new JMenuItem("Copy");
+ contextCopy.setActionCommand("context copy");
+ contextCopy.setName("context copy");
+ contextCopy.addActionListener(this);
+
+ JMenuItem contextPaste = new JMenuItem("Paste");
+ contextPaste.setActionCommand("context paste");
+ contextPaste.setName("context paste");
+ contextPaste.addActionListener(this);
+
+ JMenuItem contextFind = new JMenuItem("Find");
+ contextFind.setActionCommand("context find");
+ contextFind.setName("context find");
+ contextFind.addActionListener(this);
+
+ JMenuItem contextReplace = new JMenuItem("Replace");
+ contextReplace.setActionCommand("context replace");
+ contextReplace.setName("context replace");
+ contextReplace.addActionListener(this);
+
+ JMenuItem contextSelect = new JMenuItem("Select Expression");
+ contextSelect.setActionCommand("context select");
+ contextSelect.setName("context select");
+ contextSelect.addActionListener(this);
+
+ myContext.add(contextCut);
+ myContext.add(contextCopy);
+ myContext.add(contextPaste);
+ myContext.addSeparator();
+ myContext.add(contextFind);
+ myContext.add(contextReplace);
+ myContext.add(contextSelect);
+
+ MouseListener popupListener = new PopupListener(myContext, pane);
+ pane.addMouseListener(popupListener);
+
+ //////////////// BWP END
+
+ setLocation(50+10, 50+10);
+ setSize(600, 500);
+ setBackground(Color.white);
+ setResizable(true);
+ setVisible(true);
+ this.setClosable(true);
+ this.setMaximizable(true);
+ this.setIconifiable(true);
+ setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
+
+ System.out.println("Adding component listener");
+ filePane.addComponentListener(this);
+
+ doc.addDocumentListener(
+ new DocumentListener() {
+ public void changedUpdate(DocumentEvent e) {
+ }
+ public void removeUpdate(DocumentEvent e) {
+ //filePane.synchronousUpdate(null);
+ if (!modified) {
+ modified = true;
+ thisFile.setTitle(thisFile.getTitle() + "*");
+ }
+ }
+ public void insertUpdate(DocumentEvent e) {
+ // System.out.println("insertUpdate calls thread.update");
+ //filePane.synchronousUpdate(null);
+ if (!modified) {
+ modified = true;
+ thisFile.setTitle(thisFile.getTitle() + "*");
+ }
+ }
+ });
+ //revertTo = pane.getText(); // BWP
+ }
+
+ public void doFileSave() {
+ if (file != null) save(file.getParent());
+ else saveAs("");
+ }
+
+ //// BWP BEGIN
+ public void actionPerformed(ActionEvent e)
+ {
+ //System.out.println(e.getActionCommand());
+
+ // File Menu options
+ if (e.getActionCommand().equals("load")) {
+ doFileSave();
+ myParent.loadFile(file);
+ } else if (e.getActionCommand().equals("save")) {
+ doFileSave();
+ } else if (e.getActionCommand().equals("save as")) {
+ if (file != null) saveAs(file.getParent());
+ else saveAs("");
+ } else if (e.getActionCommand().equals("revert")) {
+ if (modified && file != null) {
+ readFile(file);
+ myParent.loadFile(file);
+ //pane.setText(revertTo);
+ modified = false;
+ thisFile.setTitle(thisFile.getTitle().substring(0,
+ thisFile.getTitle().length() - 1));
+ }
+ } else if (e.getActionCommand().equals("close")) {
+ int input = 1;
+
+ if (modified)
+ input = JOptionPane.showConfirmDialog(null,
+ "Close without saving?", "Closing...",
+ JOptionPane.YES_NO_OPTION);
+ else this.dispose();
+
+ if (input == 0) this.dispose();
+ // Edit Menu options
+ } else if (e.getActionCommand().equals("cut")) {
+ pane.cut();
+ } else if (e.getActionCommand().equals("copy")) {
+ pane.copy();
+ } else if (e.getActionCommand().equals("paste")) {
+ pane.paste();
+ } else if (e.getActionCommand().equals("find")) {
+ FindDialog findDialog = new FindDialog(thisFile, myParent);
+ } else if (e.getActionCommand().equals("next")) {
+ if (!lastFound.equals("")) find(lastFound);
+ } else if (e.getActionCommand().equals("replace")) {
+ ReplaceDialog replaceDialog = new ReplaceDialog(thisFile, myParent);
+ } else if (e.getActionCommand().equals("select expression")) {
+ myParent.doEditSelectExpression(e);
+ // Context Menu Options
+ } else if (e.getActionCommand().equals("context cut")) {
+ pane.cut();
+ } else if (e.getActionCommand().equals("context copy")) {
+ pane.copy();
+ } else if (e.getActionCommand().equals("context paste")) {
+ pane.paste();
+ } else if (e.getActionCommand().equals("context find")) {
+ FindDialog findDialog = new FindDialog(thisFile, myParent);
+ } else if (e.getActionCommand().equals("context replace")) {
+ ReplaceDialog replaceDialog = new ReplaceDialog(thisFile, myParent);
+ } else if (e.getActionCommand().equals("context select")) {
+ myParent.doEditSelectExpression(e);
+ }
+ //// BWP END
+ }
+
+ public void componentResized(ComponentEvent e) {
+ System.out.println(e.getComponent().getClass().getName() +
+ " --- Resized ");
+ filePane.synchronousUpdate();
+ }
+
+ public void componentHidden(ComponentEvent e) {
+ System.out.println(e.getComponent().getClass().getName() +
+ " --- Hidden ");
+ }
+
+ public void componentMoved(ComponentEvent e) {
+ System.out.println(e.getComponent().getClass().getName() +
+ " --- Moved ");
+ }
+
+
+ public void componentShown(ComponentEvent e) {
+ System.out.println(e.getComponent().getClass().getName() +
+ " --- Shown ");
+ }
+
+
+ String currentSelection() {
+ System.out.println("currentSelection: this " + this + " pane " + pane);
+ int p = pane.getSelectionStart();
+ int q = pane.getSelectionEnd();
+ try {
+ return doc.getText(p, q - p);
+ } catch(Exception e) {
+ System.out.println(e);
+ return "";
+ }
+ }
+
+ public void setCursor(int line, int col) {
+ try { // because getText raises an exception BadLocationException
+ String text = doc.getText(0, doc.getLength());
+ int i = 0;
+ int j = 0;
+ while (j < line - 1)
+ if (text.charAt(i++) == '\n') j++;
+ final int pos = i + col - 1;
+ EventQueue.invokeLater(
+ new Runnable() {
+ public void run() {
+ System.out.println("Automatically move caret to " + pos);
+ pane.select(pos, pos);
+ }
+ });
+ } catch(Exception e) {
+ System.out.println(e);
+ }
+ }
+
+
+ public void selectExpression() {
+ int docLength;
+ String text;
+ try {
+ docLength = doc.getLength();
+ text = doc.getText(0, docLength);
+ } catch (Exception e) {
+ System.out.println(e); return;
+ }
+ int p = pane.getSelectionStart();
+ int openParenLoc = CodePane.findOpenParen(text, p);
+ if (openParenLoc == p) return;
+ if (openParenLoc < 0) return; // no open paren enclosing start of selection
+ // now findx is the beginning of the expression and closed == 0
+ // go forward from p to find close paren
+
+ int closed = 0;
+ while (p < text.length() && closed < 1) {
+ char c = text.charAt(p);
+ if (c == '(' || c == ')') {
+ if (!CodePane.inComment(text, p)) {
+ if (c == '(') closed--;
+ else if (c == ')') closed++;
+ }
+ }
+ if (closed < 1) // not done, keep going
+ p = forward(text, p, false);
+ }
+
+ pane.select(openParenLoc, p + 1); // add one to include close paren
+ }
+
+
+ private static int forward(String text, int pos, boolean inString)
+ // find an index in text after pos by skipping over strings and
+ // escaped characters of the form #\A, also skip comment
+ // lines. If pos is text.length() - 1, return text.length()
+ {
+ boolean comment = false;
+ boolean string = false;
+ while (pos < text.length()) {
+ char c = text.charAt(pos);
+ if (comment) {
+ if (c == '\n') {
+ comment = false;
+ }
+ } else if (string) {
+ if (c == '"') { // skip string
+ string = false;
+ }
+ } else if (c == '\\') { // skip quoted char
+ pos++;
+ } else if (c == '"') {
+ string = true;
+ } else if (c == ';') {
+ comment = true;
+ }
+ pos++;
+ if (!comment && !string) return pos;
+ }
+ return pos;
+ }
+
+
+ public boolean find(String pat) {
+ String docText = "";
+ int start = pane.getSelectionEnd();
+ //System.out.print("location ");
+ //System.out.println(start);
+ try {
+ docText = doc.getText(0, doc.getLength());
+ } catch(Exception e) {System.out.println(e);}
+
+ //System.out.print(docText);
+ int found = docText.indexOf(pat, start);
+ if (found == -1) {
+ found = docText.indexOf(pat, 0);
+ }
+ if (found == -1) return false;
+ pane.select(found, found + pat.length());
+ return true;
+ }
+
+ public String copy(boolean a, boolean b)
+ {
+ String selectedText = pane.getSelectedText();
+ pane.copy();
+ return selectedText;
+ }
+
+ public boolean paste(String text)
+ {
+ pane.replaceSelection(text);
+ return true;
+ }
+
+ public String getAbsolutePath()
+ {
+ return file.getAbsolutePath();
+ }
+
+ public boolean save(String currentDir)
+ // saves the file if there is a file name, otherwise calls saveAs.
+ // returns false if the operation fails or is cancelled.
+ // returns true if save succeeds or if file is unmodified.
+ {
+ if (modified) {
+ if (file == null)
+ return saveAs(currentDir);
+ else {
+ try {
+ long length = file.length();
+ long newLength = doc.getLength();
+ System.out.println("existing " + length + " new " + newLength);
+ String msg = null;
+ if (length > 0 && newLength == 0) {
+ msg = "Replace existing file with an empty document?";
+ } else if (length > newLength * 2) {
+ msg = "Replace file with new document that is less than 1/2 the existing size?";
+ }
+ if (msg != null) {
+ int n = JOptionPane.showConfirmDialog(this, msg, "WARNING",
+ JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+ if (n == JOptionPane.NO_OPTION) return false;
+ }
+
+ FileOutputStream saveFileStream =
+ new FileOutputStream(file);
+
+ String fileStr = doc.getText(0, doc.getLength());
+ saveFileStream.write(fileStr.getBytes());
+ saveFileStream.flush();
+ }
+ catch(Exception e) {
+ System.out.println(e);
+ return false; // did not save file
+ }
+
+ modified = false;
+ thisFile.setTitle(thisFile.getTitle().substring(
+ 0, thisFile.getTitle().length() - 1));
+ }
+ }
+ //revertTo = pane.getText();
+ return true;
+ }
+
+ public boolean saveAs(String currentDir) {
+ // select a file and write to it. Return true if success.
+ JFileChooser chooser = new JFileChooser();
+ LispFileFilter filter = new LispFileFilter();
+ SalFileFilter salFilter = new SalFileFilter();
+ String name; // new file name
+ chooser.setFileFilter(filter);
+ chooser.setFileFilter(salFilter);
+
+ File curdir = new File(currentDir);
+ chooser.setCurrentDirectory(curdir);
+
+ while (true) { // loop until file is chosen
+ int returnVal = chooser.showSaveDialog(this);
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ file = chooser.getSelectedFile();
+ name = file.getName();
+ System.out.println("You chose to save this file: " + name);
+ String lower = name.toLowerCase();
+ if (lower.endsWith(".sal") ||
+ lower.endsWith(".lsp")) break;
+ JOptionPane dialog = new JOptionPane();
+ System.out.println("creating dialog");
+ int result = dialog.showConfirmDialog(this,
+ "Do you really want to save a file without a " +
+ ".lsp or .sal extension?", "Warning",
+ JOptionPane.YES_NO_OPTION);
+ System.out.println("return from dialog " + result);
+ if (result == JOptionPane.YES_OPTION) break;
+ } else { // file chooser cancel, early return
+ return false;
+ }
+ }
+ setTitle(name + "*");
+ determineType();
+ modified = true;
+ return save(currentDir);
+ }
+
+}
diff --git a/jnyqide/NyquistThread.java b/jnyqide/NyquistThread.java
new file mode 100644
index 0000000..e579558
--- /dev/null
+++ b/jnyqide/NyquistThread.java
@@ -0,0 +1,424 @@
+package jnyqide;
+
+import java.io.*;
+import javax.swing.*;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+public class NyquistThread extends Thread {
+
+ Process myProcess;
+ InputStream stdout;
+ InputStreamReader isrStdout;
+ BufferedReader brStdout;
+ OutputStream stdin;
+ byte b[];
+// JTextPane textIn;
+ JTextArea textOut;
+ Runnable update;
+ String plotFilename;
+ boolean plotNow = false;
+ boolean envelopeNow = false;
+ boolean editNow = false;
+ boolean eqNow = false;
+ boolean preferenceDataSent = false;
+ boolean initialLoad = false;
+ String envData;
+ String eqData;
+ PlotFrame plotFrame;
+ MainFrame mainFrame; // used to find current directory
+ String soundBrowser; // path for sound browser
+ String scoreEditFileName;
+ public NyquistThread() {
+ }
+
+/* public void setInputArea( JTextPane in )
+ {
+ textIn = in;
+ }*/
+
+ public String StringFromFile(String filename, String default_string) {
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(filename));
+ default_string = br.readLine();
+ br.close();
+ } catch (Exception e) {
+ // do nothing
+ }
+ return default_string;
+ }
+
+ public void start(JTextArea out, Runnable u,
+ PlotFrame plot, MainFrame main) {
+ textOut = out;
+ update = u;
+ plotFrame = plot;
+ mainFrame = main;
+
+ try {
+ // Get the current working directory where we can find lib and runtime
+ // get the "." file present in all directories
+ //java.io.File f = new java.io.File(".");
+ // get the absolute path to the "." file
+ //String cwd2 = f.getAbsolutePath();
+ // return the absolute path minus the "."
+ //cwd2 = cwd2.substring(0, cwd2.length() - 2);
+ // the code above works, but the following is simpler:
+
+ // find full path to instruments.txt
+ String cwd = System.getProperty("user.dir");
+ soundBrowser = cwd.concat("/lib/instruments.txt");
+ System.out.println("soundBrowser file is " + soundBrowser);
+
+ // build XLISPPATH environment specification
+ String path = System.getenv("XLISPPATH"); // use getenv
+ if (path == null) { // getenv failed, use a default setting
+ path = cwd + "/lib/;" + cwd + "/runtime/;";
+ }
+ // if xlisppath file exists, use it instead
+ path = "XLISPPATH=" + StringFromFile("xlisppath", path);
+
+ // construct SystemRoot for environment from file
+ String systemroot = StringFromFile("systemroot", "SystemRoot=C:/windows");
+
+ // See if we can get the USER
+ String user = System.getenv("USER");
+ if (user == null) user = "";
+ user = StringFromFile("user", user); // file value overrides all
+ if (user == "") user = "IGNORE="; // default value
+ else user = "USER=" + user;
+
+ // Construct the environment for nyquist subprocess
+ System.out.println(path);
+ System.out.println(user);
+
+ // make environment from 3 strings
+ String[] envp = {path, user, systemroot};
+ System.out.println("envp has " + systemroot);
+
+ try {
+ myProcess = Runtime.getRuntime().exec( "./ny", envp );
+ } catch (Exception e3) {
+ System.out.println("no ./ny found, trying ./nyquist");
+ try {
+ myProcess = Runtime.getRuntime().exec("./nyquist", envp);
+ } catch (Exception e4) {
+ System.out.println("no ./nyquist found, trying ny");
+ // try using PATH to find ny (for linux systems where
+ // ny is installed)
+ myProcess = Runtime.getRuntime().exec("ny", envp);
+ // if this one fails, we'll take the exception below
+ }
+ }
+ System.out.print("myProcess: " + myProcess);
+
+ stdout = myProcess.getInputStream();
+ isrStdout = new InputStreamReader(stdout);
+ brStdout = new BufferedReader(isrStdout);
+ stdin = myProcess.getOutputStream();
+ stdin.write(6); // control-f turns off console echo for Mac and Linux
+ stdin.flush();
+ }
+ catch( Exception e2 ) { System.out.println(e2); }
+
+ b = new byte[1000];
+ if (brStdout != null) {
+ super.start();
+ } else {
+ textOut.append("Nyquist (ny or nyquist) not found or could not be started.");
+ }
+ }
+
+ public void run() {
+ final int max_buf_len = 256;
+ StringBuffer buffer = new StringBuffer(max_buf_len);
+ int buffer_index = 0;
+ boolean nyquist_is_running = true;
+ // this is tricky -- we want to accumulate lines to test
+ // for plot commands, but we want to append chars to
+ // textOut even if there is no end-of-line.
+ //
+ // We're going to flush the buffer after every line.
+ // That will be expensive if lines are very short, but
+ // that's pretty rare. So we'll loop until we either
+ // accumulate a line or there are no characters ready.
+ // To avoid re-appending characters to textOut, use
+ // buffer_index to remember how many characters were
+ // output from the current line.
+ //
+ // Algorithm:
+ // accumulate chars while input is ready and newline not found
+ // if we have a newline, test for plot command
+ // append characters to text box
+ // if we have a newline, reset the buffer
+
+ String line = null;
+ //String debug_strings[] = new String[100];
+ //int debug_strings_x = 0;
+ while (nyquist_is_running) {
+ try {
+ // initialLoad is true when we see text that indicates
+ // Nyquist has just started. But we want to wait for the
+ // first prompt. We do this by delaying this process a bit
+ // hoping that Nyquist will finish output and issue the
+ // prompt. Then we process the input until we are about to
+ // block, meaning that (maybe) Nyquist has finished output
+ // and is waiting at the prompt.
+ if (initialLoad && !brStdout.ready()) {
+ mainFrame.sendPreferenceData();
+ initialLoad = false;
+ }
+ // block until you read at least one character
+ int ic = brStdout.read();
+ //System.out.println("got char");
+ if (ic != -1) buffer.append((char) ic);
+ // read many characters to avoid the overhead of single
+ // character output. On the other hand, it's expensive
+ // to build huge buffers if Nyquist outputs a giant
+ // list, so limit the buffer length to max_buf_len.
+ while (brStdout.ready() && ic != '\n' && ic != -1 &&
+ buffer.length() < max_buf_len) {
+ //System.out.println("block on char in while");
+ ic = brStdout.read();
+ //System.out.println("got it");
+ if (ic != -1) buffer.append((char) ic);
+ }
+ if ((char) ic == '\n') {
+ line = new String(buffer);
+ testForPlot(line);
+ } else if (buffer.length() >= max_buf_len) {
+ // pretend we found a line in order to flush
+ // characters building up in buffer
+ line = " ";
+ } else if (ic == -1) {
+ buffer.append("The Nyquist process has terminated. Please save your files and exit.\n");
+ nyquist_is_running = false;
+ }
+ textOut.append(buffer.substring(buffer_index));
+ buffer_index = buffer.length();
+ if (line != null) { // end of line, reset the buffer
+ line = null;
+ buffer.setLength(0);
+ buffer_index = 0;
+ // limit number of lines and characters in the textOut box
+ int lines = textOut.getLineCount();
+ if (lines > 5000 ||
+ textOut.getLineEndOffset(lines - 1) > 50000) {
+ // take out about 100 lines at a time:
+ textOut.replaceRange("", 0,
+ textOut.getLineStartOffset(
+ Math.max(1, lines - 4900)));
+ }
+ }
+ // cause the scroll to go to the end of the new text
+ SwingUtilities.invokeLater(update);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ }
+
+ private NyquistFile findFile(String filename) {
+ JInternalFrame[] frames = mainFrame.jDesktop.getAllFrames();
+ int i;
+ for (i = 0; i < frames.length; i++) {
+ if (frames[i] instanceof NyquistFile) {
+ NyquistFile nyquistFile = (NyquistFile) frames[i];
+ System.out.println("findFile search: " +
+ nyquistFile.file.getName() +
+ " file " + nyquistFile.file + " getAbsolutePath " +
+ nyquistFile.file.getAbsolutePath());
+ if (nyquistFile.file.getAbsolutePath().equals(filename))
+ return nyquistFile;
+ }
+ }
+ return null;
+ }
+
+
+ // testForPlot looks for Nyquist output that the jNyqIDE wants to know
+ // about -- originally just plot command output, but now there are many
+ // Lisp functions that communicate and synchronize with the jNyqIDE
+ public void testForPlot(String output) {
+ int iNameStart;
+ int iNameStop;
+ //System.out.print("plot's text output:");
+ //System.out.println(output);
+ if (!plotNow) {
+ iNameStart = output.indexOf("s-plot: writing ");
+ if (iNameStart >= 0) {
+ iNameStop = output.indexOf(" ...");
+ plotFilename = output.substring(iNameStart + 16, iNameStop);
+ // Nyquist file should be absolute or current directories
+ // should be synchronized. Appending the current directory
+ // causes problems when Nyquist already prints a full path
+ //if (!mainFrame.currentDir.equals("")) {
+ // plotFilename = mainFrame.currentDir + plotFilename;
+ //}
+ System.out.println("file:" + plotFilename + ":");
+ plotNow = true;
+ }
+ }
+ // this is not ...else if... because output can have many lines
+ if (plotNow) {
+ iNameStart = output.indexOf(" points from");
+ // now, the file is written and closed so we can open it
+ if (iNameStart >= 0) {
+ System.out.println("Calling NyqPlot.plot");
+ NyqPlot.plot(plotFilename, plotFrame);
+ plotNow = false;
+ }
+ }
+ // test for loading workspace and saving workspace
+ if (output.indexOf("workspace loaded") >= 0) {
+ mainFrame.workspaceLoaded = true;
+ } else if (output.indexOf("workspace saved") >= 0) {
+ mainFrame.workspaceSaved = true;
+ } else if (!envelopeNow) { // test for envelope data
+ int index = output.indexOf("get-env-data: begin");
+ if (index >= 0) {
+ output = output.substring(index);
+ envData = "";
+ envelopeNow = true;
+ }
+ }
+ if (envelopeNow) {
+ envData += output;
+ int index = envData.indexOf("get-env-data: end");
+ // remove first line
+ if (index >= 0) {
+ int begin = envData.indexOf("\n");
+ envData = envData.substring(begin + 1, index);
+ mainFrame.loadEnvData(envData);
+ envelopeNow = false;
+ }
+ }
+ if (!eqNow) {
+ int index = output.indexOf("get-eq-data: begin");
+ if (index >= 0) {
+ output = output.substring(index);
+ eqData = "";
+ eqNow = true;
+ }
+ }
+ if (eqNow) {
+ eqData += output;
+ int index = eqData.indexOf("get-eq-data: end");
+ // remove first line
+ if (index >= 0) {
+ int begin = eqData.indexOf("\n");
+ eqData = eqData.substring(begin + 1, index);
+ mainFrame.loadEqData(eqData);
+ eqNow = false;
+ }
+ }
+ if (!editNow) {
+ iNameStart = output.indexOf("score-edit: writing ");
+ if (iNameStart >= 0) {
+ iNameStop = output.indexOf(" ...");
+ scoreEditFileName = output.substring(iNameStart + 20, iNameStop);
+ if (!mainFrame.currentDir.equals("")) {
+ scoreEditFileName = mainFrame.currentDir + scoreEditFileName;
+ }
+ System.out.println("file:" + scoreEditFileName + ":");
+ editNow = true;
+ }
+ }
+ if (editNow) {
+ iNameStart = output.indexOf("score-edit: wrote ");
+ if (iNameStart >= 0) {
+ Piano_Roll.scoreEdit(scoreEditFileName);
+ editNow = false;
+ }
+ }
+ if (!preferenceDataSent) {
+ iNameStart = output.indexOf("by Roger B. Dannenberg");
+ if (iNameStart >= 0) {
+ try { Thread.sleep(200); }
+ catch (InterruptedException ie) { }
+ initialLoad = true;
+ preferenceDataSent = true;
+ }
+ }
+ // System.out.println("OUTPUT FOR PROMPT SEARCH: " + output);
+ // determine command input mode from prompt by Nyquist:
+ int promptLoc = output.indexOf("> ");
+ if (output.indexOf("Entering SAL mode ...") >= 0) {
+ mainFrame.setSalMode(true);
+ } else if (output.indexOf("Returning to Lisp ...") >= 0) {
+ mainFrame.setSalMode(false);
+ } else if (output.indexOf("[ back to top level ]") >= 0) {
+ mainFrame.setSalMode(false);
+ } else if (output.indexOf("if continued: return from BREAK") >= 0) {
+ mainFrame.setSalMode(false);
+ } else if (promptLoc == 2 && output.indexOf(">>> in ") == 0) {
+ System.out.println("... detected >>> in (error line location) ");
+ int lineLoc = output.indexOf(", line ");
+ int colLoc = output.indexOf(", col ");
+ if (lineLoc > 0 && colLoc > 0) {
+ String filename = output.substring(7, lineLoc);
+ String lineString = output.substring(lineLoc + 7, colLoc);
+ String colString = output.substring(colLoc + 6,
+ output.length() - 2);
+ NyquistFile nf = findFile(filename);
+ System.out.println("nf.setCursor line " + lineString +
+ " col " + colString + " file " + filename + " nf " + nf);
+ if (isDigits(lineString) && isDigits(colString) && nf != null) {
+ nf.setCursor(Integer.parseInt(lineString),
+ Integer.parseInt(colString));
+ }
+ }
+ } else if (promptLoc >= 0) {
+ if (output.indexOf("SAL> ") == 0) {
+ mainFrame.setSalMode(true);
+ // System.out.println("in SAL mode");
+ } else if (isDigits(output.substring(0, promptLoc))) {
+ mainFrame.setSalMode(false);
+ // System.out.println("in LISP mode");
+ }
+ }
+ }
+
+ private boolean isDigits(String s) {
+ // returns true if all chars in s are digits
+ for (int i = 0; i < s.length(); i++)
+ if (!Character.isDigit(s.charAt(i))) return false;
+ return true;
+ }
+
+
+ public OutputStream getStdin() {
+ return stdin;
+ }
+
+ public void sendInput(String s) {
+ sendInput(s, false);
+ }
+
+ public void sendInput(String s, boolean hide) {
+ try {
+ //System.out.println("Sending:" + hide + ": " + s);
+ if (!hide) textOut.append(s);
+ stdin.write( s.getBytes() );
+ stdin.flush();
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
diff --git a/jnyqide/NyquistWords.txt b/jnyqide/NyquistWords.txt
new file mode 100644
index 0000000..a5c5798
--- /dev/null
+++ b/jnyqide/NyquistWords.txt
@@ -0,0 +1,1520 @@
+* expr ...)
+part19.html#index1460
+*a4-hertz*
+part9.html#index789
+*applyhook*
+part19.html#index1298
+*autonorm*
+part9.html#index790
+*autonorm-max-samples*
+part9.html#index792
+*autonorm-previous-peak*
+part9.html#index793
+*autonorm-target*
+part9.html#index794
+*autonorm-type*
+part9.html#index795
+*autonormflag*
+part9.html#index791
+*breakenable*
+part19.html#index1293
+*breakenable*
+part19.html#index1293
+*control-srate*
+part9.html#index797
+*control-srate*
+part9.html#index797
+*debug-io*
+part19.html#index1292
+*default-control-srate*
+part9.html#index802
+*default-plot-file*
+part8.html#index629
+*default-sf-bits*
+part9.html#index798
+*default-sf-dir*
+part9.html#index799
+*default-sf-format*
+part9.html#index800
+*default-sf-srate*
+part9.html#index801
+*default-sound-srate*
+part9.html#index803
+*error-output*
+part19.html#index1290
+*evalhook*
+part19.html#index1297
+*file-separator*
+part9.html#index804
+*float-format*
+part19.html#index1304
+*gc-flag*
+part19.html#index1301
+*gc-hook*
+part19.html#index1302
+*integer-format*
+part19.html#index1303
+*loud*
+part4.html#index130
+*obarray*
+part19.html#index1287
+*print-case*
+part19.html#index1305
+*readtable*
+part19.html#index1299
+*rslt*
+part9.html#index805
+*sound-srate*
+part9.html#index806
+*sound-srate*
+part9.html#index806
+*soundenable*
+part9.html#index807
+*standard-input*
+part19.html#index1288
+*standard-output*
+part19.html#index1289
+*start*
+part4.html#index133
+*stop*
+part4.html#index134
+*sustain*
+part4.html#index132
+*table*
+part9.html#index788
+*trace-output*
+part19.html#index1291
+*tracelimit*
+part19.html#index1296
+*tracelist*
+part19.html#index1294
+*tracenable*
+part19.html#index1295
+*tracenable*
+part19.html#index1295
+*transpose*
+part4.html#index131
+*unbound*
+part19.html#index1300
+*warp*
+part4.html#index129
++ expr ...)
+part19.html#index1458
+- expr ...)
+part19.html#index1459
+/ expr ...)
+part19.html#index1461
+1+ expr)
+part19.html#index1462
+1- expr)
+part19.html#index1463
+< n1 n2 ...)
+part19.html#index1483
+abs expr)
+part19.html#index1471
+abs-env beh)
+part8.html#index546
+add-action-to-workspace symbol)
+part14.html#index1144
+add-to-workspace symbol)
+part14.html#index1141
+address-of expr)
+part19.html#index1612
+agc input range rise-time fall-time [lookahead])
+part15.html#index1170
+alloc num)
+part19.html#index1602
+allpass2 signal hz [q])
+part8.html#index438
+allpoles-from-lpc snd lpc-frame)
+part12.html#index970
+alpass sound decay hz [minhz])
+part8.html#index401
+amosc pitch modulation [table phase])
+part8.html#index367
+and expr ...)
+part19.html#index1407
+append expr ...)
+part19.html#index1353
+apply fun args)
+part19.html#index1308
+apply-banded-bass-boost s lowp highp num-bands num-boost gain)
+part15.html#index1198
+apply-banded-delay s lowp highp num-bands lowd highd fb wet)
+part15.html#index1196
+apply-banded-treble-boost s lowp highp num-bands num-boost gain)
+part15.html#index1200
+arc-sine-dist )
+part14.html#index1069
+aref array n)
+part19.html#index1337
+areson sound center bandwidth n)
+part8.html#index423
+args name)
+part13.html#index983
+arrayp expr)
+part19.html#index1391
+assoc expr alist :test test :test-not test-not)
+part19.html#index1357
+at time beh)
+part8.html#index547
+at-abs time beh)
+part8.html#index549
+atan expr[expr2])
+part19.html#index1479
+atom expr)
+part19.html#index1379
+atone sound cutoff)
+part8.html#index418
+autonorm-off )
+part8.html#index608
+autonorm-on )
+part8.html#index607
+backquote expr)
+part19.html#index1312
+baktrace [n])
+part19.html#index1450
+bandpass2 signal hz [q])
+part8.html#index436
+bernoulli-dist px1 [x1 x2])
+part14.html#index1076
+beta-dist a b)
+part14.html#index1074
+bigendianp )
+part19.html#index1608
+bilateral-exponential-dist xmu tau [low high])
+part14.html#index1062
+binomial-dist n p)
+part14.html#index1078
+biquad signal b0 b1 b2 a0 a1 a2)
+part8.html#index432
+biquad-m signal b0 b1 b2 a0 a1 a2)
+part8.html#index433
+block name expr ...)
+part19.html#index1430
+both-case-p chr)
+part19.html#index1524
+boundp sym)
+part19.html#index1395
+bowed step bowpress-env)
+part8.html#index496
+bowed-freq step bowpress-env freq-env)
+part8.html#index498
+break [bmsg[arg]])
+part19.html#index1445
+build-harmonic n table-size)
+part8.html#index334
+buzz n pitch modulation)
+part8.html#index371
+car expr)
+part19.html#index1341
+case expr case ...)
+part19.html#index1412
+catch sym expr ...)
+part19.html#index1418
+cauchy-dist tau [low high])
+part14.html#index1064
+cdr expr)
+part19.html#index1342
+cerror cmsg emsg[arg])
+part19.html#index1444
+char string index)
+part19.html#index1521
+char-code chr)
+part19.html#index1526
+char-downcase chr)
+part19.html#index1529
+char-equalp chr1 chr2 ...)
+part19.html#index1541
+char-greaterp chr1 chr2 ...)
+part19.html#index1544
+char-int chr)
+part19.html#index1531
+char-lessp chr1 chr2 ...)
+part19.html#index1539
+char-not-equalp chr1 chr2 ...)
+part19.html#index1542
+char-not-greaterp chr1 chr2 ...)
+part19.html#index1540
+char-not-lessp chr1 chr2 ...)
+part19.html#index1543
+char-upcase chr)
+part19.html#index1528
+char/= chr1 chr2 ...)
+part19.html#index1536
+char< chr1 chr2 ...)
+part19.html#index1533
+char<= chr1 chr2 ...)
+part19.html#index1534
+char= chr1 chr2 ...)
+part19.html#index1535
+char> chr1 chr2 ...)
+part19.html#index1538
+char>= chr1 chr2 ...)
+part19.html#index1537
+characterp expr)
+part19.html#index1390
+chorus snd maxdepth depth rate saturation)
+part15.html#index1191
+clarinet step breath-env)
+part8.html#index474
+clarinet-all step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise)
+part8.html#index480
+clarinet-freq step breath-env freq-env)
+part8.html#index477
+clean-up)
+part19.html#index1446
+clip sound peak)
+part8.html#index514
+close stream)
+part19.html#index1561
+code-char code)
+part19.html#index1527
+comb sound decay hz)
+part8.html#index402
+compress input map rise-time fall-time [lookahead])
+part15.html#index1168
+compress-map compress-ratio compress-threshold expand-ratio expand-ratio :limit limit :transition transition)
+part15.html#index1166
+cond pair ...)
+part19.html#index1406
+congen gate risetime falltime)
+part8.html#index404
+cons expr1 expr2)
+part19.html#index1351
+consp expr)
+part19.html#index1386
+const value [duration])
+part8.html#index322
+continue)
+part19.html#index1448
+continuous-control-warp beh)
+part8.html#index551
+continuous-sound-warp beh)
+part8.html#index552
+control sound)
+part8.html#index321
+control-srate-abs srate beh)
+part8.html#index553
+control-warp warp-fn signal [wrate])
+part8.html#index338
+convolve sound response)
+part8.html#index407
+cos expr)
+part19.html#index1477
+cue sound)
+part8.html#index318
+cue-file filename)
+part8.html#index319
+current-path )
+part13.html#index995
+cxxr expr)
+part19.html#index1343
+cxxxr expr)
+part19.html#index1344
+cxxxxr expr)
+part19.html#index1345
+db-average input)
+part15.html#index1167
+db-to-linear x)
+part8.html#index283
+decf symbol)
+part13.html#index987
+defmacro sym fargs expr ...)
+part19.html#index1323
+defun sym fargs expr ...)
+part19.html#index1322
+delete expr :test test :test-not test-not)
+part19.html#index1374
+delete-if test list)
+part19.html#index1375
+delete-if-not test list)
+part19.html#index1376
+describe symbol [description])
+part14.html#index1143
+diff a b)
+part8.html#index585
+digit-char n)
+part19.html#index1530
+digit-char-p chr)
+part19.html#index1525
+do (binding ...) (texpr rexpr ...) expr ...)
+part19.html#index1423
+do* (binding ...) (texpr rexpr ...) expr ...)
+part19.html#index1424
+dolist (sym expr [rexpr]) expr ...)
+part19.html#index1425
+dotimes (sym expr [rexpr]) expr ...)
+part19.html#index1426
+dribble [fname])
+part19.html#index1599
+drum tracknum patternnum bpm)
+part15.html#index1241
+drum-loop snd duration numtimes)
+part15.html#index1242
+dtmf-tone key len space)
+part15.html#index1211
+echoenabled flag)
+part19.html#index1617
+endp list)
+part19.html#index1385
+env t1 t2 t4 l1 l2 l3 [dur])
+part8.html#index324
+eq expr1 expr2)
+part19.html#index1402
+eq-band signal hz gain width)
+part8.html#index443
+eq-highshelf signal hz gain [slope])
+part8.html#index441
+eq-lowshelf signal hz gain [slope])
+part8.html#index439
+eql expr1 expr2)
+part19.html#index1403
+equal expr1 expr2)
+part19.html#index1404
+error emsg[arg])
+part19.html#index1443
+errset expr [pflag])
+part19.html#index1449
+eval expr)
+part19.html#index1307
+evalhook expr ehook ahook [env])
+part19.html#index1453
+evenp expr)
+part19.html#index1400
+event-dur event)
+part14.html#index1092
+event-end event)
+part14.html#index1096
+event-expression event)
+part14.html#index1094
+event-get-attr event attribute [default])
+part14.html#index1101
+event-has-attr event attribute)
+part14.html#index1100
+event-set-attr event attribute value)
+part14.html#index1102
+event-set-dur event dur)
+part14.html#index1093
+event-set-expression event dur)
+part14.html#index1095
+event-set-time event time)
+part14.html#index1091
+event-time event)
+part14.html#index1090
+exit )
+part19.html#index1613
+exp x-expr)
+part19.html#index1481
+exp-dec hold halfdec length)
+part8.html#index325
+expand num)
+part19.html#index1601
+exponential-dist delta [high])
+part14.html#index1059
+expr-get-attr expression attribute [default])
+part14.html#index1098
+expr-has-attr expression attribute)
+part14.html#index1097
+expr-set-attr expr attribute value)
+part14.html#index1099
+expt x-expr y-expr)
+part19.html#index1480
+extract start stop beh)
+part8.html#index555
+extract-abs start stop beh)
+part8.html#index556
+fboundp sym)
+part19.html#index1396
+feedback-delay sound delay feedback)
+part8.html#index410
+filep expr)
+part19.html#index1394
+find-in-xlisp-path filename)
+part19.html#index1575
+first expr)
+part19.html#index1346
+flange snd)
+part15.html#index1186
+flatc expr)
+part19.html#index1553
+flatsize expr)
+part19.html#index1552
+flet (binding ...) expr ...)
+part19.html#index1415
+float expr)
+part19.html#index1457
+floatp expr)
+part19.html#index1388
+flute step breath-env)
+part8.html#index490
+flute-all step breath-env freq-env vibrato-freq vibrato-gain jet-delay noise)
+part8.html#index494
+flute-freq step breath-env freq-env)
+part8.html#index492
+fmfb pitch index [dur])
+part8.html#index369
+fmlfo freq [table phase])
+part8.html#index332
+fmosc pitch modulation [table phase])
+part8.html#index368
+follow sound floor risetime falltime lookahead)
+part8.html#index284
+force-srate srate sound)
+part8.html#index327
+format stream fmt arg ...)
+part19.html#index1555
+fourth expr)
+part19.html#index1349
+funcall fun arg ...)
+part19.html#index1309
+function expr)
+part19.html#index1311
+gamma-dist nu [high])
+part14.html#index1061
+gate sound lookahead risetime falltime floor threshold)
+part8.html#index288
+gaussian-dist xmu sigma [low high])
+part14.html#index1072
+gc )
+part19.html#index1600
+gcd n1 n2 ...)
+part19.html#index1472
+gensym [tag])
+part19.html#index1324
+geometric-dist p)
+part14.html#index1080
+get sym prop)
+part19.html#index1333
+get-duration dur)
+part8.html#index303
+get-env name)
+part19.html#index1593
+get-lambda-expression closure)
+part19.html#index1314
+get-loud )
+part8.html#index304
+get-output-stream-list stream)
+part19.html#index1591
+get-output-stream-string stream)
+part19.html#index1590
+get-slider-value index)
+part8.html#index642
+get-sustain )
+part8.html#index305
+get-temp-path )
+part19.html#index1569
+get-transpose )
+part8.html#index306
+get-user )
+part19.html#index1572
+get-warp )
+part8.html#index307
+go sym)
+part19.html#index1434
+grindef name)
+part13.html#index981
+hash sym n)
+part19.html#index1331
+highpass2 signal hz [q])
+part8.html#index435
+highpass4 signal hz)
+part8.html#index448
+highpass6 signal hz)
+part8.html#index449
+highpass8 signal hz)
+part8.html#index450
+hp sound cutoff)
+part8.html#index416
+hyperbolic-cosine-dist [low high])
+part14.html#index1066
+hz-to-step freq)
+part8.html#index290
+hzosc hz [table phase])
+part8.html#index358
+if texpr expr1[expr2])
+part19.html#index1409
+incf symbol)
+part13.html#index985
+info )
+part19.html#index1603
+int-char int)
+part19.html#index1532
+integerp expr)
+part19.html#index1387
+integrate signal)
+part8.html#index350
+intern pname)
+part19.html#index1325
+interpolate x x1 y1 x2 y2)
+part14.html#index1148
+intersection a b)
+part14.html#index1150
+jcrev sound decay mix)
+part8.html#index458
+labels (binding ...) expr ...)
+part19.html#index1416
+lambda args expr ...)
+part19.html#index1313
+last list)
+part19.html#index1355
+length expr)
+part19.html#index1361
+length-of-beat bpm)
+part15.html#index1243
+let (binding ...) expr ...)
+part19.html#index1413
+let* (binding ...) expr ...)
+part19.html#index1414
+lfo freq [duration table phase])
+part8.html#index330
+linear-dist g)
+part14.html#index1057
+linear-to-db x)
+part8.html#index291
+list expr ...)
+part19.html#index1352
+listdir path)
+part19.html#index1564
+listp expr)
+part19.html#index1384
+load fname [:verbose verbose] [:print print])
+part19.html#index1596
+local-to-global local-time)
+part8.html#index308
+log x)
+part8.html#index293
+logand expr ...)
+part19.html#index1490
+logior expr ...)
+part19.html#index1491
+logistic-dist alpha beta [low high])
+part14.html#index1067
+lognot expr)
+part19.html#index1493
+logxor expr ...)
+part19.html#index1492
+loop expr ...)
+part19.html#index1422
+loud volume beh)
+part8.html#index557
+loud-abs volume beh)
+part8.html#index558
+lower-case-p chr)
+part19.html#index1523
+lowpass2 signal hz [q])
+part8.html#index434
+lowpass4 signal hz)
+part8.html#index445
+lowpass6 signal hz)
+part8.html#index446
+lowpass8 signal hz)
+part8.html#index447
+lp sound cutoff)
+part8.html#index413
+lpc-frame-err frame)
+part12.html#index974
+lpc-frame-filter-coefs frame)
+part12.html#index975
+lpc-frame-rms1 frame)
+part12.html#index972
+lpc-frame-rms2 frame)
+part12.html#index973
+lpreson snd lpc-iterator skiptime)
+part12.html#index971
+macroexpand form)
+part19.html#index1315
+macroexpand-1 form)
+part19.html#index1316
+macrolet (binding ...) expr ...)
+part19.html#index1417
+make-accumulate sub-pattern :for for :max maximum :min minimum :name name :trace trace)
+part14.html#index1028
+make-accumulation items :name name :trace trace)
+part14.html#index1022
+make-array size)
+part19.html#index1338
+make-copier sub-pattern :repeat repeat :merge merge :for for :name name :trace trace)
+part14.html#index1025
+make-cycle items :for for :name name :trace trace)
+part14.html#index1007
+make-eval expr :for for :name name :trace trace)
+part14.html#index1037
+make-heap items :for for :max max :name name :trace trace)
+part14.html#index1019
+make-length pattern length-pattern :name name :trace trace)
+part14.html#index1044
+make-line items :for for :name name :trace trace)
+part14.html#index1010
+make-lpanal-iterator sound framedur skiptime npoles)
+part12.html#index966
+make-lpc-file-iterator filename)
+part12.html#index967
+make-markov rules :past past :produces produces :for for :name name :trace trace)
+part14.html#index1048
+make-palindrome items :elide elide :for for :name name :trace trace)
+part14.html#index1016
+make-product x y :for for :name name :trace trace)
+part14.html#index1034
+make-random items :for for :name name :trace trace)
+part14.html#index1013
+make-string-input-stream str[start[end]])
+part19.html#index1588
+make-string-output-stream) )
+part19.html#index1589
+make-sum x y :for for :name name :trace trace)
+part14.html#index1031
+make-symbol pname)
+part19.html#index1326
+make-window pattern length-pattern skip-pattern :name name :trace trace)
+part14.html#index1047
+maketable sound)
+part8.html#index333
+mandolin step dur [detune])
+part8.html#index500
+mapc fcn list1 list ...)
+part19.html#index1364
+mapcar fcn list1 list ...)
+part19.html#index1365
+mapl fcn list1 list ...)
+part19.html#index1366
+maplist fcn list1 list ...)
+part19.html#index1367
+markov-create-rules sequence order [generalize])
+part14.html#index1051
+max expr ...)
+part19.html#index1469
+member expr list :test test :test-not test-not)
+part19.html#index1356
+midi-show the-seq [out-file])
+part15.html#index1206
+midi-show-file file-name)
+part15.html#index1203
+min expr ...)
+part19.html#index1467
+minusp expr)
+part19.html#index1397
+modalbar preset step dur)
+part8.html#index510
+mult a [b ...])
+part8.html#index582
+mult beh1 beh2 ...)
+part8.html#index582
+nband input gains)
+part15.html#index1177
+nband-range input gains lowf highf)
+part15.html#index1174
+nconc list ...)
+part19.html#index1373
+noise [duration])
+part8.html#index538
+not expr)
+part19.html#index1383
+notch2 signal hz [q])
+part8.html#index437
+nrev sound decay mix)
+part8.html#index454
+nstring-downcase str :start start :end end)
+part19.html#index1504
+nstring-upcase str :start start :end end)
+part19.html#index1503
+nth n list)
+part19.html#index1362
+nthcdr n list)
+part19.html#index1363
+null expr)
+part19.html#index1382
+numberp expr)
+part19.html#index1381
+Ny:all
+part2.html#index67
+objectp expr)
+part19.html#index1393
+oddp expr)
+part19.html#index1401
+open fname :direction direction)
+part19.html#index1557
+open-binary fname :direction direction)
+part19.html#index1558
+or expr ...)
+part19.html#index1408
+osc pitch [duration table phase])
+part8.html#index355
+osc-enable flag)
+part8.html#index309
+osc-note pitch [duration env loud table])
+part8.html#index529
+osc-pulse hz bias [compare-shape])
+part8.html#index363
+osc-saw hz)
+part8.html#index359
+osc-tri hz)
+part8.html#index361
+pan sound where)
+part8.html#index341
+params-scale params keyword amount)
+part14.html#index1147
+params-transpose params keyword amount)
+part14.html#index1146
+partial pitch env)
+part8.html#index356
+patternp expression)
+part14.html#index1145
+peak expression maxlen)
+part8.html#index687
+peek addrs)
+part19.html#index1606
+peek-char [flag[stream]])
+part19.html#index1578
+phaser snd)
+part15.html#index1184
+piano-midi midi-file-name)
+part15.html#index1164
+piano-midi2file midi-file-name sound-file-name)
+part15.html#index1165
+piano-note duration step dynamic)
+part15.html#index1161
+piano-note-2 step dynamic)
+part15.html#index1163
+pitshift sound shift mix)
+part8.html#index470
+pl-center snd)
+part15.html#index1233
+pl-doppler snd r)
+part15.html#index1238
+pl-left snd)
+part15.html#index1232
+pl-pan2d snd x y)
+part15.html#index1236
+pl-position snd x y config)
+part15.html#index1237
+pl-rear snd)
+part15.html#index1235
+pl-right snd)
+part15.html#index1234
+play sound
+part8.html#index591
+play-file filename)
+part8.html#index606
+pluck pitch [duration final-amplitude])
+part8.html#index372
+plusp expr)
+part19.html#index1399
+poisson-dist delta)
+part14.html#index1082
+poke addrs value)
+part19.html#index1607
+pop lis)
+part13.html#index990
+power x y)
+part13.html#index1001
+pprint expr[stream])
+part19.html#index1550
+prcrev sound decay mix)
+part8.html#index462
+prin1 expr[stream])
+part19.html#index1548
+princ expr[stream])
+part19.html#index1549
+print expr [stream])
+part19.html#index1547
+prod beh1 beh2 ...)
+part8.html#index343
+prod beh1 beh2 ...)
+part8.html#index343
+profile flag)
+part19.html#index1454
+prog (binding ...) expr ...)
+part19.html#index1428
+prog* (binding ...) expr ...)
+part19.html#index1429
+prog1 expr1 expr ...)
+part19.html#index1436
+prog2 expr1 expr2 expr ...)
+part19.html#index1437
+progn expr ...)
+part19.html#index1438
+progv slist vlist expr ...)
+part19.html#index1435
+prologic l c r s)
+part15.html#index1229
+psetq [sym expr] ...)
+part19.html#index1320
+push val lis)
+part13.html#index989
+putprop sym val prop)
+part19.html#index1334
+pwe t1 l1 t2 l2 ... tn)
+part8.html#index390
+pwe-list breakpoints)
+part8.html#index391
+pwer i1 l1 i2 l2 ... in)
+part8.html#index394
+pwer-list breakpoints)
+part8.html#index395
+pwev l1 t2 l2 t3 t3 ... tn ln)
+part8.html#index392
+pwev-list breakpoints)
+part8.html#index393
+pwevr l1 i2 l2 i3 i3 ... in ln)
+part8.html#index397
+pwevr-list breakpoints)
+part8.html#index398
+pwl t1 l1 t2 l2 ... tn)
+part8.html#index382
+pwl-list breakpoints)
+part8.html#index383
+pwlr i1 l1 i2 l2 ... in)
+part8.html#index386
+pwlr-list breakpoints)
+part8.html#index387
+pwlv l1 t2 l2 t3 t3 ... tn ln)
+part8.html#index384
+pwlv-list breakpoints)
+part8.html#index385
+pwlvr l1 i2 l2 i3 i3 ... in ln)
+part8.html#index388
+pwlvr-list breakpoints)
+part8.html#index389
+quantize sound steps)
+part8.html#index530
+quote expr)
+part19.html#index1310
+ramp [duration])
+part11.html#index947
+random n)
+part19.html#index1473
+read [stream[eof[rflag]]])
+part19.html#index1546
+read-byte [stream])
+part19.html#index1585
+read-char [stream])
+part19.html#index1576
+read-float [stream[length]])
+part19.html#index1582
+read-int [stream[length]])
+part19.html#index1580
+read-line [stream])
+part19.html#index1584
+real-random from to)
+part13.html#index1000
+recip sound)
+part8.html#index533
+rem expr ...)
+part19.html#index1464
+remove expr list :test test :test-not test-not)
+part19.html#index1358
+remove-if test list)
+part19.html#index1359
+remove-if-not test list)
+part19.html#index1360
+remprop sym prop)
+part19.html#index1335
+require-from fnsymbol filename [path])
+part13.html#index993
+resample sound srate)
+part8.html#index344
+reson sound center bandwidth n)
+part8.html#index419
+rest expr)
+part19.html#index1350
+restore fname)
+part19.html#index1598
+return [expr])
+part19.html#index1431
+return-from name[value])
+part19.html#index1432
+reverb snd time)
+part15.html#index1207
+reverse expr)
+part19.html#index1354
+rms sound [rate window-size])
+part8.html#index532
+room )
+part19.html#index1604
+rplaca list expr)
+part19.html#index1371
+rplacd list expr)
+part19.html#index1372
+rrandom )
+part19.html#index1474
+s-abs sound)
+part8.html#index516
+s-add-to expression maxlen filename [offset])
+part8.html#index618
+s-exp sound)
+part8.html#index520
+s-log sound)
+part8.html#index522
+s-max sound1 sound2)
+part8.html#index525
+s-min sound1 sound2)
+part8.html#index527
+s-overwrite expression maxlen filename [offset])
+part8.html#index621
+s-plot sound [dur n])
+part8.html#index627
+s-print-tree sound)
+part8.html#index630
+s-read filename :time-offset offset :srate sr :dur dur :nchans chans :format format :mode mode :bits n :swap flag)
+part8.html#index615
+s-read-reverse filename :time-offset offset :srate sr :dur dur :nchans chans :format format :mode mode :bits n :swap flag)
+part15.html#index1183
+s-rest [duration])
+part8.html#index537
+s-reverse snd)
+part15.html#index1179
+s-save expression maxlen filename :format format :mode mode :bits bits :swap flag :play play)
+part8.html#index611
+s-sqrt sound)
+part8.html#index518
+sampler pitch modulation [sample npoints])
+part8.html#index378
+save fname)
+part19.html#index1597
+save-lpc-file lpc-iterator filename)
+part12.html#index968
+save-workspace )
+part14.html#index1142
+sax step breath-env)
+part8.html#index487
+sax-all step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise blow-pos reed-table-offset)
+part8.html#index488
+sax-freq step breath-env freq-env)
+part8.html#index485
+scale scale sound)
+part8.html#index345
+scale-db db sound)
+part8.html#index346
+scale-srate sound scale)
+part8.html#index347
+score-adjacent-events score function :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1126
+score-append score1 score2 ...)
+part14.html#index1112
+score-apply score function :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1127
+score-filter-length score cutoff)
+part14.html#index1120
+score-filter-overlap score)
+part14.html#index1123
+score-gen :k1 e1 :k2 e2 ...)
+part14.html#index1087
+score-get-begin score)
+part14.html#index1116
+score-get-end score)
+part14.html#index1118
+score-indexof score function :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1128
+score-last-indexof score function :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1129
+score-merge score1 score2 ...)
+part14.html#index1111
+score-must-have-begin-end score)
+part14.html#index1119
+score-play score)
+part14.html#index1125
+score-print score)
+part14.html#index1124
+score-randomize-start score amt :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1130
+score-read-smf filename)
+part14.html#index1136
+score-repeat score n)
+part14.html#index1121
+score-scale score keyword amount :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1108
+score-select score predicate :from-index i :to-index j :from-time x :to-time y :reject flag)
+part14.html#index1113
+score-set-begin score time)
+part14.html#index1115
+score-set-end score time)
+part14.html#index1117
+score-shift score offset :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1105
+score-sort score [copy-flag])
+part14.html#index1104
+score-sorted score)
+part14.html#index1103
+score-stretch score factor :dur dur-flag :time time-flag :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1106
+score-stretch-to-length score length)
+part14.html#index1122
+score-sustain score factor :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1109
+score-transpose score keyword amount :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1107
+score-voice score replacement-list :from-index i :to-index j :from-time x :to-time y)
+part14.html#index1110
+score-write-smf score filename [programs])
+part14.html#index1138
+second expr)
+part19.html#index1347
+Self
+part19.html#index1286
+seq beh1 [beh2 ...])
+part8.html#index574
+seqrep var limit beh)
+part8.html#index575
+set sym expr)
+part19.html#index1318
+set-control-srate rate)
+part8.html#index294
+set-difference a b)
+part14.html#index1155
+set-logical-stop beh time)
+part8.html#index579
+set-pitch-names )
+part8.html#index298
+set-sound-srate rate)
+part8.html#index296
+setdir path[verbose])
+part19.html#index1562
+setf [place expr] ...)
+part19.html#index1321
+setq [sym expr] ...)
+part19.html#index1319
+setup-console )
+part19.html#index1614
+sf-granulate filename grain-dur grain-dev ioi ioi-dev pitch-dev [file-start file-end])
+part15.html#index1202
+sf-info filename)
+part8.html#index624
+shape signal table origin)
+part8.html#index425
+shift-time sound shift)
+part8.html#index348
+show-lpc-data lpc-iterator iniframe endframe [poles?])
+part12.html#index969
+sim [beh1 beh2 ...])
+part8.html#index576
+simrep var limit beh)
+part8.html#index577
+sin expr)
+part19.html#index1476
+sine pitch [duration])
+part8.html#index357
+siosc pitch modulation tables)
+part8.html#index376
+sitar step dur)
+part8.html#index512
+slope signal)
+part8.html#index352
+snd-abs sound)
+part8.html#index644
+snd-add sound1 sound)
+part8.html#index648
+snd-allpoles snd lpc-coefs gain)
+part12.html#index977
+snd-alpass sound delay feedback)
+part8.html#index713
+snd-alpasscv sound delay feedback)
+part8.html#index714
+snd-alpassvv sound delay feedback maxdelay)
+part8.html#index715
+snd-amosc sound step sr hz t0 am phase)
+part8.html#index747
+snd-areson sound hz bw normalization)
+part8.html#index716
+snd-aresoncv sound hz bw normalization)
+part8.html#index717
+snd-aresonvc sound hz bw normalization)
+part8.html#index718
+snd-aresonvv sound hz bw normalization)
+part8.html#index719
+snd-atone sound hz)
+part8.html#index720
+snd-atonev sound hz)
+part8.html#index721
+snd-avg sound blocksize stepsize operation)
+part8.html#index652
+snd-bandedwg freq bowpress-env preset sr)
+part8.html#index757
+snd-biquad sound b0 b1 b2 a1 a2 z1init z2init)
+part8.html#index722
+snd-bowed freq bowpress-env sr)
+part8.html#index759
+snd-bowed-freq freq bowpress-env freq-env sr)
+part8.html#index761
+snd-buzz n sr hz t0 fm)
+part8.html#index751
+snd-chase sound risetime falltime)
+part8.html#index723
+snd-clarinet freq breath-env sr)
+part8.html#index763
+snd-clarinet-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise sr)
+part8.html#index767
+snd-clarinet-freq freq breath-env freq-env sr)
+part8.html#index765
+snd-clip sound peak)
+part8.html#index657
+snd-compose f g)
+part8.html#index660
+snd-congen gate risetime falltime)
+part8.html#index724
+snd-const value t0 srate duration)
+part8.html#index633
+snd-convolve sound response)
+part8.html#index725
+snd-copy sound)
+part8.html#index673
+snd-coterm s1 s2)
+part8.html#index637
+snd-delay sound delay feedback)
+part8.html#index726
+snd-delaycv sound delay feedback)
+part8.html#index727
+snd-down srate sound)
+part8.html#index675
+snd-exp sound)
+part8.html#index676
+snd-extent sound maxsamples)
+part8.html#index256
+snd-fetch sound)
+part8.html#index259
+snd-fetch-array sound len step)
+part8.html#index261
+snd-fft sound length skip window)
+part10.html#index812
+snd-flatten sound maxlen)
+part8.html#index262
+snd-flute freq breath-env sr)
+part8.html#index768
+snd-flute-all freq vibrato-freq vibrato-gain freq-env breath-env jet-delay noise sr)
+part8.html#index772
+snd-flute-freq freq breath-env freq-env sr)
+part8.html#index770
+snd-fmfb t0 hz sr index dur)
+part8.html#index749
+snd-fmfbv t0 hz sr index)
+part8.html#index750
+snd-fmosc s step sr hz t0 fm phase)
+part8.html#index748
+snd-follow sound floor risetime falltime lookahead)
+part8.html#index677
+snd-from-array t0 sr array)
+part8.html#index252
+snd-fromarraystream t0 sr object)
+part8.html#index253
+snd-fromobject t0 sr object)
+part8.html#index254
+snd-gate sound lookahead risetime falltime floor threshold)
+part8.html#index680
+snd-ifft time srate iterator skip window)
+part10.html#index814
+snd-inverse signal start srate)
+part8.html#index684
+snd-length sound maxlen)
+part8.html#index263
+snd-log sound)
+part8.html#index685
+snd-lpanal samps npoles)
+part12.html#index976
+snd-lpreson snd lpc-iterator skiptime)
+part12.html#index978
+snd-mandolin t0 freq dur body-size detune sr)
+part8.html#index774
+snd-max expression maxlen)
+part8.html#index688
+snd-maxsamp sound)
+part8.html#index264
+snd-maxv sound1 sound2)
+part8.html#index690
+snd-modalbar t0 freq preset dur sr)
+part8.html#index776
+snd-multiseq array closure)
+part8.html#index785
+snd-normalize sound)
+part8.html#index692
+snd-offset sound offset)
+part8.html#index649
+snd-oneshot sound threshold ontime)
+part8.html#index693
+snd-osc s step sr hz t0 d phase)
+part8.html#index753
+snd-overwrite expression maxlen filename offset format mode bits swap)
+part8.html#index636
+snd-partial sr hz t0 env)
+part8.html#index754
+snd-play expression)
+part8.html#index265
+snd-pluck sr hz t0 d final-amp)
+part8.html#index752
+snd-print expression maxlen)
+part8.html#index274
+snd-print-tree sound)
+part8.html#index266
+snd-prod sound1 sound2)
+part8.html#index696
+snd-pwl t0 sr lis)
+part8.html#index699
+snd-quantize sound steps)
+part8.html#index701
+snd-read filename offset t0 format channels mode bits swap sr dur)
+part8.html#index634
+snd-recip sound)
+part8.html#index702
+snd-resample f rate)
+part8.html#index703
+snd-resamplev f rate g)
+part8.html#index705
+snd-reson sound hz bw normalization)
+part8.html#index728
+snd-resoncv sound hz bw normalization)
+part8.html#index729
+snd-resonvc sound hz bw normalization)
+part8.html#index730
+snd-resonvv sound hz bw normalization)
+part8.html#index731
+snd-samples sound limit)
+part8.html#index268
+snd-save expression maxlen filename format mode bits swap play)
+part8.html#index635
+snd-sax freq breath-env sr)
+part8.html#index778
+snd-sax-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise blow-pos reed-table-offset sr)
+part8.html#index781
+snd-sax-freq freq freq-env breath-env sr)
+part8.html#index780
+snd-scale scale sound)
+part8.html#index708
+snd-seq sound closure)
+part8.html#index784
+snd-set-latency latency)
+part8.html#index316
+snd-set-logical-stop sound time)
+part8.html#index276
+snd-shape signal table origin)
+part8.html#index709
+snd-sine t0 hz sr d)
+part8.html#index755
+snd-siosc tables sr hz t0 fm)
+part8.html#index756
+snd-sitar t0 freq dur sr)
+part8.html#index782
+snd-slider index t0 srate duration)
+part8.html#index643
+snd-sqrt sound)
+part8.html#index646
+snd-srate sound)
+part8.html#index271
+snd-sref sound time)
+part8.html#index277
+snd-stkchorus sound delay depth freq mix sr)
+part8.html#index732
+snd-stkpitshift sound shift mix sr)
+part8.html#index736
+snd-stkrev rev-type sound decay mix sr)
+part8.html#index740
+snd-stop-time sound)
+part8.html#index278
+snd-t0 sound)
+part8.html#index273
+snd-tapf sound offset vardelay maxdelay)
+part8.html#index670
+snd-tapv sound offset vardelay maxdelay)
+part8.html#index665
+snd-time sound)
+part8.html#index272
+snd-tone sound hz)
+part8.html#index744
+snd-tonev sound hz)
+part8.html#index746
+snd-trigger s closure)
+part8.html#index786
+snd-up srate sound)
+part8.html#index710
+snd-white t0 sr d)
+part8.html#index640
+snd-xform sound sr time start stop scale)
+part8.html#index711
+snd-yin sound minstep maxstep rate)
+part8.html#index712
+snd-zero t0 srate)
+part8.html#index641
+soften-clipping snd cutoff)
+part15.html#index1172
+sort list test)
+part19.html#index1377
+sound sound)
+part8.html#index320
+sound-off )
+part8.html#index610
+sound-on )
+part8.html#index609
+sound-srate-abs srate beh)
+part8.html#index559
+sound-warp warp-fn signal [wrate])
+part8.html#index349
+soundfilename name)
+part8.html#index626
+soundp sound)
+part8.html#index279
+span snd amt)
+part15.html#index1225
+speed-dial thelist)
+part15.html#index1212
+sqrt expr)
+part19.html#index1482
+sref sound time)
+part8.html#index248
+sref-inverse sound value)
+part8.html#index250
+stats )
+part8.html#index280
+step-to-hz pitch)
+part8.html#index302
+stereo-chorus snd)
+part15.html#index1190
+stereoize snd)
+part15.html#index1217
+stkchorus sound depth freq mix [delay])
+part8.html#index466
+strcat expr ...)
+part19.html#index1505
+streamp expr)
+part19.html#index1392
+stretch factor beh)
+part8.html#index561
+stretch-abs factor beh)
+part8.html#index562
+string expr)
+part19.html#index1495
+string-downcase str :start start :end end)
+part19.html#index1502
+string-equalp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1516
+string-greaterp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1519
+string-left-trim bag str)
+part19.html#index1499
+string-lessp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1514
+string-not-equalp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1517
+string-not-greaterp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1515
+string-not-lessp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1518
+string-right-trim bag str)
+part19.html#index1500
+string-search pat str :start start :end end)
+part19.html#index1496
+string-trim bag str)
+part19.html#index1498
+string-upcase str :start start :end end)
+part19.html#index1501
+string/= str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1511
+string< str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1508
+string<= str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1509
+string= str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1510
+string> str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1513
+string>= str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2)
+part19.html#index1512
+stringp expr)
+part19.html#index1389
+sublis alist expr :test test :test-not test-not)
+part19.html#index1369
+subseq string start[end])
+part19.html#index1507
+subsetp a b)
+part14.html#index1156
+subst to from expr :test test :test-not test-not)
+part19.html#index1368
+sum a [b ...])
+part8.html#index580
+sustain factor beh)
+part8.html#index563
+sustain-abs factor beh)
+part8.html#index567
+swapchannels snd)
+part15.html#index1226
+symbol-function sym)
+part19.html#index1329
+symbol-name sym)
+part19.html#index1327
+symbol-plist sym)
+part19.html#index1330
+symbol-value sym)
+part19.html#index1328
+symbolp expr)
+part19.html#index1380
+tagbody expr ...)
+part19.html#index1433
+tan expr)
+part19.html#index1478
+tapv sound offset vardelay maxdelay)
+part8.html#index451
+terpri [stream])
+part19.html#index1551
+third expr)
+part19.html#index1348
+throw sym[expr])
+part19.html#index1419
+timed-seq score)
+part8.html#index587
+tone sound cutoff)
+part8.html#index415
+top-level)
+part19.html#index1447
+trace sym)
+part19.html#index1441
+transpose amount beh)
+part8.html#index568
+transpose-abs amount beh)
+part8.html#index569
+trigger s beh)
+part8.html#index578
+truncate expr)
+part19.html#index1456
+type-of expr)
+part19.html#index1605
+union a b)
+part14.html#index1152
+unless texpr expr ...)
+part19.html#index1411
+untrace sym)
+part19.html#index1442
+unwind-protect expr cexpr ...)
+part19.html#index1420
+upper-case-p chr)
+part19.html#index1522
+vector expr ...)
+part19.html#index1339
+warp fn beh)
+part8.html#index570
+warp-abs fn beh)
+part8.html#index571
+wg-glass-harm step bowpress-env)
+part8.html#index506
+wg-tibetan-bowl step bowpress-env)
+part8.html#index508
+wg-tuned-bar step bowpress-env)
+part8.html#index504
+wg-uniform-bar step bowpress-env)
+part8.html#index502
+when test action)
+part19.html#index1410
+when texpr expr ...)
+part19.html#index1410
+while test expr1 expr2 ...)
+part13.html#index991
+widen snd amt)
+part15.html#index1220
+write-byte byte[stream])
+part19.html#index1586
+write-char ch[stream])
+part19.html#index1579
+write-float ch[stream[length]])
+part19.html#index1583
+write-int ch[stream[length]])
+part19.html#index1581
+yin sound minstep maxstep stepsize)
+part8.html#index539
+zerop expr)
+part19.html#index1398
diff --git a/jnyqide/Pair.java b/jnyqide/Pair.java
new file mode 100644
index 0000000..ca1caa9
--- /dev/null
+++ b/jnyqide/Pair.java
@@ -0,0 +1,38 @@
+package jnyqide;
+
+import java.io.*;
+import java.util.*;
+
+public class Pair
+{
+ private double time, value;
+
+ public Pair(){
+ time = 0;
+ value = 0;
+ }
+
+ public Pair(double t, double v){
+
+ if (t < 0) {
+ System.out.println("Warning: negative time scale input.");
+ }
+
+ // plotted functions are not signals, so you shouldn't expect them to stay within [-1, 1]
+ //if (v < -1 || v > 1){
+ // System.out.println("Warning: Value is out of bounds.");
+ //}
+
+ time = t;
+ value = v;
+ }
+
+ public double getTime(){
+ return time;
+ }
+
+ public double getValue(){
+ return value;
+ }
+
+} \ No newline at end of file
diff --git a/jnyqide/Piano_Roll.java b/jnyqide/Piano_Roll.java
new file mode 100755
index 0000000..b2844ac
--- /dev/null
+++ b/jnyqide/Piano_Roll.java
@@ -0,0 +1,1104 @@
+/*
+ * Ming Yang Koh (mykoh@andrew.cmu.edu)
+ * Eugene Ang (ewee@andrew.cmu.edu)
+ * Priscilla (cyp@andrew.cmu.edu)
+ *
+ * PianoRoll application which takes in an array of strings
+ * and creates a graphical representation of a piano roll
+ *
+ */
+
+ /* SOME NOTES BY ROGER B. DANNENBERG:
+
+ This software is not ready for real use.
+ Some problems include:
+ 1) there's no way to zoom in on scores or scroll the score view
+ 2) there's no display of pitch information
+ 3) there's no way to edit anything but pitch and time
+ 4) there's no way to copy a note and its attributes, so any new note
+ will lack attributes that might be necessary
+ 5) there's no color coding of note types, e.g. instrumentation
+ 6) everytime you modify the score, the score is written to a file;
+ instead the file should be written explicitly
+ 7) when the file is written, you should tell Nyquist to evaluate
+ (score-restore) to read in the score and assign it to the global
+ variable it came from
+ 8) the score write command probably does not put the score name
+ (a lisp variable name) as the first line
+ 9) it looks like there's one representation for the score data
+ as read from the file and another for a display list -- this
+ should be simplified to one structure with accessor methods
+ if necessary to translate into different representation for display
+ 10) the score window should be resizable
+ 11) should the score window be a subwindow to the jNyqIDE main window?
+
+ How does it work? See xm.lsp for SCORE-EDIT, the function that you
+ call to open a score editor, and SCORE-RESTORE, the function this
+ editor should call to return score data to Nyquist. Also see
+ NyquistThread.java for code that opens the score editor. Look for
+ "score-edit: writing " around line 230.
+ */
+
+package jnyqide;
+import java.io.*;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowListener;
+import java.awt.event.WindowEvent;
+import java.awt.*;
+import javax.swing.*;
+import java.util.StringTokenizer;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+
+public class Piano_Roll {
+
+ // global variable to store the String
+ // for the time being, the Invariant will be, each String will
+ // contain 3 ints: x, y, and duration.
+
+ // let user click and select centre left or right. center is to move to new location
+ // left and right is for user to drag along the axis
+ // start of global variables in Piano_Roll class
+ static ScoreManipulator sm = new ScoreManipulator();
+ static Piano_Roll.ScoreManipulator.Event[] inputArray = new Piano_Roll.ScoreManipulator.Event[0];
+ static int currentOption = 2; // 0 = add, 1 = delete, 2 = arrange
+
+ //static Piano_Roll.ScoreManipulator.Event[] inputArray = new Piano_Roll.ScoreManipulator.Event[0];
+ static String filename;
+ static String scoreName;
+
+ // START OF BAOPANEL CLASS
+ static class BaoPanel extends JPanel implements MouseListener
+ {
+ private static final long serialVersionUID = 1L;
+ // for dragNotStretch : 0 = drag, 1 = stretch from
+ // left(change start time), 2 = stretch from right(change dur)
+ private int dragNotStretch;
+ private int pitchStartCoord = 500,
+ pitchHeight = 10,
+ WINDOWWIDTH = 1024,
+ maxClickableWidth = 946,
+ lengthUnit = 3;
+ /*
+ * each box shown on screen is 3 pixels wide
+ * each box represents 0.1 seconds
+ * the screen will hold approximately 90 seconds of music
+ */
+ private int selectedIndex = -1, lastClickedX;
+
+ /*drawing horizontal lines of grid
+ * if pitchHeight is 10, then there will be...
+ * 49 segments. 49 pitches + 1 pitchless
+ * A1 to G7
+ */
+
+
+ // START OF PAINTCOMPONENT FUNCTION TO DRAW OUT THE SCREEN
+ protected void paintComponent (Graphics g) {
+ int inputArrayLength = inputArray.length;
+ int tempX, tempY, tempDur;
+ super.paintComponent(g);
+ Graphics2D g2 = (Graphics2D) g;
+ Color oldColor = g2.getColor();
+ g2.setColor(Color.BLACK);
+
+ // drawing horizontal lines of grid
+ for(int i=20; i <= pitchStartCoord; i+= pitchHeight){
+ g2.draw3DRect(0, i-10, WINDOWWIDTH, pitchHeight, false);
+ }
+
+ /* drawing vertical lines of grid,
+ * as well as the blue vertical markers
+ * to mark out every second
+ */
+ for(int i=0, j=0; i <= WINDOWWIDTH; i += lengthUnit, j++){
+ if(j == 15){
+ g2.setColor(Color.BLUE);
+ g2.draw3DRect(i, 10, 1, pitchStartCoord, false);
+ j = 0;
+ g2.setColor(Color.BLACK);
+ }
+ g2.draw3DRect(i, 10, lengthUnit, pitchStartCoord, false);
+ }
+
+
+ g2.setColor(Color.BLUE);
+
+ //drawing the notes onto the grid
+ for(int i = 0; i < inputArrayLength; i++){
+ tempX = inputArray[i].getTime();
+ tempY = pitchHeight * (inputArray[i].getPitch());
+ tempDur = inputArray[i].getDur();
+
+ /* the lowest pitch starts from bottom
+ * need to check if its zero, if so, then plot it in special area.
+ * this for loop is also responsible to draw the yellow sides
+ * for user to recognise that its the area for stretching notes
+ */
+ if(tempY != 0) {
+ g2.fill3DRect(tempX+lengthUnit, (tempY+10),
+ (tempDur-(2*lengthUnit)), 10, false);
+ g2.setColor(Color.YELLOW);
+ g2.fill3DRect(tempX, (tempY+10), lengthUnit, 10, false);
+ g2.fill3DRect((tempX+tempDur-lengthUnit),
+ (tempY+10), lengthUnit, 10, false);
+ g2.setColor(Color.BLUE);
+ }
+ else{
+ g2.setColor(Color.BLACK);
+ g2.fill3DRect(tempX, (tempY+10), tempDur, 10, false);
+ g2.setColor(Color.BLUE);
+ }
+ }
+
+
+ // setting back colour to prevent future
+ // screw-ups, eg, the border colours etc..
+ g2.setColor(oldColor);
+ addMouseListener(this);
+ }
+
+ // START OF DETERMINEACTION FUNCTION FOR DIFFERENTIATING
+ // DRAG AND STRETCH..
+ private void determineAction(MouseEvent e){
+ int arraySize = inputArray.length;
+ for(int i = 0; i < arraySize; i++){
+ if(inputArray[i].checkWithinDuration(e.getX(), e.getY())){
+ selectedIndex = i;
+ dragNotStretch = inputArray[i].checkDragNotStretch(e.getX(), e.getY());
+
+ return;
+ }
+ }
+ }
+
+ /* whenever theres a change in the array,
+ * 1) change the array,
+ * 2) as well as call the function to notify's eugene's part
+ */
+
+
+ /*
+ * START OF MOUSELISTENERS
+ * RESPONSIBLE FOR ALL THE USER INPUTS/CHANGES
+ * TO THE SCORE
+ */
+
+ /*
+ * mouseReleased basically first differentiates
+ * different actions before doing anthing, that
+ * refers to: add, delete or drag/stretch
+ *
+ * then, it will proceed to do the specifed action
+ * within the case of drag/stretch, then the code
+ * will differentiate drag or stretch and proceed
+ * on respectively
+ *
+ * the check of selectedIndex != -1 ensures the user
+ * is operating on a certain notes.
+ *
+ */
+ public void mouseReleased(MouseEvent e) {
+
+ // *** IF DRAG/STRETCH
+ if(currentOption == 2){
+ /*
+ * the following are done in drag/stretch action:
+ * a)ensure that bounds are kept, ie no
+ * notes are dragged out of the screen, or
+ * 'dragged into itself..'
+ * b)changing the Event in the array and subsequently
+ * send it to the score through the changeScore,
+ * add_Event or delete_Event functions
+ *
+ */
+
+ if(selectedIndex != -1){
+ int originalTime = inputArray[selectedIndex].getTime(),
+ originalDur = inputArray[selectedIndex].getDur(),
+ newX = e.getX(),
+ newY = e.getY();
+
+
+ if(newX >= maxClickableWidth){
+ selectedIndex = -1;
+ return;
+ }
+ // *** DRAG action
+ if(dragNotStretch == 0){
+ int originalPitch = inputArray[selectedIndex].getPitch();
+ int newStartTime = newX - lastClickedX + originalTime;
+ int newPitch = ((newY-10)/10);
+
+ if(newStartTime + inputArray[selectedIndex].getDur()
+ >= maxClickableWidth){
+ selectedIndex = -1;
+ return;
+ }
+
+ if((originalPitch == 0) && (((newY - 10)/10) != 0)){
+ selectedIndex = -1;
+ return;
+ }
+
+
+ // the following ensures the notes stay within bounds
+ if(newStartTime < 0)
+ newStartTime = 0;
+ if(newPitch > 49)
+ newPitch = 49;
+ else if(newPitch < 0)
+ newPitch = 1;
+
+ inputArray[selectedIndex].setStartTime(newStartTime);
+ inputArray[selectedIndex].setPitch(newPitch);
+
+ }
+ else if(dragNotStretch == 1){ // stretch from left
+ if(newX > originalTime + originalDur - 12)
+ newX = originalTime + originalDur - 12;
+ inputArray[selectedIndex].setDur(
+ originalDur + originalTime - newX);
+ inputArray[selectedIndex].setStartTime(newX);
+
+ }
+ else { // stretch from right
+ if(newX < originalTime + 12)
+ newX = originalTime + 12;
+ inputArray[selectedIndex].setDur(newX - originalTime);
+
+ }
+ //sends the data back to The middleman to send it back to nyquist
+
+ inputArray = sm.my_score.changeScore(
+ inputArray[selectedIndex].getIndex(),
+ inputArray[selectedIndex].getTime(),
+ inputArray[selectedIndex].getDur(),
+ inputArray[selectedIndex].getPitch());
+ repaint();
+ revalidate();
+ selectedIndex = -1; //end of drag or stretch. selectedIndex back to -1..
+
+ sm.writeFile();
+ }
+ }
+ // *** IF DELETE
+ else if(currentOption == 1){
+ if(selectedIndex != -1){
+
+ inputArray = sm.my_score.del_Event(inputArray[selectedIndex]);
+ repaint();
+ revalidate();
+ //at end. selectedIndex back to -1
+ selectedIndex = -1;
+ sm.writeFile();
+ return;
+ }
+ }
+ // *** IF ADD
+ else if(currentOption == 0){
+ int tempY = (e.getY()-10)/10;
+ if((e.getX() + 20) > maxClickableWidth){
+ return;
+ }
+ if( !(tempY <= 49 && tempY >=0)){
+ return;
+ }
+
+ inputArray = sm.my_score.add_Event(new
+ Piano_Roll.ScoreManipulator.Event(e.getX(), tempY, 20 , -1));
+ repaint();
+ revalidate();
+ //at end. selectedIndex back to -1
+ selectedIndex = -1;
+ sm.writeFile();
+ return;
+ }
+
+ }
+ /*
+ * mousePressed just does 2 things
+ * a) determine if its a drag or stretch action,
+ * as well as determining the Event manipulated
+ * b) logging down te x-coordinate of the click,
+ * for use of dragging nicely later
+ */
+ public void mousePressed(MouseEvent e) {
+ determineAction(e);
+ lastClickedX = e.getX();
+ }
+
+ public void mouseEntered(MouseEvent e) {/* do nothing*/}
+ public void mouseExited(MouseEvent e) { /* do nothing*/}
+ public void mouseClicked(MouseEvent e) { /* do nothing*/}
+
+ }
+ /*
+ * addComponentsToPane function deals with the layout
+ * and components outside the grid, such as text, buttons
+ * and xaxis and yaxis scales..
+ *
+ */
+ public static void addComponentsToPane (Container pane) {
+ // zero is center alignment....
+ // can use HTML ways to edit the font/type
+ JLabel topLabel = new JLabel("<html><font face=Verdana size=3>" +
+ "Piano roll display:</font></html>", 0);
+ JLabel bottomLabel = new JLabel(
+ "<html><font face=Verdana size=2><ul><li>To stretch, " +
+ "click on the yellow sections of notes</li><li>To transpose," +
+ " click on blue section of notes</li></ul></font></html>", 0);
+
+ topLabel.setPreferredSize(new Dimension(1024, 50));
+
+ JLabel leftPanel = new JLabel();
+ JLabel bottomCenterLabel = new JLabel();
+
+ ImageIcon xAxis = new ImageIcon("xAxis.jpg");
+ ImageIcon yAxis = new ImageIcon("xxx.jpg");
+ bottomCenterLabel.setIcon(xAxis);
+
+
+ JPanel mainPanel = new JPanel();
+ mainPanel.setLayout(new BorderLayout());
+
+ // for center panel
+ JPanel subCenterPanel = new BaoPanel();
+ mainPanel.add(bottomCenterLabel, BorderLayout.SOUTH);
+ mainPanel.add(subCenterPanel, BorderLayout.CENTER);
+
+
+ // for left panel
+ leftPanel.setIcon(yAxis);
+ leftPanel.setPreferredSize(new Dimension(30, 800));
+
+ //for bottom panel
+ JPanel bottomPanel = new JPanel();
+ JPanel subBottomPanel = new JPanel();
+ bottomPanel.setLayout(new BorderLayout());
+
+ // setting up the buttons, and adding listeners
+ JButton okButton = new JButton("Add");
+ JButton deleteButton = new JButton("Delete");
+ JButton arrangeButton = new JButton("Drag/Stretch");
+
+ okButton.addActionListener(new okButtonListener(
+ okButton, deleteButton, arrangeButton));
+ deleteButton.addActionListener(new deleteButtonListener(
+ okButton, deleteButton, arrangeButton));
+ arrangeButton.addActionListener(new arrangeButtonListener(
+ okButton, deleteButton, arrangeButton));
+ arrangeButton.setEnabled(false);
+ subBottomPanel.setLayout(new FlowLayout());
+ subBottomPanel.add(okButton);
+ subBottomPanel.add(deleteButton);
+ subBottomPanel.add(arrangeButton);
+
+
+ // combining the 2 sub panels together to form the bottomPanel
+ bottomPanel.add(bottomLabel, BorderLayout.CENTER);
+ bottomPanel.add(subBottomPanel, BorderLayout.EAST);
+
+ JLabel fillerLabel2 = new JLabel("");
+
+ fillerLabel2.setSize(10, 600);
+ fillerLabel2.setVisible(true);
+
+ // combining all the panels together to
+ // form the bulk of the screen
+ pane.add(topLabel, BorderLayout.NORTH);
+ pane.add(mainPanel, BorderLayout.CENTER);
+ pane.add(bottomPanel, BorderLayout.SOUTH);
+ pane.add(leftPanel, BorderLayout.WEST);
+ pane.add(fillerLabel2, BorderLayout.EAST);
+ }
+
+ /*
+ * below are the 3 listener classes that deal with the 3 main
+ * operations: add, delete, drag/drop.
+ *
+ * what they do is to initialise the buttons and to set
+ * the respective buttons to become enabled/disabled
+ * when clicked.
+ *
+ * the MouseReleased function will deal with user inputs
+ * eg, drags or deletes instead of the listeners below
+ *
+ */
+ private static class okButtonListener implements ActionListener {
+ private JButton ok, delete, arrange;
+
+ public okButtonListener(JButton ok, JButton delete, JButton arrange){
+ this.ok = ok;
+ this.delete = delete;
+ this.arrange = arrange;
+ }
+
+ public void actionPerformed(ActionEvent e){
+ currentOption = 0;
+ ok.setEnabled(false);
+ delete.setEnabled(true);
+ arrange.setEnabled(true);
+ }
+ }
+
+ private static class deleteButtonListener implements ActionListener {
+ private JButton ok, delete, arrange;
+ public deleteButtonListener(JButton ok, JButton delete, JButton arrange){
+ this.ok = ok;
+ this.delete = delete;
+ this.arrange = arrange;
+ }
+ public void actionPerformed(ActionEvent e){
+ currentOption = 1;
+ ok.setEnabled(true);
+ delete.setEnabled(false);
+ arrange.setEnabled(true);
+ }
+ }
+
+ private static class arrangeButtonListener implements ActionListener {
+ private JButton ok, delete, arrange;
+ public arrangeButtonListener(JButton ok, JButton delete, JButton arrange){
+ this.ok = ok;
+ this.delete = delete;
+ this.arrange = arrange;
+ }
+ public void actionPerformed(ActionEvent e){
+ currentOption = 2;
+ ok.setEnabled(true);
+ delete.setEnabled(true);
+ arrange.setEnabled(false);
+ }
+ }
+
+
+ /**
+ * Create the GUI and show it. For thread safety,
+ * this method should be invoked from the
+ * event-dispatching thread.
+ */
+ private static void createAndShowGUI() {
+ //Create and set up the window.
+ JFrame.setDefaultLookAndFeelDecorated(true);
+ JFrame frame = new JFrame("Piano Bao : by Priscilla, Eugene and Damon. ");
+ frame.setResizable(false);
+
+ frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ frame.addWindowListener(new prepareToComeBackListener());
+ //Set up the content pane.
+ //frame is the most most outermost enclosure
+ frame.getContentPane().setLayout(new BorderLayout());
+ addComponentsToPane(frame.getContentPane());
+
+ //Display the window, crops off exactly where the grid stops printing
+ frame.setSize(984, 672);
+ frame.setVisible(true);
+ }
+
+
+ public static void scoreEdit(String scoresaveFilename) {
+
+ //Schedule a job for the event-dispatching thread:
+ //creating and showing this application's GUI.
+
+ if (scoresaveFilename == null)
+ {
+ System.out.println("Error. No file argument.");
+ return;
+ }
+
+ filename = scoresaveFilename;
+
+ try
+ {
+ BufferedReader in = new BufferedReader(new FileReader(filename));
+ scoreName = in.readLine();
+ String str;
+ //make score object
+ while ((str = in.readLine()) != null)
+ {
+ sm.my_score.addNote(sm.makeNote(str));
+ }
+
+ in.close();
+
+ //parse it to Event list, for GUI functions
+ inputArray = sm.my_score.toEventList();
+
+ }
+ catch (IOException e)
+ {
+ System.out.println("IOException caught: " + e.getMessage());
+ }
+
+ javax.swing.SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ createAndShowGUI();
+ }
+
+ });
+
+}
+ private static class prepareToComeBackListener implements WindowListener{
+ public void windowActivated(WindowEvent e){}
+ public void windowClosed(WindowEvent e){
+ currentOption = 2;
+
+
+ }
+ public void windowClosing(WindowEvent e){/*do nothing*/}
+ public void windowDeactivated(WindowEvent e){/*do nothing*/}
+ public void windowDeiconified(WindowEvent e){/*do nothing*/}
+ public void windowIconified(WindowEvent e){/*do nothing*/}
+ public void windowOpened(WindowEvent e){/*do nothing*/}
+ }
+
+// This is a data structure that stores and
+// changes notes from a Nyquist score. It
+// nests another data structure, ScoreNote.
+public static class ScoreManipulator
+{
+
+ public ScoreNote my_score; // a collection of notes, with functions to
+ // add, delete and change the collection.
+
+ public ScoreManipulator()
+ {
+ my_score = new ScoreNote();
+ }
+
+ // takes in a String of the following format:
+ // start_time duration pitch option_str1 ... option_strn
+ // and parses it into a Note object.
+ public Note makeNote(String str)
+ {
+ int numTokens;
+ StringTokenizer st = new StringTokenizer(str);
+ if ( (numTokens = st.countTokens()) < 3)
+ {
+ System.out.println("ERROR in makeNote: some string too short: "
+ + str);
+ return null;
+ }
+
+ String st_time, dur, pitch;
+
+ // the remainder of the string must be the options
+ String []opts = new String[numTokens - 3];
+
+ int numOpts = 0;
+
+ st_time = st.nextToken();
+ dur = st.nextToken();
+ pitch = st.nextToken();
+
+ while (st.hasMoreTokens()) {
+ opts[numOpts] = st.nextToken();
+ numOpts++;
+ }
+
+ //System.out.println("st_time " + st_time + " dur " + dur +
+ // " pitch " + pitch + " opts " + opts);
+
+ double stime = Double.parseDouble(st_time);
+ double duration = Double.parseDouble(dur);
+ int ptch = -9999;
+ if (!pitch.equals("NIL")) ptch = Integer.parseInt(pitch);
+
+ return new Note(stime,duration,ptch,opts,numOpts);
+ }
+
+ public void writeFile()
+ {
+ try {
+ FileWriter fwr = new FileWriter(filename);
+ fwr.write(my_score.writeScore());
+ fwr.close();
+ }
+ catch (IOException e) {
+ System.out.println("writeFile: IOException.");
+ }
+
+ }
+
+
+ // The Note class stores information about a Nyquist
+ // score note such that it is easy to access the fields
+ // that we need in this piano roll application.
+ // Notice that the field pitch can be zero (0).
+ public class Note
+ {
+
+ // fields
+ private double start_time; // Note's starting time
+ private double duration;
+ private int pitch, numopts;
+ private String []options; // all other information that the piano roll will
+ // not use, but that we must preserve
+
+ public Note(double st_time, double dur, int pitch, String []opts, int numopts)
+ {
+ start_time = st_time;
+ duration = dur;
+ this.pitch = pitch;
+ this.numopts = numopts;
+ options = opts;
+ }
+
+ //accessors
+ public double get_start()
+ {
+ return start_time;
+ }
+
+ public double get_dur()
+ {
+ return duration;
+ }
+
+ public int get_pitch()
+ {
+ return pitch;
+ }
+
+ public int get_numopts()
+ {
+ return numopts;
+ }
+
+ public String [] get_opts()
+ {
+ return options;
+ }
+
+ // for debugging
+ public void PrintNote()
+ {
+ System.out.print("Start: " + start_time + " Duration: " + duration
+ + " Pitch: " + pitch);
+ for (int i = 0; i < numopts; i++)
+ {
+ System.out.print(" Opt string " + i + ": " + options[i]);
+ }
+ System.out.println();
+ }
+
+ }
+
+
+ // ScoreNote is a collection of notes.
+ // It also has a collection of functions
+ // such as add, delete and change that
+ // is used by the GUI functions to change
+ // the score when the user drags/shifts/adds/
+ // deletes notes.
+ public class ScoreNote
+ {
+ private Note[] score; // the collection of notes
+ private int num_notes; // capacity of the score
+ private int notes_used; // number of notes in the
+ // collection that are
+ // presently non-empty.
+
+ public ScoreNote()
+ {
+ num_notes = 0;
+ notes_used = 0;
+ score = new Note[0];
+ }
+
+ //adds a Note to the data structure sorted
+ //in order of start time.
+ //Invariant: score starts out sorted. This is
+ //true at the start => invariant is preserved
+ //each time we call this
+ public void addNote(Note newnote)
+ {
+ // If there exists a note in the score of the exact
+ // pitch duration and start time, then don't add it
+ // in.
+ for(int j = 0; j < notes_used; j++) {
+ if(score[j].get_start() == newnote.get_start()
+ && score[j].get_pitch() == newnote.get_pitch()
+ && score[j].get_dur() == newnote.get_dur()){
+ return;
+
+ }
+ }
+
+ if (notes_used >= num_notes)
+ {
+ if (notes_used == 0)
+ {
+ score = new Note[10];
+ num_notes = 10;
+ }
+ else
+ {
+ Note [] tempscore = new Note[num_notes * 2];
+ for (int i = 0; i < notes_used; i++)
+ {
+ tempscore[i] = score[i];
+ }
+ score = tempscore;
+ num_notes *= 2;
+ }
+ }
+
+ for (int i = 0; i < notes_used; i++)
+ {
+ // when we find the index that newnote should be in,
+ // place it there and return
+ if (score[i].get_start() >= newnote.get_start())
+ {
+ shift_right(i);
+ score[i] = newnote;
+ notes_used++;
+ return;
+ }
+ }
+
+ // otherwise, newnote's start time is
+ // the largest in the score, and we
+ // put it at the back of the array.
+ score[notes_used] = newnote;
+ notes_used++;
+ }
+
+ // shifts all notes in the array after and including
+ // index by one to the right.
+ public void shift_right(int index)
+ {
+ for (int i = notes_used - 1; i >= index; i--)
+ {
+ score[i+1] = score[i];
+ }
+
+ }
+
+ // deletes the note specified by index from the score
+ // while maintaining the invariant that notes in score
+ // are sorted by start time.
+ public void delNote(int index)
+ {
+ if (index < 0 || index >= notes_used)
+ {
+ System.out.println("del_note: Error! index out of bounds!");
+ return;
+ }
+
+ shift_left(index);
+ notes_used--;
+ }
+
+ // shifts all notes in score after
+ // index by one to the left.
+ public void shift_left(int index)
+ {
+ for (int i = index; i < notes_used; i++)
+ {
+ score[i] = score[i+1];
+ }
+
+ }
+
+ // accessor for number of used notes in the score
+ public int getLength()
+ {
+ return notes_used;
+ }
+
+ // accessor for a note at the particular index
+ public Note getNote(int index)
+ {
+ if (index < 0 || index >= notes_used)
+ {
+ System.out.println("getNote: trying to index note out of bounds!");
+ return null;
+ }
+
+ return score[index];
+ }
+
+ // makes an incremental change to the score, but makes sure to
+ // preserve the invariant that score remains sorted by start time.
+ public Event[] changeScore(int index, int new_start, int new_dur, int new_pitch)
+ {
+ if (index < 0 || index >= notes_used)
+ {
+ System.out.println("changeScore: index out of bounds!");
+ return null;
+ }
+
+ // make the new note
+ Note note = new Note( (double)(new_start / 10), (double)(new_dur / 10),
+ convertPitch(new_pitch), score[index].get_opts(),
+ score[index].get_numopts() );
+
+ // delNote and addNote both preserve the invariant that
+ // the notes in score are sorted in order of start time.
+ delNote(index);
+ addNote(note);
+
+ // add one more layer of abstraction for the convenience of
+ // the GUI functions, by using Event objects rather than
+ // Note objects. The difference is basically in the standards
+ // of time and note values, documented below.
+ return toEventList();
+ }
+
+ // converts from a MIDI note to a note in
+ // our representation and vice versa.
+ public int convertPitch(int pitch)
+ {
+ if (pitch == 0)
+ return pitch;
+
+ return 84 - (pitch - 1);
+ }
+
+ // Gets the list for the GUI functions to manipulate.
+ // Invariant: the size of the event list returned is
+ // exactly the number of notes in our score.
+ public Event [] toEventList()
+ {
+ Event [] result = new Event[notes_used];
+ int num_events = 0;
+
+ for (int i = 0; i < notes_used; i++)
+ {
+ Note temp = score[i];
+
+ // Note: we multiply by 10 for convenience of computation,
+ // as Event stores time and duration as integers, not doubles.
+ int start = (int)(temp.get_start() * 10);
+ int dur = (int)(temp.get_dur() * 10);
+ Event new_event = new Event(start,convertPitch(temp.get_pitch()),dur,i);
+ result[i] = new_event;
+ num_events++;
+
+ }
+
+ // size the array
+ return shape_Event_List(result,num_events);
+ }
+
+ // The original event list may have some redundant
+ // blank entries at the end. We use this shape_Event_List
+ // to size it nicely to the number of events that are actually
+ // needed.
+ public Event [] shape_Event_List(Event [] original, int num_events)
+ {
+ if (original == null)
+ {
+ System.out.println("shape_Event_List: null array given.");
+ return null;
+ }
+
+ Event [] result = new Event [num_events];
+
+ for (int i = 0; i < num_events; i++)
+ {
+ result[i] = original[i];
+ }
+ return result;
+ }
+
+ // When the user clicks to add a new note,
+ // this function is called to add an event into the
+ // existing Event array.
+ public Event [] add_Event(Event e)
+ {
+
+ // create new note
+ String [] def_string = new String[1];
+ def_string[0] = "(NOTE)";
+ Note newnote = new Note(e.getTime()/10,
+ e.getDur()/10,
+ convertPitch(e.getPitch()),
+ def_string,
+ 1);
+
+ // add it to score
+ addNote(newnote);
+
+ // return new list of events
+ return toEventList();
+ }
+
+ // When user clicks to delete a note from
+ // the piano roll, this function is called
+ // to cleanly remove the event, maintaining
+ // the invariant that the notes in score are
+ // sorted in order of start time.
+ public Event [] del_Event(Event e)
+ {
+ delNote(e.getIndex());
+ return toEventList();
+ }
+
+ // This function outputs a string
+ // that represents the score
+ // in the format of the default file
+ // from which we parsed the original score
+ public String writeScore()
+ {
+ String result = scoreName + "\n";
+ for (int i = 0; i < notes_used; i++)
+ {
+ result += Double.toString(score[i].get_start());
+ result += " ";
+ result += Double.toString(score[i].get_dur());
+ result += " ";
+ if (score[i].get_pitch() == -9999) result += "NIL";
+ else result += Integer.toString(score[i].get_pitch());
+ for (int j = 0; j < score[i].get_numopts(); j++)
+ {
+ result += " ";
+ result += (score[i].get_opts())[j];
+ }
+ result += "\n";
+ }
+ return result;
+ }
+
+ // debugging function
+ public void PrintScore()
+ {
+ System.out.println("Printing Score..");
+ System.out.println("Variables: notes_used = " + notes_used
+ + " num_notes = " + num_notes);
+ for (int i = 0; i < notes_used; i++)
+ {
+ Note temp = getNote(i);
+ temp.PrintNote();
+ }
+ System.out.println("Done Printing Score!");
+ }
+
+ }
+
+
+ /*
+ the Event class, which defines a stretch of note on the piano roll
+ 15-392 - Pianobao project
+
+ Most of the fields in the Event object are derived from
+ those in the Note class. The GUI functions use Events as
+ the representation of the actual Note, for simplicity.
+ For example, start time and duration are ints in Event
+ but are doubles in Note. Also, the values of start time and
+ duration are 10 times larger than its counterparts in Note
+ because the scaling prevents the notes from being too small
+ in the piano roll picture.
+
+ Another point to note is that the pitch in Event is not
+ in standard MIDI format, while that in Note is. This is
+ because it was easier to use a range of 0-49 (these are
+ graphical coordinates) when plotting the pitch-axis in
+ a GUI, and this range corresponds to the MIDI pitches
+ 36-84 (C2 -> C4).
+
+ The index field the index of the array in which this Event
+ resides. This is for book-keeping purposes.
+ the values stored in this Event object is a graphical location
+ on the interface. A set of value converters will parse these
+ coordinates into actual musical values when we need to update
+ the score in Nyquist.
+
+ */
+
+
+ public static class Event {
+ private int time, pitch, dur, index;
+
+
+ public Event(int startTime, int givenPitch, int duration, int index) {
+ time = startTime;
+ pitch = givenPitch;
+ dur = duration;
+ this.index = index;
+ }
+
+ public Event(int startTime, int givenPitch) {
+ time = startTime;
+ pitch = givenPitch;
+ dur = 1;
+ }
+
+ /*
+ checks whether the given x and y coordiante is within this particular event
+ 20 is the pitchHeight. Basically works by checking whether the coordinates
+ clicked is within the rectangle of the Event on screen
+
+ */
+ public boolean checkWithinDuration(int timeX, int pitchY) {
+
+ return (((pitchY) <= ((pitch*10) + 20 )) &&
+ (pitchY >= ((10*pitch) + 10)) &&
+ (timeX >= time) &&
+ (timeX <= (time + dur))
+ );
+ }
+
+ // uses coordinates of user's click to determine whether
+ // user intends to drag the note or stretch its duration.
+ // returns : 0 if drag,
+ // 1 if stretch from left,
+ // 2 if stretch from right (change dur)
+ public int checkDragNotStretch(int timeX, int pitchY) {
+ if ((timeX <= (time+3)) && (timeX >= time)) {
+ return 1;
+ }
+ if ((timeX <= (time + dur)) && (timeX >= dur + time - 3)){
+ return 2;
+ }
+ return 0;
+ }
+
+ //accessors
+ public int getTime() {
+ return time;
+ }
+
+ public int getPitch() {
+ return pitch;
+ }
+
+ public int getDur() {
+ return dur;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ //mutators
+ public void editEvent(int startTime, int givenPitch, int duration) {
+ time = startTime;
+ pitch = givenPitch;
+ dur = duration;
+ return;
+ }
+
+ public void setDur(int duration) {dur = duration;}
+ public void setStartTime(int startTime) {time = startTime;}
+ public void setPitch(int newPitch) {pitch = newPitch;}
+ public void setIndex(int newIndex) {index = newIndex;}
+
+ public String toString(){
+ return "Event of Pitch: " + pitch + " , start time = " + time + " , duration = " +
+ dur + ", index = " + index + "\n";
+ }
+
+ }
+ // end of Event class
+
+
+ }
+
+
+}
+
diff --git a/jnyqide/PlotFrame.java b/jnyqide/PlotFrame.java
new file mode 100644
index 0000000..866cebd
--- /dev/null
+++ b/jnyqide/PlotFrame.java
@@ -0,0 +1,333 @@
+package jnyqide;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.*;
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+// Note: originally this code put plots in JInternalFrames. The code to
+// support this is commented out and marked with "JPANEL:"
+
+public class PlotFrame extends JPanel { //JPANEL: JInternalFrame {
+
+ double minX, minY, height, width; // range of data values to be plotted
+ double minXlabel, minYlabel, xSpacing, ySpacing;
+ int numXlines, numYlines; // number of lines to be plotted
+ double minLabel, spacing; // computed by AxisLayout
+ int numLines; // computed by AxisLayout
+ double xExtent, yExtent; // value range of plot area
+ Vector<Pair> data;
+ PlotMouseAdapter mouse;
+ Graphics g; // the whole thing, including labels
+ Graphics gGraph; // the graph image without labels
+ Image buffer;
+ Image graphBuffer;
+ int bufferHeight; // size of plot with labels
+ int bufferWidth; // size of plot with labels
+ //JPANEL: int offsetWindowSide = 3; // To clear the side bar
+ //JPANEL: int offsetWindowTop = 21; // To clear the title bar
+ int offsetX = 40; // how wide is label space to left of gGraph
+ int offsetRight = 10; // how wide is space to right of gGraph
+ int offsetY = 5; // how high is space above of gGraph
+ int dotSize = 3; // diameter of data points on the plot image
+ int textHeight = 20;
+ // width of plot area (without labels)
+ int graphBufferWidth;
+ // height of plot area (without labels)
+ int graphBufferHeight;
+ int axisMinSpacing = 30;
+ //JPANEL: int gadgetHeight = 10;
+
+ public void CalcBufferSize()
+ {
+ graphBufferWidth = bufferWidth - offsetX - offsetRight;
+ graphBufferWidth = Math.max(10, graphBufferWidth);
+ graphBufferHeight = bufferHeight - textHeight; //JPANEL: - gadgetHeight;
+ graphBufferHeight = Math.max(10, graphBufferHeight);
+ }
+
+
+ public PlotFrame(JPanel jPanel) {
+ minX = 0;
+ minY = -1;
+ width = 1;
+ height = 2;
+ xExtent = 1;
+ yExtent = 2;
+ data = new Vector<Pair>();
+ data.add(new Pair(0.0, 0.0));
+ data.add(new Pair(1.0, 0.0));
+ mouse = new PlotMouseAdapter(this);
+ setPreferredSize(new Dimension(400, 100));
+ // setResizable(true);
+ addMouseMotionListener(mouse);
+ addMouseListener(mouse);
+ setVisible(true);
+ jPanel.add(this, BorderLayout.CENTER);
+ CalcBufferSize();
+
+ renderGraph();
+ }
+
+ public void PlotData(Vector<Pair> d, double minx, double miny,
+ double maxx, double maxy) {
+ //System.out.println("PlotData called.");
+ minX = minx;
+ minY = miny;
+ height = maxy - miny;
+ width = maxx - minx;
+ data = d;
+ //System.out.println("PlotData calling repaint");
+ renderGraph();
+ repaint();
+ }
+
+
+
+ //JPANEL: This is old code to put a plot in a JInternalFrame
+ // public PlotFrame(JDesktopPane jDesktop, Vector d, double minx, double miny,
+ // double maxx, double maxy) {
+ // minX = minx;
+ // minY = miny;
+ // height = maxy - miny;
+ // width = maxx - minx;
+ // data = d;
+ // mouse = new PlotMouseAdapter(this);
+ //
+ // setSize(new Dimension(720, 520));
+ // //JPANEL: setResizable(true);
+ // //JPANEL: this.setClosable(true);
+ // //JPANEL: this.setIconifiable(true);
+ //
+ // addMouseMotionListener(mouse);
+ // addMouseListener(mouse);
+ //
+ // //JPANEL: setTitle("Plot");
+ // setVisible(true);
+ // jDesktop.add(this);
+ // CalcBufferSize();
+ //
+ // renderGraph();
+ // }
+ //
+ // private int degree(double n)
+ // {
+ // int deg = 0;
+ // while (n < 10) {
+ // n *= 10.0;
+ // deg++;
+ // }
+ // return deg;
+ // }
+ // (END JPANEL:)
+
+ // do label layouts for x and y axes. Returns values by setting
+ // spacing, minLabel, and numLines
+ //
+ public void AxisLayout(int buffersize, int axisMinSpacing,
+ double minval, double range)
+ {
+ if (range < 0.000001) range = 1.0; // convert range of zero
+ // compute axis layout
+ // first, figure out about how many label divisions there can be
+ int nlabels = buffersize / axisMinSpacing;
+ if (nlabels <= 0) nlabels = 1; // avoid divide by zero
+ // now figure out what that is in terms of the data
+ // spacing is a proposed spacing for labels in terms of actual data
+ spacing = range / nlabels;
+ // now increase spacing to nearest multiple of 0.1, 0.2, 0.5, ...
+ // first, get spacing between 0.1 and 1.0
+ double tens = 1.0;
+ //System.out.print("spacing "); System.out.println(spacing);
+ while (spacing < 0.1) {
+ spacing = spacing * 10.0;
+ tens = tens * 0.1;
+ }
+ while (spacing > 1.0) {
+ spacing = spacing * 0.1;
+ tens = tens * 10.0;
+ }
+ // now 0.1 <= spacing <= 1.0, and spacing * tens is original value
+ // adjust spacing up to 0.2, 0.5, or 1.0
+ // this will result in greater than minimum spacing
+ if (spacing < 0.2) spacing = 0.2;
+ else if (spacing < 0.5) spacing = 0.5;
+ else spacing = 1.0;
+ // now translate back to original power of ten
+ spacing = spacing * tens;
+ // figure out minLabel, the first multiple of spacing less or equal to minval
+ // the extra 0.1% added by multiplying by 1.001 is there so that if
+ // minval is already very close to a multiple of spacing, it is used
+ // Sometimes this happens due to floating point rounding even when
+ // minval is an exact multiple of spacing.
+ minLabel = ((int) ((minval / spacing) * 1.001)) * spacing;
+ // (int) rounds toward zero, so if minval is negative, subtract one
+ if (minLabel > minval + spacing * 0.0001) minLabel -= spacing;
+ // since spacing may have increased, we may not need so many divisions to
+ // span the range of the data
+ numLines = (int) ((minval + range - minLabel) / spacing);
+ // increase by one in case we rounded down
+ if (numLines < (minval + range - minLabel) / spacing) numLines += 1;
+ // increase by one again. E.g. if the graph is divided in two, there are
+ // three lines. (Always one more line than division.)
+ numLines += 1;
+ System.out.print("minLabel "); System.out.print(minLabel);
+ System.out.print(" spacing "); System.out.println(spacing);
+ System.out.print(" numLines " + numLines);
+ }
+
+ public void renderGraph()
+ {
+ System.out.println("renderGraph");
+ if (gGraph == null) {
+ System.out.print("creating graphbuffer");
+ System.out.print(graphBufferWidth); System.out.print(", ");
+ System.out.println(graphBufferHeight);
+ graphBuffer = createImage(graphBufferWidth, graphBufferHeight);
+ //System.out.println(graphBuffer);
+ if (graphBuffer == null) return; // Why does this fail?
+ gGraph = graphBuffer.getGraphics();
+ }
+
+ gGraph.setColor(new Color(220, 220, 220));
+ gGraph.fillRect(0, 0, graphBufferWidth, graphBufferHeight);
+
+ System.out.println("calling AxisLayout");
+ AxisLayout(graphBufferWidth, axisMinSpacing, minX, width);
+ //System.out.print("return from AxisLayout");
+ xExtent = spacing * (numLines - 1);
+ minXlabel = minLabel;
+ xSpacing = spacing;
+ numXlines = numLines;
+
+ AxisLayout(graphBufferHeight, axisMinSpacing, minY, height);
+ yExtent = spacing * (numLines - 1);
+ minYlabel = minLabel;
+ ySpacing = spacing;
+ numYlines = numLines;
+
+ // draw graph as lines first, then overlay circles
+ ListIterator iter = data.listIterator();
+ Pair prev = (Pair) iter.next();
+ int x1 = (int) ((prev.getTime() - minXlabel) / xExtent * graphBufferWidth);
+ int y1 = (int) ((1.0 - ((prev.getValue() - minYlabel) / yExtent)) *
+ graphBufferHeight);
+ Color pointColor = new Color(220, 220, 0);
+ while (iter.hasNext()) {
+ Pair p = (Pair) iter.next();
+ gGraph.setColor(Color.black);
+ int x2 = (int) ((p.getTime() - minXlabel) / xExtent * graphBufferWidth);
+ int y2 = (int) ((1.0 - ((p.getValue() - minYlabel) / yExtent)) *
+ graphBufferHeight);
+ gGraph.drawLine(x1, y1, x2, y2);
+ gGraph.setColor(pointColor);
+ x1 = x1 - dotSize / 2;
+ y1 = y1 - dotSize / 2;
+ gGraph.fillOval(x1, y1, dotSize, dotSize);
+ gGraph.setColor(Color.black);
+ gGraph.drawOval(x1, y1, dotSize, dotSize);
+ x1 = x2;
+ y1 = y2;
+ }
+ // draw the last point
+ gGraph.setColor(pointColor);
+ x1 = x1 - dotSize / 2;
+ y1 = y1 - dotSize / 2;
+ gGraph.fillOval(x1, y1, dotSize, dotSize);
+ gGraph.setColor(Color.black);
+ gGraph.drawOval(x1, y1, dotSize, dotSize);
+
+ double x = minXlabel;
+ for (int i = 0; i < numXlines; i++) {
+ //System.out.println(x);
+ int axisX = (int) (((x - minXlabel) / ((numXlines - 1) * xSpacing)) *
+ graphBufferWidth + 0.5);
+ gGraph.setColor(new Color(170, 170, 170));
+ gGraph.drawLine(axisX, 0, axisX, graphBufferHeight );
+ x += xSpacing;
+ }
+
+ double y = minYlabel;
+ for (int i = 0; i < numYlines; i++) {
+ //double y = minYlabel; y < minYlabel + height; y += ySpacing) {
+ int axisY = (int) ((1.0 - ((y - minYlabel) / ((numYlines - 1) * ySpacing))) *
+ graphBufferHeight + 0.5);
+ gGraph.setColor(new Color(170, 170, 170));
+ gGraph.drawLine(0, axisY, graphBufferWidth, axisY );
+ y += ySpacing;
+ }
+ }
+
+ public void paint(Graphics g2) {
+ // Graphics g = getContentPane().getGraphics();
+ System.out.println("Painting...");
+ // because the window can be resized, check if we have the right width and height
+ //System.out.print("graph dim "); System.out.print(getWidth());
+ //System.out.print(", "); System.out.println(getHeight());
+
+ if ((getHeight() != bufferHeight) ||
+ (getWidth() != bufferWidth)) {
+ g = null; // delete any existing double buffer to force an update
+ gGraph = null; // the plot image is here, update this too
+ //System.out.println("recalculate width and height");
+ }
+
+ if (g == null) { // create matching image buffer for double buffer update
+ bufferHeight = getHeight();
+ bufferWidth = getWidth();
+ buffer = createImage(bufferWidth, bufferHeight);
+ g = buffer.getGraphics();
+ CalcBufferSize();
+ }
+
+ if (gGraph == null) {
+ renderGraph();
+ }
+
+ if (g2 != null) {
+ g.setColor(new Color(150, 150, 150));
+ g.fillRect(0, 0, bufferWidth, bufferHeight); //JPANEL: - gadgetHeight);
+
+ if (gGraph != null) {
+ g.drawImage(graphBuffer, offsetX, offsetY, offsetX + graphBufferWidth,
+ offsetY + graphBufferHeight, 0, 0,
+ graphBufferWidth, graphBufferHeight, this);
+ }
+
+ double x = minXlabel;
+ for (int i = 0; i < numXlines; i++) {
+ int axisX = (int) (((x - minXlabel) / (xSpacing * (numXlines - 1))) *
+ graphBufferWidth + 0.5);
+ g.setColor(Color.black);
+ String s = Double.toString(Math.round(x * 1000) / 1000.0);
+ g.drawString(s, offsetX + axisX - s.length() * 2 -
+ (i == numXlines - 1 ? s.length() * 2 : 0),
+ offsetY + graphBufferHeight + textHeight - 8);
+ x += xSpacing;
+ }
+
+ double y = minYlabel;
+ for (int i = 0; i < numYlines; i++) {
+ int axisY = (int) (((y - minYlabel) / (ySpacing * (numYlines - 1))) *
+ graphBufferHeight + 0.5);
+ g.setColor(Color.black);
+ String s = Double.toString(Math.round(y * 1000) / 1000.0);
+ // note: offset top string to fit within graphics area
+ g.drawString(s, offsetX - s.length() * 5 - 5,
+ offsetY + graphBufferHeight - axisY +
+ (i == numYlines - 1 ? textHeight - 8 : 0));
+ y += ySpacing;
+ }
+ }
+ super.paint(g2);
+ //JPANEL: g2.drawImage(buffer, offsetWindowSide, offsetWindowTop, this );
+ g2.drawImage(buffer, 0, 0, this );
+ }
+}
diff --git a/jnyqide/PlotMouseAdapter.java b/jnyqide/PlotMouseAdapter.java
new file mode 100644
index 0000000..571660a
--- /dev/null
+++ b/jnyqide/PlotMouseAdapter.java
@@ -0,0 +1,67 @@
+package jnyqide;
+
+import javax.swing.event.MouseInputAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.*;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+public class PlotMouseAdapter extends MouseInputAdapter {
+
+ int dx, dy;
+ int startx, starty;
+ int shiftx, shifty;
+ boolean shifting;
+ PlotFrame frame;
+
+ public PlotMouseAdapter(PlotFrame f)
+ {
+ dx = 0;
+ dy = 0;
+ shiftx = 0;
+ shifty = 0;
+ shifting = false;
+ frame = f;
+ }
+
+ public void mouseDragged(MouseEvent e)
+ {
+ System.out.println("mouseDragged");
+ if (!shifting) {
+ shifting = true;
+ startx = e.getX();
+ starty = e.getY();
+ }
+ dx = e.getX() - startx;
+ dy = e.getY() - starty;
+ frame.repaint();
+ }
+
+ public void mouseClicked( MouseEvent e )
+ {
+ }
+
+ public void mouseReleased( MouseEvent e )
+ {
+ shiftx += dx;
+ shifty += dy;
+ shifting = false;
+ }
+
+ public int getShiftX()
+ {
+ return shiftx+dx;
+ }
+
+ public int getShiftY()
+ {
+ return shifty+dy;
+ }
+} \ No newline at end of file
diff --git a/jnyqide/PopupListener.java b/jnyqide/PopupListener.java
new file mode 100644
index 0000000..7b07792
--- /dev/null
+++ b/jnyqide/PopupListener.java
@@ -0,0 +1,46 @@
+package jnyqide;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.event.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.undo.*;
+import jnyqide.*;
+
+class PopupListener extends MouseAdapter {
+ JPopupMenu popup;
+ JTextPane pane;
+
+ PopupListener(JPopupMenu popupMenu, JTextPane textPane)
+ {
+ popup = popupMenu;
+ pane = textPane;
+ }
+
+ public void mousePressed(MouseEvent e)
+ {
+ maybeShowPopup(e);
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ maybeShowPopup(e);
+ }
+
+ private void maybeShowPopup(MouseEvent e)
+ {
+ if (e.isPopupTrigger()) {
+ MenuElement[] items = popup.getSubElements();
+ for (int i = 0; i < items.length; i++) {
+ String name = items[i].getComponent().getName();
+ if (name.equals("context copy") || name.equals("context cut")) {
+ ((JMenuItem) items[i]).setEnabled(pane.getSelectedText() !=
+ null);
+ }
+ }
+ popup.show(e.getComponent(), e.getX(), e.getY());
+ }
+ }
+} \ No newline at end of file
diff --git a/jnyqide/PreferencesDialog.java b/jnyqide/PreferencesDialog.java
new file mode 100644
index 0000000..fb6b04b
--- /dev/null
+++ b/jnyqide/PreferencesDialog.java
@@ -0,0 +1,426 @@
+/*
+ * Preferences dialog based on ReplaceDialog.java
+ */
+
+// Current elements are:
+//
+// Restore Defaults
+// [] Automatically insert close-parentheses
+// <-|--> Relative height of completion box
+//
+package jnyqide;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import java.io.File;
+
+import com.sun.corba.se.spi.servicecontext.SendingContextServiceContext;
+
+import jnyqide.*;
+
+class PreferencesDialog extends JInternalFrame implements ActionListener {
+ private MainFrame mainFrame;
+ private JScrollPane scrollPane;
+ private JPanel panel;
+ private JButton defaultPrefs; // "Restore Defaults"
+ private JCheckBox startInSalMode; // "Start in SAL mode (not Lisp)"
+ private JCheckBox salShowLisp; // "Show translation of SAL to Lisp"
+ private JCheckBox parenAutoInsert;
+ // "Automatically insert close-parentheses"
+ private JCheckBox enableSound; // "Enable sound output in PLAY command"
+ private JCheckBox autoNorm; // "AutoNorm"
+ private JCheckBox salTraceBack; // "Print SAL traceback on SAL error"
+ private JCheckBox salBreak; // "Enable XLISP break on SAL error"
+ private JCheckBox xlispBreak; // "Enable XLISP break on XLISP error"
+ private JCheckBox xlispTraceBack; // "Print XLISP traceback on XLISP error"
+ private JCheckBox printGC; // "Print info about garbage collection"
+ private JCheckBox fullSearch;
+ // "Use full search for code completion"
+ private JCheckBox internalBrowser;
+ // "Use window in jNyqIDE for help browser"
+ private JCheckBox onlineManual;
+ // "Use online manual instead of local copy"
+ private JScrollBar completionListPercent;
+ // "Relative height of completion box"
+ private JComboBox audioRate; // "Audio Sample Rate"
+ private JTextField controlRate; // "Control Sample Rate"
+ private JComboBox fontSize; // "Font Size"
+ private JButton sfDirectory; // "Set Default Sound File Directory"
+ private JButton initialDirectory; // "Set Initial Directory"
+ private JFileChooser startfd;
+ private JFileChooser fd;
+ private String[] audioRates = { "96000", "48000", "44100", "22050", "16000",
+ "11025", "8000" };
+ private String currentFontSize;
+ private String[] fontSizes = { "6", "7", "8", "9", "10", "11", "12", "14",
+ "16", "18", "20", "24", "28", "32", "36" };
+ protected JCheckBox makeCheckBox(String doc, boolean val) {
+ //JPanel contentPane = (JPanel) getContentPane();
+ JCheckBox cb = new JCheckBox(doc, val);
+ cb.setAlignmentX(Component.LEFT_ALIGNMENT);
+ //contentPane.add(cb);
+ panel.add(cb);
+ return cb;
+ }
+
+ public PreferencesDialog(MainFrame mainFrame_) {
+ super();
+ final PreferencesDialog preferencesDialog = this;
+ //super(mainFrame_, "Preferences", true); // initialize Dialog
+ setTitle("Preferences");
+
+ mainFrame = mainFrame_;
+
+ addInternalFrameListener(new InternalFrameListener() {
+ public void internalFrameClosing(InternalFrameEvent e) {
+ mainFrame.prefStartInSalMode = startInSalMode.isSelected();
+
+ boolean enable = salShowLisp.isSelected();
+ mainFrame.setBoolean("*sal-compiler-debug*", enable);
+ mainFrame.prefSalShowLisp = enable;
+
+ mainFrame.prefParenAutoInsert = parenAutoInsert.isSelected();
+
+ enable = enableSound.isSelected();
+ mainFrame.callFunction(
+ enable ? "sound-on" : "sound-off", "");
+ mainFrame.prefEnableSound = enable;
+
+ enable = autoNorm.isSelected();
+ mainFrame.callFunction(
+ enable ? "autonorm-on" : "autonorm-off", "");
+ mainFrame.prefAutoNorm = enable;
+
+ enable = salTraceBack.isSelected();
+ mainFrame.callFunction("sal-tracenable",
+ mainFrame.tOrNil(enable));
+ mainFrame.prefSalTraceBack = enable;
+
+ enable = salBreak.isSelected();
+ mainFrame.callFunction("sal-breakenable",
+ mainFrame.tOrNil(enable));
+ mainFrame.prefSalBreak = enable;
+
+ enable = (xlispBreak.isSelected() || xlispTraceBack.isSelected());
+ mainFrame.callFunction("xlisp-breakenable",
+ mainFrame.tOrNil(enable));
+ mainFrame.prefXlispBreak = enable;
+
+ enable = xlispTraceBack.isSelected();
+ mainFrame.callFunction("xlisp-tracenable",
+ mainFrame.tOrNil(enable));
+ mainFrame.prefXlispTraceBack = enable;
+
+ enable = printGC.isSelected();
+ if (enable != mainFrame.prefPrintGC) {
+ mainFrame.setBoolean("*gc-flag*", enable);
+ mainFrame.prefPrintGC = enable;
+ }
+
+ mainFrame.prefFullSearch = fullSearch.isSelected();
+
+ mainFrame.prefInternalBrowser = internalBrowser.isSelected();
+
+ mainFrame.prefOnlineManual = onlineManual.isSelected();
+
+ if ((int) mainFrame.prefCompletionListPercent !=
+ (int) (completionListPercent.getValue())) {
+ mainFrame.prefCompletionListPercent =
+ completionListPercent.getValue();
+ mainFrame.tileCompletion();
+ }
+
+ String rateString = (String) audioRate.getSelectedItem();
+ //audioRate.setSize(50, 20);
+ int rate = validate(rateString);
+ if (rate > 0 && !rateString.equals(mainFrame.prefAudioRate)) {
+ mainFrame.callFunction("set-sound-srate", rateString);
+ mainFrame.prefAudioRate = rateString;
+ }
+
+ rateString = controlRate.getText();
+ rate = validate(rateString);
+ if (rate > 0 && !rateString.equals(mainFrame.prefControlRate)) {
+ mainFrame.callFunction("set-control-srate ", rateString);
+ mainFrame.prefControlRate = rateString;
+ }
+
+ String fontString = (String) fontSize.getSelectedItem();
+ int size = validate(fontString);
+ if (size > 0 && !fontString.equals(mainFrame.prefFontSize)) {
+ mainFrame.prefFontSize = fontString;
+ mainFrame.setFontSize(size);
+ }
+
+ File file = startfd.getSelectedFile();
+
+ System.out.println("startfd.getSelectedFile() -> " + file);
+
+ if (file != null) {
+ String dir = file.toString().replaceAll("\\\\", "/");
+ System.out.println("startfd.getSelectedFile: " + dir);
+ if (dir != null && dir.length() > 0) {
+ mainFrame.prefDirectory = dir;
+ mainFrame.changeDirectory(dir);
+ }
+ } else {
+ mainFrame.prefDirectory = "";
+ }
+
+ file = fd.getSelectedFile();
+ if (file != null) {
+ String dir = file.toString().replaceAll("\\\\", "/");
+ System.out.println("fd.getSelectedFile: " + dir);
+ if (dir != null && dir.length() > 0) {
+ mainFrame.prefSFDirectory = dir;
+ mainFrame.setVariable("*default-sf-dir*",
+ "\"" + dir + "\"");
+ }
+ } else {
+ mainFrame.prefSFDirectory = "";
+ }
+
+ mainFrame.prefsHaveBeenSet = true;
+ dispose();
+ }
+
+ public void internalFrameOpened(InternalFrameEvent e) {
+ }
+ public void internalFrameClosed(InternalFrameEvent e) {
+ mainFrame.disconnectPreferences();
+ //System.out.println("FrameClosed");
+ }
+ public void internalFrameIconified(InternalFrameEvent e) {
+ }
+ public void internalFrameDeiconified(InternalFrameEvent e) {
+ }
+ public void internalFrameActivated(InternalFrameEvent e) {
+ }
+ public void internalFrameDeactivated(InternalFrameEvent e) {
+ }
+ });
+
+ panel = new JPanel();
+ scrollPane = new JScrollPane(panel);
+ JPanel contentPane = (JPanel) getContentPane();
+ contentPane.add(scrollPane, BorderLayout.CENTER);
+ //contentPane
+ panel.setLayout(
+ new BoxLayout(panel, BoxLayout.Y_AXIS));
+
+ panel.add(new JLabel("Preferences are updated when you close this Preferences Window"));
+ panel.add(Box.createRigidArea(new Dimension(0, 10)));
+
+ // button to restore default preferences
+ defaultPrefs = new JButton("Restore Defaults");
+ defaultPrefs.addActionListener(this);
+ defaultPrefs.setAlignmentX(Component.LEFT_ALIGNMENT);
+ panel.add(defaultPrefs);
+
+ panel.add(Box.createRigidArea(new Dimension(0, 10)));
+
+ // Start in Sal mode (not Lisp)"
+ startInSalMode = makeCheckBox("Start in SAL mode (not Lisp)",
+ mainFrame.prefStartInSalMode);
+ // Show translation of SAL to Lisp
+ salShowLisp = makeCheckBox("Show translation of SAL to Lisp",
+ mainFrame.prefSalShowLisp);
+ // Automatically insert close-parenthesis (checkbox)
+ parenAutoInsert = makeCheckBox(
+ "Automatically insert close-parentheses",
+ mainFrame.prefParenAutoInsert);
+ // Enable sound output (checkbox)
+ enableSound = makeCheckBox("Enable sound output in PLAY command",
+ mainFrame.prefEnableSound);
+ // AutoNorm (checkbox)
+ autoNorm = makeCheckBox("AutoNorm", mainFrame.prefAutoNorm);
+
+ // Enable SAL Stack Traceback on Error
+ salTraceBack = makeCheckBox("Print SAL traceback on SAL error",
+ mainFrame.prefSalTraceBack);
+ // break into XLISP debugger on SAL error
+ salBreak = makeCheckBox("Enable XLISP break on SAL error",
+ mainFrame.prefSalBreak);
+ // Enable XLISP Break when XLISP encounters error
+ xlispBreak = makeCheckBox("Enable XLISP break on XLISP error",
+ mainFrame.prefXlispBreak);
+ // print XLISP TraceBack on XLISP error
+ xlispTraceBack = makeCheckBox("Print XLISP traceback on XLISP error",
+ mainFrame.prefXlispTraceBack);
+ // printGC
+ printGC = makeCheckBox("Print info about garbage collection",
+ mainFrame.prefPrintGC);
+
+ // Use full search for code completion (checkbox)
+ fullSearch = makeCheckBox("Use full search for code completion",
+ mainFrame.prefFullSearch);
+ // Use internal window for manual (checkbox)
+ internalBrowser = makeCheckBox("Use window in jNyqIDE for help browser",
+ mainFrame.prefInternalBrowser);
+ // Use online manual (checkbox)
+ onlineManual = makeCheckBox("Use online manual instead of local copy",
+ mainFrame.prefOnlineManual);
+
+ panel.add(Box.createRigidArea(new Dimension(0, 10)));
+
+ // Relative height of completion box (slider)
+ panel.add(new JLabel("Relative height of completion box",
+ JLabel.CENTER));
+ completionListPercent = new JScrollBar(JScrollBar.HORIZONTAL,
+ (int) mainFrame.prefCompletionListPercent, 1, 0, 100);
+ panel.add(completionListPercent);
+
+ panel.add(Box.createRigidArea(new Dimension(0, 10)));
+
+ // Audio Sample Rate (editable combobox)
+ panel.add(new JLabel("Audio Sample Rate"));
+ audioRate = new JComboBox(audioRates);
+ // Set correct selection
+ for (int i = 0; i < audioRates.length; i++) {
+ if (mainFrame.prefAudioRate.equals(audioRates[i])) {
+ audioRate.setSelectedIndex(i);
+ break;
+ }
+ }
+ audioRate.setEditable(true);
+ audioRate.setAlignmentX(Component.LEFT_ALIGNMENT);
+ audioRate.setMaximumSize(
+ new Dimension(100, audioRate.getPreferredSize().height));
+ panel.add(audioRate);
+
+ panel.add(Box.createRigidArea(new Dimension(0, 10)));
+
+ // Control Rate (text field)
+ panel.add(new JLabel("Control Sample Rate"));
+ controlRate = new JTextField(mainFrame.prefControlRate);
+ controlRate.setAlignmentX(Component.LEFT_ALIGNMENT);
+ controlRate.setMaximumSize(
+ new Dimension(100, controlRate.getPreferredSize().height));
+ panel.add(controlRate);
+
+ panel.add(Box.createRigidArea(new Dimension(0, 10)));
+
+ // Font Size (editable combobox)
+ panel.add(new JLabel("Font Size"));
+ fontSize = new JComboBox(fontSizes);
+ // Set correct selection
+ for (int i = 0; i < fontSizes.length; i++) {
+ if (mainFrame.prefFontSize.equals(fontSizes[i])) {
+ fontSize.setSelectedIndex(i);
+ break;
+ }
+ }
+ fontSize.setEditable(true);
+ fontSize.setAlignmentX(Component.LEFT_ALIGNMENT);
+ fontSize.setMaximumSize(
+ new Dimension(100, fontSize.getPreferredSize().height));
+ panel.add(fontSize);
+
+ panel.add(Box.createRigidArea(new Dimension(0, 10)));
+
+ // Select Startup Directory (button)
+ startfd = new JFileChooser("Select Initial Directory");
+ startfd.setCurrentDirectory(new File(mainFrame.prefDirectory));
+ startfd.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+
+ initialDirectory = new JButton("Set Initial Directory");
+ initialDirectory.addActionListener(this);
+ initialDirectory.setAlignmentX(Component.LEFT_ALIGNMENT);
+ panel.add(initialDirectory);
+
+ // Select Sound File Output Directory (button)
+ fd = new JFileChooser("Select Default Soundfile Directory");
+ fd.setCurrentDirectory(new File(mainFrame.prefSFDirectory));
+ fd.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+
+ sfDirectory = new JButton("Set Default Soundfile Directory");
+ sfDirectory.addActionListener(this);
+ sfDirectory.setAlignmentX(Component.LEFT_ALIGNMENT);
+ panel.add(sfDirectory);
+
+ panel.add(Box.createVerticalGlue());
+
+ /*
+ * The Nyquist IDE has a preferences dialog with a couple of things you
+ * can change. It would be great to have a graphical way to set things
+ * like the normalization style, default audio and control sample rates,
+ * whether to play sounds or save audio to disk or both when calling the
+ * play function, whether to apply reverb and/or EQ to the output signal
+ * when using PLAY, a default sound file directory, whether to print a
+ * stack trace when an error is encountered, etc. (All of these things
+ * can be set in Nyquist, but most users do not know how.)
+ */
+
+ pack();
+ Dimension size = new Dimension(400, 400);
+ setSize(size);
+ Point mfloc = mainFrame.getLocation();
+ setLocation(mfloc.x + 25, mfloc.y + 25);
+ setResizable(true);
+ setVisible(true);
+ setClosable(true);
+ setMaximizable(true);
+ setIconifiable(true);
+ repaint();
+ }
+
+ private int validate(String s) {
+ try {
+ int temp = Integer.parseInt(s);
+ if (temp > 0) return temp;
+ } catch (Exception e) {
+ }
+ return -1;
+ }
+
+
+ /*
+ // On Mac OS X, we can select directories using the native file open dialog
+ void getDirectoryUsingFileDialog(String title) {
+ boolean saveUseJFC = Prefs.useJFileChooser;
+ Prefs.useJFileChooser = false;
+ System.setProperty("apple.awt.fileDialogForDirectories", "true");
+ OpenDialog od = new OpenDialog(title, defaultDir, null);
+ if (od.getDirectory()==null)
+ directory = null;
+ else
+ directory = od.getDirectory() + od.getFileName() + "/";
+ defaultDir = directory;
+ System.setProperty("apple.awt.fileDialogForDirectories", "false");
+ Prefs.useJFileChooser = saveUseJFC;
+ }
+ */
+
+ public void actionPerformed(ActionEvent evt) {
+ if (evt.getSource() == sfDirectory) {
+ fd.showOpenDialog(this);
+ } else if (evt.getSource() == initialDirectory) {
+ startfd.showOpenDialog(this);
+ } else if (evt.getSource() == defaultPrefs) {
+ startInSalMode.setSelected(mainFrame.prefStartInSalModeDefault);
+ salShowLisp.setSelected(mainFrame.prefSalShowLispDefault);
+ parenAutoInsert.setSelected(
+ mainFrame.prefParenAutoInsertDefault);
+ enableSound.setSelected(mainFrame.prefEnableSoundDefault);
+ autoNorm.setSelected(mainFrame.prefAutoNormDefault);
+ salTraceBack.setSelected(mainFrame.prefSalTraceBackDefault);
+ salBreak.setSelected(mainFrame.prefSalBreakDefault);
+ xlispBreak.setSelected(mainFrame.prefXlispBreakDefault);
+ xlispTraceBack.setSelected(mainFrame.prefXlispTraceBackDefault);
+ printGC.setSelected(mainFrame.prefPrintGCDefault);
+ fullSearch.setSelected(mainFrame.prefFullSearchDefault);
+ internalBrowser.setSelected(mainFrame.prefInternalBrowserDefault);
+ onlineManual.setSelected(mainFrame.prefOnlineManualDefault);
+ completionListPercent.setValue(
+ (int) (mainFrame.prefCompletionListPercentDefault + 0.5));
+ audioRate.setSelectedItem(mainFrame.prefAudioRateDefault);
+ controlRate.setText(mainFrame.prefControlRateDefault);
+ fontSize.setSelectedItem(mainFrame.prefFontSizeDefault);
+ startfd.setSelectedFile(null);
+ fd.setSelectedFile(null);
+ }
+ }
+}
diff --git a/jnyqide/README.txt b/jnyqide/README.txt
new file mode 100644
index 0000000..3bbe5d3
--- /dev/null
+++ b/jnyqide/README.txt
@@ -0,0 +1,152 @@
+15-392 Final Project Description
+
+Dave Mowatt dmowatt@andrew.cmu.edu
+
+Source Code:
+
+ Main.java - main executable
+ Creates a MainFrame swing window
+
+ nyquist/ - All the ide files for text editing
+ nyquist/MainFrame.java - root frame for the IDE
+ This uses a basic swing interface, with a menu bar,
+ quick-action buttons, and the basic components of the
+ nyquist IDE: the input window (upper left), the output
+ window (left side), and a desktop for all the opened files.
+
+ nyquist/NyquistThread.java - i/o to nyquist executable
+ Executes nyquist and maintains the input/output streams
+ for communication to and from the input and output windows
+ inside of MainFrame. The executable path (currently
+ "nyquist.exe" or "ny" should be set to reflect whatever
+ location the nyquist executable is on that particular machine.
+
+ nyquist/NyquistFile.java - data for one open file in nyquist
+ On a new instance, creates an empty file. Save will write
+ to the current file unless it is a new file - where SaveAs
+ will automatically be called. (If the file is new then the
+ java File file variable will be null) Whenever a file is
+ modified, a * will be placed next to the file's name in the
+ title bar.
+
+ nyquist/LispFileFilter.java* - filters out .lsp files.
+
+ colortext/ - All the files relating to text coloring and
+ paren checking
+ colortext/SyntaxThread.java - maintains syntax highlighting for
+ one document
+ This is also used on the input window, where the paren
+ balencing is used to prevent invalid input to nyquist.
+
+ colortext/ColorText.java - text highlighting functions
+ formatAll will go through the entire file to find the balanced
+ parens, strings, comments, and the keywords. The keywords are
+ currently in a list at the bottom, just append any missing ones
+ or read them in from a file. The format() functions take
+ in the syntax thread that is calling them. This is so they
+ will automatically exit as soon as the thread's document is
+ changed. That way if the user types another letter while the
+ current check is running, it will stop the current one and
+ start a new check from the beginning.
+
+
+ nyquistplot/ - All the files for plotting
+ nyquistplot/Pair.java - Stores the x, y coordinates of one data point
+ time is along the x axis, v is along the y axis
+
+ nyquistplot/NyqPlot.java - Handles reading in the data, finding
+ mins/maxes
+ Pretty straightforward, reads in the data storing the sonud
+ data, then creates a graph based on that.
+
+ nyquistplot/PlotFrame.java - Plots a graph of the file
+ Upon creation, draws the full graph to an image. From then on,
+ parts of that image are drawn to the double buffered window.
+ This is so scrolling can be done easily without re-drawing
+ the image again. The full graph image should be re-drawn
+ on scaling.
+
+ nyquistplot/PlotMouseAdapter.java* - Handles data for mouse
+ scrolling/zooming
+ Counts how far the mouse has been dragged to just store the
+ change on how far to scroll.
+
+* not currently used, but the framework is there
+
+----- design notes for SAL -----
+
+to move to SAL, we must support two languages: XLISP and SAL
+
+when you open an edit window, the type, XLISP or SAL, should become
+a property of the window. I think we can just assume XLISP unless
+the file extension is SAL. Another option would be to try to detect
+the file type if the extension is not .lsp, .sal, or .ny. Maybe we could
+compute the ratio of parens to non-parens, but this might fail for
+data files (lists of numbers, in XLISP syntax), so we could add other
+features like counts of SAL keywords, etc. Let's try the simple
+file extension test first.
+
+When you open a new file, the editor should know whether it's a
+new lisp window or a new sal window. We won't support a new
+text window, but users can edit text and ignore syntax coloring
+if they want to.
+
+Syntax editor is needed for SAL. Coloring should match SAL examples
+on the CLM/SAL web pages, which look very good.
+
+Indentation should be suggested by the editor when you type newline.
+It would be great if TAB would indent the line instead of inserting a TAB.
+
+The IDE needs know when the user is in SAL mode or LISP mode. SAL
+prompts with "SAL>", so the sequence "\nSAL> " should put the IDE
+into SAL mode. In SAL mode, the IDE should expect SAL to be
+entered into the input window. Input should only be parsed when
+the user types two newlines in a row -- that allows multiple line
+input.
+
+Also, in SAL mode, errors need to be detected, parsed, and used
+to position the cursor at the error location in an edit window.
+
+----- notes on Java -----
+
+DETECTING A MAC
+
+ if (System.getProperty("mrj.version") == null) {
+ mb.add(createJUnitMenu());
+ } else {
+ // the Mac specific code will go here
+ }
+
+from http://java.sun.com/developer/technicalArticles/JavaLP/JavaToMac2/
+
+ public boolean isMac() {
+ return System.getProperty("mrj.version") != null;
+ }
+
+from http://www.kfu.com/~nsayer/Java/reflection.html
+
+LOADING CLASSES ONLY ON MAC
+
+That is, we really want to do this:
+
+ if (isMac()) {
+ new SpecialMacHandler(this);
+ }
+but we will land in hot water because the class loader doesn't know what isMac() will return. It will only see that SpecialMacHandler wants com.apple.mrj.MRJApplicationUtils and fail to start the program on non-Macs. We must achieve the same end without referencing the class directly in the code. Reflection offers us the way. The reflected version of the same code looks like this:
+
+ if (isMac()) {
+ try {
+ Object[] args = { this };
+ Class[] arglist = { Program.class };
+ Class mac_class = class.forName("SpecialMacHandler");
+ Constructor new_one = mac_class.getConstructor(arglist);
+ new_one.newInstance(args);
+ }
+ catch(Exception e) {
+ System.out.println(e);
+ }
+ }
+
+from http://www.kfu.com/~nsayer/Java/reflection.html
+
+
diff --git a/jnyqide/ReplaceDialog.java b/jnyqide/ReplaceDialog.java
new file mode 100644
index 0000000..0578d07
--- /dev/null
+++ b/jnyqide/ReplaceDialog.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1997 John Jensen. All rights reserved.
+ *
+ * This software is FREE FOR COMMERCIAL AND NON-COMMERCIAL USE,
+ * provided the following condition is met.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that any copy or derivative of this software or documentation
+ * retaining the name "John Jensen" also retains this condition and the
+ * following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
+ *
+ * CopyrightVersion 1.0
+ */
+package jnyqide;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import jnyqide.*;
+
+class ReplaceDialog extends Dialog implements WindowListener, ActionListener
+{
+ private Button fbutton,rbutton,cbutton;
+ private TextField pattern;
+ private TextField replace;
+ private MainFrame mainFrame;
+ private NyquistFile nyquistFile;
+ private Properties strings;
+
+ private boolean foundOnce = false;
+
+ public ReplaceDialog(NyquistFile tf, MainFrame mainFrame_)
+ {
+ super(mainFrame_, "Replace", true);
+
+ mainFrame = mainFrame_;
+
+ setBackground(Color.lightGray);
+
+ nyquistFile = tf;
+
+ Panel p1 = new Panel();
+
+ GridBagLayout gridbag = new GridBagLayout();
+ GridBagConstraints constraints = new GridBagConstraints();
+ p1.setLayout(gridbag);
+
+ Label flabel = new Label("Find");
+ constraints.anchor = GridBagConstraints.NORTHWEST;
+ gridbag.setConstraints(flabel, constraints);
+
+ pattern = new TextField();
+ pattern.setColumns(35);
+
+ if(tf.pane.getSelectedText() == null) // BWP
+ pattern.setText(mainFrame.findPattern);
+ else // BWP
+ pattern.setText(tf.pane.getSelectedText()); // BWP
+
+ constraints.gridwidth = GridBagConstraints.REMAINDER;
+ gridbag.setConstraints(pattern, constraints);
+
+ p1.add(flabel);
+ p1.add(pattern);
+
+ Label rlabel = new Label("Replace");
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.gridwidth = 1;
+ gridbag.setConstraints(rlabel, constraints);
+
+ replace = new TextField();
+ replace.setColumns(35);
+
+ replace.setText(mainFrame.replacePattern);
+
+ constraints.gridwidth = GridBagConstraints.REMAINDER;
+ gridbag.setConstraints(replace, constraints);
+
+ p1.add(rlabel);
+ p1.add(replace);
+
+ add("Center", p1);
+
+ Panel p3 = new Panel();
+ fbutton = new Button("Find Next");
+ fbutton.addActionListener(this);
+ p3.add(fbutton);
+ rbutton = new Button("Replace");
+ rbutton.addActionListener(this);
+ p3.add(rbutton);
+ cbutton = new Button("Close");
+ cbutton.addActionListener(this);
+ p3.add(cbutton);
+ add("South",p3);
+
+ Dimension size = new Dimension(400,120);
+ setSize(size);
+ Point tfloc = tf.getLocation();
+ Point mfloc = mainFrame.getLocation();
+ setLocation(mfloc.x + tfloc.x,
+ mfloc.y + tfloc.y + 75);
+
+ addWindowListener(this);
+ setVisible(true);
+ }
+
+ public void windowDeiconified(WindowEvent event) {}
+ public void windowIconified(WindowEvent event) {}
+ public void windowActivated(WindowEvent event) {}
+ public void windowDeactivated(WindowEvent event) {}
+ public void windowOpened(WindowEvent event) {}
+ public void windowClosed(WindowEvent event) {}
+ public void windowClosing(WindowEvent event)
+ {
+ mainFrame.findPattern = pattern.getText();
+ mainFrame.replacePattern = replace.getText();
+ dispose();
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ if (evt.getSource() == cbutton)
+ {
+ mainFrame.findPattern = pattern.getText();
+ mainFrame.replacePattern = replace.getText();
+ dispose();
+ return;
+ }
+
+ if (evt.getSource() == fbutton)
+ foundOnce = nyquistFile.find(pattern.getText());
+ else if (evt.getSource() == rbutton)
+ {
+ if (!foundOnce)
+ {
+ String selection= nyquistFile.copy(false,false);
+ if (selection != null)
+ foundOnce = selection.equals(pattern.getText());
+ }
+
+ if (foundOnce)
+ nyquistFile.paste(replace.getText());
+
+ foundOnce = nyquistFile.find(pattern.getText());
+ }
+
+ if (!foundOnce)
+ {
+ NotFoundDialog nf = new NotFoundDialog(mainFrame, strings,
+ getLocation());
+ nf.setVisible(true);
+ }
+ }
+}
diff --git a/jnyqide/SalFileFilter.java b/jnyqide/SalFileFilter.java
new file mode 100644
index 0000000..641ff37
--- /dev/null
+++ b/jnyqide/SalFileFilter.java
@@ -0,0 +1,41 @@
+//
+// SalFileFilter.java
+// nyquist
+//
+// Created by Roger Dannenberg on 12/23/07.
+// Copyright 2007 __MyCompanyName__. All rights reserved.
+//
+
+package jnyqide;
+
+import javax.swing.filechooser.*;
+import java.io.File;
+
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2002</p>
+ * <p>Company: </p>
+ * @author unascribed
+ * @version 1.0
+ */
+
+public class SalFileFilter extends FileFilter {
+
+ public SalFileFilter() {
+ }
+
+ public boolean accept(File f) {
+ if (f.getName().endsWith(".sal")) return true;
+ for (int x = 0; x < f.getName().length(); x++) {
+ if ((f.getName().charAt(x) == '.'))
+ return false;
+ }
+ return true;
+ }
+
+ public String getDescription() {
+ return "Sal files.";
+ }
+}
diff --git a/jnyqide/SalWordList.java b/jnyqide/SalWordList.java
new file mode 100644
index 0000000..5874be8
--- /dev/null
+++ b/jnyqide/SalWordList.java
@@ -0,0 +1,57 @@
+//
+// SalWordList.java
+// nyquist
+//
+// Created by Roger Dannenberg on 12/18/07.
+// Copyright 2007 __MyCompanyName__. All rights reserved.
+//
+
+package jnyqide;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class SalWordList {
+ public static String[] reservedWords = {
+ "below", "by", "else", "finally", "for", "function", "in", "over",
+ "repeat", "then", "from", "to", "unless", "until", "variable",
+ "when", "while", "with" };
+
+ public static String[] commandWords = {
+ "begin", "end", "chdir", "define", "open", "exec", "exit", "display",
+ "load", "loop", "open", "print", "if", "return", "set", // "system",
+ "play" };
+
+ public static Map<String, String> reservedWordsTable;
+
+ public static Map<String, String> commandWordsTable;
+
+
+ static public void init() {
+ int i;
+ reservedWordsTable = new HashMap<String, String>();
+ for (i = 0; i < reservedWords.length; i++) {
+ reservedWordsTable.put(reservedWords[i], null);
+ }
+ commandWordsTable = new HashMap<String, String>();
+ for (i = 0; i < commandWords.length; i++) {
+ commandWordsTable.put(commandWords[i], null);
+ }
+ }
+
+
+ static public boolean isReservedWord(String word) {
+ boolean rslt = reservedWordsTable.containsKey(word);
+ // System.out.println("Sal:isReservedWord " + word + " -> " + rslt);
+ return rslt;
+ }
+
+
+ static public boolean isCommandWord(String word) {
+ boolean rslt = commandWordsTable.containsKey(word);
+ // System.out.println("Sal:isCommandWord " + word + " -> " + rslt);
+ return rslt;
+ }
+
+}
diff --git a/jnyqide/SpecialMacHandler.java b/jnyqide/SpecialMacHandler.java
new file mode 100644
index 0000000..f48024a
--- /dev/null
+++ b/jnyqide/SpecialMacHandler.java
@@ -0,0 +1,70 @@
+package jnyqide;
+
+import jnyqide.*;
+import com.apple.eawt.ApplicationAdapter;
+import com.apple.eawt.ApplicationEvent;
+import com.apple.eawt.Application;
+/* import com.apple.mrj.*; */
+import javax.swing.SwingUtilities;
+
+/* OLD CODE -- the MRJ classes are deprecated.
+public class SpecialMacHandler
+ implements MRJQuitHandler, MRJPrefsHandler, MRJAboutHandler {
+ MainFrame us;
+ public SpecialMacHandler(jnyqide.MainFrame theProgram) {
+ us = theProgram;
+ System.setProperty("com.apple.macos.useScreenMenubar", "true");
+ System.setProperty("com.apple.mrj.application.apple.menu.about.name", "jNyqIDE");
+ MRJApplicationUtils.registerAboutHandler(this);
+ MRJApplicationUtils.registerPrefsHandler(this);
+ MRJApplicationUtils.registerQuitHandler(this);
+ System.out.println("\n\n\nRegistered handlers for Mac Application Menu\n\n\n");
+ }
+ public void handleAbout() {
+ us.About();
+ }
+ public void handlePrefs() {
+ us.Prefs();
+ }
+ public void handleQuit() {
+ System.out.println("handleQuit in SpecialMacHandler.java called");
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ us.Quit();
+ }
+ });
+ throw new IllegalStateException("Let the quit handler do it");
+ }
+}
+*/
+
+public class SpecialMacHandler extends ApplicationAdapter {
+
+ MainFrame us;
+
+ public SpecialMacHandler(jnyqide.MainFrame theProgram) {
+ System.out.println("SpecialMacHandler created");
+ us = theProgram;
+ Application app = Application.getApplication();
+ app.addApplicationListener(this);
+ app.setEnabledPreferencesMenu(true);
+ }
+
+ public void handleAbout(ApplicationEvent e) {
+ e.setHandled(true);
+ us.About();
+ }
+
+ public void handlePreferences(ApplicationEvent e) {
+ us.Prefs();
+ }
+
+ public void handleQuit(ApplicationEvent e) {
+ System.out.println("handleQuit in SpecialMacHandler called");
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ us.Quit();
+ }
+ });
+ }
+}
diff --git a/jnyqide/SpringUtilities.java b/jnyqide/SpringUtilities.java
new file mode 100644
index 0000000..fff3af6
--- /dev/null
+++ b/jnyqide/SpringUtilities.java
@@ -0,0 +1,194 @@
+package jnyqide;
+
+import javax.swing.*;
+import javax.swing.SpringLayout;
+import java.awt.*;
+
+/**
+ * A 1.4 file that provides utility methods for
+ * creating form- or grid-style layouts with SpringLayout.
+ * These utilities are used by several programs, such as
+ * SpringBox and SpringCompactGrid.
+ */
+public class SpringUtilities {
+ /**
+ * A debugging utility that prints to stdout the component's
+ * minimum, preferred, and maximum sizes.
+ */
+ public static void printSizes(Component c) {
+ System.out.println("minimumSize = " + c.getMinimumSize());
+ System.out.println("preferredSize = " + c.getPreferredSize());
+ System.out.println("maximumSize = " + c.getMaximumSize());
+ }
+
+ /**
+ * Aligns the first <code>rows</code> * <code>cols</code>
+ * components of <code>parent</code> in
+ * a grid. Each component is as big as the maximum
+ * preferred width and height of the components.
+ * The parent is made just big enough to fit them all.
+ *
+ * @param rows number of rows
+ * @param cols number of columns
+ * @param initialX x location to start the grid at
+ * @param initialY y location to start the grid at
+ * @param xPad x padding between cells
+ * @param yPad y padding between cells
+ */
+ public static void makeGrid(Container parent,
+ int rows, int cols,
+ int initialX, int initialY,
+ int xPad, int yPad) {
+ SpringLayout layout;
+ try {
+ layout = (SpringLayout)parent.getLayout();
+ } catch (ClassCastException exc) {
+ System.err.println("The first argument to makeGrid must use SpringLayout.");
+ return;
+ }
+
+ Spring xPadSpring = Spring.constant(xPad);
+ Spring yPadSpring = Spring.constant(yPad);
+ Spring initialXSpring = Spring.constant(initialX);
+ Spring initialYSpring = Spring.constant(initialY);
+ int max = rows * cols;
+
+ //Calculate Springs that are the max of the width/height so that all
+ //cells have the same size.
+ Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)).
+ getWidth();
+ Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)).
+ getWidth();
+ for (int i = 1; i < max; i++) {
+ SpringLayout.Constraints cons = layout.getConstraints(
+ parent.getComponent(i));
+
+ maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
+ maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
+ }
+
+ //Apply the new width/height Spring. This forces all the
+ //components to have the same size.
+ for (int i = 0; i < max; i++) {
+ SpringLayout.Constraints cons = layout.getConstraints(
+ parent.getComponent(i));
+
+ cons.setWidth(maxWidthSpring);
+ cons.setHeight(maxHeightSpring);
+ }
+
+ //Then adjust the x/y constraints of all the cells so that they
+ //are aligned in a grid.
+ SpringLayout.Constraints lastCons = null;
+ SpringLayout.Constraints lastRowCons = null;
+ for (int i = 0; i < max; i++) {
+ SpringLayout.Constraints cons = layout.getConstraints(
+ parent.getComponent(i));
+ if (i % cols == 0) { //start of new row
+ lastRowCons = lastCons;
+ cons.setX(initialXSpring);
+ } else { //x position depends on previous component
+ cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST),
+ xPadSpring));
+ }
+
+ if (i / cols == 0) { //first row
+ cons.setY(initialYSpring);
+ } else { //y position depends on previous row
+ cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH),
+ yPadSpring));
+ }
+ lastCons = cons;
+ }
+
+ //Set the parent's size.
+ SpringLayout.Constraints pCons = layout.getConstraints(parent);
+ pCons.setConstraint(SpringLayout.SOUTH,
+ Spring.sum(
+ Spring.constant(yPad),
+ lastCons.getConstraint(SpringLayout.SOUTH)));
+ pCons.setConstraint(SpringLayout.EAST,
+ Spring.sum(
+ Spring.constant(xPad),
+ lastCons.getConstraint(SpringLayout.EAST)));
+ }
+
+ /* Used by makeCompactGrid. */
+ private static SpringLayout.Constraints getConstraintsForCell(
+ int row, int col,
+ Container parent,
+ int cols) {
+ SpringLayout layout = (SpringLayout) parent.getLayout();
+ Component c = parent.getComponent(row * cols + col);
+ return layout.getConstraints(c);
+ }
+
+ /**
+ * Aligns the first <code>rows</code> * <code>cols</code>
+ * components of <code>parent</code> in
+ * a grid. Each component in a column is as wide as the maximum
+ * preferred width of the components in that column;
+ * height is similarly determined for each row.
+ * The parent is made just big enough to fit them all.
+ *
+ * @param rows number of rows
+ * @param cols number of columns
+ * @param initialX x location to start the grid at
+ * @param initialY y location to start the grid at
+ * @param xPad x padding between cells
+ * @param yPad y padding between cells
+ */
+ public static void makeCompactGrid(Container parent,
+ int rows, int cols,
+ int initialX, int initialY,
+ int xPad, int yPad) {
+ SpringLayout layout;
+ try {
+ layout = (SpringLayout)parent.getLayout();
+ } catch (ClassCastException exc) {
+ System.err.println("The first argument to makeCompactGrid must use SpringLayout.");
+ return;
+ }
+
+ //Align all cells in each column and make them the same width.
+ Spring x = Spring.constant(initialX);
+ for (int c = 0; c < cols; c++) {
+ Spring width = Spring.constant(0);
+ for (int r = 0; r < rows; r++) {
+ width = Spring.max(width,
+ getConstraintsForCell(r, c, parent, cols).
+ getWidth());
+ }
+ for (int r = 0; r < rows; r++) {
+ SpringLayout.Constraints constraints =
+ getConstraintsForCell(r, c, parent, cols);
+ constraints.setX(x);
+ constraints.setWidth(width);
+ }
+ x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad)));
+ }
+
+ //Align all cells in each row and make them the same height.
+ Spring y = Spring.constant(initialY);
+ for (int r = 0; r < rows; r++) {
+ Spring height = Spring.constant(0);
+ for (int c = 0; c < cols; c++) {
+ height = Spring.max(height,
+ getConstraintsForCell(r, c, parent, cols).
+ getHeight());
+ }
+ for (int c = 0; c < cols; c++) {
+ SpringLayout.Constraints constraints =
+ getConstraintsForCell(r, c, parent, cols);
+ constraints.setY(y);
+ constraints.setHeight(height);
+ }
+ y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad)));
+ }
+
+ //Set the parent's size.
+ SpringLayout.Constraints pCons = layout.getConstraints(parent);
+ pCons.setConstraint(SpringLayout.SOUTH, y);
+ pCons.setConstraint(SpringLayout.EAST, x);
+ }
+}
diff --git a/jnyqide/TextColor.java b/jnyqide/TextColor.java
new file mode 100644
index 0000000..55b501c
--- /dev/null
+++ b/jnyqide/TextColor.java
@@ -0,0 +1,984 @@
+package jnyqide;
+
+import javax.swing.*;
+// import java.awt.*; -- includes List, which conflicts
+import java.awt.Color;
+import java.awt.event.*;
+import java.awt.Point;
+import java.awt.Dimension;
+import javax.swing.text.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import java.util.*;
+/*
+import java.util.Iterator;
+import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Point;
+*/
+import java.io.*;
+
+public class TextColor {
+ static final boolean TCDEBUG = false;
+ static final String TEXT_FONT = "Courier";
+ static final int TEXT_SIZE = 12;
+ static final Color COLOR_NORMAL = Color.black;
+ static final Color COLOR_COMMENT = new Color(0, 100, 0); // darkish green
+ static final Color COLOR_BUILTIN = Color.blue;
+ static final Color COLOR_STRING = new Color(130, 140, 0); // brown
+ static final Color COLOR_ERROR = new Color(250, 0, 0);
+ static final Color COLOR_COMMAND = new Color(0, 0, 196); // darkBlue;
+ static final Color COLOR_RESERVED = new Color(96, 0, 196); // purple
+ static final Color COLOR_KEYWORD = new Color(255, 128, 128); // pink
+ static final Color COLOR_HIGHLIGHT_FG = Color.black;
+ static final Color COLOR_HIGHLIGHT_BG = Color.lightGray;
+ static final Color COLOR_BLINK_FG = Color.white;
+ static final Color COLOR_BLINK_BG = Color.black;
+
+ // TextColor is set up to be non-reentrant, with some state saved
+ // as static variables that can be referenced by helper functions
+ // like setColor. For example, you call format to colorize the
+ // visible portions of a window. It saves some state that setColor
+ // (called from many places) can use to find the document, the
+ // visible region, etc. When format returns, TextColor is ready
+ // for another call to fix another window.
+
+ static DefaultStyledDocument doc; // the document being colorized
+ static int start; // the start of the visible region
+ static int end; // the end of the visible region
+ static int indentPos; // where we want indent information
+ static int indentBefore; // special return values for editing
+ static int indentAfter;
+
+ public static SimpleAttributeSet attrNormal, attrComment, attrBuiltin,
+ attrString, attrError, attrCommand, attrKeyword, attrReserved,
+ attrHighlight, attrBlink;
+
+ private static SimpleAttributeSet newTextAttr(Color color) {
+ SimpleAttributeSet attr = new SimpleAttributeSet();
+ attr.addAttribute(StyleConstants.ColorConstants.Foreground, color);
+ StyleConstants.setFontFamily(attr, TEXT_FONT);
+ StyleConstants.setFontSize(attr, TEXT_SIZE);
+ return attr;
+ }
+
+ private static SimpleAttributeSet newTextHighlight(Color fg, Color bg) {
+ SimpleAttributeSet attr = new SimpleAttributeSet();
+ attr.addAttribute(StyleConstants.ColorConstants.Foreground, fg);
+ attr.addAttribute(StyleConstants.ColorConstants.Background, bg);
+ return attr;
+ }
+
+ // public static Set<String> keywords = new HashSet<String>();
+
+ public static void init() {
+ // System.out.println("initializing TextColor.java");
+ attrNormal = newTextAttr(COLOR_NORMAL);
+ attrComment = newTextAttr(COLOR_COMMENT);
+ attrBuiltin = newTextAttr(COLOR_BUILTIN);
+ attrCommand = newTextAttr(COLOR_COMMAND);
+ attrKeyword = newTextAttr(COLOR_KEYWORD);
+ attrReserved = newTextAttr(COLOR_RESERVED);
+ attrError = newTextAttr(COLOR_ERROR);
+ attrString = newTextAttr(COLOR_STRING);
+ attrHighlight = newTextHighlight(COLOR_HIGHLIGHT_FG, COLOR_HIGHLIGHT_BG);
+ attrBlink = newTextHighlight(COLOR_BLINK_FG, COLOR_BLINK_BG);
+ }
+
+
+ public static boolean format(CodePane codePane, int nlLoc)
+ {
+ JTextPane pane = codePane.pane;
+ doc = codePane.doc;
+ JViewport v = codePane.getViewport();
+ indentBefore = 0;
+ indentAfter = 0;
+ indentPos = nlLoc; // position of interest for indentation info
+ //System.out.println("format begin");
+ Point point = v.getViewPosition();
+ start = pane.viewToModel(point);
+ //System.out.print("text loc for origin: ");
+ //System.out.println(start);
+ Dimension extent = v.getExtentSize();
+ point.translate(extent.width, extent.height);
+ end = pane.viewToModel(point);
+ //System.out.print("text loc for bottom right: ");
+ //System.out.println(end);
+ boolean b;
+ int docLength = doc.getLength();
+ String docText;
+ try {
+ docText = doc.getText(0, docLength);
+ } catch(Exception e ) { System.out.println(e);
+ return false; }
+ if (codePane.isSal && (docLength == 0 || docText.charAt(0) != '(')) {
+ b = formatVisibleSal(codePane, docText, docLength);
+ } else {
+ b = formatVisible(codePane, docText, docLength);
+ }
+ // System.out.println("format end: isSal " + codePane.isSal +
+ // " indentBefore " + indentBefore +
+ // " After " + indentAfter);
+ return b;
+ }
+
+
+ public static void setColor(int pos, int len,
+ SimpleAttributeSet color)
+ {
+ // if color region overlaps visible region, update doc with color
+ if (!(end < pos || pos + len < start)) {
+ doc.setCharacterAttributes(pos, len, color, true);
+ }
+ }
+
+ static final int INDENT = 2; // how much to indent
+ // these are codes for different bracket types:
+ static final int ONESHOT = 0;
+ static final int IF_THEN = 1;
+ static final int COMMAND = 2;
+ static final int BRACE = 3;
+ static final int BRACKET = 4;
+ static final int PAREN = 5;
+ static final int IF = 6;
+ static final int BEGIN = 7;
+ static final int TOP = 8; // imaginary initial/final brackets used
+ // to detect and mark any unclosed real brackets like begin, (, etc.
+ // debugging support (I guess I should have used enumerated type):
+ static String[] stateName = { "ONESHOT", "IF_THEN", "COMMAND",
+ "BRACE", "BRACKET", "PAREN", "IF", "BEGIN", "TOP" };
+
+
+ // find the column of pos in text by searching back to newline
+ public static int columnFor(String text, int pos) {
+ int col = 0;
+ while (pos > 0 && text.charAt(pos - 1) != '\n') {
+ col++;
+ pos--;
+ }
+ return col;
+ }
+
+ // placed here so it is accessible by inner classes -- not ideal
+ static int lineIndent;
+
+ public static boolean formatVisibleSal(CodePane pane,
+ final String docText, int docLength) {
+ // start and end give the visible range over which we actually
+ // change the document.
+ //
+ // Parse the whole file (well, almost):
+ // Use a stack for matching tokens and to compute indent:
+ // The stack contains the indentation to restore to when
+ // the matching close token is found. Also, if the close
+ // token does not match the top of the stack, there is some
+ // balance problem -- use precedence to decide what to match to, e.g.
+ // and END will skip an unclosed open-paren to match a BEGIN because
+ // BEGIN/END has higher precedence.
+ //
+ // This idea breaks down when there are local syntax errors, e.g.
+ // if you type a "todo" list at the top of a file, and the text
+ // is (intentionally) full of SAL syntax errors (because it's not
+ // supposed to be SAL), then far down in the file, you may find
+ // indentation breaks down completely. To work around this problem
+ // the syntax coloring is RESET whenever "define" appears
+ //
+ // In SAL, IF-THEN-ELSE does not have close tokens, so indentation
+ // is very tricky. IF is actually closed by THEN, but THEN must
+ // be followed by a statement. We record this by pushing IF_THEN,
+ // meaning that there's an IF-THEN construct holding a place for
+ // a possible ELSE. Then we push a COMMAND,
+ // a placeholder for the next statement. After any statement word,
+ // we pop COMMAND. If we find an ELSE, we pop the matching IF-THEN.
+ // If we get a statement when we're not expecting COMMAND, we pop
+ // all the IF-THEN's because the statement is going to stop any
+ // ELSE from matching and therefore we have to pop the indentation
+ // level back before any pending IF-THENs.
+ //
+ // Note that indentBefore and indentAfter and indentPos are used
+ // so that indentation can be computed and inserted from external
+ // editing functions. These basically serve as probes into the
+ // parsing algorithm.
+ //
+ // Coloring:
+ // as for LISP:
+ // known functions are in blue
+ // strings are in brown
+ // comments are in green
+ // as in Common Music SAL:
+ // reserved words are in purple
+ // keyword parameters are in pink
+ // commands are in dark blue
+ //
+ boolean allMatched = true;
+ boolean afterNewline = true; // set to true after each newline, and
+ // false after first token after each newline; used for indentation
+ lineIndent = 0; // will hold the correct indentation for the
+ // current line when a newline is reached.
+ // This is in contrast to the ParseStack.indent number, which is
+ // the "nominal" indentation that will be adjusted if the first
+ // token on the line closes an open bracket (e.g. begin or "(")
+ // or if the first token is not an expected command word
+ class ParseState {
+ public int indent; // the indentation level
+ public int indent2; // indent level if not a command
+ public int elseIndent; // used only for IF and IF_THEN to
+ // remember indentation for a possible ELSE clause
+ public int pos; // location of the token
+ public int len; // length of the token
+ public int state; // the saved state
+ public ParseState(int i, int i2, int p, int l, int s) {
+ indent = i; indent2 = i2; pos = p; len = l; state = s;
+ elseIndent = 0;
+ }
+ };
+
+ class ParseStack {
+ public Stack<ParseState> stack;
+ public int indent;
+ public int indent2; // the indentation if a command is continued
+ public ParseStack() {
+ stack = new Stack<ParseState>();
+ stack.push(new ParseState(0, 0, 0, 0, TOP));
+ indent = 0;
+ indent2 = 0;
+ }
+
+ // push an indentation level on the stack, the keyword responsible
+ // starts at pos and had length len. The new indentation level will
+ // be at the column of pos + offset
+ public void push(int offset, int offset2, int pos, int len, int state) {
+ offset += columnFor(docText, pos) - indent;
+ pushOffset(offset, offset2, pos, len, state);
+ }
+
+ // pushOffset is like push except the offset is relative to the
+ // current indentation, not the position of the keyword (useful
+ // for "define function foo()" where function causes the indent
+ // (because you can have "define var" that does not indent), but
+ // you want to indent relative to define rather than function.
+ public void pushOffset(int offset, int offset2, int pos, int len,
+ int state) {
+ stack.push(new ParseState(indent, indent2, pos, len, state));
+ indent += offset;
+ indent2 = indent + offset2;
+ if (TCDEBUG) { System.out.println("pushOffset " + offset +
+ " indent " + indent); }
+ }
+
+ // pop stack back to a matching token: bracket tokens have
+ // priorities, e.g. begin is higher priority than "(", so
+ // and "end" will jump over an unmatched "(" to find a "begin"
+ // This is done to obtain more reasonable warnings to user,
+ // otherwise, for example, "begin ( end" would all be red
+ // instead of just showing the "(" in red. If anything is
+ // unmatched, return false so caller knows there is an error
+ // somewhere.
+ boolean pop(int state) {
+ boolean matched = true;
+ // System.out.println("pop " + stack);
+ while (!stack.empty() && stack.peek().state <= state) {
+ ParseState ps = stack.pop();
+ indent = ps.indent;
+ indent2 = ps.indent2;
+ // System.out.println("pop indent " + indent + " indent2 " + indent2);
+ if (ps.state == state) return matched;
+ if (ps.state != IF_THEN) { // ignore these ;
+ matched = false;
+ setColor(ps.pos, ps.len, attrError);
+ }
+ }
+ if (TCDEBUG) System.out.println("pop return false at end");
+ return false;
+ }
+
+ // after a command like define, the indentation level
+ // is incremented, but the level should be returned as soon as
+ // a command word is encountered
+ public void popCommandAndIfThen() {
+ // System.out.println("popCommand");
+ if (stack.peek().state == COMMAND) {
+ pop(COMMAND);
+ if (TCDEBUG) {
+ System.out.println(" --> poppedCommand"); print(); }
+ } else while (stack.peek().state == IF_THEN) {
+ pop(IF_THEN);
+ lineIndent = indent2 = indent;
+ if (TCDEBUG) {
+ System.out.println(" --> popped IF_THEN"); print(); }
+ }
+ }
+
+ // add COMMAND to stack after an IF_THEN in response to "else"
+ // this is tricky because the column inherits from the IF_THEN,
+ // not the current indent value, and indent gets elseIndent
+ public int ifElseCommand(int pos, int len) {
+ ParseState ps = stack.peek();
+ if (ps.state == IF_THEN) { // good, "else" follows if...then
+ // rather than popping IF_THEN and pushing COMMAND, just
+ // change ps:
+ indent = indent2 = ps.elseIndent + INDENT;
+ ps.pos = pos;
+ ps.len = len;
+ ps.state = COMMAND;
+ return ps.elseIndent;
+ }
+ return 0;
+ }
+
+
+ public void startCommand() {
+ // remove COMMAND if present and retain indentation
+ // otherwise pop out of IF_THEN's
+ if (stack.peek().state == COMMAND) {
+ ParseState ps = stack.pop();
+ indent2 = indent = ps.indent;
+ // back up indentation to prepare for an ELSE:
+ ps = stack.peek();
+ if (ps.state == IF_THEN) {
+ indent2 = indent = ps.elseIndent;
+ }
+ //lineIndent = indent;
+ //indent = indent2 = ps.indent;
+ } else {
+ popCommandAndIfThen();
+ }
+ }
+
+ public void convertCommand(int pos, int len, int state) {
+ // remove COMMAND if present and replace with state
+ if (stack.peek().state == COMMAND) {
+ ParseState ps = stack.peek();
+ ps.pos = pos;
+ ps.len = len;
+ ps.state = state;
+ } else {
+ popCommandAndIfThen();
+ pushOffset(0, len + 1, pos, len, state);
+ }
+ }
+
+ public void finishCommand() {
+ // remove COMMAND if present
+ if (stack.peek().state == COMMAND) {
+ pop(COMMAND);
+ } else {
+ popCommandAndIfThen();
+ }
+ }
+
+ public boolean convertIf() {
+ if (stack.peek().state == IF) {
+ ParseState ps = stack.peek();
+ ps.state = IF_THEN;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void print() {
+ ParseState state = stack.peek();
+ System.out.println("State: indent " + state.indent +
+ " indent2 " + state.indent2 +
+ " pos " + state.pos +
+ " len " + state.len +
+ " state " + stateName[state.state] +
+ " (cur) indent " + indent +
+ " (cur) indent2 " + indent +
+ " (cur) lineIndent " + lineIndent);
+ for (int i = 0; i < stack.size(); i++) {
+ System.out.print(stateName[stack.get(i).state] + " " +
+ stack.get(i).indent + " ");
+ }
+ System.out.println();
+ }
+
+ //public boolean expectingStmt() {
+ // int s = stack.peek().state;
+ // return (s == BEGIN || s == TOP);
+ // }
+ };
+
+ //System.out.println("formatVisibleSal");
+ try {
+ // To parse the file, we use a state machine with these states:
+ // comment -- in a comment started by ";"
+ // word -- in normal text, possibly a keyword
+ // hash -- we detected a hash mark (this state is implied)
+ // escape -- we detected a backslash (this state is implied)
+ // hashComment -- we're in a comment #| ... |#
+ // string -- in a string
+ // barSymbol -- in a symbol like |...|
+ // space -- in space between other tokens
+ // normal -- this state is orthogonal to the others.
+ // it records when we are accumulating a run of normal
+ // (black) characters. To make things run a little faster
+ // we don't color each black character individually but
+ // group them together into a run. It also helps at the end
+ // of the string to be able to color what's left.
+ boolean normal = false;
+ int normalStart = 0; // start of normal black characters
+ boolean comment = false;
+ int commentStart = 0;
+ boolean word = false;
+ int wordStart = 0;
+ boolean string = false;
+ int stringStart = 0;
+ boolean barSymbol = false;
+ int barSymbolStart = 0;
+ boolean space = false;
+ int spaceStart = 0;
+ int pos;
+ ParseStack stack = new ParseStack();
+
+ // originally, this code accumulated words in buf, but this
+ // caused many string allocations and ran very slowly, so now
+ // we just mark where the word begins and when the word ends
+ // we extract a string from docText
+
+
+ // process document text while you have not reached the end
+ // of the visible area and while there are unmatched parens
+ // (i.e. the parenStack isn't empty, but stop if you reach
+ // the end of the whole file.
+ //
+ // System.out.println("begin parse loop, docLength " + docLength);
+ for (pos = 0;
+ pos < docLength && (pos < end || !stack.stack.empty());
+ pos++) {
+ char c = docText.charAt(pos);
+ // System.out.print("CHAR |" + c + "| ");
+ if (comment) {
+ if (c == '\n') {
+ if (pos >= start) {
+ setColor(commentStart, pos - commentStart,
+ attrComment);
+ }
+ comment = false;
+ } // note that escape chars are ignored in comments
+ } else if (string) {
+ if (c == '"') {
+ if (pos >= start)
+ setColor(stringStart, pos - stringStart + 1,
+ attrString);
+ string = false;
+ } else if (c == '\\') { // skip the quoted char
+ pos++;
+ }
+ } else if (word) {
+ // see if the word ends because of a character or end of text
+ boolean terminated = (c == ' ' || c == '(' || c == ')' ||
+ c == '\n' || c == '"' || c == '{' ||
+ c == '}' || c == '[' || c == ']');
+ if (terminated || pos >= docLength - 1) {
+ word = false;
+ int stop = pos;
+ if (!terminated) stop++;
+ String buf = docText.substring(wordStart, stop);
+ if (TCDEBUG)
+ System.out.println("formatVisibleSal: " + buf);
+ buf = buf.toLowerCase(); // for simplified lookup
+ SimpleAttributeSet color;
+ // WordList.printList(buf); // to get words list.
+ if (SalWordList.isReservedWord(buf)) {
+ color = attrReserved;
+ // note that "then" is not included here because
+ // "then" in a "for" clause does not need to be
+ // followed by a COMMAND
+ if (buf.equals("function") || buf.equals("finally")) {
+ if (afterNewline) {
+ lineIndent = stack.indent;
+ }
+ stack.startCommand();
+ stack.pushOffset(INDENT, 0, wordStart,
+ buf.length(), COMMAND);
+ } else if (buf.equals("else")) {
+ int i = stack.ifElseCommand(wordStart, 4);
+ if (afterNewline) {
+ lineIndent = i;
+ }
+ if (TCDEBUG) {
+ System.out.println("ifElseCommand");
+ stack.print(); }
+ } else if (buf.equals("when") ||
+ buf.equals("unless")) {
+ stack.push(INDENT, buf.length() + 1 - INDENT,
+ wordStart, buf.length(), COMMAND);
+ } else if (buf.equals("variable")) {
+ stack.startCommand();
+ stack.indent2 = columnFor(docText, wordStart) +
+ buf.length() + 1;
+ } else if (buf.equals("with") ||
+ buf.equals("while") ||
+ buf.equals("until")) {
+ stack.startCommand();
+ stack.push(0, buf.length() + 1,
+ wordStart, buf.length(), COMMAND);
+// stack.indent2 = columnFor(docText, wordStart) +
+// buf.length() + 1;
+ } else if (buf.equals("then")) {
+ if (TCDEBUG) {
+ System.out.println("at then");
+ stack.print(); }
+ // if there's an if on the stack, pop it
+ if (stack.convertIf()) {
+ if (afterNewline) {
+ lineIndent = stack.indent;
+ }
+ stack.pushOffset(INDENT, INDENT, wordStart,
+ 4, COMMAND);
+ } else {
+ stack.indent2 =
+ columnFor(docText, wordStart) +
+ buf.length() + 1;
+ }
+ if (TCDEBUG) {
+ System.out.println("after then");
+ stack.print(); }
+ } else if (buf.equals("for")) {
+ stack.popCommandAndIfThen();
+ stack.indent2 = stack.indent + INDENT;
+ }
+ afterNewline = false;
+ } else if (SalWordList.isCommandWord(buf)) {
+ stack.indent2 = stack.indent;
+ color = attrCommand;
+ if (afterNewline) {
+ lineIndent = stack.indent;
+ }
+ if (buf.equals("define")) {
+ // reset syntax coloring
+ stack.pop(TOP); // color unmatched stuff
+ stack = new ParseStack(); // reset stack
+ } else if (buf.equals("begin") || buf.equals("loop")) {
+ stack.push(INDENT, INDENT, wordStart, 5, BEGIN);
+ } else if (buf.equals("end")) {
+ if (!stack.pop(BEGIN)) {
+ allMatched = false;
+ setColor(wordStart, 3, attrError);
+ }
+ if (TCDEBUG) {
+ System.out.println("end token after stack.pop");
+ stack.print(); }
+ // if this is the first word on the line, then
+ // match indentation to the matching BEGIN
+ if (afterNewline) {
+ lineIndent = stack.indent;
+ }
+ stack.finishCommand();
+ if (TCDEBUG) {
+ System.out.println("end end");
+ stack.print(); }
+ } else if (buf.equals("if")) {
+ if (TCDEBUG) {
+ System.out.println("at if");
+ stack.print(); }
+ // int i = stack.indent;
+ stack.convertCommand(wordStart, 2, IF);
+ stack.stack.peek().elseIndent = stack.indent;
+ // stack.indent = stack.indent2 = i;
+ // stack.push(0, 0, wordStart, 2, IF);
+ if (TCDEBUG) {
+ System.out.println("after if");
+ stack.print(); }
+ } else if (buf.equals("print")) {
+ stack.startCommand();
+ stack.indent2 = columnFor(docText, wordStart) +
+ buf.length() + 1;
+ } else {
+ stack.startCommand();
+ stack.indent2 = stack.indent + INDENT + INDENT;
+ }
+ afterNewline = false;
+ } else if (WordList.isKeyword(buf)) {
+ if (afterNewline) {
+ lineIndent = stack.indent2;
+ afterNewline = false;
+ }
+ color = attrBuiltin;
+ } else if (buf.charAt(buf.length() - 1) == ':') {
+ if (afterNewline) {
+ lineIndent = stack.indent2;
+ afterNewline = false;
+ }
+ color = attrKeyword;
+ } else {
+ if (afterNewline) {// && stack.expectingStmt()) {
+ lineIndent = stack.indent2;
+ if (TCDEBUG) {
+ System.out.println("buf " + buf +
+ " afterNewline " + afterNewline +
+ " lineIndent becomes " + lineIndent); }
+ afterNewline = false;
+ }
+ color = attrNormal;
+ }
+ // System.out.println(color);
+ if (color != attrNormal) {
+ setColor(normalStart,
+ wordStart - normalStart, attrNormal);
+ setColor(wordStart, pos - wordStart + 1,
+ color);
+ normal = true;
+ normalStart = pos + 1;
+ } else {
+ // continue normal (black) color
+ }
+ } else if (c == '\\') {
+ pos++; // skip the quoted char
+ }
+ if (terminated) {
+ pos = pos - 1; // reexamine character at pos
+ continue; // back to for loop, skip indentation tests
+ }
+ // Starts
+ } else if (c == ' ' || c == '\t' || c == '\n') {
+ space = true;
+ spaceStart = pos;
+ if (!normal) normalStart = pos;
+ normal = true;
+ } else if (c == ';') { // Comment Start
+ comment = true;
+ commentStart = pos;
+ space = false;
+ if (pos >= start && normal) {
+ setColor(normalStart, pos - normalStart, attrNormal);
+ }
+ normal = false;
+ } else if (c == '"') { // String start
+ if (afterNewline) {
+ lineIndent = stack.indent2;
+ afterNewline = false;
+ }
+ string = true;
+ stringStart = pos;
+ space = false;
+ if (pos >= start && normal) {
+ setColor(normalStart, pos - normalStart, attrNormal);
+ }
+ normal = false;
+ } else if (c == '(' || c == ')' || c == '{' || c == '}' ||
+ c == '[' || c == ']') {
+ // Paren/Brace start and end
+ if ((c == '(' || c == '{' || c == '[') && afterNewline) {
+ lineIndent = stack.indent2;
+ afterNewline = false;
+ }
+ space = false;
+ if (pos >= start && normal) {
+ setColor(normalStart, pos - normalStart, attrNormal);
+ }
+ normal = false;
+ if (pos >= start)
+ setColor(pos, 1, attrNormal);
+ if (c == '(' ) stack.push(1, 0, pos, 1, PAREN);
+ else if (c == '{') stack.push(1, 0, pos, 1, BRACE);
+ else if (c == '[') stack.push(1, 0, pos, 1, BRACKET);
+ else { // must be ')' or '}' or ']'
+ if (afterNewline) {
+ lineIndent = stack.indent - 1;
+ }
+ if (stack.pop(c == ')' ? PAREN :
+ (c == ']' ? BRACKET : BRACE))) {
+ // System.out.println("after ), ], or }: indent " + stack.indent);
+ } else {
+ allMatched = false;
+ setColor(pos, 1, attrError);
+ }
+ }
+ //System.out.println("highlight/blink " + c + " pos " + pos +
+ // " highlightLoc " + pane.highlightLoc +
+ // " blinkLoc " + pane.blinkLoc);
+ // there could be a race condition here, but failure
+ // is not critical -- this just blinks the closing paren
+ if (pane != null && pane.blinkLoc == pos && pane.blinkOn) {
+ setColor(pos, 1, attrBlink);
+ } else if (pane != null && pane.highlightLoc == pos) {
+ setColor(pos, 1, attrHighlight);
+ }
+ } else { // Word start
+ word = true;
+ wordStart = pos;
+ if (!normal) normalStart = pos;
+ normal = true;
+ if (c == '\\' && pos + 1 < docLength) {
+ pos++; // parse the quoted char
+ }
+ }
+ if (c == '\n') { // possibly store indentation info
+ //System.out.println(pos + " indentPos " + indentPos +
+ // " indent " + stack.indent);
+ if (pos == indentPos) {
+ indentBefore = lineIndent;
+ indentAfter = stack.indent;
+ }
+ lineIndent = stack.indent;
+
+ afterNewline = true;
+ if (TCDEBUG) {
+ System.out.println("at newline"); stack.print(); }
+ }
+ /*
+ System.out.print("At end of loop, pos ");
+ System.out.println(pos);
+ */
+ } // END FOR LOOP
+ //System.out.println("end parse loop");
+ if (normal) {
+ setColor(normalStart, pos - normalStart + 1, attrNormal);
+ } else if (comment) {
+ setColor(commentStart, pos - commentStart + 1, attrComment);
+ } else if (string) {
+ setColor(stringStart, pos - stringStart + 1, attrString);
+ }
+ // set error color to any unmatched tokens on stack:
+ if (!stack.pop(TOP)) allMatched = false;
+ } catch(Exception e ) {
+ System.out.println(e);
+ e.printStackTrace();
+ }
+ //System.out.println("salFormatVisible returns " + allMatched);
+ return allMatched;
+ }
+
+
+ public static boolean formatVisible(CodePane pane,
+ String docText, int docLength)
+ // start and end give the visible range over which we actually
+ // change the document.
+ {
+ boolean evenParens = false;
+
+ try {
+ //System.out.println(docText);
+
+ // To parse the file, we use a state machine with these states:
+ // comment -- in a comment started by ";"
+ // word -- in normal text, possibly a keyword
+ // hash -- we detected a hash mark (this state is implied)
+ // escape -- we detected a backslash (this state is implied)
+ // hashComment -- we're in a comment #| ... |#
+ // string -- in a string
+ // barSymbol -- in a symbol like |...|
+ // space -- in space between other tokens
+ // normal -- this state is orthogonal to the others.
+ // it records when we are accumulating a run of normal
+ // (black) characters. To make things run a little faster
+ // we don't color each black character individually but
+ // group them together into a run. It also helps at the end
+ // of the string to be able to color what's left.
+ boolean normal = false;
+ int normalStart = 0; // start of normal black characters
+ boolean comment = false;
+ int commentStart = 0;
+ boolean word = false;
+ int wordStart = 0;
+ boolean string = false;
+ int stringStart = 0;
+ boolean hashComment = false;
+ int hashCommentStart = 0;
+ boolean barSymbol = false;
+ int barSymbolStart = 0;
+ boolean space = false;
+ int spaceStart = 0;
+ int pos;
+ Stack<Integer> parenStack = new Stack<Integer>();
+ // originally, this code accumulated words in buf, but this
+ // caused many string allocations and ran very slowly, so now
+ // we just mark where the word begins and when the word ends
+ // we extract a string from docText
+
+
+ // process document text while you have not reached the end
+ // of the visible area and while there are unmatched parens
+ // (i.e. the parenStack isn't empty, but stop if you reach
+ // the end of the whole file.
+ //
+ //System.out.println("begin parse loop");
+ for (pos = 0; pos < docLength && (pos < end || !parenStack.empty());
+ pos++) {
+ char c = docText.charAt(pos);
+ if (comment) {
+ if (c == '\n') {
+ if (pos >= start) {
+ setColor(commentStart, pos - commentStart,
+ attrComment);
+ }
+ comment = false;
+ } // note that escape chars are ignored in comments
+ } else if (string) {
+ if (c == '"') {
+ if (pos >= start)
+ setColor(stringStart, pos - stringStart + 1,
+ attrString);
+ string = false;
+ } else if (c == '\\') { // skip the quoted char
+ pos++;
+ }
+ } else if (word) {
+ // see if the word ends because of a character or end of text
+ boolean terminated = (c == ' ' || c == '(' || c == ')' ||
+ c == '\n' || c == '"');
+ if (terminated || pos >= docLength - 1) {
+ word = false;
+ int stop = pos;
+ if (!terminated) stop++;
+ String buf = docText.substring(wordStart, stop);
+ // WordList.printList(buf); // to get words list.
+ if (WordList.isKeyword(buf)) {
+ setColor(normalStart, wordStart - normalStart,
+ attrNormal);
+ setColor(wordStart, pos - wordStart + 1,
+ attrBuiltin);
+ normal = true;
+ normalStart = pos + 1;
+ } else {
+ // continue normal (black) color
+ }
+ } else if (c == '\\') {
+ pos++; // skip the quoted char
+ }
+ if (terminated) pos = pos - 1; // reexamine character at pos
+ } else if (hashComment) {
+ if (c == '|' && pos + 1 < docLength &&
+ docText.charAt(pos + 1) == '#') {
+ pos++;
+ if (pos >= start) {
+ if (normal) {
+ setColor(normalStart,
+ hashCommentStart - normalStart,
+ attrNormal);
+ }
+ setColor(hashCommentStart,
+ pos - hashCommentStart + 1, attrComment);
+ }
+ normal = false;
+ hashComment = false;
+ } else if (c == '\\') pos++; // skip the quoted char
+ } else if (barSymbol) {
+ if (c == '|') {
+ if (pos >= start) {
+ if (normal) {
+ setColor(normalStart, wordStart - normalStart,
+ attrNormal);
+ }
+ normal = false;
+ setColor(wordStart, pos - wordStart, attrNormal);
+ }
+ } else if (c == '\\') pos++; // skip the quoted char
+ // Starts
+ } else if (c == ' ' || c == '\t' || c == '\n') {
+ space = true;
+ spaceStart = pos;
+ if (!normal) normalStart = pos;
+ normal = true;
+ } else if (c == ';') { // Comment Start
+ comment = true;
+ commentStart = pos;
+ space = false;
+ if (pos >= start && normal) {
+ setColor(normalStart, pos - normalStart, attrNormal);
+ }
+ normal = false;
+ } else if (c == '"') { // String start
+ string = true;
+ stringStart = pos;
+ space = false;
+ if (pos >= start && normal) {
+ setColor(normalStart, pos - normalStart, attrNormal);
+ }
+ normal = false;
+ } else if (c == '(' || c == ')') { // Paren start and end
+ space = false;
+ if (pos >= start && normal) {
+ setColor(normalStart, pos - normalStart, attrNormal);
+ }
+ normal = false;
+ if (pos >= start)
+ setColor(pos, 1, attrNormal);
+ if (c == '(' ) {
+ parenStack.push(new Integer(pos));
+ } else {
+ if (parenStack.empty()) {
+ if (pos >= start)
+ setColor(pos, 1, attrError);
+ } else {
+ // System.out.println("pop stack");
+ parenStack.pop();
+ }
+ }
+ //System.out.println("highlight/blink " + c + " pos " + pos +
+ // " highlightLoc " + pane.highlightLoc +
+ // " blinkLoc " + pane.blinkLoc);
+ // there could be a race condition here, but failure
+ // is not critical -- this just blinks the closing paren
+ if (pane != null && pane.blinkLoc == pos && pane.blinkOn) {
+ setColor(pos, 1, attrBlink);
+ } else if (pane != null && pane.highlightLoc == pos) {
+ setColor(pos, 1, attrHighlight);
+ }
+ } else if (c == '#') {
+ space = false;
+ if (pos >= start && normal) {
+ setColor(normalStart, pos - normalStart, attrNormal);
+ }
+ normal = true;
+ normalStart = pos;
+ if (pos + 1 < docLength) {
+ char c2 = docText.charAt(pos + 1);
+ if (c2 == '\'' || c2 == 'x' || c2 == 'o' || c2 == 'b' ||
+ c2 == ':') {
+ // ignore all these: #' #x #o #b #:
+ word = true;
+ wordStart = pos;
+ pos++;
+ } else if (c2 == '|') {
+ hashComment = true;
+ hashCommentStart = pos;
+ pos++;
+ normal = false;
+ } else {
+ word = true;
+ wordStart = pos;
+ }
+ }
+ } else { // Word start
+ word = true;
+ wordStart = pos;
+ if (!normal) normalStart = pos;
+ normal = true;
+ if (c == '\\' && pos + 1 < docLength) {
+ pos++; // parse the quoted char
+ }
+ }
+ /*
+ System.out.print("At end of loop, pos ");
+ System.out.println(pos);
+ */
+ } // END FOR LOOP
+ //System.out.println("end parse loop");
+ if (normal) {
+ setColor(normalStart, pos - normalStart + 1, attrNormal);
+ } else if (comment) {
+ setColor(commentStart, pos - commentStart + 1, attrComment);
+ } else if (hashComment) {
+ setColor(hashCommentStart, pos - hashCommentStart + 1,
+ attrComment);
+ } else if (string) {
+ setColor(stringStart, pos - stringStart + 1, attrString);
+ }
+
+ evenParens = parenStack.empty();
+ while( !parenStack.empty()) {
+ int parenPos = ((Integer)parenStack.pop()).intValue();
+ if (pos >= start)
+ setColor(parenPos, 1, attrError);
+ }
+ }
+ catch(Exception e ) { System.out.println(e); }
+
+ return evenParens;
+ }
+}
diff --git a/jnyqide/Trie.java b/jnyqide/Trie.java
new file mode 100644
index 0000000..7c76727
--- /dev/null
+++ b/jnyqide/Trie.java
@@ -0,0 +1,129 @@
+/*
+package jnyqide;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+public class Trie {
+ Node root;
+
+ /**
+ * Creates an WordMode object with the given dictionary.
+ *
+ * @param strs
+ * A list of strings containing the words in dictionary file which
+ * contains the list of valid words sorted by frequency
+ */
+/* public Trie()
+ {
+ root = new Node();
+ }
+
+ public void addWord(String word)
+ {
+ char[] letters = word.toCharArray();
+ Node n = root;
+ for(int i = 0; i < letters.length; i++)
+ {
+ if(n.get((int)letters[i]) == null)
+ {
+ Node x = n.addNode((int)letters[i]);
+ x.parent = n;
+ n = x;
+ }
+ else
+ n = n.get((int)letters[i]);
+ }
+ if(letters[letters.length-1] == ')')
+ word = "(" + word;
+ n.addWord(word);
+ while(n.parent != null)
+ {
+ n = n.parent;
+ n.addWord(word);
+ }
+ }
+
+ /* Since you are not allowed to use anything from java.util (except for the
+ * Iterator interface and AbstractList), you must create your own implementation
+ * of a list. (You may choose to extend AbstractList if you would like)
+ *
+ * If you would like to return an AbstractList,
+ * **Hint: What are the methods you need to implement in order to extend
+ * AbstractList? Also, in order for the AbstractList to function,
+ * what other methods must you override?
+ */
+ // if full, must match all letters
+/* public List getWordsFor(String s, Boolean full) {
+ char[] letters = s.toCharArray();
+ Node n = root;
+ for(int i = 0; i < letters.length; i++)
+ {
+ if(n.get((int)letters[i]) == null)
+ return (full ? null : n.unmodifiableList);
+ else
+ n = n.get((int)letters[i]);
+ }
+ return n.unmodifiableList;
+ }
+
+
+ public List getAllWordsFor(String s)
+ {
+ List r = new ArrayList<String>();
+ List l = getWordsFor("", false);
+ int i = 0;
+ while (i < l.size())
+ {
+ if (l.get(i).toString().contains(s)) {
+ r.add(l.get(i).toString());
+ }
+ i++;
+ }
+ return r;
+ }
+
+
+ private class Node {
+ Node parent;
+ Node nodes [] = new Node [128];
+ ArrayList <String> words = new ArrayList <String> ();
+ List unmodifiableList;
+
+ public Node()
+ {
+ parent = null;
+ unmodifiableList = Collections.unmodifiableList(new AbstractList() {
+ public int size() {
+ return words.size();
+ }
+
+ public String get(int i) {
+ return (String) words.get(i);
+ }
+ });
+ }
+
+ public Node get(int index)
+ {
+ return nodes[index];
+ }
+
+ public Node addNode(int i)
+ {
+ if(nodes[i] == null)
+ nodes[i] = new Node();
+ return nodes[i];
+ }
+
+ public void addWord(String str)
+ {
+ words.add(str);
+// System.out.println("( " + str + " ) is added to Trie");
+ }
+ }
+}
+*/ \ No newline at end of file
diff --git a/jnyqide/UPICFrame.java b/jnyqide/UPICFrame.java
new file mode 100644
index 0000000..5c93c67
--- /dev/null
+++ b/jnyqide/UPICFrame.java
@@ -0,0 +1,1425 @@
+// Code: Dmitry Portnoy, 5/1/09
+// Revised 2011 by Roger B. Dannenberg
+/*
+ Graphics organization:
+
+ mainframe -- the MainFrame
+ UPICFrame -- this editor, a JInternalFrame
+ mainPanel -- a JPanel
+ topPanel -- a JPanel
+ dataPanel -- a JPanel, border "Current Envelope"
+ varNameLabel -- a JLabel ("Name:")
+ varName -- a JTextField
+ waveformNameLabel -- a JLabel ("Waveform:")
+ waveformName -- a JComboBox
+ envNameLabel -- a JLabel("Envelope:")
+ envName -- a JComboBox
+ rangePanel - a JPanel, border "Range"
+ update - JButton("Update Range")
+ jMaxTL - a JLabel("Stop Time")
+ jMaxT - a JTextField
+ jMinAL - a JLabel("Min Freq")
+ jMinA - a JTextField
+ jMaxAL - a JLabel("Max Freq")
+ jMaxA - a JTextField
+ undoPanel - a JPanel, border "Undo/Redo"
+ undo - a JButton("Undo")
+ redo - a JButton("Redo")
+ canvas - a PiecewiseCanvas (a JPanel)
+
+if endpoints are specified, e.g. if times[0] is 0 or last value in times
+ matches the ending time, then use PWLV or PWEV version
+ Be careful not to drop first/last point unless the time matches the
+ begin/end time.
+
+
+ */
+
+/* Design notes by Dannenberg:
+
+Too much data to treat this like envelopes. Instead, load/save data a a file.
+Menu items: save, save as, revert, clear
+Use variable name box to give a variable name for the data.
+Use waveform name drop-down box to name waveforms.
+Use envelope name drop-down box to name envelopes.
+File format will be a waveform name, envelope name, and
+list of lists of alternating time value coordinates.
+File will have the format:
+------------
+;; data saved from NyquistIDE UPIC editor
+set data-name = {
+{ waveform envelope first list }
+{ waveform envelope second list }
+...
+}
+------------
+It's up to the user to interpret this data, but we'll add some
+functions to do this.
+
+*/
+
+package jnyqide;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import java.awt.image.*;
+import java.util.*;
+import java.text.*;
+import java.io.*;
+import javax.imageio.ImageIO;
+
+@SuppressWarnings("serial")
+public class UPICFrame extends JInternalFrame implements ActionListener {
+
+ double EPSILON = 0.00000001; // small number -- allow for rounding error
+ int LEFT_BORDER = 3; // inset everything by 3 pixels
+ int TOP_BORDER = 3;
+ int BOTTOM_BORDER = 5;
+ int RIGHT_BORDER = 5;
+ MainFrame mainframe;
+
+ private JPanel mainPanel;
+
+ private JTextPane jInputArea;
+ private PiecewiseCanvas canvas;
+
+ private JTextField jMaxT;
+ private double maxT;
+ private JTextField jMinHz;
+ private double minHz;
+ private JTextField jMaxHz;
+ private double maxHz;
+ private JCheckBox jLinear;
+ private boolean isLinear = true;
+ private JTextField varName;
+ private String currentVarName;
+ private JComboBox envName;
+ private String currentEnvName = "upic-env";
+ private JComboBox waveformName;
+ private String currentWaveformName = "*sine-table*";
+ private boolean showCs;
+ private boolean showGrandStaff;
+ private boolean showPicture;
+ // when saving envelopes, we copy current envelope to the collection,
+ // but this makes the combobox think that an envelope was selected,
+ // and we get a request to save the same envelope were saving. To
+ // avoid this, the "saving" flag is used to disable the check.
+ private boolean saving = false;
+ private File file; // the file backing the current data
+ private String name; // name of file
+
+ //hashtable for storing envelopes
+ private Hashtable<String, String> envColl;
+
+ static double initTime=0.0;
+ static double finalTime=1.0;
+ static boolean displayCoord = false;
+ static boolean valueType=false;
+ static DecimalFormat form = new DecimalFormat("#.###");
+ private boolean modified; // tells when any aspect of envelope
+ // has changed
+ // envelope is modified by: entering a point, deleting a point, changing
+ // the end-time (update), or clearing
+ // modified is reset when envelope is loaded or saved
+
+ private JButton MakeButton(String name, String cmd) {
+ JButton b = new JButton(name);
+ b.addActionListener(this);
+ b.setActionCommand(cmd);
+ return b;
+ }
+
+ private void AddMenuItem(JMenu menu, String name, String cmd, int code) {
+ AddMenuItem(menu, name, cmd, code, false, false);
+ }
+
+ private void AddMenuItem(JMenu menu, String name, String cmd, int code,
+ boolean shift) {
+ AddMenuItem(menu, name, cmd, code, shift, false);
+ }
+
+ private void AddMenuItem(JMenu menu, String name, String cmd,
+ int code, boolean shift, boolean check) {
+ int keyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+ JMenuItem item;
+ if (check) {
+ item = new JCheckBoxMenuItem(name);
+ } else {
+ item = new JMenuItem(name);
+ }
+ item.setActionCommand(cmd);
+ item.addActionListener(this);
+ if (code != -1) {
+ item.setAccelerator(KeyStroke.getKeyStroke(code, keyMask |
+ (shift ? java.awt.event.InputEvent.SHIFT_MASK : 0)));
+ }
+ menu.add(item);
+ }
+
+ private JComboBox MakeCombo(String cmd) {
+ JComboBox b = new JComboBox();
+ b.setPreferredSize(new Dimension(150, 20));
+ b.setEditable(true);
+ b.addActionListener(this);
+ b.setActionCommand(cmd);
+ return b;
+ }
+
+ // Constructor
+ public UPICFrame(final MainFrame parent, JTextPane inputArea) {
+ super();
+ mainframe = parent;
+ jInputArea = inputArea;
+ mainPanel = (JPanel) getContentPane();
+
+ envColl = new Hashtable<String, String>();
+ name = "UPIC Editor";
+ setTitle(name);
+ setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
+ final UPICFrame upicFrame = this;
+ modified = false;
+ addInternalFrameListener(
+ new InternalFrameListener() {
+ public void internalFrameClosing(InternalFrameEvent e) {
+ //System.out.println("FrameClosing");
+ int r = JOptionPane.OK_OPTION;
+ if (upicFrame.modified) {
+ r = JOptionPane.showConfirmDialog(upicFrame,
+ "Really close without saving?",
+ "Alert", JOptionPane.OK_CANCEL_OPTION);
+ }
+ if (r == JOptionPane.OK_OPTION) {
+ upicFrame.dispose();
+ }
+ }
+ public void internalFrameOpened(InternalFrameEvent e) {
+ }
+ public void internalFrameClosed(InternalFrameEvent e) {
+ parent.disconnectUPIC();
+ //System.out.println("FrameClosed");
+ }
+ public void internalFrameIconified(InternalFrameEvent e) {
+ }
+ public void internalFrameDeiconified(InternalFrameEvent e) {
+ }
+ public void internalFrameActivated(InternalFrameEvent e) {
+ }
+ public void internalFrameDeactivated(InternalFrameEvent e) {
+ }
+ }
+ );
+
+ System.out.println("EnvelopeFrame constructor 1");
+
+ JMenuBar menuBar = new JMenuBar();
+ // File Menu
+ JMenu fileMenu = new JMenu("File");
+ AddMenuItem(fileMenu, "Load", "loadUpicData",
+ java.awt.event.KeyEvent.VK_K);
+ AddMenuItem(fileMenu, "Open", "openUpicData",
+ java.awt.event.KeyEvent.VK_O);
+ AddMenuItem(fileMenu, "Save", "saveUpicData",
+ java.awt.event.KeyEvent.VK_S);
+ AddMenuItem(fileMenu, "Save As...", "saveUpicDataAs",
+ java.awt.event.KeyEvent.VK_S, true);
+ AddMenuItem(fileMenu, "Revert", "revertUpicData", -1);
+ AddMenuItem(fileMenu, "Clear", "clearUpicData", -1);
+
+ JMenu backgroundMenu = new JMenu("Background");
+ AddMenuItem(backgroundMenu, "C's", "showCs",
+ java.awt.event.KeyEvent.VK_C, false, true);
+ AddMenuItem(backgroundMenu, "Grand Staff", "showGrandStaff",
+ java.awt.event.KeyEvent.VK_G, false, true);
+ AddMenuItem(backgroundMenu, "Show Picture", "showPicture",
+ java.awt.event.KeyEvent.VK_V, false, true);
+ AddMenuItem(backgroundMenu, "Load Picture...", "loadPicture", -1);
+
+ menuBar.add(fileMenu);
+ menuBar.add(backgroundMenu);
+ setJMenuBar(menuBar);
+
+ JLabel varNameLabel = new JLabel("Name: ");
+ varName = new JTextField("upicdata", 10);
+ currentVarName = "upicdata";
+
+ JLabel waveformNameLabel = new JLabel("Waveform:");
+ waveformName = MakeCombo("waveformNameSelected");
+
+ JLabel envNameLabel = new JLabel("Envelope:");
+ envName = MakeCombo("envNameSelected");
+
+ JPanel dataPanel = new JPanel();
+ GridBagLayout layout0 = new GridBagLayout();
+ dataPanel.setLayout(layout0);
+ GridBagConstraints cons0 = new GridBagConstraints();
+
+ cons0.fill = GridBagConstraints.NONE;
+ cons0.anchor = GridBagConstraints.EAST;
+ cons0.insets = new Insets(2, 2, 2, 2); // TEST
+ cons0.weightx = 0;
+ cons0.weighty = 0;
+ cons0.gridy = 0;
+ cons0.gridx = 0;
+ cons0.gridheight = 1;
+ cons0.gridwidth = 1;
+ dataPanel.add(varNameLabel, cons0);
+ cons0.anchor = GridBagConstraints.WEST;
+ cons0.gridx = 1;
+ cons0.fill = GridBagConstraints.HORIZONTAL; //TEST
+ dataPanel.add(varName, cons0);
+ cons0.anchor = GridBagConstraints.EAST;
+ cons0.fill = GridBagConstraints.NONE;
+ cons0.gridy = 1;
+ cons0.gridx = 0;
+ dataPanel.add(waveformNameLabel, cons0);
+ cons0.anchor = GridBagConstraints.WEST;
+ cons0.gridx = 1;
+ dataPanel.add(waveformName, cons0);
+ cons0.gridy = 2;
+ cons0.gridx = 0;
+ dataPanel.add(envNameLabel, cons0);
+ cons0.anchor = GridBagConstraints.WEST;
+ cons0.gridx = 1;
+ dataPanel.add(envName, cons0);
+
+ // panel to contain time and amplitude parameters
+ JPanel rangePanel = new JPanel();
+ //JPanel paramPanel = new JPanel();
+ //paramPanel.setBorder(BorderFactory.createTitledBorder("Range"));
+ rangePanel.setLayout(new GridBagLayout());
+ rangePanel.setBorder(BorderFactory.createTitledBorder("Range")); //TEST
+ //paramPanel.setLayout(new GridBagLayout());
+
+ jMaxT = new JTextField("20.0", 5);
+ maxT = 20.0;
+ jMinHz = new JTextField("20.0", 5);
+ minHz = 20.0;
+ jMaxHz = new JTextField("2000.0", 5);
+ maxHz = 2000;
+ jLinear = new JCheckBox("linear", true);
+ showCs = false;
+ showGrandStaff = false;
+ showPicture = false;
+
+ JLabel jMaxTL = new JLabel("Stop Time: ");
+ JLabel jMinHzL = new JLabel("Min Freq: ");
+ JLabel jMaxHzL = new JLabel("Max Freq: ");
+
+ JButton update = new JButton("Update Range");
+ cons0.gridx = 0;
+ cons0.gridy = 0;
+ cons0.gridwidth = 2;
+ rangePanel.add(update, cons0);
+ cons0.gridwidth = 1;
+ cons0.gridx = 2;
+ cons0.gridy = 0;
+ rangePanel.add(jMaxTL, cons0);
+ cons0.gridx = 3;
+ cons0.gridy = 0;
+ rangePanel.add(jMaxT, cons0);
+ cons0.gridx = 0;
+ cons0.gridy = 1;
+ rangePanel.add(jMinHzL, cons0);
+ cons0.gridx = 2;
+ rangePanel.add(jMaxHzL, cons0);
+ cons0.gridx = 1;
+ rangePanel.add(jMinHz, cons0);
+ cons0.gridx = 3;
+ rangePanel.add(jMaxHz, cons0);
+ cons0.gridx = 4;
+ rangePanel.add(jLinear, cons0);
+
+ update.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (getMaxT() <= 0) {
+ JOptionPane.showMessageDialog(mainPanel,
+ "Stop Time cannot be negative or zero");
+ } else if (getMinHz() > getMaxHz()) {
+ JOptionPane.showMessageDialog(mainPanel,
+ "Minimum frequency cannot be greater than maximum frequency");
+ } else if ((canvas.endTime() > getMaxT())) {
+ JOptionPane.showMessageDialog(mainPanel,
+ "Stop Time is less than the time of an existing envelope point");
+ } else if (getMinHz() < 20.0) {
+ JOptionPane.showMessageDialog(mainPanel,
+ "Minimum frequency cannot be less than 20 Hz");
+ } else {
+ setModified();
+ maxT = getMaxT();
+ minHz = getMinHz();
+ maxHz = getMaxHz();
+ isLinear = getLinear();
+ canvas.history.save(canvas);
+ canvas.repaint();
+ return;
+ }
+ // an error occurred, reset the Range (using complete restore)
+ canvas.restore();
+ }
+ });
+
+ JPanel undoPanel = new JPanel();
+ undoPanel.setLayout(new GridBagLayout());
+ undoPanel.setBorder(BorderFactory.createTitledBorder("Undo/Redo"));
+ JButton undo = new JButton("Undo");
+ undo.setActionCommand("undo");
+ undo.addActionListener(this);
+ JButton redo = new JButton("Redo");
+ redo.setActionCommand("redo");
+ redo.addActionListener(this);
+ cons0.gridx = 0;
+ cons0.gridy = 0;
+ undoPanel.add(undo, cons0);
+ cons0.gridy = 1;
+ undoPanel.add(redo, cons0);
+
+ //insert components into the larger panels
+ cons0.fill = GridBagConstraints.NONE;
+ cons0.anchor = GridBagConstraints.WEST;
+ cons0.weightx = 0;
+ cons0.weighty = 0;
+ cons0.gridx = 0;
+ cons0.gridy = 0;
+ cons0.gridheight = 1;
+ cons0.gridwidth = 1;
+ //cons0.insets = new Insets(5,0,0,5);
+ //paramPanel.add(rangePanel, cons0);
+ // cons0.fill = GridBagConstraints.NONE;
+ // cons0.anchor = GridBagConstraints.CENTER;
+ // cons0.weightx = 0;
+ // cons0.weighty = 0;
+ // cons0.gridx = 0;
+ // cons0.gridy = 1;
+ // cons0.gridheight = 1;
+ // cons0.gridwidth = 1;
+ // //cons0.insets = new Insets(0,0,0,5);
+ // paramPanel.add(update, cons0);
+
+ JPanel topPanel = new JPanel();
+ //topPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 30, 0));
+ topPanel.setLayout(new GridBagLayout());
+ cons0.anchor = GridBagConstraints.NORTHWEST;
+ cons0.gridx = 0;
+ cons0.gridy = 0;
+ topPanel.add(dataPanel, cons0);
+ cons0.gridx = 1;
+ topPanel.add(rangePanel, cons0); //TEST
+ cons0.gridx = 2;
+ topPanel.add(undoPanel, cons0);
+
+ canvas = new PiecewiseCanvas();
+ //insert panels into main frame and display
+ mainPanel.add(BorderLayout.NORTH, topPanel);
+ mainPanel.add(BorderLayout.CENTER, canvas);
+ pack();
+
+ //resize and center the window
+ //Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+
+ setLocation(100, 100);
+ setSize(650, 580);
+ // setBackground(Color.white);
+ setResizable(true);
+ setVisible(true);
+ setClosable(true);
+ setMaximizable(true);
+ setIconifiable(true);
+ clearUpicData(true);
+ System.out.println("UPICFrame constructor 2 after setIconifiable");
+ repaint();
+ }
+
+ public boolean waveformNameSelected() {
+ String name = (String) waveformName.getSelectedItem();
+ if (name == null || name.equals("")) return false;
+ currentWaveformName = name;
+ return true;
+ }
+
+ public void waveformNewName() {
+ if (waveformNameSelected()) {
+ waveformName.addItem(currentWaveformName);
+ }
+ }
+
+ public boolean envNameSelected() {
+ String name = (String) envName.getSelectedItem();
+ if (name == null) return false;
+
+ String originalName = currentEnvName;
+ currentEnvName = name.trim();
+ if (!originalName.equals(currentEnvName)) {
+ modified = true;
+ }
+
+ // make name be the selected name
+ envName.setSelectedItem(name);
+ currentEnvName = name;
+ return true;
+ }
+
+
+ public void envNewName() {
+ if (envNameSelected()) {
+ envName.addItem(currentEnvName);
+ }
+ }
+
+
+ public void varNameSelected() {
+ if (saving) return; // ignore selection generated by "save" button
+ // If the name is different from the current envelope name, do
+ // a "save". Then switch to editing the newly selected envelope.
+ String name = (String) varName.getText();
+ // when we load the JComboBox with new names, the contentsChanged
+ // method of JComboBox invokes a selection action, even if nothing
+ // is selected. I don't know why, but we have to handle the null
+ // selection case.
+ if (name == null) return;
+
+ String originalName = currentVarName;
+ currentVarName = varName.getText().trim();
+ if (!originalName.equals(currentVarName)) {
+ modified = true;
+ }
+ varName.setText(name);
+ currentVarName = name;
+ }
+
+
+ //public double getMinT() { return Double.parseDouble(minT.getText().trim()); }
+ public double getMaxT() { return Double.parseDouble(jMaxT.getText().trim()); }
+ public double getMinHz() { return Double.parseDouble(jMinHz.getText().trim()); }
+ public double getMaxHz() { return Double.parseDouble(jMaxHz.getText().trim()); }
+ public boolean getLinear() { return jLinear.isSelected(); }
+
+ public boolean within(double x, double y, double eps) {
+ return Math.abs(x - y) < eps;
+ }
+
+
+ // prompt for a file name and write the data
+ public boolean saveUpicDataAs() {
+ // select a file and write to it. Return true if success.
+ JFileChooser chooser = new JFileChooser();
+ SalFileFilter salFilter = new SalFileFilter();
+ chooser.setFileFilter(salFilter);
+ File tmpfile;
+ String tmp;
+
+ File curdir = new File(mainframe.currentDir);
+ chooser.setCurrentDirectory(curdir);
+
+ while (true) { // loop until file is chosen
+ int returnVal = chooser.showSaveDialog(this);
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ tmpfile = chooser.getSelectedFile();
+ tmp = tmpfile.getName();
+ System.out.println("You chose to save this file: " + tmp);
+ tmp = tmp.toLowerCase();
+ if (tmp.endsWith(".sal")) break;
+ JOptionPane dialog = new JOptionPane();
+ System.out.println("creating dialog");
+ int result = dialog.showConfirmDialog(this,
+ "Do you really want to save a file without a " +
+ ".lsp or .sal extension?", "Warning",
+ JOptionPane.YES_NO_OPTION);
+ System.out.println("return from dialog " + result);
+ if (result == JOptionPane.YES_OPTION) break;
+ } else { // file chooser cancel, early return
+ return false;
+ }
+ }
+ name = tmp;
+ file = tmpfile;
+ mainframe.changeDirectory(mainframe.fileDirectory(file));
+ modified = true; // for saveUpicData, do not need to add "*"
+ return saveUpicData();
+ }
+
+
+ private void setModified() {
+ if (modified) return;
+ setTitle(name + "*");
+ modified = true;
+ }
+
+ public boolean saveUpicData()
+ // saves the file if there is a file name, otherwise calls saveAs.
+ // returns false if the operation fails or is cancelled.
+ // returns true if save succeeds or if file is unmodified.
+ {
+ if (modified) {
+ if (file == null)
+ return saveUpicDataAs();
+ else {
+ try {
+ FileWriter saveFileStream = new FileWriter(file);
+ BufferedWriter out = new BufferedWriter(saveFileStream);
+ String s = ";; data saved from NyquistIDE UPIC editor\n";
+ s += String.format(
+ ";!; maxT %g minHz %g maxHz %g linear %s\n",
+ maxT, minHz, maxHz, (isLinear ? "t" : "nil"));
+ s += String.format("set %s = {\n",
+ varName.getText().trim());
+ out.write(s);
+ for (Curve c : canvas.curves) {
+ if (c.times.size() > 0) {
+ out.write(String.format("{ %s %s\n",
+ c.waveform, c.envelope));
+ for (int i = 0; i < c.times.size(); i++) {
+ out.write(String.format(" %.4f %.1f",
+ c.times.get(i), c.freqs.get(i)));
+ }
+ out.write(" }\n\n");
+ }
+ }
+ out.write("}\n");
+ out.close();
+ }
+ catch(Exception e) {
+ System.out.println("exception in saveUpicData" + e);
+ return false; // did not save file
+ }
+
+ modified = false;
+ setTitle(name);
+ }
+ }
+ return true;
+ }
+
+
+ public void actionPerformed(ActionEvent e)
+ {
+ String cmd = e.getActionCommand();
+
+ // File Menu options
+ if (cmd.equals("saveUpicData")) saveUpicData();
+ else if (cmd.equals("loadUpicData")) {
+ saveUpicData();
+ mainframe.loadFile(file);
+ } else if (cmd.equals("saveUpicDataAs")) saveUpicDataAs();
+ else if (cmd.equals("openUpicData")) openUpicData();
+ else if (cmd.equals("clearUpicData")) clearUpicData(false);
+ else if (cmd.equals("envNameSelected")) envNameSelected();
+ else if (cmd.equals("waveformNameSelected")) waveformNameSelected();
+ else if (cmd.equals("showCs")) {
+ showCs = ((JCheckBoxMenuItem) e.getSource()).getState();
+ canvas.history.save(canvas);
+ canvas.repaint();
+ } else if (cmd.equals("showGrandStaff")) {
+ showGrandStaff = ((JCheckBoxMenuItem) e.getSource()).getState();
+ canvas.history.save(canvas);
+ canvas.repaint();
+ } else if (cmd.equals("showPicture")) {
+ showPicture = ((JCheckBoxMenuItem) e.getSource()).getState();
+ canvas.history.save(canvas);
+ canvas.repaint();
+ } else if (cmd.equals("loadPicture")) {
+ canvas.loadPicture();
+ canvas.repaint();
+ } else if (cmd.equals("undo")) {
+ canvas.history.undo();
+ canvas.restore();
+ } else if (cmd.equals("redo")) {
+ canvas.history.redo();
+ canvas.restore();
+ } else if (cmd.equals("comboBoxEdited")) {
+ if (e.getSource() == envName) envNewName();
+ else if (e.getSource() == waveformName) waveformNewName();
+ else System.out.println("COMBOBOXEDITED not handled\n");
+ } else System.out.println("ACTION NOT HANDLED: " + cmd);
+ }
+
+
+ public void clearUpicData(boolean init) {
+ canvas.clearUpicData(init);
+ waveformName.removeAllItems();
+ waveformName.addItem("*sine-table*");
+ waveformName.addItem("*tri-table*");
+ waveformName.addItem("*saw-table*");
+ waveformName.setSelectedItem("*sine-table*");
+
+ envName.removeAllItems();
+ envName.addItem("upic-env");
+ envName.setSelectedItem("upic-env");
+ }
+
+
+ public void addToComboBox(JComboBox cb, String s) {
+ int n = cb.getItemCount();
+ for (int i = 0; i < n; i++) {
+ if (s.equals(cb.getItemAt(i))) return;
+ }
+ cb.addItem(s);
+ }
+
+
+ public void readUpicData(File fileToOpen) {
+ clearUpicData(false);
+ name = fileToOpen.getName();
+ setTitle(name);
+ double maxt = 20, minhz = 0, maxhz = 2000;
+ boolean islinear = true;
+ // this disabled saving state for undo:
+ canvas.mouseDown = true;
+ try {
+ Scanner sc = new Scanner(fileToOpen);
+ String next = sc.next();
+ while (next.charAt(0) == ';') {
+ if (next.equals(";!;")) { // parse parameters
+ if (!sc.next().equals("maxT") )
+ throw new Exception("syntax - maxT");
+ maxt = Double.parseDouble(sc.next());
+ if (!sc.next().equals("minHz") )
+ throw new Exception("syntax - minHz");
+ minhz = Double.parseDouble(sc.next());
+ if (!sc.next().equals("maxHz") )
+ throw new Exception("syntax - maxHz");
+ maxhz = Double.parseDouble(sc.next());
+ if (!sc.next().equals("linear") )
+ throw new Exception("syntax - linear");
+ islinear = !sc.next().equals("nil");
+ if (maxt < 0 || minhz < 20.0 || maxhz < minhz) {
+ throw new Exception("bad maxt, minhz, maxhz");
+ }
+ }
+ sc.nextLine();
+ next = sc.next();
+ }
+ // next tokens are (s)et variable =
+ if (!next.equals("set")) throw new Exception("syntax - set");
+ currentVarName = sc.next();
+ varName.setText(currentVarName);
+ if (!sc.next().equals("=")) throw new Exception("syntax - =");
+ // now read the first {
+ if (!sc.next().equals("{")) throw new Exception("syntax - {");
+ // read lists
+ next = sc.next();
+ while (next.equals("{")) {
+ String waveform = sc.next();
+ addToComboBox(waveformName, waveform);
+ String envelope = sc.next();
+ addToComboBox(envName, envelope);
+ System.out.println("waveform " + waveform + " env " + envelope);
+ canvas.startNewCurve();
+ next = sc.next();
+ while (!next.equals("}")) {
+ // System.out.println("time " + next);
+ double time = Double.parseDouble(next);
+ double freq = Double.parseDouble(sc.next());
+ if (time < 0) time = 0;
+ canvas.insertInOrder(time, freq);
+ next = sc.next();
+ }
+ next = sc.next();
+ }
+ if (!next.equals("}")) {
+ throw new Exception("syntax");
+ }
+ // make sure whole thing fits on canvas
+ maxT = Math.max(canvas.endTime(), maxt);
+ minHz = Math.min(canvas.lowHz(), minhz);
+ maxHz = Math.max(canvas.highHz(), maxhz);
+ isLinear = islinear;
+
+ jMaxT.setText(String.valueOf(maxT));
+ jMinHz.setText(String.valueOf(minHz));
+ jMaxHz.setText(String.valueOf(maxHz));
+ jLinear.setSelected(isLinear);
+ } catch (Exception e) {
+ System.out.println("readUpicData " + e);
+ JOptionPane.showMessageDialog(this,
+"A problem was encountered reading a upic data file, data may have been lost");
+ }
+ canvas.mouseDown = false;
+ }
+
+
+ public void openUpicData() {
+ JFileChooser chooser = new JFileChooser();
+ SalFileFilter salFilter = new SalFileFilter();
+ chooser.addChoosableFileFilter(salFilter);
+ File curdir = new File(mainframe.currentDir);
+ chooser.setCurrentDirectory(curdir);
+ int returnVal = chooser.showOpenDialog(this);
+ System.out.println("openUpicData chooser returns " + returnVal);
+ file = null; // in case open fails
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ file = chooser.getSelectedFile();
+ mainframe.changeDirectory(mainframe.fileDirectory(file));
+ System.out.println("reading from " + file);
+ readUpicData(file);
+ modified = false;
+ }
+ }
+
+ /* data = data.toLowerCase();
+ //System.out.println("openUpicData: data |" + data + "| len " + data.length());
+ envName.removeAllItems(); // clear and reload combo box
+ while (data.length() > 0) {
+ int eolx = data.indexOf("\n");
+ if (eolx < 0) return; // shouldn't happen, but bail if it does
+ String line = data.substring(0, eolx);
+ //System.out.println("openUpicData: line " + line);
+ data = data.substring(eolx + 1);
+ String name = line.substring(0, line.indexOf(' '));
+ System.out.println("openUpicData: name " + name);
+ String env = line.substring(name.length() + 1);
+ System.out.println("openUpicData: env " + env);
+ if (name.length() > 0) envColl.put(name, env);
+ envName.addItem(name);
+ } */
+
+ private class State {
+ public double maxT;
+ public double minHz;
+ public double maxHz;
+ public boolean linear;
+ public boolean cs;
+ public boolean gs;
+ public boolean picture;
+
+ public State(double stop, double low, double hi, boolean lin,
+ boolean showcs, boolean showgs, boolean showpic) {
+ maxT = stop; minHz = low; maxHz = hi; linear = lin;
+ cs = showcs; gs = showgs; picture = showpic;
+ }
+ }
+
+ private class History {
+ /* consider a sequence of undo/redo to be a single edit operation -- thus
+ * the end of the versions list is set to the latest undo/redo selection
+ */
+ private boolean undoRedo = false;
+ private ArrayList<ArrayList<Curve>> history =
+ new ArrayList<ArrayList<Curve>>();
+ private ArrayList<State> state_history = new ArrayList<State>();
+ private int version = -1;
+
+ @SuppressWarnings("unchecked")
+ public void save(PiecewiseCanvas canvas) {
+ history.add((ArrayList<Curve>) canvas.curves.clone());
+ state_history.add(new State(maxT, minHz, maxHz, isLinear,
+ showCs, showGrandStaff, showPicture));
+ version = history.size() - 1;
+ System.out.println("Saved version " + version);
+ undoRedo = false; /* clear flag for next undoRedo sequence */
+ }
+
+ public boolean canGet() {
+ boolean result = version >= 0 && version < history.size();
+ System.out.println("canGet returns " + result + " version " +
+ version);
+ return result;
+ }
+
+ public ArrayList<Curve> getCurves() { return history.get(version); }
+
+ public State getState() { return state_history.get(version); }
+
+ @SuppressWarnings("unchecked")
+ private void processUndoRedo() {
+ if (!undoRedo) { /* extend with copy of the version */
+ history.add((ArrayList<Curve>) (history.get(version).clone()));
+ state_history.add(state_history.get(version));
+ } else { /* replace with different version */
+ history.set(history.size() - 1,
+ (ArrayList<Curve>) (history.get(version).clone()));
+ state_history.set(state_history.size() - 1,
+ state_history.get(version));
+ }
+ undoRedo = true;
+ }
+
+ public void undo() {
+ if (version > 0) {
+ version--;
+ processUndoRedo();
+ }
+ }
+ public void redo() {
+ if (version < history.size() - 1) {
+ version++;
+ processUndoRedo();
+ }
+ }
+ }
+
+ private class Curve {
+ public String waveform;
+ public String envelope;
+ public ArrayList<Double> times;
+ public ArrayList<Double> freqs;
+
+ public Curve(String wave, String env) {
+ waveform = wave;
+ envelope = env;
+ times = new ArrayList<Double>();
+ freqs = new ArrayList<Double>();
+ }
+ }
+
+ // Class for the drawing area
+ //private class PiecewiseCanvas extends Canvas implements MouseListener,
+ private class PiecewiseCanvas extends JPanel implements MouseListener,
+ MouseMotionListener, KeyListener {
+ private int currentHz;
+ private int currentTime;
+ public BufferedImage image = null;
+ public boolean selectCheck = false;
+ public int selection;
+ public History history;
+
+ public boolean mouseDown = false; // used to detect version for undo
+ private boolean changed = false; // used to detect version for undo
+
+ // Vectors to store the absolute parameters of the points in the
+ // envelope.
+ public ArrayList<Curve> curves = new ArrayList<Curve>();
+ public int selectedCurve;
+ private int left, top, width, height;
+
+ private BufferedImage background;
+
+ // Constructor
+ public PiecewiseCanvas() {
+ setBackground(Color.white);
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ addKeyListener(this);
+ selection = -1;
+ history = new History();
+ history.save(this);
+ selectedCurve = -1;
+ background = null;
+ }
+
+
+ public void loadPicture() {
+ JFileChooser chooser = new JFileChooser();
+ File curdir = new File(mainframe.currentDir);
+ chooser.setCurrentDirectory(curdir);
+ int returnVal = chooser.showOpenDialog(this);
+ File file = null; // in case open fails
+ if (returnVal == JFileChooser.APPROVE_OPTION) {
+ file = chooser.getSelectedFile();
+ mainframe.changeDirectory(mainframe.fileDirectory(file));
+ System.out.println("reading image from " + file);
+ try {
+ background = ImageIO.read(file);
+ } catch (Exception e) {
+ System.out.println("Image read failed " + e);
+ JOptionPane.showMessageDialog(this,
+ "Could not open image file");
+ background = null;
+ }
+ }
+ }
+
+
+ public double endTime() {
+ double m = 0;
+ for (Curve c : curves) {
+ for (double time : c.times) {
+ m = Math.max(m, time);
+ }
+ }
+ return m;
+ }
+
+ public double lowHz() {
+ double low = 20000;
+ for (Curve c : curves) {
+ for (double hz : c.freqs) {
+ low = Math.min(low, hz);
+ }
+ }
+ return low;
+ }
+
+ public double highHz() {
+ double high = 0;
+ for (Curve c : curves) {
+ for (double hz : c.freqs) {
+ high = Math.max(high, hz);
+ }
+ }
+ return high;
+ }
+
+
+ // erase the canvas and clear the parameter vectors -
+ // completely reset the envelope
+ public void clearUpicData(boolean init) {
+ curves.clear();
+ if (!init) setModified();
+ repaint();
+ history.save(this);
+ }
+
+
+ // Allow JPanel to accept keyboard events
+ public boolean isFocusable() {
+ return true;
+ }
+
+ //try to make the canvas the correct size
+ public Dimension getMinimumSize() {
+ return new Dimension(0, 0);
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(575, 256);
+ }
+
+ public double impliedAmp() {
+ return 0.0;
+ }
+
+
+ /*
+ public Dimension getMaximumSize() {
+ return getPreferredSize();
+ }*/
+
+ // draw the graphics inside the full canvas, so use these
+ // functions to get the size and coordinates of the drawing
+ // area that is usable
+ private int graphLeft() { return LEFT_BORDER; }
+ private int graphWidth() {
+ return getWidth() - (LEFT_BORDER + RIGHT_BORDER);
+ }
+ private int graphTop() { return TOP_BORDER; }
+ private int graphHeight() {
+ return getHeight() - (TOP_BORDER + BOTTOM_BORDER);
+ }
+ private int clipX(int x) {
+ return Math.max(LEFT_BORDER, Math.min(left + width, x)); }
+ private int clipY(int y) {
+ return Math.max(BOTTOM_BORDER, Math.min(top + height, y)); }
+
+ // public String getExpression() {
+ // String env;
+ //
+ // /*if (type == PWL_TYPE) env = (valueType ? "pwlv" : "pwl");
+ // else env = (valueType ? "pwev" : "pwe");*/
+ //
+ // env = "pwlv";
+ //
+ // return outputEnv(env, true, 0.0, // getMinT(),
+ // getMaxT(), getMinHz(), getMaxHz());
+ // }
+
+ //draw the canvas image
+ public void paint(Graphics g) {
+ super.paint(g);
+
+ Graphics2D drawArea = (Graphics2D) g;
+ if (showCs) { // draw line for C in all octaves
+ double hz = 16.3516;
+ while (hz < maxHz) {
+ drawPitch(drawArea, hz);
+ hz *= 2;
+ }
+ }
+
+ if (showPicture && (background != null)) {
+ drawArea.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ int x = time2x(0);
+ int y = hz2y(maxHz);
+ int w = time2x(maxT) - x;
+ int h = hz2y(minHz) - y;
+ drawArea.drawImage(background, x, y, w, h, null);
+ }
+
+ if (showGrandStaff) { // draw GrandStaff lines
+ drawPitch(drawArea, 698.456); // top line F
+ drawPitch(drawArea, 587.330); // D
+ drawPitch(drawArea, 493.883); // B
+ drawPitch(drawArea, 391.995); // G
+ drawPitch(drawArea, 329.628); // E
+
+ drawPitch(drawArea, 220.000); // A
+ drawPitch(drawArea, 174.614); // F
+ drawPitch(drawArea, 146.832); // D
+ drawPitch(drawArea, 123.471); // B
+ drawPitch(drawArea, 97.9989); // G
+ }
+
+ connectTheDots(drawArea);
+ drawArea.dispose();
+ }
+
+ private void drawPitch(Graphics2D g, double hz) {
+ g.setColor(Color.lightGray);
+ int y = hz2y(hz);
+ g.drawLine(time2x(0), y, time2x(maxT), y);
+ }
+
+ private void draw_connect(Graphics2D g, double t1, double a1,
+ double t2, double a2) {
+ int x1 = time2x(t1);
+ int x2 = time2x(t2);
+ int y1 = hz2y(a1);
+ int y2 = hz2y(a2);
+
+ g.drawLine(x1, y1, x2, y2);
+ }
+
+ private void cacheSize() {
+ left = graphLeft();
+ top = graphTop();
+ width = graphWidth() - 1;
+ height = graphHeight() - 1;
+ }
+
+ //connect adjacent points in the envelope by lines
+ private void connectTheDots(Graphics2D g) {
+ cacheSize();
+ for (int j = 0; j < curves.size(); j++) {
+ g.setColor(selectedCurve == j ? Color.red : Color.blue);
+ Curve c = curves.get(j);
+ if (c.times.size() > 0) {
+ //connect the points in the envelope
+ double t1 = c.times.get(0);
+ double a1 = c.freqs.get(0);
+
+ for (int i = 1; i < c.times.size(); i++) {
+ double t2 = c.times.get(i);
+ double a2 = c.freqs.get(i);
+ draw_connect(g, t1, a1, t2, a2);
+ t1 = t2;
+ a1 = a2;
+ }
+ }
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public void restore() {
+ if (history.canGet()) {
+ curves = (ArrayList<Curve>) (history.getCurves().clone());
+ State state = history.getState();
+ maxT = state.maxT;
+ jMaxT.setText(String.valueOf(state.maxT));
+ minHz = state.minHz;
+ jMinHz.setText(String.valueOf(state.minHz));
+ maxHz = state.maxHz;
+ jMaxHz.setText(String.valueOf(state.maxHz));
+ isLinear = state.linear;
+ jLinear.setSelected(state.linear);
+ showCs = state.cs;
+ showGrandStaff = state.gs;
+ showPicture = state.picture;
+ selection = -1;
+ repaint();
+ }
+ }
+
+ //set time and amplitude on click by inserting the point into the vectors.
+ public void mousePressed(MouseEvent e) {
+ requestFocus();
+ cacheSize();
+ // check for curve selection
+ if (e.getButton() == MouseEvent.BUTTON3) {
+ for (int x = 0; x < curves.size(); x++) {
+ Curve c = curves.get(x);
+ for (int y = 0; y < c.times.size(); y++) {
+ if (Math.abs(time2x(c.times.get(y)) - e.getX()) <= 8 &&
+ Math.abs(hz2y(c.freqs.get(y)) - e.getY()) <= 8) {
+ selectedCurve = x;
+ repaint();
+ System.out.println("Selected curve " + x);
+ System.out.println("e.getX(): " + e.getX()+
+ ", e.getY: " + e.getY());
+ System.out.println("c.times.get(y): " +
+ c.times.get(y) +
+ ", c.freqs.get(y): " +
+ c.freqs.get(y));
+ return;
+ }
+ }
+ }
+
+ selectedCurve = -1;
+ repaint();
+ System.out.println("No curve selected");
+ return;
+ }
+
+ // not button3, so start a new curve
+ startNewCurve();
+ mouseDown = true;
+ System.out.println("mouseDown true\n");
+ this.requestFocus();
+ currentTime = e.getX();
+ currentHz = e.getY();
+ insertInOrder(x2time(currentTime), y2hz(currentHz));
+ repaint();
+ }
+
+
+ public void mouseDragged(MouseEvent e) {
+ // if this is not the left button drawing event, return
+ if (!mouseDown) return;
+ currentTime = clipX(e.getX());
+ currentHz = clipY(e.getY());
+
+ if (currentTime <= left + width && currentTime >= left &&
+ currentHz >= top && currentHz <= top + height) {
+
+ insertInOrder(x2time(currentTime), y2hz(currentHz));
+ repaint();
+ }
+ }
+
+
+ public void startNewCurve() {
+ curves.add(new Curve((String) waveformName.getSelectedItem(),
+ (String) envName.getSelectedItem()));
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ requestFocus(); // otherwise, delete key may not work
+ if (e.getButton() != MouseEvent.BUTTON1)
+ return;
+ if (changed) {
+ history.save(this);
+ changed = false;
+ }
+ mouseDown = false;
+ }
+
+
+ // convert time coordinate to time in seconds
+ private double x2time(int x) {
+ return (x - left) * maxT / width;
+ }
+
+ private int time2x(double time) {
+ return (int) Math.round(time * width / maxT) + left;
+ }
+
+ // convert amp coordinate to real amplitude
+ private double y2hz(int y) {
+ double mx, mn, r;
+ if (isLinear) {
+ mx = maxHz;
+ mn = minHz;
+ r = mx - mn;
+ return mx - ((y - top) * r / height);
+ }
+ mx = Math.log(maxHz);
+ mn = Math.log(minHz);
+ r = mx - mn;
+ return Math.exp(mx - ((y - top) * r / height));
+ }
+
+ private int hz2y(double hz) {
+ double mx, mn;
+ if (isLinear) {
+ mx = maxHz;
+ mn = minHz;
+ } else {
+ mx = Math.log(maxHz);
+ mn = Math.log(minHz);
+ hz = Math.log(hz);
+ }
+ double r = mx - mn;
+ return (int) Math.round((mx - hz) * height / r) + top;
+ }
+
+ private void addPoint(int i, double absT, double absA) {
+ addPoint(curves.size() - 1, i, absT, absA);
+ }
+
+ private void addPoint(int curve, int i, double absT, double absA) {
+ //System.out.println("addPoint: " + i + " " + absT + " " + absA);
+ Curve c = curves.get(curve);
+ c.times.add(i, absT);
+ c.freqs.add(i, Math.max(absA, 0.0));
+ //System.out.println("addPoint time: " + absT + ", text " + form.format(absT));
+ selection = i;
+ changed = true;
+ setModified();
+ }
+
+
+ //insert the time and amplitude in the vectors in time sorted order
+ private void insertInOrder(double time, double amp) {
+ Curve c = curves.get(curves.size() - 1);
+ int i = c.times.size();
+ while (i > 0 && time < c.times.get(i - 1)) {
+ i--;
+ }
+ addPoint(i, time, amp);
+ }
+
+
+ // Check if mouse click corresponds to existing envelope point
+ // return index of point or -1 if no point is close
+ // private int getSelection(int x, int y) {
+ // int cutoff = 7;
+ // int bestDist = cutoff * 2;
+ // int bestIndex = -1;
+ // if (times == null) return bestIndex;
+ // for (int i = 0; i < times.get(curCurve).size(); i++) {
+ // int xi = time2x(times.get(curCurve).get(i));
+ // int yi = hz2y(freqs.get(curCurve).get(i));
+ // int dx = Math.abs(x - xi);
+ // int dy = Math.abs(y - yi);
+ // if (dx < cutoff && dy < cutoff && dx + dy < bestDist) {
+ // bestDist = dx + dy;
+ // bestIndex = i;
+ // }
+ // }
+ // selection = bestIndex;
+ // return bestIndex;
+ // }
+
+ //Check if mouse click corresponds with existing envelope point (to select point)
+ // private boolean checkSelection(int time, int amp) {
+ // int i = getSelection(time, amp);
+ // if (i < 0) return false;
+ // repaint();
+ // return true;
+ // }
+
+ //output the envelope as a string
+ // public String outputEnv(String envType, boolean valueType, double minTime, double maxTime, double minHertz, double maxHertz) {
+ // String outputStr = "(sim";
+ //
+ // for (int j = 0; j < times.size() - 1; j++) {
+ // int start = 0;
+ // outputStr += " (osc-tri (" + envType;
+ //
+ // if (valueType) { // insert initial value
+ // if (within(times.get(j).get(0), 0.0, EPSILON)) {
+ // outputStr += " " + form.format(freqs.get(j).get(0));
+ // start = 1;
+ // } else
+ // outputStr += " " + form.format(impliedAmp());
+ // }
+ //
+ // for (int i = start; i < freqs.get(j).size(); i++) {
+ // double time = times.get(j).get(i);
+ // double amp = freqs.get(j).get(i);
+ //
+ // if (time == 1)
+ // break;
+ //
+ // outputStr += " " + form.format(time) + " " + form.format(amp);
+ // }
+ //
+ // if (valueType) { // we're already ending with a value
+ // if (within(times.get(j).lastElement(), maxTime, EPSILON)) {
+ // // we're done because we output at maxTime
+ // } else
+ // outputStr += " " + form.format(maxTime) + " " + form.format(impliedAmp());
+ // } else
+ // outputStr += " " + form.format(maxTime);
+ //
+ // outputStr += "))";
+ // }
+ // outputStr += ")";
+ // return outputStr;
+ // }
+
+ // parse envelope from string and prepare to edit
+ // public void setEnv(String envData) {
+ //
+ // System.out.println("\nCALLED setEnv\n");
+ //
+ // // System.out.println("setEnv: envData " + envData.substring(0, 100) + " ... " + envData.substring(envData.length()-5));
+ // if (envData == null) return; // just in case
+ // //check if envelope exists in collection
+ // //boolean nameIsEnv = false;
+ //
+ // // trim the open and close parens from envData
+ // int startx = envData.indexOf("(") + 5;
+ // // if no open paren, startx will be 0
+ // int endx = envData.lastIndexOf(")");
+ // if (endx < 0) endx = envData.length();
+ // envData = envData.substring(startx, endx);
+ //
+ // int x = 0;
+ // while (envData.indexOf("(") > -1) {
+ // String strCurve = envData.substring(envData.indexOf("(")+10, envData.indexOf(")"));
+ // envData = envData.substring(envData.indexOf(")")+2);
+ //
+ // StringTokenizer st = new StringTokenizer(strCurve);
+ // String type = st.nextToken();
+ // System.out.println("setEnv: type " + type);
+ //
+ // valueType = type.endsWith("v");
+ //
+ // if (times.size() <= x) {
+ // times.add(new Vector<Double>());
+ // freqs.add(new Vector<Double>());
+ // }
+ //
+ // times.get(x).removeAllElements();
+ // freqs.get(x).removeAllElements();
+ // int i = 0;
+ // // pretend mouse is down to avoid making each point undo-able
+ // boolean save = mouseDown;
+ // mouseDown = false;
+ // double time, amp;
+ // if (valueType) { // first element is value
+ // amp = new Double(st.nextToken().trim());
+ // addPoint(x, i++, 0.0, amp);
+ // }
+ // while (st.countTokens() >= 2) {
+ // String token1 = st.nextToken().trim();
+ // time = new Double(token1);
+ // String token2 = st.nextToken().trim();
+ // amp = new Double(token2);
+ // addPoint(x, i++, time, amp);
+ // /*System.out.println("time " + token1 + " amp " + token2 +
+ // " size " + times.get(x).size());*/
+ // }
+ //
+ // mouseDown = save; // restore the mouseDown state
+ // if (!valueType) { // last element is time
+ // maxT.setText(st.nextToken());
+ // }
+ //
+ // x++;
+ // }
+ //
+ // times.add(new Vector<Double>());
+ // freqs.add(new Vector<Double>());
+ // curCurve = x;
+ // System.out.println("curCurve: " + curCurve);
+ //
+ // modified = false;
+ // repaint();
+ // }
+
+
+ public void keyPressed(KeyEvent event) {
+ System.out.println("key event detected");
+ if (event.getKeyCode() == KeyEvent.VK_DELETE) {
+ curves.remove(selectedCurve);
+ selectedCurve = -1;
+ canvas.history.save(canvas);
+ System.out.println("curve should be deleted");
+ repaint();
+ }
+ }
+
+ //fill rest of mouse functions
+ public void mouseEntered(MouseEvent e) {}
+ public void mouseExited(MouseEvent e) {}
+ public void mouseClicked(MouseEvent e) {}
+ public void mouseMoved(MouseEvent e) {}
+ public void keyReleased(KeyEvent event) {}
+ public void keyTyped(KeyEvent event) {}
+ }
+}
diff --git a/jnyqide/WordList.java b/jnyqide/WordList.java
new file mode 100644
index 0000000..758476f
--- /dev/null
+++ b/jnyqide/WordList.java
@@ -0,0 +1,247 @@
+package jnyqide;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.ArrayList;
+
+
+import javax.swing.JTextArea;
+import javax.swing.JTextPane;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultStyledDocument;
+
+public class WordList {
+ //public static Trie wordsTrie = new Trie();
+ public static JTextArea textArea;
+ public static JTextPane pane;
+ public static int startPos;
+ public static int endPos;
+ public static Map<String, String> URLLinks = new HashMap<String, String>();
+ public static ArrayList<String> words = new ArrayList<String> ();
+
+ public static String getlink(String word) {
+ // strip off syntax help from word, e.g. (osc-tri hz) -> osc
+ System.out.println("getlink " + word);
+ if (word.charAt(0) == '(') {
+ int i = word.indexOf(" ");
+ if (i <= 0) i = word.length() - 1; // remove ")"
+ word = word.substring(1, i);
+ } else /* maybe SAL mode */ {
+ int i = word.indexOf("(");
+ if (i > 0) word = word.substring(0, i);
+ }
+ String s = URLLinks.get(word);
+ System.out.println("getlink(" + word + ")->" + s);
+ if (s == null) return "home.html";
+ return s;
+ }
+
+ public static void init(JTextArea a)
+ {
+ textArea = a;
+ //System.out.println("initializing WordList.java");
+ try {
+ BufferedReader inf;
+ try {
+ inf = new BufferedReader(new FileReader("NyquistWords.txt"));
+ System.out.println("\n\n***********************Opened NyquistWords.txt*********\n\n");
+ } catch (IOException e) {
+ System.out.println("could not find NyquistWords.txt, trying jnyqide/NyquistWords.txt");
+ inf = new BufferedReader(new FileReader("jnyqide/NyquistWords.txt"));
+ }
+ String word, link;
+ while ((word = inf.readLine()) != null) {
+ //wordsTrie.addWord(word);
+ words.add(word);
+ link = inf.readLine();
+ if ((link == null) || (link.equals(""))) link = "home.html";
+ //char[] letters = word.toCharArray();
+ //if (letters[letters.length-1] == ')') word = "(" + word;
+ //URLLinks.put(word, link);
+ // word is usually an expression, e.g.
+ // "transpose-abs amount beh)", so parse out the first word
+ int i = word.indexOf(" ");
+ if (i >= 0) word = word.substring(0, i);
+ i = word.indexOf(")");
+ if (i >= 0) word = word.substring(0, i);
+ URLLinks.put(word, link);
+ }
+ inf.close();
+ } catch (IOException e) {
+ System.out.println("Error: could not open NyquistWords.txt");
+ }
+ }
+
+ public static String removeChar(String word, char c) {
+ int loc = word.indexOf(c);
+ while (loc >= 0) {
+ word = word.substring(0, loc) + word.substring(loc + 1);
+ loc = word.indexOf(c);
+ }
+ return word;
+ }
+
+ public static void appendSyntaxTip(StringBuffer s, String word, boolean sal) {
+ // let's keep the brackets until we copy the hint string into an editor
+ // first, remove brackets
+ // word = removeChar(removeChar(word, '['), ']');
+ // if this is a lisp expression, append close paren
+ if (word.charAt(word.length() - 1) == ')') {
+ if (sal) {
+ // make it prefix with commas
+ int loc = word.indexOf(' '); // end of function name
+ int loc2 = loc + 1; // trim the space
+ if (loc < 0) {
+ loc = word.indexOf(')');
+ loc2 = loc; // don't trim the ')'
+ }
+ if (loc < 0) {
+ System.out.println("appendSyntaxTip internal error: |" +
+ word + "|");
+ return;
+ }
+ // now loc is the character after the function name and
+ // loc2 is the character to place after the open paren
+ word = word.substring(0, loc) + "(" + word.substring(loc2);
+ // insert commas after tokens starting after open paren
+ loc = loc + 1;
+ while (loc < word.length()) {
+ // advance to token
+ while (loc < word.length() &&
+ (word.charAt(loc) == ' ' ||
+ word.charAt(loc) == '[' ||
+ word.charAt(loc) == ']')) loc++;
+ // retain starting location for keyword processing
+ loc2 = loc;
+ // advance to end of word
+ while (loc < word.length() &&
+ word.charAt(loc) != ' ' &&
+ word.charAt(loc) != '[' &&
+ word.charAt(loc) != ']') loc++;
+ // convert to keyword or maybe add comma
+ if (loc < word.length()) {
+ if (word.charAt(loc2) == ':') {
+ word = word.substring(0, loc2) + // before keyword
+ word.substring(loc2 + 1, loc) + // after ':'
+ ":" + word.substring(loc);
+ // insert comma if this is not the last parameter,
+ // determined by looking ahead for a space
+ } else if (word.indexOf(' ', loc) > 0) {
+ word = word.substring(0, loc) + "," +
+ word.substring(loc);
+ loc = loc + 1; // skip the comma
+ }
+ }
+ // System.out.println("word |" + word + "| loc " + loc);
+ }
+ } else {
+ s.append("(");
+ }
+ }
+ s.append(word);
+ s.append("\n");
+ }
+
+
+ public static void getAllWordsFor(String str, StringBuffer s, boolean sal) {
+ for (int i = 0; i < words.size(); i++) {
+ String word = (String) words.get(i);
+ int pos = word.indexOf(str);
+ if (pos >= 0) {
+ int sp = word.indexOf(" ");
+ if (sp < 0 || sp > pos) {
+ appendSyntaxTip(s, word, sal);
+ }
+ }
+ }
+ }
+
+
+ public static boolean isKeyword(String str) {
+ String s = URLLinks.get(str);
+ return s != null;
+ /*
+ str = str.toLowerCase();
+ for (int i = 0; i < words.size(); i++) {
+ String word = (String) words.get(i);
+ int pos = word.indexOf(str);
+ if (pos == 0 &&
+ (word.length() == str.length() ||
+ (word.charAt(str.length() - 1) == ' ' ||
+ word.charAt(str.length() - 1) == ')'))) {
+ return true;
+ }
+ }
+ return false;
+ */
+ }
+
+
+ public static void getWordsFor(String str, StringBuffer s, boolean sal) {
+ for (int i = 0; i < words.size(); i++) {
+ String word = (String) words.get(i);
+ int pos = word.indexOf(str);
+ if (pos == 0) {
+ appendSyntaxTip(s, word, sal);
+ }
+ }
+ }
+
+
+ public static void printList(String str, JTextPane jTextPane,
+ int start, int end, boolean forceExact, boolean sal) {
+
+ //List l;
+ //System.out.println("printList: prefFullSearch = " + MainFrame.prefFullSearch);
+ //if (MainFrame.prefFullSearch) l = wordsTrie.getAllWordsFor(str.toLowerCase());
+ //else l = wordsTrie.getWordsFor(str.toLowerCase(), false);
+ //System.out.println(l);
+ //StringBuffer s = new StringBuffer();
+ //if (l != null) {
+ // Iterator iter = l.iterator();
+ // while (iter.hasNext()) {
+ // s.append(iter.next()).append("\n");
+ // }
+ //}
+ StringBuffer s = new StringBuffer();
+ str = str.toLowerCase();
+ if (MainFrame.prefFullSearch && !forceExact) getAllWordsFor(str, s, sal);
+ else getWordsFor(str, s, sal);
+ textArea.setText(s.toString());
+ pane = jTextPane;
+ startPos = start;
+ endPos = end; // haven't inserted character yet
+ }
+
+
+ public static void replaceWithTemplate(String template) {
+ // templates were displayed in textArea based on what the user
+ // typed. Now, the user has clicked on a template. Replace what
+ // the user typed (and parens) with the template string.
+ String before;
+ try {
+ before = pane.getText(startPos - 1, 1);
+ if (before.equals("(")) startPos--;
+ } catch (Exception ex) {
+ }
+ String after;
+ try {
+ after = pane.getText(endPos, 1);
+ while (Character.isWhitespace(after.charAt(0))) {
+ endPos++;
+ after = pane.getText(endPos, 1);
+ }
+ if (after.equals(")")) endPos++;
+ } catch (Exception ex) {
+ }
+ pane.select(startPos, endPos);
+ // remove those pesky brackets (denoting "optional")
+ template = removeChar(removeChar(template, '['), ']');
+ pane.replaceSelection(template);
+ }
+}
diff --git a/jnyqide/browser.java b/jnyqide/browser.java
new file mode 100644
index 0000000..2db6cb0
--- /dev/null
+++ b/jnyqide/browser.java
@@ -0,0 +1,439 @@
+package jnyqide;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.ArrayList;
+
+import javax.swing.BorderFactory;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JInternalFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSlider;
+import javax.swing.JTextArea;
+import javax.swing.ListModel;
+import javax.swing.border.Border;
+import javax.swing.border.EtchedBorder;
+import javax.swing.SpringLayout;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.ChangeEvent;
+
+
+/***
+** Class: Browser
+** Author: Priyanka Raghavan and Roger B. Dannenberg
+** Description: This is the frame class that implements the sound browser.
+**/
+
+class Browser extends JInternalFrame {
+
+ NyquistThread nyquistThread;
+ MainFrame mainFrame;
+ ArrayList instruments;
+ InstrumentCharacteristics currentInstr;
+
+ /**
+ * @ desc Default constructor, takes the nyquist thread from main frame
+ * @author prirags - removed all references to the log factory
+ */
+
+ public Browser(MainFrame mainFrame, NyquistThread nyquistThread) {
+ this.mainFrame = mainFrame;
+ this.nyquistThread=nyquistThread;
+ instruments = new ArrayList();
+ currentInstr = null;
+ try {
+ System.out.println("in Browser()");
+ initGUI();
+ setLocation(50+10, 50+10);
+ setSize(600, 500);
+ setResizable(true);
+ setVisible(true);
+ setClosable(true);
+ setMaximizable(true);
+ setIconifiable(true);
+ // setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
+ System.out.println("at end of Browser()");
+ }
+ catch (Exception exception) {
+ exception.printStackTrace();
+ }
+ }
+
+ /**
+ * @ desc intializes gui elements
+ * @author prirags - removed all references to the log factory
+ */
+
+ private void initGUI() {
+ setTitle("Sound Browser");
+ this.setSize(800, 513);
+ jPanel1 = new JPanel(new SpringLayout());
+ Border etchedLine;
+ etchedLine = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
+ this.getContentPane().add(jPanel1, BorderLayout.NORTH);
+ jPanel1.setBorder(etchedLine);
+ // jPanel1.setPreferredSize(new java.awt.Dimension(638, 101));
+ categoryLabel = new JLabel();
+ jPanel1.add(categoryLabel);
+ categoryLabel.setText("Sound Category:");
+ ComboBoxModel categoryComboModel = new DefaultComboBoxModel();
+ categoryCombo = new JComboBox();
+ categoryCombo.addItemListener(
+ new ItemListener() {
+ public void itemStateChanged(ItemEvent evt) {
+ if (evt.getStateChange() != evt.SELECTED) return;
+ if (subcategoryCombo == null) return; // just in case
+ // set up subcategory
+ subcategoryCombo.removeAllItems();
+ subcategoryCombo.addItem("Select One");
+ String category = (String) evt.getItem();
+ System.out.println("category is " + category);
+ for (int i = 0; i < instruments.size(); i++) {
+ if (((InstrumentCharacteristics) instruments.get(i)).
+ getCategoryName().equalsIgnoreCase(category)) {
+ subcategoryCombo.addItem(
+ ((InstrumentCharacteristics) instruments.
+ get(i)).getSubcategoryName());
+ }
+ }
+ }
+ });
+ jPanel1.add(categoryCombo);
+ categoryCombo.setModel(categoryComboModel);
+ // categoryCombo.setPreferredSize(new java.awt.Dimension(306, 25));
+ subcategoryLabel = new JLabel();
+ jPanel1.add(subcategoryLabel);
+ subcategoryLabel.setText("Sound Name:");
+ ComboBoxModel subcategoryComboModel = new DefaultComboBoxModel();
+ subcategoryCombo = new JComboBox();
+ subcategoryCombo.addItemListener(
+ new ItemListener() {
+ public void itemStateChanged(ItemEvent evt) {
+ for (int i = 0; i < instruments.size(); i++) {
+ InstrumentCharacteristics ic =
+ (InstrumentCharacteristics) instruments.get(i);
+ String name = (String) evt.getItem();
+ if (ic.getSubcategoryName().equalsIgnoreCase(name)) {
+ currentInstr = ic;
+ visitSound();
+ }
+ }
+ }
+ });
+ jPanel1.add(subcategoryCombo);
+ subcategoryCombo.setModel(subcategoryComboModel);
+ // subcategoryCombo.setPreferredSize(new java.awt.Dimension(304, 28));
+ SpringUtilities.makeCompactGrid(jPanel1, 2, 2, 6, 6, 6, 6);
+
+
+ jPanel3 = new JPanel(new SpringLayout());
+ this.getContentPane().add(jPanel3, BorderLayout.CENTER);
+ etchedLine = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
+ jPanel3.setBorder(etchedLine);
+ // jPanel3.setPreferredSize(new java.awt.Dimension(638, 148));
+
+ BorderLayout bl = new BorderLayout();
+ bl.setHgap(6);
+ bl.setVgap(6);
+ jPanel2 = new JPanel(bl);
+ this.getContentPane().add(jPanel2, BorderLayout.SOUTH);
+ etchedLine = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
+ jPanel2.setBorder(etchedLine);
+ // jPanel2.setPreferredSize(new java.awt.Dimension(791, 159));
+
+ playButton = new JButton();
+ playButton.setText("PLAY");
+ // playButton.setPreferredSize(new java.awt.Dimension(100, 36));
+ // playButton.setBounds(4, -5, 100, 36);
+ playButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ playSound();
+ }
+
+ });
+
+ // try this:
+ // (west: (north: play button))
+ // center: (north:
+ // (center: "Lisp Expression that produced the sound")
+ // center: scrolling text))
+ bl = new BorderLayout();
+ bl.setHgap(6);
+ bl.setVgap(6);
+ JPanel jPanel2a = new JPanel(bl);
+ jPanel2.add(jPanel2a, BorderLayout.WEST);
+ jPanel2a.add(playButton, BorderLayout.NORTH);
+ bl = new BorderLayout();
+ bl.setHgap(6);
+ bl.setVgap(6);
+ JPanel jPanel2b = new JPanel(bl);
+ jPanel2.add(jPanel2b, BorderLayout.CENTER);
+ bl = new BorderLayout();
+ bl.setHgap(6);
+ bl.setVgap(6);
+ JPanel jPanel2b1 = new JPanel(bl);
+ jPanel2b.add(jPanel2b1, BorderLayout.NORTH);
+ JLabel label = new JLabel("Lisp Expression that produced the sound:");
+ label.setHorizontalAlignment(label.CENTER);
+ jPanel2b1.add(label, BorderLayout.CENTER);
+ jScrollPane1 = new JScrollPane();
+ expArea = new JTextArea();
+ jScrollPane1.setViewportView(expArea);
+
+ // expArea.setPreferredSize(new java.awt.Dimension(650, 60));
+
+ jPanel2b.add(jScrollPane1, BorderLayout.CENTER);
+ jScrollPane1.setPreferredSize(new java.awt.Dimension(700, 62));
+ // SpringUtilities.makeCompactGrid(jPanel2, 2, 2, 6, 6, 6, 6);
+
+ categoryCombo.addItem("Select One");
+
+ // read the instrument.txt text file from lib
+ // and create the InstrumentCharacteristic objects.
+ //
+ BufferedReader br;
+ try {
+ br = new BufferedReader(
+ new FileReader(nyquistThread.soundBrowser));
+ } catch (Exception e) {
+ System.out.println("ERROR -- could not open " +
+ nyquistThread.soundBrowser);
+ return;
+ }
+ while (true) {
+ InstrumentCharacteristics ic =
+ new InstrumentCharacteristics();
+ if (!ic.readData(br)) break;
+ System.out.println("new IC: " + ic.getCategoryName() + ":" +
+ ic.getSubcategoryName());
+ instruments.add(ic);
+ boolean foundIt = false;
+ for (int k = 0; k < categoryCombo.getItemCount(); k++) {
+ if (categoryCombo.getItemAt(k).toString().
+ equalsIgnoreCase(ic.getCategoryName())) {
+ foundIt = true;
+ break;
+ }
+ } //end of for
+ if (!foundIt) {
+ System.out.println("Added " + ic.getCategoryName());
+ categoryCombo.addItem(ic.getCategoryName());
+ }
+ }
+ }
+
+ private JPanel jPanel1;
+ private JComboBox subcategoryCombo;
+ private JLabel subcategoryLabel;
+ private JLabel categoryLabel;
+ private JComboBox categoryCombo;
+
+ private JScrollPane jScrollPane1;
+
+ private JPanel jPanel3;
+ private JTextArea expArea;
+ private JButton playButton;
+
+ private JPanel jPanel2;
+ private JLabel[] paramLabels = null;
+ private JSlider[] paramSliders = null;
+
+ public void newParameterCount(int n) {
+ // make array for new labels and sliders
+ JLabel[] newParamLabels = paramLabels;
+ JSlider[] newParamSliders = paramSliders;
+ int oldN = 0;
+ if (paramLabels != null) {
+ oldN = paramLabels.length;
+ }
+ if (n > oldN) {
+ newParamLabels = new JLabel[n];
+ newParamSliders = new JSlider[n];
+ }
+ // make old labels and sliders invisible before reuse
+ if (paramLabels != null) {
+ // paramLabel0.setVisible(false);
+ for (int i = 0; i < oldN; i++) {
+ paramLabels[i].setVisible(false);
+ newParamLabels[i] = paramLabels[i];
+
+ paramSliders[i].setVisible(false);
+ newParamSliders[i] = paramSliders[i];
+ }
+ } else {
+ // paramLabel0 = new JLabel();
+ // paramLabel0.setText("SLIDERS");
+ // jPanel3.add(paramLabel0);
+ }
+ // if we don't have enough, make more
+ if (n > oldN) {
+ for (int i = oldN; i < n; i++) {
+ newParamLabels[i] = new JLabel();
+ jPanel3.add(newParamLabels[i]);
+ newParamSliders[i] = new JSlider();
+ jPanel3.add(newParamSliders[i]);
+ }
+ paramLabels = newParamLabels;
+ paramSliders = newParamSliders;
+ }
+ SpringUtilities.makeCompactGrid(jPanel3, n, 2, 6, 6, 6, 6);
+
+ // now we have n labels and sliders in arrays
+ // we also have paramLabel0
+ }
+
+
+ public void visitSound() {
+ System.out.println("visitSound called: " +
+ currentInstr.getSubcategoryName());
+ /*
+ * This hides the labels and the sliders that could have
+ * been created in previous runs
+ */
+ int numParams = currentInstr.getParameters().size();
+ newParameterCount(numParams);
+ System.out.println("visitSound: numParams " + numParams);
+
+ for(int i = 0; i < numParams; i++) {
+ Parameter p = (Parameter) (currentInstr.getParameters().get(i));
+ paramLabels[i].setText(p.getName().toUpperCase());
+ System.out.println("Parameter" + p.getName());
+ paramLabels[i].setVisible(true);
+ if (p.getType().equals("int")) {
+ final JSlider s = paramSliders[i];
+ int max = Integer.parseInt(p.getMaxValue());
+ s.setMaximum(max);
+ int min = Integer.parseInt(p.getMinValue());
+ s.setMinimum(min);
+ int range = max - min;
+ int major = 1;
+ while (major < range) major *= 10;
+ s.setMajorTickSpacing(major / 10);
+ s.setMinorTickSpacing(major / 100);
+ System.out.println("major " + major);
+ s.setPaintTicks(true);
+ s.setPaintLabels(true);
+ s.setValue(Integer.parseInt(p.getDefaultValue()));
+ } else if (p.getType().equals("float")) {
+ final float min = Float.valueOf(p.getMinValue()).floatValue();
+ final float max = Float.valueOf(p.getMaxValue()).floatValue();
+ final float width = max - min;
+ final Parameter param = p;
+ final JSlider s = paramSliders[i];
+ float fval = Float.valueOf(p.getDefaultValue()).floatValue();
+ param.setValue(fval);
+ s.setMinimum(0);
+ s.setMaximum(1000);
+ s.setValue((int) ((fval - min) / width * 1000));
+ java.util.Hashtable labels = new java.util.Hashtable(3);
+ labels.put(new Integer(0), new JLabel(p.getMinValue()));
+ labels.put(new Integer(500),
+ new JLabel(new Float((max + min) / 2.0f).
+ toString()));
+ labels.put(new Integer(1000), new JLabel(p.getMaxValue()));
+ s.setLabelTable(labels);
+ s.setPaintTicks(false);
+ s.setPaintLabels(true);
+ // s.setBorder(new TitledBorder("border text"));
+ s.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent e) {
+ int j = s.getValue();
+ float f = min + (j * width / 1000.0f);
+ param.setValue(f);
+ }
+ });
+ } else {
+ System.out.println("Expected int or float in " +
+ i + " |" + p.getType() + "|");
+ }
+
+ if (numParams > 1) {
+ paramSliders[i].setOrientation(JSlider.HORIZONTAL);
+ } else {
+ paramSliders[i].setOrientation(JSlider.HORIZONTAL);
+ }
+ paramSliders[i].setVisible(true);
+ }
+ }
+
+
+ public void playSound() {
+ boolean isSal = mainFrame.jScrollPane.isSal;
+ /* debugging
+ System.out.println("isSal: " + isSal + "\n" +
+ currentInstr.getFunctionName() + "\nSal: " +
+ currentInstr.getSalImplementation() + "\nLisp: " +
+ currentInstr.getLispImplementation() + "\nReq: " +
+ currentInstr.getRequire());
+ end debugging */
+ String cmd = (isSal ? "play " : "(play (") +
+ currentInstr.getFunctionName();
+ String sep = (isSal ? ", " : " ");
+ if (isSal) cmd = cmd + "(";
+ boolean first = isSal;
+ for (int i = 0; i < currentInstr.getParameters().size(); i++) {
+ Parameter p = (Parameter) currentInstr.getParameters().get(i);
+ // is this a keyword parameter? If so, put it in
+ if (p.getName().charAt(0) == ':') {
+ if (!first) cmd = cmd + sep;
+ cmd = cmd + p.getName();
+ first = false;
+ }
+ String actual;
+ if (p.getType().equals("int")) {
+ actual = new Integer(paramSliders[i].getValue()).toString();
+ } else if (p.getType().equals("float")) {
+ actual = new Float(p.getValue()).toString();
+ } else {
+ actual = "";
+ System.out.println("bad parameter type");
+ }
+ if (!first) cmd = cmd + sep;
+ first = false;
+ cmd = cmd + actual;
+ }
+ if (!isSal) cmd = cmd + ")"; // to match (play
+ cmd = cmd + ")\n";
+ String impl = (isSal ? currentInstr.getSalImplementation() :
+ currentInstr.getLispImplementation());
+ if (impl == null && currentInstr.getRequire() != null) {
+ impl = currentInstr.getRequire();
+ if (isSal) {
+ impl = "if ! fboundp(quote(" + currentInstr.getFunctionName() +
+ ")) then load " + impl + "\n";
+ } else {
+ impl = "(if (not (fboundp '" + currentInstr.getFunctionName() +
+ ")) (load " + impl + "))\n";
+ }
+ }
+ if (impl != null) {
+ if (isSal) { // for SAL, need one command
+ cmd = "begin\n " + impl + " " + cmd + "end\n";
+ } else {
+ cmd = impl + cmd; // lisp can take sequence of commands
+ }
+ }
+ cmd = cmd + "\n"; // need extra newline to cause parser to run
+ expArea.setText(cmd);
+ mainFrame.sendInput(cmd);
+ }
+}
+
diff --git a/jnyqide/closeFile.gif b/jnyqide/closeFile.gif
new file mode 100644
index 0000000..29f5fee
--- /dev/null
+++ b/jnyqide/closeFile.gif
Binary files differ
diff --git a/jnyqide/help.gif b/jnyqide/help.gif
new file mode 100644
index 0000000..7311814
--- /dev/null
+++ b/jnyqide/help.gif
Binary files differ
diff --git a/jnyqide/keywords.txt b/jnyqide/keywords.txt
new file mode 100644
index 0000000..2f36731
--- /dev/null
+++ b/jnyqide/keywords.txt
@@ -0,0 +1,512 @@
+abs
+abs-env
+address-of
+and
+alloc
+alpass
+allpass2
+amosc
+append
+apply
+aref
+areson
+arrayp
+assoc
+at
+atom
+at-abs
+atone
+autonorm-off
+autonorm-on
+backquote
+baktrace
+bandpass2
+biquad
+biquad-m
+block
+both-case-p
+boundp
+break
+build-harmonic
+buzz
+car
+catch
+cdr
+caar
+cadr
+cdar
+cddr
+caaar
+caadr
+cadar
+caddr
+cdaar
+cdadr
+cddar
+cdddr
+case
+cerror
+char
+code-char
+char-code
+char-upcase
+char-downcase
+char-int
+char<
+char<=
+char=
+char/=
+char>
+char-lessp
+char-not-greaterp
+char-equalp
+char-not-equalp
+char-not-lessp
+char-greaterp
+characterp
+clean-up
+clip
+close
+comb
+cond
+const
+cons
+consp
+congen
+const
+continue
+continuous-control-warp
+continuous-sound-warp
+control
+control-srate-abs
+control-warp
+convolve
+cos
+cue
+cue-file
+db-to-linear
+defmacro
+defun
+delete
+delete-if
+delete-if-not
+diff
+digit-char
+digit-char-p
+display
+do
+do*
+dolist
+dotimes
+do
+dribble
+endp
+env
+errset
+eq
+eq-band
+eq-highshelf
+eq-lowshelf
+eql
+equal
+error
+eval
+evalhook
+evenp
+exit
+exp
+expand
+expt
+exp-dec
+extract
+extract-abs
+fboundp
+feedback-delay
+first
+flatc
+flatsize
+flet
+float
+floatp
+fmosc
+fmlfo
+force-srate
+format
+fourth
+funcall
+function
+gc
+gcd
+gensym
+get
+get-duration
+get-lambda-expression
+get-loud
+get-output-stream-list
+get-sustain
+get-transpose
+get-warp
+go
+hash
+highpass2
+highpass4
+highpass6
+highpass8
+hp
+hz-to-step
+hzosc
+if
+int-char
+integerp
+integrate
+intern
+labels
+lambda
+last
+length
+let
+let*
+lfo
+linear-to-db
+list
+listp
+load
+local-to-global
+log
+logand
+logior
+lognot
+logxor
+loop
+loud
+loud-abs
+lower-case-p
+lowpass2
+lowpass4
+lowpass6
+lowpass8
+lp
+macroexpand
+macroexpand-1
+macrolet
+maketable
+make-array
+make-string-input-stream
+make-string-output-stream
+make-symbol
+mapc
+mapcar
+mapl
+maplist
+max
+member
+min
+minusp
+mult
+nconc
+noise
+not
+notch2
+nstring-upcase
+nstring-downcase
+nth
+nthcdr
+null
+numberp
+objectp
+oddp
+open
+open-binary
+or
+osc
+osc-note
+osc-pulse
+osc-saw
+osc-tri
+pan
+partial
+peak
+peek
+peek-char
+play
+play-file
+pluck
+plusp
+poke
+print
+prin1
+princ
+pprint
+prod
+profile
+prog
+prog*
+progv
+progl
+prog2
+progn
+psetq
+push
+putprop
+pwe
+pwe-list
+pwer
+pwer-list
+pwev
+pwev-list
+pwevr
+pwevr-list
+pwl
+pwl-list
+pwlr
+pwlr-list
+pwlv
+pwlv-list
+pwlvr
+pwlvr-list
+quantize
+quote
+ramp
+random
+read
+read-byte
+read-char
+read-int
+read-float
+read-line
+recip
+return
+return-from
+rplaca
+rplacd
+ref
+resample
+reson
+rest
+rem
+remove
+remove-if
+remove-if-not
+remprop
+restore
+reverse
+rms
+room
+s-abs
+s-add-to
+s-exp
+s-log
+s-max
+s-min
+s-overwrite
+s-plot
+s-print-tree
+s-read
+s-rest
+s-save
+s-sqrt
+sampler
+save
+scale
+scale-db
+scale-srate
+second
+send
+seq
+seq-create
+seq-get
+seq-next
+seq-reset
+seqrep
+set
+set-control-srate
+set-logical-stop
+set-pitch-names
+set-sound-srate
+setdir
+setf
+setq
+setup-console
+sf-info
+shape
+shift-time
+sim
+simrep
+sin
+sine
+siosc
+slope
+snd-abs
+snd-add
+snd-alpass
+snd-alpasscv
+snd-alpassvv
+snd-amosc
+snd-areson
+snd-aresoncv
+snd-aresonvc
+snd-aresonvv
+snd-atone
+snd-atonev
+snd-avg
+snd-biquad
+snd-buzz
+snd-chase
+snd-clip
+snd-compose
+snd-congen
+snd-const
+snd-convolve
+snd-copy
+snd-coterm
+snd-delay
+snd-delaycv
+snd-down
+snd-exp
+snd-extent
+snd-fetch
+snd-fetch-array
+snd-fft
+snd-flatten
+snd-fmosc
+snd-follow
+snd-from-array
+snd-fromarraystream
+snd-fromobject
+snd-gate
+snd-ifft
+snd-inverse
+snd-length
+snd-log
+snd-max
+snd-maxv
+snd-maxsamp
+snd-multiseq
+snd-normalize
+snd-osc
+snd-overwrite
+snd-partial
+snd-play
+snd-pluck
+snd-print
+snd-print-tree
+snd-prod
+snd-pwl
+snd-quantize
+snd-read
+snd-recip
+snd-resample
+snd-resamplev
+snd-reson
+snd-resoncv
+snd-resonvc
+snd-resonvv
+snd-samples
+snd-save
+snd-scale
+snd-seq
+snd-set-logical-stop
+snd-shape
+snd-sine
+snd-siosc
+snd-sqrt
+snd-srate
+snd-sref
+snd-stop-time
+snd-tapv
+snd-time
+snd-tone
+snd-tonev
+snd-t0
+snd-up
+snd-white
+snd-xform
+snd-zero
+sort
+sound
+sound-off
+sound-on
+sound-srate-abs
+sound-warp
+sound-srate-abs
+soundfilename
+soundp
+sublis
+subst
+sum
+sqrt
+sref
+sref-inverse
+stats
+step-to-hz
+streamp
+strcat
+stretch
+stretch-abs
+string
+string-search
+string-trim
+string-left-trim
+string-lessp
+string-not-greaterp
+string-equalp
+string-not-equalp
+string-not-lessp
+string-greaterp
+string-right-trim
+string-upcase
+string-downcase
+stringp
+string<
+string<=
+string/=
+string>=
+string>
+subseq
+sustain
+sustain-abs
+synbol-function
+symbol-name
+symbol-plist
+symbol-value
+symbolp
+system
+tagbody
+tan
+terpri
+third
+throw
+timed-seq
+type-of
+tone
+top-level
+trace
+transpose
+transpose-abs
+truncate
+unless
+untrace
+unwind-protect
+upper-case-p
+vector
+warp
+warp-abs
+when
+while
+write-byte
+write-char
+write-int
+write-float
+zerop
+1+
+1-
+/
++
+-
+*
+=
+<
+>
+<=
+>=
+/=
diff --git a/jnyqide/manifest.txt b/jnyqide/manifest.txt
new file mode 100644
index 0000000..5f6b076
--- /dev/null
+++ b/jnyqide/manifest.txt
@@ -0,0 +1 @@
+Main-Class: jnyqide/Main
diff --git a/jnyqide/openFile.gif b/jnyqide/openFile.gif
new file mode 100644
index 0000000..4a7553f
--- /dev/null
+++ b/jnyqide/openFile.gif
Binary files differ