summaryrefslogtreecommitdiff
path: root/support/meper
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/meper
Initial commit
Diffstat (limited to 'support/meper')
-rw-r--r--support/meper/README28
-rw-r--r--support/meper/src/EditorFilter.java261
-rw-r--r--support/meper/src/MEPer.java362
-rw-r--r--support/meper/src/README28
4 files changed, 679 insertions, 0 deletions
diff --git a/support/meper/README b/support/meper/README
new file mode 100644
index 0000000000..f0b956915f
--- /dev/null
+++ b/support/meper/README
@@ -0,0 +1,28 @@
+Usage
+ MEPer is a java program. To start the program, use
+ java -jar MEper.jar
+
+ A directory named "MetaPostPreviewer" will be created in the user's home
+ directory. The following files (and temporary files) will be created in this
+ directory:
+ - preview.mp, the MetaPost source file.
+ - preview.eps, the output of the MetaPost;
+ - preview.png, converted from the eps file.
+
+ The jar file and source files can be downloaed from
+ http://www.cse.ucsd.edu/~s1pan/MEPer.
+
+System requirement
+ The following tools are needed to run MEPer:
+ - the latest release of the Sun Java SE platform
+ - MetaPost
+ - ImageMagick, or ghostscript
+
+License and Disclaimer
+ MEPer is free software under the GPL (Gnu General Public License). It is free
+ to use but WITHOUT ANY WARRANTY. If you modify or redistribute it, please
+ include the orginal author's name or a link to the MEPer web page.
+
+Copyright 2009, Shengjun Pan
+
+
diff --git a/support/meper/src/EditorFilter.java b/support/meper/src/EditorFilter.java
new file mode 100644
index 0000000000..86febab96d
--- /dev/null
+++ b/support/meper/src/EditorFilter.java
@@ -0,0 +1,261 @@
+/* EditorFilter.java
+ * This file is part of source files of MEPer.
+ * It defines the behaviors of the editor.
+ *
+ * @author Shengjun Pan
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import java.util.*;
+import javax.swing.undo.*;
+
+public class EditorFilter extends DocumentFilter {
+
+ String[] keywords ={"beginfig","endfig","for","draw","drawarrow","endfor",
+ "def", "vardef", "enddef","if", "fi", "withcolor","fill",
+ "shifted", "scaled", "rotated", "withpen"};
+ String[] datatypes = {"picture","numeric","path","pair","transform","color",
+ "string", "boolean", "pen"};
+
+ int fontSize = 14;
+ HashMap<String,SimpleAttributeSet> tokenToAset;
+ JTextPane editor;
+ JButton saveButton;
+
+ public EditorFilter(JTextPane ed, JButton sb) {
+
+ editor = ed;
+ saveButton = sb;
+
+ tokenToAset = new HashMap<String,SimpleAttributeSet>();
+
+ SimpleAttributeSet aset= new SimpleAttributeSet();
+ StyleConstants.setForeground(aset, Color.BLUE);
+ StyleConstants.setBold(aset, true);
+ StyleConstants.setFontSize(aset,fontSize);
+ tokenToAset.put("keyword", aset);
+
+ aset= new SimpleAttributeSet();
+ StyleConstants.setForeground(aset, Color.GREEN);
+ StyleConstants.setBold(aset, true);
+ StyleConstants.setFontSize(aset,fontSize);
+ tokenToAset.put("digits", aset);
+
+ aset= new SimpleAttributeSet();
+ StyleConstants.setForeground(aset, Color.BLACK);
+ StyleConstants.setBold(aset, false);
+ StyleConstants.setFontSize(aset,fontSize);
+ tokenToAset.put("normal", aset);
+
+ aset= new SimpleAttributeSet();
+ StyleConstants.setForeground(aset, Color.GREEN);
+ StyleConstants.setBold(aset, true);
+ StyleConstants.setFontSize(aset,fontSize);
+ tokenToAset.put("datatype", aset);
+
+ aset= new SimpleAttributeSet();
+ StyleConstants.setForeground(aset, Color.MAGENTA);
+ StyleConstants.setBold(aset, true);
+ StyleConstants.setFontSize(aset,fontSize);
+ tokenToAset.put("quoted", aset);
+
+ //editor.addKeyListener(this);
+ editor.setFont(new Font(Font.MONOSPACED,Font.PLAIN,fontSize));
+
+ // enable undo/redo
+ final UndoManager undoManager = new UndoManager();
+ editor.getDocument().addUndoableEditListener(undoManager);
+ editor.getInputMap().put(KeyStroke.getKeyStroke("ctrl Z"), "undo");
+ editor.getActionMap().put("undo", new AbstractAction() {
+ public void actionPerformed(ActionEvent evt) {
+ try { undoManager.undo();}
+ catch (Throwable t) {Toolkit.getDefaultToolkit().beep();}
+ }});
+ editor.getInputMap().put(KeyStroke.getKeyStroke("ctrl R"), "redo");
+ editor.getActionMap().put("redo", new AbstractAction() {
+ public void actionPerformed(ActionEvent evt) {
+ try { undoManager.redo();}
+ catch (Throwable t) {Toolkit.getDefaultToolkit().beep();}
+ }});
+
+ }
+
+ @Override
+ public void insertString(FilterBypass fb, int offs,
+ String str, AttributeSet a)
+ throws BadLocationException {
+ saveButton.setEnabled(true);
+ highlightAndInsert(fb, offs, str);
+ }
+
+ @Override
+ public void replace(DocumentFilter.FilterBypass fb, int offs, int len,
+ String str, AttributeSet a) throws BadLocationException {
+ saveButton.setEnabled(true);
+ super.remove(fb, offs, len);
+ highlightAndInsert(fb,offs,str);
+ }
+
+ @Override
+ public void remove(DocumentFilter.FilterBypass fb, int offs, int len)
+ throws BadLocationException {
+ saveButton.setEnabled(true);
+ boolean removingWhite = fb.getDocument().getText(offs, len).trim().isEmpty();
+
+ super.remove(fb, offs, len);
+ String indent = "";
+ String smallerIndent ="";
+ try {
+ indent = indent(offs,false);
+ smallerIndent = indent(offs,true);
+ int newLineOffs = offs - indent.length()-1;
+ String maybeNewline=newLineOffs<0?"":editor.getDocument().getText(newLineOffs, 1);
+ if(removingWhite && indent.length()>0 && (maybeNewline.isEmpty() || maybeNewline.equals("\n"))){
+ super.remove(fb,newLineOffs+1, indent.length());
+ super.insertString(fb,newLineOffs+1,smallerIndent, tokenToAset.get("normal"));
+ } else if(offs>0) { highlightAndInsert(fb,offs,"");}
+ } catch(Throwable t) {}
+ }
+
+ private void highlightAndInsert(FilterBypass fb, int offs, String str)
+ throws BadLocationException {
+
+ // invoke automatical indentation only if a single <ENTER> is received.
+ // In the case of pasting multiple lines, the original indentation
+ // should be reserved.
+ if(str.length()==1 && str.charAt(0)=='\n') {
+ String indent = "";
+ try {
+ indent = indent(offs,false);
+ super.insertString(fb,offs, "\n"+indent, tokenToAset.get("normal"));
+ } catch(Throwable t) {}
+ return;
+ }
+
+ //translate
+ String newstr="";
+ for(int i=0;i<str.length(); i++){
+ char c= str.charAt(i);
+ switch(c) {
+ case '\t':
+ {
+ newstr += " ";
+ break;
+ }
+ default:
+ newstr += c;
+ }
+ }
+
+ String prefix, suffix;
+ // search for partial word before
+ int from=offs;
+ if (newstr.isEmpty() || !Character.isWhitespace(newstr.charAt(0))){
+ from --;
+ while(from >=0 ) {
+ char c = fb.getDocument().getText(from, 1).charAt(0);
+ if(Character.isWhitespace(c)){ break;}
+ from--;
+ }
+ from ++;
+ }
+ prefix = fb.getDocument().getText(from, offs-from);
+
+ // search for partial word after
+ int to=offs;
+ if (newstr.isEmpty() || !Character.isWhitespace(newstr.charAt(newstr.length()-1))){
+ int wholeLen = fb.getDocument().getLength();
+ while(to < wholeLen) {
+ char c = fb.getDocument().getText(to,1).charAt(0);
+ if(Character.isWhitespace(c)){break;}
+ to++;
+ }
+ }
+ suffix = fb.getDocument().getText(offs,to-offs);
+
+ // removing the partial words
+ offs -= prefix.length();
+ super.remove(fb, offs, prefix.length()+suffix.length());
+
+
+ String[] words = newstr.split(" ",-1);
+ words[0] = prefix + words[0];
+ words[words.length-1] += suffix;
+
+
+ newstr = prefix + newstr + suffix;
+ String state="normal";
+ if(offs>0){
+ Color fgcolor=StyleConstants.getForeground(editor.getStyledDocument().getCharacterElement(offs-1).getAttributes());
+ if (fgcolor.equals(StyleConstants.getForeground(tokenToAset.get("quoted"))))
+ state = "quoted";
+ }
+
+ String token="";
+ char c;
+ newstr += '\0';
+ for(int i=0;i< newstr.length();i++){
+ c = newstr.charAt(i);
+ String newstate="normal";
+ if(c=='\0') newstate = "done";
+ else if(state.equals("quoted")|| state.equals("lquote")) newstate= (c=='\"')? "rquote":"quoted";
+ else if(Character.isDigit(c)) newstate = "digits";
+ else if(Character.isLetter(c)) newstate = "word";
+ else if(c=='\"') newstate= "lquote";
+
+ if (!state.equals(newstate)) {
+ String key="normal";
+ if(state.equals("digits")) key="digits";
+ else if(state.equals("word") && isKeyword(token)) key="keyword";
+ else if(state.equals("word") && isDatatype(token)) key="datatype";
+ else if(state.equals("quoted")) key="quoted";
+
+ super.insertString(fb, offs, token, tokenToAset.get(key));
+ offs += token.length();
+ state = newstate;
+ token = "";
+ }
+ token +=c;
+ }
+
+ editor.setCaretPosition(offs-suffix.length());
+ }
+
+ // return the indent (as string of whitespaces) of the current line
+ // or closest shorter indent of previous lines if 'wantShorter' is true.
+ private String indent(int offs, boolean wantShorter) throws BadLocationException {
+ int pos=offs-1;
+ int pos_firstNonWhite = offs;
+ int firstIndentSize=-1;
+ while(pos>=0){
+ char ch= editor.getText(pos, 1).charAt(0);
+ if(ch=='\n') {
+ int previousIndentSize = pos_firstNonWhite-pos-1;
+ if(!wantShorter || previousIndentSize < firstIndentSize) break;
+ if(firstIndentSize<0) firstIndentSize = previousIndentSize;
+ pos_firstNonWhite = pos;
+ }
+ if(!Character.isWhitespace(ch)) {
+ pos_firstNonWhite = pos;
+ }
+ pos --;
+ }
+ return editor.getText(pos+1, pos_firstNonWhite-pos-1);
+ }
+
+ private boolean isKeyword(String word) {
+ for(int i=0;i<keywords.length;i++)
+ if(keywords[i].equals(word))
+ return true;
+ return false;
+ }
+ private boolean isDatatype(String word) {
+ for(int i=0;i<datatypes.length;i++)
+ if(datatypes[i].equals(word))
+ return true;
+ return false;
+ }
+}
diff --git a/support/meper/src/MEPer.java b/support/meper/src/MEPer.java
new file mode 100644
index 0000000000..62d64945ad
--- /dev/null
+++ b/support/meper/src/MEPer.java
@@ -0,0 +1,362 @@
+/* MEPer.java
+ * This file is part of source files of MEPer.
+ * It create the main window and starts the program.
+ *
+ * @author Shengjun Pan
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.text.*;
+import java.io.*;
+
+
+public class MEPer extends JFrame {
+
+ static int initWidth=1000;
+ static int initHeight=618;
+
+ boolean ispc;
+ JToolBar toolbar;
+ JTextPane editor;
+ JLabel graph;
+ JLabel statusLabel;
+
+ JButton saveButton;
+ JButton previewButton;
+ JButton helpButton;
+
+ Action saveAction;
+ Action previewAction;
+ Action helpAction;
+ JDialog helpWindow=null;
+
+ EditorFilter editorFilter;
+
+ String workingDir;
+
+ static String helpTitle = "Metapost Editor and Previewer v1.0";
+ static String dirName= "MetaPostPreview";
+ static String metapost = "mpost -interaction=nonstopmode preview.mp end";
+ static String convert = "convert preview.eps preview.png";
+ static String ghostscript = " -dBATCH -dNOPAUSE -dQUIET"+
+ " -dEPSCrop -dEPSFitPage -dGraphicsAlphaBits=4 -dTextAlphaBits=4"+
+ " -sDEVICE=pngalpha -sOutputFile=preview.png preview.eps";
+
+ private void saveFile() {
+ try {
+ FileWriter outputStream = new FileWriter(workingDir+File.separator+"preview.mp");
+ outputStream.write(editor.getText());
+ outputStream.close();
+ saveButton.setEnabled(false);
+ } catch (Throwable t){}
+ }
+
+ private void consumeRuntime(Process proc) {
+ final BufferedReader errorConsumer = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
+ final BufferedReader outputConsumer = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+ Thread errorThread = new Thread() {
+ public void run() {
+ String nextline;
+ try {
+ while ( (nextline = errorConsumer.readLine()) != null);
+ } catch (Throwable t){}
+ }};
+ Thread outputThread = new Thread(){
+ public void run() {
+ String nextline;
+ try {
+ while ( (nextline = outputConsumer.readLine()) != null);
+ } catch (Throwable t){}
+ }};
+ errorThread.start();
+ outputThread.start();
+ }
+
+ private void createActions(){
+ saveAction = new AbstractAction () {
+ public void actionPerformed(ActionEvent e) {
+ saveFile();
+ statusLabel.setText("preview.mp saved in directory: "+ workingDir);
+ editor.requestFocus();
+ }};
+ previewAction = new AbstractAction(){
+ public void actionPerformed(ActionEvent e) {
+ saveFile();
+
+ SwingUtilities.invokeLater(new Runnable () {
+ public void run() {
+ try {
+ File previewmp= new File(workingDir+File.separator+"preview.mp");
+ File preview1= new File(workingDir+File.separator+"preview.1");
+ File previeweps= new File(workingDir+File.separator+"preview.eps");
+ File previewpng= new File(workingDir+File.separator+"preview.png");
+
+ (new File(workingDir+File.separator+"preview.1")).delete();
+ (new File(workingDir+File.separator+"preview.eps")).delete();
+ (new File(workingDir+File.separator+"preview.png")).delete();
+
+ File dir = new File(workingDir);
+ Process proc=null;
+
+ if(previewmp.exists()) {
+ statusLabel.setText("Generating preview image...");
+ proc = Runtime.getRuntime().exec(metapost,null,dir);
+ if(proc != null) {
+ consumeRuntime(proc);
+ proc.waitFor();
+ proc = null;
+ } else {
+ statusLabel.setText("Error on running metapost.");
+ return;
+ }
+ } else {
+ statusLabel.setText("Can't find file: preview.mp");
+ return;
+ }
+
+ if(preview1.exists()) {
+ preview1.renameTo(previeweps);
+ statusLabel.setText("preview.1 renamed to preview.eps.");
+ } else {
+ statusLabel.setText("Cant' find file: preview.1");
+ return;
+ }
+
+ if(previeweps.exists()) {
+ // try convert
+ proc = Runtime.getRuntime().exec(convert, null,dir);
+ if(proc != null) {
+ consumeRuntime(proc);
+ proc.waitFor();
+ proc=null;
+ } else
+ statusLabel.setText("Error on running ImageMagick." +
+ "Try ghostscript...");
+ // try ghostscript
+ if(!previewpng.exists()) {
+ proc = Runtime.getRuntime().exec(ghostscript, null,dir);
+ if(proc != null) {
+ consumeRuntime(proc);
+ proc.waitFor();
+ proc=null;
+ } else {
+ statusLabel.setText("Error on running ghostscript.");
+ return;
+ }
+ }
+ } else {
+ statusLabel.setText("Can't find file: preview.eps");
+ return;
+ }
+
+ if(previewpng.exists()) {
+ statusLabel.setText("Reloading preview image...");
+ ((ImageIcon)graph.getIcon()).getImage().flush();
+ ImageIcon img = new ImageIcon(workingDir+File.separator+"preview.png");
+ graph.setIcon(img);
+ graph.repaint();
+ statusLabel.setText(" preview.[mp|eps|png] saved in directory: "+ workingDir);
+ } else {
+ statusLabel.setText("Can't find file: preview.png");
+ return;
+ }
+
+ } catch (Throwable t) {}
+ editor.requestFocus();
+ }});
+ }};
+ helpAction = new AbstractAction () {
+ public void actionPerformed(ActionEvent e) {
+ if(helpWindow==null){
+ helpWindow = new JDialog();
+ JTextArea infoPane = new JTextArea();
+ infoPane.setEditable(false);
+ infoPane.setAlignmentX(Component.CENTER_ALIGNMENT);
+ //URL readmeURL = this.getClass().getResource("README.txt");
+
+ try {
+ String nextline;
+ InputStream is = this.getClass().getResourceAsStream("README.txt");
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader inputStream = new BufferedReader(isr);
+ nextline = inputStream.readLine();
+ infoPane.getDocument().insertString(infoPane.getDocument().getLength(), nextline, null);
+ while(!(nextline = inputStream.readLine()).equals(null))
+ infoPane.getDocument().insertString(infoPane.getDocument().getLength(), "\n"+nextline, null);
+ inputStream.close();
+ } catch(Throwable t) {}
+
+ Container helpPane = helpWindow.getContentPane();
+
+ helpPane.setLayout(new BoxLayout(helpPane,BoxLayout.Y_AXIS));
+ JLabel titleLabel = new JLabel(helpTitle);
+ titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
+ helpPane.add(titleLabel);
+ infoPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
+ helpPane.add(infoPane);
+ JButton closeButton = new JButton(new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ helpWindow.setVisible(false);
+ editor.requestFocus();
+ }});
+ closeButton.setText("Close");
+ closeButton.setAlignmentX(Component.CENTER_ALIGNMENT);
+ helpPane.add(closeButton);
+ helpWindow.addWindowListener( new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ helpWindow.setVisible(false);
+ editor.requestFocus();
+ }});
+ helpWindow.pack();
+ }
+
+ int topX, topY;
+ topX = (MEPer.this.getWidth()-helpWindow.getWidth())/2;
+ topY = (MEPer.this.getHeight()-helpWindow.getHeight())/3;
+ Point helpLocation =MEPer.this.getLocation();
+ helpLocation.translate(topX, topY);
+ helpWindow.setLocation(helpLocation);
+ helpWindow.setVisible(true);
+ }
+ };
+ }
+
+ public MEPer() {
+
+ String osName=System.getProperty("os.name").toLowerCase();
+ ispc = osName.indexOf("win")!=-1;
+ ghostscript = (ispc?"gsWin32":"gs") + ghostscript;
+
+ workingDir = System.getProperty("user.dir");
+ File newdir = new File(System.getProperty("user.home") + File.separator+ dirName);
+
+ if(newdir.exists() || newdir.mkdir()) {
+ workingDir = newdir.getAbsolutePath();
+ System.setProperty("user.dir", workingDir);
+ }
+
+ // Create a toolbar
+ toolbar = new JToolBar();
+ createActions();
+
+ saveButton = new JButton(saveAction);
+ saveButton.setText("Save");
+ saveButton.setToolTipText("Ctr+S");
+ toolbar.add(saveButton);
+
+ previewButton = new JButton(previewAction);
+ previewButton.setText("Preview");
+ previewButton.setToolTipText("Ctr+P");
+ toolbar.add(previewButton);
+
+ toolbar.add(Box.createHorizontalGlue());
+
+ helpButton = new JButton(helpAction);
+ helpButton.setText("Help");
+ toolbar.add(helpButton);
+
+ statusLabel = new JLabel();
+ statusLabel.setText("Working directory: "+System.getProperty("user.dir"));
+ statusLabel.setFont(new Font(Font.SERIF,Font.PLAIN,12));
+
+ //Create a text pane for the editing area
+ editor = new JTextPane();
+
+ editorFilter = new EditorFilter(editor, saveButton);
+ ((AbstractDocument)editor.getDocument()).setDocumentFilter(editorFilter);
+ editor.getInputMap().put(KeyStroke.getKeyStroke("ctrl S"), "save");
+ editor.getInputMap().put(KeyStroke.getKeyStroke("ctrl P"), "preview");
+ editor.getActionMap().put("save", saveAction);
+ editor.getActionMap().put("preview", previewAction);
+/*
+ */
+ // load file "preview.mp" into editor
+ BufferedReader inputStream;
+ String mpName = workingDir+File.separator+"preview.mp";
+ try {
+ boolean loadTemplate = false;
+ if ((new File(mpName)).exists())
+ inputStream = new BufferedReader(new FileReader(mpName));
+ else{
+ statusLabel.setText("Can't load preview.mp; using template instead.");
+ loadTemplate=true;
+ InputStream is = this.getClass().getResourceAsStream("template.mp");
+ InputStreamReader isr = new InputStreamReader(is);
+ inputStream = new BufferedReader(isr);
+ }
+ String nextline;
+ nextline = inputStream.readLine();
+ editor.getDocument().insertString(editor.getDocument().getLength(), nextline, null);
+ while(!((nextline = inputStream.readLine())==null))
+ editor.getDocument().insertString(editor.getDocument().getLength(), "\n"+nextline, null);
+ inputStream.close();
+ if(loadTemplate) editor.setCaretPosition(editor.getDocument().getLength()-12);
+ } catch(Throwable t) {}
+
+ saveButton.setEnabled(false);
+
+ JScrollPane editorScrollPane = new JScrollPane(editor);
+
+ graph = new JLabel();
+ graph.setOpaque(true);
+ graph.setBackground(Color.WHITE);
+ ImageIcon img = new ImageIcon(workingDir+File.separator+"preview.png");
+ graph.setIcon(img);
+ graph.setHorizontalAlignment(SwingConstants.CENTER);
+ graph.setVerticalAlignment(SwingConstants.CENTER);
+
+ JScrollPane imagePane = new JScrollPane(graph);
+
+ editorScrollPane.setPreferredSize(new Dimension(initWidth/2,initHeight));
+
+ JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+ editorScrollPane, imagePane);
+
+ this.getContentPane().add(toolbar,BorderLayout.PAGE_START);
+ this.getContentPane().add(splitPane, BorderLayout.CENTER);
+ this.getContentPane().add(statusLabel,BorderLayout.PAGE_END);
+
+ addWindowListener( new WindowAdapter() {
+ @Override
+ public void windowOpened( WindowEvent e ){ editor.requestFocus();}
+ @Override
+ public void windowClosing(WindowEvent e) {
+ if( saveButton.isEnabled()) {
+ int response = JOptionPane.showConfirmDialog(
+ MEPer.this,
+ "Save file before exit?",
+ "Closing...",
+ JOptionPane.YES_NO_OPTION);
+ if (response == JOptionPane.YES_OPTION) saveFile();
+ }}
+ });
+ }
+
+ private static void initialize() {
+ MEPer mainFrame = new MEPer();
+ mainFrame.setTitle("MetaPost Editor and Previewer");
+
+ mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ int topX = (int)((screenSize.getWidth()-initWidth)/2);
+ if(topX<0) topX=0;
+ int topY =(int)((screenSize.getHeight()-initHeight)/3);
+ if(topY<0) topY=0;
+ mainFrame.setPreferredSize(new Dimension(initWidth,initHeight));
+ mainFrame.setLocation(topX, topY);
+ mainFrame.pack();
+ mainFrame.setVisible(true);
+ }
+
+ public static void main(String args[]) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ initialize();
+ }});
+}
+}
diff --git a/support/meper/src/README b/support/meper/src/README
new file mode 100644
index 0000000000..f0b956915f
--- /dev/null
+++ b/support/meper/src/README
@@ -0,0 +1,28 @@
+Usage
+ MEPer is a java program. To start the program, use
+ java -jar MEper.jar
+
+ A directory named "MetaPostPreviewer" will be created in the user's home
+ directory. The following files (and temporary files) will be created in this
+ directory:
+ - preview.mp, the MetaPost source file.
+ - preview.eps, the output of the MetaPost;
+ - preview.png, converted from the eps file.
+
+ The jar file and source files can be downloaed from
+ http://www.cse.ucsd.edu/~s1pan/MEPer.
+
+System requirement
+ The following tools are needed to run MEPer:
+ - the latest release of the Sun Java SE platform
+ - MetaPost
+ - ImageMagick, or ghostscript
+
+License and Disclaimer
+ MEPer is free software under the GPL (Gnu General Public License). It is free
+ to use but WITHOUT ANY WARRANTY. If you modify or redistribute it, please
+ include the orginal author's name or a link to the MEPer web page.
+
+Copyright 2009, Shengjun Pan
+
+