/*
* Copyright 2014 Igor Maznitsa (http://www.igormaznitsa.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.igormaznitsa.prol.easygui;
import com.igormaznitsa.prol.annotations.*;
import com.igormaznitsa.prol.data.*;
import com.igormaznitsa.prol.exceptions.*;
import com.igormaznitsa.prol.io.ProlStreamManager;
import com.igormaznitsa.prol.libraries.*;
import com.igormaznitsa.prol.logic.*;
import com.igormaznitsa.prol.parser.ProlConsult;
import com.igormaznitsa.prol.trace.TraceListener;
import com.igormaznitsa.prol.utils.Utils;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.*;
import java.util.prefs.Preferences;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.event.*;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.TreeModel;
import javax.swing.undo.*;
/**
* The class implements the main frame of the Prol Pad IDE (a small UI utility to edit and run prol scripts) because it is a very specialized auxiliary class, it is not described
* very precisely
*
* @author Igor Maznitsa (igor.maznitsa@igormaznitsa.com)
*/
public final class MainFrame extends javax.swing.JFrame implements ProlStreamManager, Runnable, UndoableEditListener, WindowListener, DocumentListener, HyperlinkListener, TraceListener {
private static final long serialVersionUID = -3816861562325125649L;
/**
* The version of the IDE
*/
private final String VERSION = getString(this.getClass().getPackage().getImplementationVersion(), "<Development>");
/**
* Inside logger
*/
private static final Logger LOG = Logger.getLogger("PROL_NOTE_PAD");
private final ThreadGroup executingScripts = new ThreadGroup("ProlExecutingScripts");
private final String PROPERTY_PROL_STACK_DEPTH = "prol.stack.depth";
@Override
public boolean onProlGoalCall(final Goal goal) {
traceEditor.addCallText(goal.getGoalTerm().forWrite());
return true;
}
@Override
public boolean onProlGoalRedo(final Goal goal) {
traceEditor.addRedoText(goal.getGoalTerm().forWrite());
return true;
}
@Override
public void onProlGoalFail(final Goal goal) {
traceEditor.addFailText(goal.getGoalTerm().forWrite());
}
@Override
public void onProlGoalExit(final Goal goal) {
traceEditor.addExitText(goal.getGoalTerm().forWrite());
}
private static String getString(final String str, final String def) {
return str == null ? def : str;
}
/**
* This class is a helper Prol library to allow a user to print messages at the Message dialog window (and the log too) directly from its scripts
*/
protected final class LogLibrary extends ProlAbstractLibrary {
public LogLibrary() {
super("JProlNotepadLog");
}
@Predicate(Signature = "msgerror/1", Reference = "The predicate allows to output information marked as error at the message window.")
@Determined
public void predicateMSGERROR(final Goal goal, final TermStruct struct) {
final Term term = Utils.getTermFromElement(struct.getElement(0));
final String text = term.forWrite();
LOG.log(Level.SEVERE, "msgerror/1 : {0}", text);
messageEditor.addErrorText(text);
}
@Predicate(Signature = "msgwarning/1", Reference = "The predicate allows to output information marked as warning at the message window.")
@Determined
public void predicateMSGWARNING(final Goal goal, final TermStruct struct) {
final Term term = Utils.getTermFromElement(struct.getElement(0));
final String text = term.forWrite();
LOG.log(Level.WARNING, "msgwarning/1 : {0}", text);
messageEditor.addWarningText(text);
}
@Predicate(Signature = "msginfo/1", Reference = "The predicate allows to output information marked as info at the message window.")
@Determined
public void predicateMSGINFO(final Goal goal, final TermStruct struct) {
final Term term = Utils.getTermFromElement(struct.getElement(0));
final String text = term.forWrite();
LOG.log(Level.INFO, "msginfo/1 : {0}", text);
messageEditor.addInfoText(text);
}
}
protected final LogLibrary logLibrary;
protected Map<String, LookAndFeelInfo> lookAndFeelMap;
protected final AtomicReference<Thread> currentExecutedScriptThread = new AtomicReference<Thread>();
protected File currentOpenedFile;
protected File lastOpenedFile;
protected final AtomicBoolean startedInTracing = new AtomicBoolean();
protected boolean documentHasBeenChangedFlag;
static final String[] PROL_LIBRARIES = new String[]{"com.igormaznitsa.prol.libraries.ProlGraphicLibrary", "com.igormaznitsa.prol.libraries.ProlStringLibrary"};
protected volatile ProlContext lastContext;
protected static final String PROL_EXTENSION = ".prl";
public static volatile WeakReference<MainFrame> MAIN_FRAME_INSTANCE;
private static final FileFilter PROL_FILE_FILTER = new FileFilter() {
@Override
public boolean accept(File f) {
if (f == null) {
return false;
}
if (f.isDirectory()) {
return true;
}
return f.getName().toLowerCase().endsWith(PROL_EXTENSION);
}
@Override
public String getDescription() {
return "Prol files (*" + PROL_EXTENSION + ')';
}
};
private static final int MAX_RECENT_FILES = 10;
private final RecentlyOpenedFileFixedList recentFiles = new RecentlyOpenedFileFixedList(MAX_RECENT_FILES);
/**
* Creates new form MainFrame
*/
public MainFrame() {
try {
initComponents();
Toolkit dt = Toolkit.getDefaultToolkit();
Dimension scr = dt.getScreenSize();
setSize((scr.width * 10) / 12, (scr.height * 10) / 12);
sourceEditor.addUndoableEditListener(this);
sourceEditor.addDocumentListener(this);
messageEditor.addHyperlinkListener(this);
addWindowListener(this);
panelProgress.setVisible(false);
logLibrary = new LogLibrary();
try {
setIconImage(new ImageIcon(this.getClass().getResource("/com/igormaznitsa/prol/easygui/icons/appico.png")).getImage());
}
catch (Exception ex) {
LOG.throwing(this.getClass().getCanonicalName(), "<init>()", ex);
}
fillLAndFeelMenu();
loadPreferences();
newFile();
this.menuItemWordWrapSources.setState(sourceEditor.getEdWordWrap());
final Action action = new AbstractAction("closeFindPanel") {
private static final long serialVersionUID = 4377386270269629176L;
@Override
public void actionPerformed(ActionEvent e) {
if (panelFindText.isVisible()) {
panelFindText.setVisible(false);
textFind.setText("");
}
}
};
final KeyStroke escKey = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
action.putValue(Action.ACCELERATOR_KEY, escKey);
this.buttonCloseFind.getActionMap().put("closeFind", action);
this.buttonCloseFind.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escKey, "closeFind");
this.panelFindText.setVisible(false);
}
finally {
MAIN_FRAME_INSTANCE = new WeakReference<MainFrame>(this);
}
}
private void fillLAndFeelMenu() {
final LookAndFeelInfo plaf[] = UIManager.getInstalledLookAndFeels();
this.lookAndFeelMap = new HashMap<String, LookAndFeelInfo>();
final ButtonGroup lfGroup = new ButtonGroup();
final ActionListener lfListener = new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
final JRadioButtonMenuItem item = (JRadioButtonMenuItem) e.getSource();
setSelectedLookAndFeel(item.getText());
}
};
for (int i = 0, n = plaf.length; i < n; i++) {
final String lfName = plaf[i].getName();
if (lfName.toLowerCase(Locale.ENGLISH).contains("nimbus")) {
continue;
}
lookAndFeelMap.put(lfName, plaf[i]);
JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(lfName);
menuItem.addActionListener(lfListener);
lfGroup.add(menuItem);
menuLookAndFeel.add(menuItem);
}
}
private void setSelectedLookAndFeel(String lookAndFeelName) {
if (lookAndFeelName != null) {
if (!this.lookAndFeelMap.containsKey(lookAndFeelName)) {
lookAndFeelName = null;
}
}
if (lookAndFeelName == null) {
// set the first
lookAndFeelName = this.menuLookAndFeel.getItem(0).getText();
}
final LookAndFeelInfo feelInfo = this.lookAndFeelMap.get(lookAndFeelName);
final JFrame thisFrame = this;
for (int li = 0; li < this.menuLookAndFeel.getItemCount(); li++) {
final JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) this.menuLookAndFeel.getItem(li);
if (menuItem.getText().equals(lookAndFeelName)) {
if (!menuItem.isSelected()) {
menuItem.setSelected(true);
}
break;
}
}
try {
UIManager.setLookAndFeel(feelInfo.getClassName());
}
catch (Exception ex) {
LOG.throwing(thisFrame.getClass().getCanonicalName(), "L&F", ex);
}
SwingUtilities.updateComponentTreeUI(thisFrame);
}
public MainFrame(final File initFile) {
this();
loadFile(initFile, true);
}
/**
* This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form
* Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
splitPaneMain = new javax.swing.JSplitPane();
splitPaneTop = new javax.swing.JSplitPane();
try {
dialogEditor = new com.igormaznitsa.prol.easygui.DialogEditor();
} catch (java.io.IOException e1) {
e1.printStackTrace();
}
editorPanel = new javax.swing.JPanel();
sourceEditor = new com.wordpress.tips4java.TextLineNumber();
panelFindText = new javax.swing.JPanel();
labelFind = new javax.swing.JLabel();
textFind = new javax.swing.JTextField();
buttonCloseFind = new javax.swing.JButton();
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
splitPanelDown = new javax.swing.JSplitPane();
messageEditor = new com.igormaznitsa.prol.easygui.MessageEditor();
traceEditor = new com.igormaznitsa.prol.easygui.TraceDialog();
panelProgress = new javax.swing.JPanel();
progressBarTask = new javax.swing.JProgressBar();
buttonStopExecuting = new javax.swing.JButton();
jMenuBar1 = new javax.swing.JMenuBar();
menuFile = new javax.swing.JMenu();
menuFileNew = new javax.swing.JMenuItem();
menuFileOpen = new javax.swing.JMenuItem();
menuFileSaveAs = new javax.swing.JMenuItem();
menuFileSave = new javax.swing.JMenuItem();
jSeparator1 = new javax.swing.JPopupMenu.Separator();
menuFileRecentFiles = new javax.swing.JMenu();
jSeparator4 = new javax.swing.JPopupMenu.Separator();
menuExit = new javax.swing.JMenuItem();
menuEdit = new javax.swing.JMenu();
menuUndo = new javax.swing.JMenuItem();
menuRedo = new javax.swing.JMenuItem();
jSeparator2 = new javax.swing.JPopupMenu.Separator();
menuClearText = new javax.swing.JMenuItem();
menuEditCommentSelected = new javax.swing.JMenuItem();
menuEditUncommentSelected = new javax.swing.JMenuItem();
jSeparator3 = new javax.swing.JPopupMenu.Separator();
menuitemFindText = new javax.swing.JMenuItem();
menuItemWordWrapSources = new javax.swing.JCheckBoxMenuItem();
menuItemFullScreen = new javax.swing.JMenuItem();
jSeparator5 = new javax.swing.JPopupMenu.Separator();
menuEditOptions = new javax.swing.JMenuItem();
menuRun = new javax.swing.JMenu();
menuRunScript = new javax.swing.JMenuItem();
menuTraceScript = new javax.swing.JMenuItem();
menuRunStop = new javax.swing.JMenuItem();
menuView = new javax.swing.JMenu();
menuViewKnowledgeBase = new javax.swing.JMenuItem();
menuItemLibraryInfo = new javax.swing.JMenuItem();
menuLookAndFeel = new javax.swing.JMenu();
menuHelp = new javax.swing.JMenu();
menuHelpHelp = new javax.swing.JMenuItem();
menuAbout = new javax.swing.JMenuItem();
setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
splitPaneMain.setDividerLocation(350);
splitPaneMain.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
splitPaneMain.setResizeWeight(0.8);
splitPaneMain.setOneTouchExpandable(true);
splitPaneTop.setDividerLocation(500);
splitPaneTop.setResizeWeight(0.9);
splitPaneTop.setOneTouchExpandable(true);
dialogEditor.setToolTipText("The window allows to communicate with a user");
splitPaneTop.setRightComponent(dialogEditor);
editorPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Editor"));
editorPanel.setLayout(new java.awt.BorderLayout());
sourceEditor.setBorder(null);
sourceEditor.setToolTipText("The editor allows to enter and edit text of a program");
sourceEditor.setFont(new java.awt.Font("DejaVu Sans", 1, 13)); // NOI18N
editorPanel.add(sourceEditor, java.awt.BorderLayout.CENTER);
panelFindText.setLayout(new java.awt.GridBagLayout());
labelFind.setText("Find:");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
panelFindText.add(labelFind, gridBagConstraints);
textFind.setToolTipText("Enter text for search (wildcard chars ? and * are supported)");
textFind.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
textFindKeyReleased(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.ipadx = 300;
panelFindText.add(textFind, gridBagConstraints);
buttonCloseFind.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/cross.png"))); // NOI18N
buttonCloseFind.setToolTipText("Hide the find text panel (ESC)");
buttonCloseFind.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
buttonCloseFind.setIconTextGap(0);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 0;
panelFindText.add(buttonCloseFind, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.weightx = 1000.0;
panelFindText.add(filler1, gridBagConstraints);
editorPanel.add(panelFindText, java.awt.BorderLayout.PAGE_END);
splitPaneTop.setLeftComponent(editorPanel);
splitPaneMain.setTopComponent(splitPaneTop);
splitPanelDown.setDividerLocation(500);
splitPanelDown.setResizeWeight(0.8);
splitPanelDown.setOneTouchExpandable(true);
messageEditor.setToolTipText("The window shows messages during an execution of the script");
splitPanelDown.setLeftComponent(messageEditor);
traceEditor.setToolTipText("The window shows trace information if the engine is being started at the trace mode");
splitPanelDown.setRightComponent(traceEditor);
splitPaneMain.setBottomComponent(splitPanelDown);
getContentPane().add(splitPaneMain, java.awt.BorderLayout.CENTER);
panelProgress.setBorder(javax.swing.BorderFactory.createEtchedBorder());
panelProgress.setLayout(new java.awt.GridBagLayout());
progressBarTask.setMaximumSize(new java.awt.Dimension(100, 20));
progressBarTask.setPreferredSize(new java.awt.Dimension(40, 20));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1000.0;
panelProgress.add(progressBarTask, gridBagConstraints);
buttonStopExecuting.setBackground(new java.awt.Color(255, 156, 156));
buttonStopExecuting.setFont(new java.awt.Font("DejaVu Sans", 1, 13)); // NOI18N
buttonStopExecuting.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/flag_red.png"))); // NOI18N
buttonStopExecuting.setText("STOP EXECUTION");
buttonStopExecuting.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
buttonStopExecuting.setMaximumSize(new java.awt.Dimension(100, 23));
buttonStopExecuting.setMinimumSize(new java.awt.Dimension(60, 23));
buttonStopExecuting.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
buttonStopExecutingActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
panelProgress.add(buttonStopExecuting, gridBagConstraints);
getContentPane().add(panelProgress, java.awt.BorderLayout.SOUTH);
menuFile.setText("File");
menuFileNew.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/page.png"))); // NOI18N
menuFileNew.setText("New");
menuFileNew.setToolTipText("Create new document");
menuFileNew.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuFileNewActionPerformed(evt);
}
});
menuFile.add(menuFileNew);
menuFileOpen.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
menuFileOpen.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/page_edit.png"))); // NOI18N
menuFileOpen.setText("Open");
menuFileOpen.setToolTipText("Open a saved document");
menuFileOpen.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuFileOpenActionPerformed(evt);
}
});
menuFile.add(menuFileOpen);
menuFileSaveAs.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/page_save.png"))); // NOI18N
menuFileSaveAs.setText("Save As..");
menuFileSaveAs.setToolTipText("Save the current document as a file");
menuFileSaveAs.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuFileSaveAsActionPerformed(evt);
}
});
menuFile.add(menuFileSaveAs);
menuFileSave.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
menuFileSave.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/page_go.png"))); // NOI18N
menuFileSave.setText("Save");
menuFileSave.setToolTipText("Save the current document");
menuFileSave.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuFileSaveActionPerformed(evt);
}
});
menuFile.add(menuFileSave);
menuFile.add(jSeparator1);
menuFileRecentFiles.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/folder.png"))); // NOI18N
menuFileRecentFiles.setText("Recent files...");
menuFileRecentFiles.setToolTipText("List of files opened early");
menuFileRecentFiles.addMenuListener(new javax.swing.event.MenuListener() {
public void menuSelected(javax.swing.event.MenuEvent evt) {
menuFileRecentFilesMenuSelected(evt);
}
public void menuDeselected(javax.swing.event.MenuEvent evt) {
}
public void menuCanceled(javax.swing.event.MenuEvent evt) {
}
});
menuFile.add(menuFileRecentFiles);
menuFile.add(jSeparator4);
menuExit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, java.awt.event.InputEvent.ALT_MASK));
menuExit.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/door_in.png"))); // NOI18N
menuExit.setText("Exit");
menuExit.setToolTipText("Close the editor");
menuExit.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuExitActionPerformed(evt);
}
});
menuFile.add(menuExit);
jMenuBar1.add(menuFile);
menuEdit.setText("Edit");
menuUndo.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Z, java.awt.event.InputEvent.CTRL_MASK));
menuUndo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/book_previous.png"))); // NOI18N
menuUndo.setText("Undo");
menuUndo.setToolTipText("Undo last changes in the document");
menuUndo.setEnabled(false);
menuUndo.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuUndoActionPerformed(evt);
}
});
menuEdit.add(menuUndo);
menuRedo.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Y, java.awt.event.InputEvent.CTRL_MASK));
menuRedo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/book_next.png"))); // NOI18N
menuRedo.setText("Redo");
menuRedo.setToolTipText("Redo canceled changes in the document");
menuRedo.setEnabled(false);
menuRedo.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuRedoActionPerformed(evt);
}
});
menuEdit.add(menuRedo);
menuEdit.add(jSeparator2);
menuClearText.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_R, java.awt.event.InputEvent.CTRL_MASK));
menuClearText.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/page_white.png"))); // NOI18N
menuClearText.setText("Clear");
menuClearText.setToolTipText("Just clear text in the current document");
menuClearText.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuClearTextActionPerformed(evt);
}
});
menuEdit.add(menuClearText);
menuEditCommentSelected.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_5, java.awt.event.InputEvent.CTRL_MASK));
menuEditCommentSelected.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/comment_add.png"))); // NOI18N
menuEditCommentSelected.setText("Comment selection");
menuEditCommentSelected.setToolTipText("Place the commenting symbol as the first one into selected lines");
menuEditCommentSelected.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuEditCommentSelectedActionPerformed(evt);
}
});
menuEdit.add(menuEditCommentSelected);
menuEditUncommentSelected.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_U, java.awt.event.InputEvent.CTRL_MASK));
menuEditUncommentSelected.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/comment_delete.png"))); // NOI18N
menuEditUncommentSelected.setText("Uncomment selection");
menuEditUncommentSelected.setToolTipText("Remove the first commenting symbol from selected lines");
menuEditUncommentSelected.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuEditUncommentSelectedActionPerformed(evt);
}
});
menuEdit.add(menuEditUncommentSelected);
menuEdit.add(jSeparator3);
menuitemFindText.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, java.awt.event.InputEvent.CTRL_MASK));
menuitemFindText.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/zoom.png"))); // NOI18N
menuitemFindText.setText("Find text");
menuitemFindText.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuitemFindTextActionPerformed(evt);
}
});
menuEdit.add(menuitemFindText);
menuItemWordWrapSources.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_W, java.awt.event.InputEvent.CTRL_MASK));
menuItemWordWrapSources.setSelected(true);
menuItemWordWrapSources.setText("Word wrap (editor)");
menuItemWordWrapSources.setToolTipText("Word-wrap mode for the document editor");
menuItemWordWrapSources.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/text_align_justify.png"))); // NOI18N
menuItemWordWrapSources.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuItemWordWrapSourcesActionPerformed(evt);
}
});
menuEdit.add(menuItemWordWrapSources);
menuItemFullScreen.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
menuItemFullScreen.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/shape_move_forwards.png"))); // NOI18N
menuItemFullScreen.setText("Full screen");
menuItemFullScreen.setToolTipText("Turn on the full screen mode if it is supported by the device");
menuItemFullScreen.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuItemFullScreenActionPerformed(evt);
}
});
menuEdit.add(menuItemFullScreen);
menuEdit.add(jSeparator5);
menuEditOptions.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/cog.png"))); // NOI18N
menuEditOptions.setText("Options");
menuEditOptions.setToolTipText("Open editor options");
menuEditOptions.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuEditOptionsActionPerformed(evt);
}
});
menuEdit.add(menuEditOptions);
jMenuBar1.add(menuEdit);
menuRun.setText("Run");
menuRunScript.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F5, 0));
menuRunScript.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/flag_green.png"))); // NOI18N
menuRunScript.setText("Start");
menuRunScript.setToolTipText("Execute the current document");
menuRunScript.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuRunScriptActionPerformed(evt);
}
});
menuRun.add(menuRunScript);
menuTraceScript.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/flag_blue.png"))); // NOI18N
menuTraceScript.setText("Trace");
menuTraceScript.setToolTipText("Execute the current document with tracing");
menuTraceScript.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuTraceScriptActionPerformed(evt);
}
});
menuRun.add(menuTraceScript);
menuRunStop.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/flag_red.png"))); // NOI18N
menuRunStop.setText("Stop");
menuRunStop.setToolTipText("Stop the current execution");
menuRunStop.setEnabled(false);
menuRunStop.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuRunStopActionPerformed(evt);
}
});
menuRun.add(menuRunStop);
jMenuBar1.add(menuRun);
menuView.setText("View");
menuViewKnowledgeBase.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F12, 0));
menuViewKnowledgeBase.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/eye.png"))); // NOI18N
menuViewKnowledgeBase.setText("Show Knowledge base");
menuViewKnowledgeBase.setToolTipText("Take and show the snapshot of the current knowledge base saved in the memory");
menuViewKnowledgeBase.setEnabled(false);
menuViewKnowledgeBase.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuViewKnowledgeBaseActionPerformed(evt);
}
});
menuView.add(menuViewKnowledgeBase);
menuItemLibraryInfo.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F1, 0));
menuItemLibraryInfo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/table.png"))); // NOI18N
menuItemLibraryInfo.setText("Library info");
menuItemLibraryInfo.setToolTipText("Show all predicates found in embedded libraries");
menuItemLibraryInfo.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuItemLibraryInfoActionPerformed(evt);
}
});
menuView.add(menuItemLibraryInfo);
jMenuBar1.add(menuView);
menuLookAndFeel.setText("Look&Feel");
jMenuBar1.add(menuLookAndFeel);
menuHelp.setText("Help");
menuHelpHelp.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/information.png"))); // NOI18N
menuHelpHelp.setText("Help");
menuHelpHelp.setToolTipText("Show information about usage of the utility");
menuHelpHelp.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuHelpHelpActionPerformed(evt);
}
});
menuHelp.add(menuHelpHelp);
menuAbout.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/igormaznitsa/prol/easygui/icons/emoticon_smile.png"))); // NOI18N
menuAbout.setText("About");
menuAbout.setToolTipText("Show the information about the application and license");
menuAbout.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuAboutActionPerformed(evt);
}
});
menuHelp.add(menuAbout);
jMenuBar1.add(menuHelp);
setJMenuBar(jMenuBar1);
pack();
}// </editor-fold>//GEN-END:initComponents
private void menuRunScriptActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuRunScriptActionPerformed
startExecution(false);
}//GEN-LAST:event_menuRunScriptActionPerformed
private void menuUndoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuUndoActionPerformed
try {
this.sourceEditor.getUndoManager().undo();
}
catch (CannotUndoException ex) {
}
UndoManager undo = sourceEditor.getUndoManager();
this.menuUndo.setEnabled(undo.canUndo());
this.menuRedo.setEnabled(undo.canRedo());
}//GEN-LAST:event_menuUndoActionPerformed
private void menuRedoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuRedoActionPerformed
try {
this.sourceEditor.getUndoManager().redo();
}
catch (CannotRedoException ex) {
}
UndoManager undo = this.sourceEditor.getUndoManager();
this.menuUndo.setEnabled(undo.canUndo());
this.menuRedo.setEnabled(undo.canRedo());
}//GEN-LAST:event_menuRedoActionPerformed
private void menuExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuExitActionPerformed
windowClosing(null);
}//GEN-LAST:event_menuExitActionPerformed
private void menuClearTextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuClearTextActionPerformed
if (this.sourceEditor.getEditor().getDocument().getLength() > 10) {
if (JOptionPane.showConfirmDialog(this, "Do you really want to clean?", "Confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
this.sourceEditor.getUndoManager().discardAllEdits();
this.sourceEditor.clearText();
}
}
}//GEN-LAST:event_menuClearTextActionPerformed
private void menuFileOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuFileOpenActionPerformed
loadFile(this.lastOpenedFile, false);
}//GEN-LAST:event_menuFileOpenActionPerformed
private void menuFileSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuFileSaveActionPerformed
saveFile(false);
}//GEN-LAST:event_menuFileSaveActionPerformed
private void menuFileSaveAsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuFileSaveAsActionPerformed
saveFile(true);
}//GEN-LAST:event_menuFileSaveAsActionPerformed
private void buttonStopExecutingActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonStopExecutingActionPerformed
final Thread executingThread = this.currentExecutedScriptThread.get();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (executingThread != null) {
try {
executingThread.interrupt();
dialogEditor.cancelRead();
executingThread.join();
}
catch (Throwable tr) {
tr.printStackTrace();
}
finally {
hideTaskControlPanel();
}
messageEditor.addWarningText("Execution is canceled.");
}
}
});
}//GEN-LAST:event_buttonStopExecutingActionPerformed
private void menuAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuAboutActionPerformed
final JHtmlLabel label = new JHtmlLabel("<html><body><h1>JProl Notepad</h1>Version: " + VERSION + "<br><b>Project page:</b> <a href=\"https://github.com/raydac/jprol\">https://github.com/raydac/jprol</a><br><b>Author:</b> Igor Maznitsa (<a href=\"http://www.igormaznitsa.com\">http://www.igormaznitsa.com</a>)<br><br>(C)2010-2016 Igor A. Maznitsa. <a href=\"https://www.apache.org/licenses/LICENSE-2.0\">Apache 2.0 License</a><br>Icons from the free icon set <a href=\"http://www.famfamfam.com/lab/icons/silk/\">http://www.famfamfam.com/lab/icons/silk/</a><br><br>If you like the application you could make some donation:<br><ul><li><a href=\"https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=AHWJHJFBAWGL2\">PayPal</a></li><li><a href=\"https://money.yandex.ru/embed/small.xml?account=41001158080699&quickpay=small&yamoney-payment-type=on&button-text=01&button-size=l&button-color=orange&targets=%D0%9F%D0%BE%D0%B6%D0%B5%D1%80%D1%82%D0%B2%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BD%D0%B0+%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D1%8B+%D1%81+%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D0%BC+%D0%B8%D1%81%D1%85%D0%BE%D0%B4%D0%BD%D1%8B%D0%BC+%D0%BA%D0%BE%D0%B4%D0%BE%D0%BC&default-sum=100&successURL=\">Yandex.Money</a></li></ul></body></html>");
label.addLinkListener(new JHtmlLabel.LinkListener() {
@Override
public void onLinkActivated(final JHtmlLabel source, final String link) {
try {
final Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
desktop.browse(new URI(link));
}
}
catch (Exception ex) {
LOG.log(Level.SEVERE, "Can't open URL : " + link, ex);
}
}
});
JOptionPane.showMessageDialog(this, label, "About", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(this.getIconImage()));
}//GEN-LAST:event_menuAboutActionPerformed
private void menuViewKnowledgeBaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuViewKnowledgeBaseActionPerformed
if (lastContext == null) {
return;
}
final KnowledgeBaseSnapshotViewDialog dialog = new KnowledgeBaseSnapshotViewDialog(this, lastContext);
dialog.setSize(600, 400);
dialog.setLocationRelativeTo(this);
dialog.setVisible(true);
}//GEN-LAST:event_menuViewKnowledgeBaseActionPerformed
private void menuRunStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuRunStopActionPerformed
buttonStopExecutingActionPerformed(evt);
}//GEN-LAST:event_menuRunStopActionPerformed
private void menuHelpHelpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuHelpHelpActionPerformed
new HelpDialog(this).setVisible(true);
}//GEN-LAST:event_menuHelpHelpActionPerformed
private void menuEditOptionsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuEditOptionsActionPerformed
OptionsDialog dialog = new OptionsDialog(this, new TreeModel[]{sourceEditor, dialogEditor, messageEditor, traceEditor});
dialog.setVisible(true);
}//GEN-LAST:event_menuEditOptionsActionPerformed
private void menuItemLibraryInfoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuItemLibraryInfoActionPerformed
final java.util.List<String> list = new ArrayList<String>(PROL_LIBRARIES.length + 2);
list.add(ProlCoreLibrary.class.getCanonicalName());
list.addAll(Arrays.asList(PROL_LIBRARIES));
list.add(MainFrame.class.getCanonicalName() + "$LogLibrary");
final LibraryInfoDialog infoDialog;
try {
infoDialog = new LibraryInfoDialog(this, list.toArray(new String[list.size()]));
}
catch (Exception ex) {
LOG.throwing(this.getClass().getCanonicalName(), "MenuItemLibraryInfoActionPerformed()", ex);
this.messageEditor.addErrorText("Can't show library info dialog [" + ex.getMessage() + ']');
return;
}
infoDialog.setSize(512, 480);
infoDialog.setLocationRelativeTo(this);
infoDialog.setVisible(true);
infoDialog.dispose();
}//GEN-LAST:event_menuItemLibraryInfoActionPerformed
private void menuItemWordWrapSourcesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuItemWordWrapSourcesActionPerformed
this.sourceEditor.setEdWordWrap(this.menuItemWordWrapSources.isSelected());
}//GEN-LAST:event_menuItemWordWrapSourcesActionPerformed
private void menuFileNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuFileNewActionPerformed
final Thread executingThread = this.currentExecutedScriptThread.get();
if (executingThread != null && executingThread.isAlive()) {
JOptionPane.showMessageDialog(this, "Wait until current Prolog application is completed.", "Can't create new one", JOptionPane.WARNING_MESSAGE);
}
else {
if (this.documentHasBeenChangedFlag) {
if (JOptionPane.showConfirmDialog(this, "Document is changed and not saved. Do you really want to make new one?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
newFile();
}
}
else {
newFile();
}
}
}//GEN-LAST:event_menuFileNewActionPerformed
private long extractStackDepth() {
final long MINIMAL_STACK = 5 * 1024 * 1024;
long stackSize = MINIMAL_STACK;
final String definedProlStackDepth = System.getProperty(PROPERTY_PROL_STACK_DEPTH);
if (definedProlStackDepth != null) {
int scale = 1;
final String trimmed = definedProlStackDepth.trim().toLowerCase(Locale.ENGLISH);
String text = trimmed;
if (trimmed.endsWith("m")) {
scale = 1024 * 1024;
text = trimmed.substring(0, trimmed.length() - 1);
}
else if (trimmed.endsWith("k")) {
scale = 1024;
text = trimmed.substring(0, trimmed.length() - 1);
}
try {
stackSize = Math.max(MINIMAL_STACK, Long.parseLong(text) * scale);
}
catch (NumberFormatException ex) {
LOG.log(Level.SEVERE, "Can't extract stack depth value [" + definedProlStackDepth + ']', ex);
}
}
return stackSize;
}
private void startExecution(final boolean tracing) {
final Thread executingThread = this.currentExecutedScriptThread.get();
if (executingThread != null && executingThread.isAlive()) {
JOptionPane.showMessageDialog(this, "Prolog program is already started!.", "Can't trace", JOptionPane.WARNING_MESSAGE);
}
else {
if (!this.currentExecutedScriptThread.compareAndSet(executingThread, null)) {
return;
}
final long stackSize = extractStackDepth();
if (tracing) {
LOG.info("Start TRACING with the stack depth " + stackSize + " bytes");
}
else {
LOG.info("Start execution with the stack depth " + stackSize + " bytes");
}
final Thread newThread = new Thread(this.executingScripts, this, tracing ? "JPROL_TRACING_EXEC" : "JPROL_EXEC", stackSize);
newThread.setDaemon(false);
if (this.currentExecutedScriptThread.compareAndSet(null, newThread)) {
this.startedInTracing.set(tracing);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
clearTextAtAllWindowsExcludeSource();
dialogEditor.initBeforeSession();
showTaskControlPanel();
newThread.start();
}
});
}
}
}
private void menuTraceScriptActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuTraceScriptActionPerformed
startExecution(true);
}//GEN-LAST:event_menuTraceScriptActionPerformed
private void menuFileRecentFilesMenuSelected(javax.swing.event.MenuEvent evt) {//GEN-FIRST:event_menuFileRecentFilesMenuSelected
JMenu menu = (JMenu) evt.getSource();
menu.removeAll();
for (final String path : this.recentFiles.getCollection()) {
final JMenuItem newItem = new JMenuItem(path);
newItem.setActionCommand(path);
newItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
final String text = e.getActionCommand();
if (text != null) {
try {
loadFile(new File(text), true);
}
catch (Exception ex) {
LOG.throwing(this.getClass().getCanonicalName(), "MenuFileRecentFilesMenuSelected()", ex);
}
}
}
});
menu.add(newItem);
}
}//GEN-LAST:event_menuFileRecentFilesMenuSelected
private void menuEditCommentSelectedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuEditCommentSelectedActionPerformed
// TODO add your handling code here:
if (this.sourceEditor.commentSelectedLines()) {
documentChanged();
}
}//GEN-LAST:event_menuEditCommentSelectedActionPerformed
private void menuEditUncommentSelectedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuEditUncommentSelectedActionPerformed
// TODO add your handling code here:
if (this.sourceEditor.uncommentSelectedLines()) {
documentChanged();
}
}//GEN-LAST:event_menuEditUncommentSelectedActionPerformed
private void menuItemFullScreenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuItemFullScreenActionPerformed
final GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
if (gd != null && gd.isFullScreenSupported()) {
if (gd.getFullScreenWindow() == null) {
gd.setFullScreenWindow(this);
}
else {
gd.setFullScreenWindow(null);
}
}
}//GEN-LAST:event_menuItemFullScreenActionPerformed
private void menuitemFindTextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuitemFindTextActionPerformed
this.panelFindText.setVisible(true);
this.textFind.setText("");
this.textFind.requestFocus();
}//GEN-LAST:event_menuitemFindTextActionPerformed
private int searchText(final String text, final Pattern pattern, final int cursorPos) {
if (cursorPos >= text.length()) {
return -1;
}
final Matcher matcher = pattern.matcher(text);
if (matcher.find(cursorPos)) {
return matcher.start();
}
return -1;
}
private void textFindKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_textFindKeyReleased
if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
final Pattern patternToFind = UIUtils.makePattern(textFind.getText());
final String text = this.sourceEditor.getText();
int cursorPos = searchText(text, patternToFind, this.sourceEditor.getCaretPosition() + 1);
if (cursorPos < 0) {
cursorPos = searchText(text, patternToFind, 0);
}
if (cursorPos >= 0) {
this.sourceEditor.setCaretPosition(cursorPos);
}
}
}//GEN-LAST:event_textFindKeyReleased
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton buttonCloseFind;
private javax.swing.JButton buttonStopExecuting;
private com.igormaznitsa.prol.easygui.DialogEditor dialogEditor;
private javax.swing.JPanel editorPanel;
private javax.swing.Box.Filler filler1;
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JPopupMenu.Separator jSeparator1;
private javax.swing.JPopupMenu.Separator jSeparator2;
private javax.swing.JPopupMenu.Separator jSeparator3;
private javax.swing.JPopupMenu.Separator jSeparator4;
private javax.swing.JPopupMenu.Separator jSeparator5;
private javax.swing.JLabel labelFind;
private javax.swing.JMenuItem menuAbout;
private javax.swing.JMenuItem menuClearText;
private javax.swing.JMenu menuEdit;
private javax.swing.JMenuItem menuEditCommentSelected;
private javax.swing.JMenuItem menuEditOptions;
private javax.swing.JMenuItem menuEditUncommentSelected;
private javax.swing.JMenuItem menuExit;
private javax.swing.JMenu menuFile;
private javax.swing.JMenuItem menuFileNew;
private javax.swing.JMenuItem menuFileOpen;
private javax.swing.JMenu menuFileRecentFiles;
private javax.swing.JMenuItem menuFileSave;
private javax.swing.JMenuItem menuFileSaveAs;
private javax.swing.JMenu menuHelp;
private javax.swing.JMenuItem menuHelpHelp;
private javax.swing.JMenuItem menuItemFullScreen;
private javax.swing.JMenuItem menuItemLibraryInfo;
private javax.swing.JCheckBoxMenuItem menuItemWordWrapSources;
private javax.swing.JMenu menuLookAndFeel;
private javax.swing.JMenuItem menuRedo;
private javax.swing.JMenu menuRun;
private javax.swing.JMenuItem menuRunScript;
private javax.swing.JMenuItem menuRunStop;
private javax.swing.JMenuItem menuTraceScript;
private javax.swing.JMenuItem menuUndo;
private javax.swing.JMenu menuView;
private javax.swing.JMenuItem menuViewKnowledgeBase;
private javax.swing.JMenuItem menuitemFindText;
private com.igormaznitsa.prol.easygui.MessageEditor messageEditor;
private javax.swing.JPanel panelFindText;
private javax.swing.JPanel panelProgress;
private javax.swing.JProgressBar progressBarTask;
private com.wordpress.tips4java.TextLineNumber sourceEditor;
private javax.swing.JSplitPane splitPaneMain;
private javax.swing.JSplitPane splitPaneTop;
private javax.swing.JSplitPane splitPanelDown;
private javax.swing.JTextField textFind;
private com.igormaznitsa.prol.easygui.TraceDialog traceEditor;
// End of variables declaration//GEN-END:variables
private void setLastContext(ProlContext context) {
this.lastContext = context;
this.menuViewKnowledgeBase.setEnabled(lastContext != null);
}
@Override
public Reader getReaderForResource(String resourceName) throws IOException {
boolean successful = false;
boolean notTraceable = false;
try {
if (resourceName.equals("user")) {
successful = true;
notTraceable = true;
return this.dialogEditor.getInputReader();
}
else {
final FileReader reader = new FileReader(resourceName);
successful = true;
notTraceable = false;
return reader;
}
}
finally {
if (!notTraceable) {
if (successful) {
this.messageEditor.addInfoText("The reader for \'" + resourceName + "\' has been opened.");
}
else {
this.messageEditor.addWarningText("The reader for \'" + resourceName + "\' can't be opened.");
}
}
}
}
@Override
public Writer getWriterForResource(String resourceName, boolean append) throws IOException {
boolean successful = false;
boolean notTraceable = false;
try {
if (resourceName.equals("user")) {
successful = true;
notTraceable = true;
return this.dialogEditor.getOutputWriter();
}
else {
final Writer writer = new FileWriter(resourceName);
successful = true;
notTraceable = false;
return writer;
}
}
finally {
if (!notTraceable) {
if (successful) {
this.messageEditor.addInfoText("The writer for \'" + resourceName + "\' has been opened.");
}
else {
this.messageEditor.addWarningText("The writer for \'" + resourceName + "\' can't be opened.");
}
}
}
}
@Override
public void run() {
ProlContext context = null;
boolean successfully = false;
boolean canceled = false;
ProlHaltExecutionException halted = null;
ParserException parserException = null;
long startTime = 0;
final Thread executing = this.currentExecutedScriptThread.get();
try {
this.dialogEditor.setEnabled(true);
this.dialogEditor.requestFocus();
this.messageEditor.addInfoText("Creating Context...");
try {
context = new ProlContext("ProlScript", this);
if (this.startedInTracing.get()) {
context.setDefaultTraceListener(this);
}
for (final String str : PROL_LIBRARIES) {
final ProlAbstractLibrary lib = (ProlAbstractLibrary) Class.forName(str).newInstance();
context.addLibrary(lib);
this.messageEditor.addInfoText("Library \'" + lib.getLibraryUID() + "\' has been added...");
}
context.addLibrary(logLibrary);
this.messageEditor.addInfoText("Library \'" + logLibrary.getLibraryUID() + "\' has been added...");
setLastContext(context);
}
catch (Throwable ex) {
LOG.log(Level.WARNING, "ExecutionThread.run()", ex);
this.messageEditor.addErrorText("Can't create context for exception [" + ex.getMessage() + ']');
return;
}
this.messageEditor.addInfoText("Consult with the script... ");
final ProlConsult consult = new ProlConsult(sourceEditor.getText(), context);
startTime = System.currentTimeMillis();
try {
consult.consult();
// wait for async threads
context.getContextExecutorService().shutdown();
context.getContextExecutorService().awaitTermination(60, TimeUnit.SECONDS);
}
catch (ParserException ex) {
LOG.log(Level.WARNING, "ExecutionThread.run()", ex);
parserException = ex;
final Throwable cause = ex.getCause();
if (cause instanceof StackOverflowError) {
this.messageEditor.addErrorText("Stack Overflow!");
JOptionPane.showMessageDialog(this, "Stack overflow exception detected!", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
else if (cause instanceof OutOfMemoryError) {
this.messageEditor.addErrorText("Out of Memory!");
JOptionPane.showMessageDialog(this, "Out of Memory exception detected!", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
if (cause instanceof ProlHaltExecutionException) {
halted = (ProlHaltExecutionException) ex.getCause();
}
if (cause instanceof InterruptedException) {
canceled = true;
}
else {
this.messageEditor.addText("Parser exception [" + ex.getMessage() + ']', MessageEditor.TYPE_ERROR, "source://" + ex.getLine() + ';' + ex.getPos(), "line " + ex.getLine() + ":" + ex.getPos());
return;
}
}
catch (ThreadDeath death) {
canceled = true;
}
catch (Throwable ex) {
LOG.log(Level.WARNING, "ExecutionThread.run()", ex);
if (ex instanceof ProlHaltExecutionException || ex.getCause() instanceof ProlHaltExecutionException) {
if (ex instanceof ProlHaltExecutionException) {
halted = (ProlHaltExecutionException) ex;
}
else {
halted = (ProlHaltExecutionException) ex.getCause();
}
}
else {
this.messageEditor.addErrorText("Can't parse script for exception [" + ex.getMessage() + ']');
return;
}
}
successfully = true;
}
finally {
try {
this.messageEditor.addInfoText("Total time " + ((System.currentTimeMillis() - startTime) / 1000f) + " sec.");
if (halted == null) {
if (!canceled) {
if (successfully) {
this.messageEditor.addInfoText("Completed successfully.");
}
else {
this.messageEditor.addErrorText("Completed with errors or not started.");
}
}
}
else {
this.messageEditor.addText("Halted [" + halted.getMessage() + ']', MessageEditor.TYPE_WARNING, parserException != null ? ("source://" + parserException.getLine() + ';' + parserException.getPos()) : null, parserException != null ? ("line " + parserException.getLine() + ":" + parserException.getPos()) : null);
}
this.dialogEditor.setEnabled(false);
this.currentExecutedScriptThread.compareAndSet(executing, null);
}
finally {
if (context != null) {
try {
context.halt();
}
catch (IllegalStateException ex) {
}
}
hideTaskControlPanel();
}
}
}
@Override
public void undoableEditHappened(final UndoableEditEvent e) {
final UndoManager undo = this.sourceEditor.getUndoManager();
undo.addEdit(e.getEdit());
this.menuUndo.setEnabled(undo.canUndo());
this.menuRedo.setEnabled(undo.canRedo());
}
@Override
public void windowOpened(final WindowEvent e) {
}
@Override
public void windowClosing(final WindowEvent e) {
if (this.documentHasBeenChangedFlag) {
if (JOptionPane.showConfirmDialog(this, "Document is changed but not saved. Do you really want to exit?", "Confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
return;
}
}
if (this.currentExecutedScriptThread.get() != null) {
if (JOptionPane.showConfirmDialog(this, "Task is under execution. Do you really want to exit?", "Confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
this.dialogEditor.cancelRead();
this.dialogEditor.close();
final Thread executingThread = this.currentExecutedScriptThread.get();
try {
executingThread.interrupt();
executingThread.join();
}
catch (Throwable thr) {
}
}
else {
return;
}
}
else {
this.dialogEditor.cancelRead();
this.dialogEditor.close();
}
savePreferences();
try {
this.dispose();
}
catch (Exception ex) {
}
finally {
System.exit(0);
}
}
@Override
public void windowClosed(final WindowEvent e) {
}
@Override
public void windowIconified(final WindowEvent e) {
}
@Override
public void windowDeiconified(final WindowEvent e) {
}
@Override
public void windowActivated(final WindowEvent e) {
if (this.currentExecutedScriptThread != null) {
this.dialogEditor.requestFocus();
}
else {
this.sourceEditor.requestFocus();
}
}
@Override
public void windowDeactivated(final WindowEvent e) {
}
@Override
public void insertUpdate(final DocumentEvent e) {
documentChanged();
}
@Override
public void removeUpdate(final DocumentEvent e) {
documentChanged();
}
@Override
public void changedUpdate(final DocumentEvent e) {
documentChanged();
}
private void documentChanged() {
if (!this.documentHasBeenChangedFlag) {
this.documentHasBeenChangedFlag = true;
if (this.currentOpenedFile != null) {
this.menuFileSave.setEnabled(true);
}
setTitle("*" + getTitle());
}
}
private void setTextToDocument(final String text) {
this.sourceEditor.clearText();
this.sourceEditor.getEditor().setText(text);
this.sourceEditor.setCaretPosition(0);
if (this.currentOpenedFile != null) {
this.menuFileSave.setEnabled(true);
}
else {
this.menuFileSave.setEnabled(false);
}
this.sourceEditor.getUndoManager().discardAllEdits();
this.menuUndo.setEnabled(false);
this.menuRedo.setEnabled(false);
this.documentHasBeenChangedFlag = false;
}
private void saveFile(final boolean saveAs) {
File file = this.currentOpenedFile;
if (saveAs || this.currentOpenedFile == null) {
JFileChooser fileChooser = new JFileChooser(file);
fileChooser.addChoosableFileFilter(PROL_FILE_FILTER);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setDragEnabled(false);
fileChooser.setMultiSelectionEnabled(false);
if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
file = fileChooser.getSelectedFile();
if (!file.exists() && fileChooser.getFileFilter().equals(PROL_FILE_FILTER)) {
// ake auto extension
if (!file.getName().toLowerCase().endsWith(PROL_EXTENSION)) {
file = new File(file.getAbsolutePath() + PROL_EXTENSION);
}
}
if (saveAs || !file.equals(this.currentOpenedFile)) {
if (file.exists()) {
if (JOptionPane.showConfirmDialog(this, "File \'" + file.getAbsolutePath() + "\' exists, to overwrite it?", "File exists", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
return;
}
}
}
}
else {
return;
}
}
final String textFromEditor = this.sourceEditor.getEditor().getText();
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false), "UTF-8"));
writer.write(textFromEditor);
writer.flush();
this.recentFiles.put(file.getAbsolutePath());
}
catch (Throwable thr) {
LOG.throwing(this.getClass().getCanonicalName(), "saveFile()", thr);
JOptionPane.showMessageDialog(this, "Can't save file for error \'" + (thr.getMessage() == null ? thr.getClass().getCanonicalName() : thr.getLocalizedMessage()), "Can't save file", JOptionPane.ERROR_MESSAGE);
return;
}
finally {
if (writer != null) {
try {
writer.close();
}
catch (Throwable thr) {
}
}
}
this.currentOpenedFile = file;
this.lastOpenedFile = currentOpenedFile;
setTitle(this.currentOpenedFile.getAbsolutePath());
this.sourceEditor.getUndoManager().discardAllEdits();
this.menuFileSave.setEnabled(true);
this.documentHasBeenChangedFlag = false;
}
private void newFile() {
// make new
this.sourceEditor.clearText();
clearTextAtAllWindowsExcludeSource();
this.currentOpenedFile = null;
this.documentHasBeenChangedFlag = false;
setTitle("The Prol Notepad utility. Version: " + VERSION);
repaint();
}
private void clearTextAtAllWindowsExcludeSource() {
this.traceEditor.clearText();
this.dialogEditor.clearText();
this.messageEditor.clearText();
}
private void loadFile(final File file, final boolean justLoadFile) {
if (this.documentHasBeenChangedFlag) {
if (JOptionPane.showConfirmDialog(this, "Document is changed and not saved. To load new one?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.NO_OPTION) {
return;
}
}
JFileChooser fileChooser = new JFileChooser(file);
if (!justLoadFile) {
fileChooser.addChoosableFileFilter(PROL_FILE_FILTER);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setDragEnabled(false);
fileChooser.setMultiSelectionEnabled(false);
fileChooser.setFileFilter(PROL_FILE_FILTER);
}
if (justLoadFile || fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File fileToOpen = justLoadFile ? file : fileChooser.getSelectedFile();
this.lastOpenedFile = fileToOpen;
Reader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileToOpen), "UTF-8"));
final StringBuilder buffer = new StringBuilder((int) fileToOpen.length() < 0 ? 16384 : (int) fileToOpen.length());
while (true) {
final int chr = reader.read();
if (chr < 0) {
break;
}
buffer.append((char) chr);
}
setTextToDocument(buffer.toString());
this.currentOpenedFile = fileToOpen;
setTitle(this.currentOpenedFile.getCanonicalPath());
this.repaint();
this.recentFiles.put(fileToOpen.getAbsolutePath());
}
catch (Throwable thr) {
LOG.throwing(this.getClass().getCanonicalName(), "loadFile()", thr);
JOptionPane.showMessageDialog(this, "Can't load file " + fileToOpen.getAbsolutePath() + " [" + thr.getMessage() + "]");
this.recentFiles.remove(fileToOpen.getAbsolutePath());
}
finally {
if (reader != null) {
try {
reader.close();
}
catch (Throwable thr) {
}
}
}
}
}
private void showTaskControlPanel() {
this.panelProgress.setVisible(true);
this.progressBarTask.setIndeterminate(true);
this.menuRunStop.setEnabled(true);
}
private void hideTaskControlPanel() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
panelProgress.setVisible(false);
progressBarTask.setIndeterminate(false);
menuRunStop.setEnabled(false);
}
});
}
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) {
return;
}
String path = e.getDescription();
if (path.startsWith("source://")) {
path = path.substring(9);
String[] parsed = path.split(";");
if (parsed.length == 2) {
try {
int line = Integer.parseInt(parsed[0].trim());
int pos = Integer.parseInt(parsed[1].trim());
this.sourceEditor.setCaretPosition(line, pos + 1);
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
private void loadPreferences() {
final Preferences prefs = Preferences.userNodeForPackage(this.getClass());
setSelectedLookAndFeel(prefs.get("lookandfeel", menuLookAndFeel.getItem(0).getText()));
int recentFileIndex = 1;
this.recentFiles.clear();
while (true) {
final String path = prefs.get("RecentFile" + recentFileIndex, null);
if (path == null) {
break;
}
this.recentFiles.add(path);
recentFileIndex++;
}
if (prefs.getBoolean("maximized", false)) {
setExtendedState(JFrame.MAXIMIZED_BOTH);
invalidate();
doLayout();
}
else {
setSize(prefs.getInt("mainwidth", 640), prefs.getInt("mainheight", 600));
setLocation(prefs.getInt("mainx", 0), prefs.getInt("mainy", 0));
}
this.splitPaneMain.setDividerLocation(prefs.getInt("splitpanemainpos", 400));
this.splitPaneTop.setDividerLocation(prefs.getInt("splitpanetoppos", 300));
final String lastFile = prefs.get("lastfile", "");
if (lastFile.length() > 0) {
this.lastOpenedFile = new File(lastFile);
}
else {
this.lastOpenedFile = null;
}
this.sourceEditor.loadPreferences(prefs);
this.messageEditor.loadPreferences(prefs);
this.dialogEditor.loadPreferences(prefs);
this.traceEditor.loadPreferences(prefs);
}
private void savePreferences() {
final Preferences prefs = Preferences.userNodeForPackage(this.getClass());
LookAndFeelInfo currentInfo = null;
final String landfClass = UIManager.getLookAndFeel().getClass().getName();
for (final LookAndFeelInfo i : UIManager.getInstalledLookAndFeels()) {
if (i.getClassName().equals(landfClass)) {
currentInfo = i;
break;
}
}
if (currentInfo != null) {
prefs.put("lookandfeel", currentInfo.getName());
}
int recentFileIndex = 1;
for (final String recentFile : this.recentFiles.getCollection()) {
prefs.put("RecentFile" + recentFileIndex, recentFile);
recentFileIndex++;
}
prefs.putBoolean("maximized", (getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH);
prefs.putInt("mainwidth", getWidth());
prefs.putInt("mainheight", getHeight());
prefs.putInt("mainx", getX());
prefs.putInt("mainy", getY());
prefs.putInt("splitpanemainpos", splitPaneMain.getDividerLocation());
prefs.putInt("splitpanetoppos", splitPaneTop.getDividerLocation());
prefs.put("lastfile", this.lastOpenedFile == null ? "" : this.lastOpenedFile.getAbsolutePath());
this.sourceEditor.savePreferences(prefs);
this.messageEditor.savePreferences(prefs);
this.dialogEditor.savePreferences(prefs);
this.traceEditor.savePreferences(prefs);
}
}