package vg.modules.notepad;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.*;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.swing.*;
import vg.core.VisualGraph;
import vg.core.event.UIEventCloseAIF;
import vg.core.event.UIEventCreateNewConnection;
import vg.core.event.UIEventDeleteConnection;
import vg.core.plugin.PluginParameter;
import vg.core.request.UIRequestGoToInAIF;
import vg.modules.notepad.components.ConnectionStatistic;
import vg.modules.notepad.components.Desktop;
import vg.modules.notepad.components.connectorComponent.Connector;
import vg.modules.notepad.components.textComponent.ITextComponent;
import vg.modules.notepad.components.textComponent.TextComponent;
import vg.userInterface.swingComponents.SimpleStatusBar;
/**
* This is a class for reading of the documents,
* has the ability to copy, cut, paste & select all text.
* @author tzolotuhin
*/
public class Notepad extends JFrame{
private static final long serialVersionUID = 1L;
// Main data
private boolean init = false;
private List<UIEventCreateNewConnection>connections;
private PluginParameter param;
// Toolbar
private JToolBar toolBar;
// Status bar
private SimpleStatusBar statusBar;
// Buttons
private JButton openButton;
private JButton searchButton, connectButton, connectionStatisticButton;
private JTextField searchField;
// Panels
private Desktop desktop;
private Connector connector;
private ConnectionStatistic connectionStatistic;
// Mutex
private final Object theMutexObject;
// Defines
private final String DEF_NOTEPAD_FOLDER = "NotepadPluginSave";
//-------------------------------------------------------------------------
private final static String DEF_WINDOWS_SIZE_X = "NotepadPlugin_WindowSizeX";
private final static String DEF_WINDOWS_SIZE_Y = "NotepadPlugin_WindowSizeY";
private final static String DEF_WINDOWS_POS_X = "NotepadPlugin_WindowPosX";
private final static String DEF_WINDOWS_POS_Y = "NotepadPlugin_WindowPosY";
private Integer windowSizeX, windowSizeY;
private Integer windowPosX, windowPosY;
//-------------------------------------------------------------------------
/**
* Constructor of Notepad.
*/
public Notepad(final PluginParameter param){
// save input parameter
this.param = param;
// init mutex
this.theMutexObject = new Object();
}
/**
* This method opens notepad.
*/
public void open() {
synchronized (this.theMutexObject) {
if(!init) {
if(SwingUtilities.isEventDispatchThread()) {
init();
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
init();
};
});
}
}
// open notepad
if(SwingUtilities.isEventDispatchThread()) {
this.setVisible(true);
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Notepad.this.setVisible(true);
};
});
}
}
}
/**
* This method closes notepad.
*/
public void close() {
synchronized (theMutexObject) {
if(SwingUtilities.isEventDispatchThread()) {
dispose();
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
synchronized (theMutexObject) {
dispose();
}
};
});
}
}
}
public void closeAIF(final UIEventCloseAIF aif) {
synchronized (theMutexObject) {
for(UIEventCreateNewConnection buf : this.connections) {
if(aif != null && buf.getFileId() == aif.getFileId()) {
this.connections.remove(buf);
UIEventDeleteConnection event = new UIEventDeleteConnection(buf.getConnectionId());
this.param.userInterface.addEvent(event);
break;
}
}
}
}
public void addConnection(final UIEventCreateNewConnection connect) {
synchronized (theMutexObject) {
this.connections.add(connect);
this.connectionStatistic.addConnection(connect);
}
}
public void deleteConnection(final UIEventDeleteConnection connect) {
synchronized (theMutexObject) {
for(UIEventCreateNewConnection buf : this.connections) {
if(connect != null && buf.getConnectionId() == connect.getConnectId()) {
this.connections.remove(buf);
this.connectionStatistic.removeConnection(buf.getConnectionId());
break;
}
}
}
}
/**
* This method updates user interface theme.
*/
public void updateUITheme() {
synchronized (theMutexObject) {
if(init) {
if(SwingUtilities.isEventDispatchThread()) {
SwingUtilities.updateComponentTreeUI(Notepad.this);
desktop.updateUITheme();
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
synchronized (theMutexObject) {
SwingUtilities.updateComponentTreeUI(Notepad.this);
desktop.updateUITheme();
}
}
});
}
}
}
}
public void goToAIF(final UIRequestGoToInAIF aif) {
synchronized (theMutexObject) {
for(UIEventCreateNewConnection buf : this.connections) {
if(aif != null && buf.getConnectionId() == aif.getConnectId()) {
ITextComponent tc = this.desktop.getComponent(buf.getFileId());
if(tc != null) {
tc.selectAnchor(aif.getAnchorValue());
}
this.desktop.selectTabAt(buf.getFileId());
break;
}
}
}
}
public void reset() {
synchronized (theMutexObject) {
this.desktop.closeAllTab();
this.connectionStatistic.removeAllConnections();
}
}
public void saveProject(String path) {
synchronized (theMutexObject) {
// create folder for saving of different parts of notepad
File outputFolder = new File(path + File.separator + DEF_NOTEPAD_FOLDER);
if(outputFolder.exists()) {
deleteDirectory(outputFolder);
}
if(!outputFolder.mkdir()) {
VisualGraph.windowMessage.errorMessage("Can't save notepad's files and current connections.", "Save notepad's files");
return;
}
for(UIEventCreateNewConnection buf : this.connections) {
File dir = new File(outputFolder.getAbsolutePath() + File.separator + buf.toString());
if(!dir.mkdir()) {
VisualGraph.windowMessage.errorMessage("Can't save notepad's files.", "Save notepad's files");
return;
}
try {
File oldFile = new File(this.desktop.getFullFileNameAt(buf.getFileId()));
File newFile = new File(dir.getAbsolutePath() + File.separator + oldFile.getName());
//we dont want have problems with coping file into itself
if (oldFile.compareTo(newFile) == 0) {
continue;
}
FileChannel originalGraphFile = new FileInputStream(oldFile).getChannel();
FileChannel copyFile = new FileOutputStream(newFile).getChannel();
try {
originalGraphFile.transferTo(0, originalGraphFile.size(), copyFile);
} catch (IOException e1) {
throw e1;
} finally {
if (originalGraphFile != null)
originalGraphFile.close();
if (copyFile != null)
copyFile.close();
}
} catch (IOException e1) {
VisualGraph.log.printException(e1);
}
}
// save connections
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File(outputFolder + File.separator + "connections.txt"));
DataOutputStream dos = new DataOutputStream(fos);
for(UIEventCreateNewConnection buf : this.connections) {
dos.writeBytes("Connection #" + buf.getConnectionId());dos.writeBytes("\r\n");
dos.writeBytes(buf.getConnectionName());dos.writeBytes("\r\n");
dos.writeBytes(Integer.valueOf(buf.getFileId()).toString());dos.writeBytes("\r\n");
dos.writeBytes(Integer.valueOf(buf.getGraphId()).toString());dos.writeBytes("\r\n");
dos.writeBytes(buf.getGraphName());dos.writeBytes("\r\n");
dos.writeBytes(buf.getAnchor());dos.writeBytes("\r\n");
}
} catch (IOException ex) {
VisualGraph.windowMessage.errorMessage("Can't save connections.", "Save notepad's files");
} finally {
if(fos != null) {
try {
fos.close();
} catch (Exception ex) {
}
}
}
}
}
public void loadProject(String path) {
synchronized (theMutexObject) {
File inputFolder = new File(path + File.separator + DEF_NOTEPAD_FOLDER);
if(inputFolder.exists() && inputFolder.isDirectory()) {
// load notepad's files
String[] dirs = inputFolder.list();
for(int i = 0; i < dirs.length; i++) {
File innerDir = new File(inputFolder.getAbsolutePath() + File.separator + dirs[i]);
if(innerDir.exists()) {
String[] list = innerDir.list();
if(list != null) {
if(list.length >= 1) {
final File workFile = new File(innerDir.getAbsolutePath() + File.separator + list[0]);
if(SwingUtilities.isEventDispatchThread()) {
ITextComponent tc = open(workFile);
if(tc != null) {
try {
Integer tabId = new Integer(dirs[i]);
this.desktop.addTab(tabId, workFile.getName(), workFile.getAbsolutePath(), tc);
} catch (Throwable ex) {
}
}
} else {
final String tmp = dirs[i];
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ITextComponent tc = open(workFile);
if(tc != null) {
try {
Integer tabId = new Integer(tmp);
Notepad.this.desktop.addTab(tabId, workFile.getName(), workFile.getAbsolutePath(), tc);
} catch (Throwable ex) {
}
}
}
});
}
}
}
}
}
// load connections
File connectionsFile = new File(inputFolder.getAbsolutePath() + File.separator + "connections.txt");
if (connectionsFile.exists()) {
FileInputStream fis = null;
try {
fis = new FileInputStream(connectionsFile);
Scanner scanner = new Scanner(fis);
while(scanner.hasNext()) {
scanner.nextLine();
String connectionName = scanner.nextLine();
int fileId = scanner.nextInt();
int graphId = scanner.nextInt();scanner.nextLine();
String graphName = scanner.nextLine();
String anchor = scanner.nextLine();
this.connector.addConnection(connectionName, anchor, graphId, graphName, fileId);
}
} catch (Throwable ex) {
VisualGraph.windowMessage.errorMessage("Can't load connections.", "Load notepad's files");
} finally {
if(fis != null) {
try {
fis.close();
} catch (Exception ex) {
}
}
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
///////////////////////////////////////////////////////////////////////////
/**
* Initializes all swing(and other) graphical components.
*/
private void init() {
this.init = true;
//set the title for Notepad and set the size for it.
loadWindowOptions();
this.setTitle("Notepad");
this.setSize(this.windowSizeX, this.windowSizeY);
this.setLocation(this.windowPosX, this.windowPosY);
this.setDefaultCloseOperation(HIDE_ON_CLOSE);
this.setLayout(new BorderLayout());
this.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
super.componentResized(e);
Component c = (Component)e.getSource();
Integer sizeX = c.getSize().width;
Integer sizeY = c.getSize().height;
VisualGraph.config.setProperty(DEF_WINDOWS_SIZE_X, sizeX.toString());
VisualGraph.config.setProperty(DEF_WINDOWS_SIZE_Y, sizeY.toString());
}
public void componentMoved(ComponentEvent e) {
super.componentMoved(e);
Component c = (Component)e.getSource();
Integer posX = c.getLocation().x;
Integer posY = c.getLocation().y;
VisualGraph.config.setProperty(DEF_WINDOWS_POS_X, posX.toString());
VisualGraph.config.setProperty(DEF_WINDOWS_POS_Y, posY.toString());
}
});
// init main data
this.connections = new ArrayList<UIEventCreateNewConnection>();
// create components
this.connector = new Connector(param, this);
this.connectionStatistic = new ConnectionStatistic(this, param);
this.toolBar = new JToolBar("Tool Bar");
this.toolBar.setLayout(new GridBagLayout());
this.toolBar.setFloatable(false);
this.desktop = new Desktop(param);
this.statusBar = new SimpleStatusBar();
this.openButton = new JButton(new ImageIcon("./data/resources/textures/notepad/openFile.png"));
this.openButton.setToolTipText("Open file");
this.searchButton = new JButton(new ImageIcon("./data/resources/textures/notepad/search.png"));
this.searchButton.setToolTipText("Search");
this.searchButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
synchronized (theMutexObject) {
find();
}
}
});
this.searchField = new JTextField();
this.searchField.setColumns(15);
this.searchField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
synchronized (theMutexObject) {
find();
}
}
});
this.connectButton = new JButton(new ImageIcon("./data/resources/textures/notepad/addConnection.png"));
this.connectButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
synchronized (theMutexObject) {
int fileId = Notepad.this.desktop.getCurrentId();
for(UIEventCreateNewConnection buf : Notepad.this.connections) {
if(buf.getFileId() == fileId) {
Notepad.this.connector.replace(buf.getConnectionId(), buf.getConnectionName(), fileId, buf.getGraphId(), buf.getAnchor());
return;
}
}
String shortName = Notepad.this.desktop.getCurrentShortFileName();
Notepad.this.connector.open(fileId, shortName);
}
}
});
this.connectionStatisticButton = new JButton(new ImageIcon("./data/resources/textures/notepad/editConnection.png"));
this.connectionStatisticButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
synchronized (theMutexObject) {
Notepad.this.connectionStatistic.open();
}
}
});
this.openButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
synchronized (theMutexObject) {
JFileChooser jfc = new JFileChooser(".");
int returnVal = jfc.showOpenDialog(Notepad.this); //to show JFileChooser
if(returnVal == JFileChooser.APPROVE_OPTION){
ITextComponent tc = open(jfc.getSelectedFile());
desktop.addTab(jfc.getSelectedFile().getName(), jfc.getSelectedFile().getAbsolutePath(), tc);
}
}
}
});
// pack ui
this.add(this.toolBar, BorderLayout.NORTH);
this.add(this.desktop.getView(), BorderLayout.CENTER);
this.add(this.statusBar, BorderLayout.SOUTH);
// pack toolbar
GridBagConstraints gbc = null;
gbc = new GridBagConstraints(0,0, 1,1, 0,0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0,0,0,0), 0,0);
this.toolBar.add(this.openButton, gbc);
gbc = new GridBagConstraints(1,0, 1,1, 0,0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0,0,0,0), 0,0);
this.toolBar.add(this.connectButton, gbc);
gbc = new GridBagConstraints(2,0, 1,1, 0,0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0,0,0,0), 0,0);
this.toolBar.add(this.connectionStatisticButton, gbc);
gbc = new GridBagConstraints(3,0, 1,1, 1,0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0,5,0,0), 0,0);
this.toolBar.add(this.searchField, gbc);
gbc = new GridBagConstraints(4,0, 1,1, 0,0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0,0,0,5), 0,0);
this.toolBar.add(this.searchButton, gbc);
// good
this.setVisible(false);
}
private ITextComponent open(File input) {
//to erase any text in the text area before adding new text
ITextComponent textComponent = new TextComponent();
StringBuffer str = new StringBuffer(1024*4);
Reader in = null;
try{
//to read the selected file
in = new FileReader(input);
//100000 is the max. char can be written in the text area
char[] buff = new char[100000];
int nch;
while((nch = in.read(buff, 0, buff.length)) != -1) {
str.append(new String(buff, 0, nch));
}
textComponent.setText(str.toString());
return(textComponent);
} catch(Exception ex){
VisualGraph.log.printException(ex);
} finally {
if(in != null) {
try {
in.close();
} catch (IOException ex) {
}
}
}
return(null);
}
private synchronized void find() {
String whatFind = this.searchField.getText();
ITextComponent textComponent = this.desktop.getCurrentTextComponent();
if(textComponent != null) {
textComponent.find(whatFind);
}
}
/**
* This method deletes non-empty directory.
*/
static public boolean deleteDirectory(File path) {
if (path.exists()) {
File[] files = path.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
deleteDirectory(files[i]);
} else {
files[i].delete();
}
}
}
return (path.delete());
}
/**
* This method loads window options.
*/
private void loadWindowOptions() {
String wSizeStrX = VisualGraph.config.getProperty(DEF_WINDOWS_SIZE_X);
String wSizeStrY = VisualGraph.config.getProperty(DEF_WINDOWS_SIZE_Y);
String wPosStrX = VisualGraph.config.getProperty(DEF_WINDOWS_POS_X);
String wPosStrY = VisualGraph.config.getProperty(DEF_WINDOWS_POS_Y);
//set size X(width of window)
if(wSizeStrX == null) {
this.windowSizeX = 800;
VisualGraph.config.setProperty(DEF_WINDOWS_SIZE_X, this.windowSizeX.toString());
} else {
try {
this.windowSizeX = new Integer(wSizeStrX);
} catch(NumberFormatException ex) {
this.windowSizeX = 800;
VisualGraph.config.setProperty(DEF_WINDOWS_SIZE_X, this.windowSizeX.toString());
}
}
//set size Y(height of window)
if(wSizeStrY == null) {
this.windowSizeY = 600;
VisualGraph.config.setProperty(DEF_WINDOWS_SIZE_Y, this.windowSizeY.toString());
} else {
try {
this.windowSizeY = new Integer(wSizeStrY);
} catch(NumberFormatException ex) {
this.windowSizeY = 600;
VisualGraph.config.setProperty(DEF_WINDOWS_SIZE_Y, this.windowSizeY.toString());
}
}
//set position X
if(wPosStrX == null) {
this.windowPosX = 800;
VisualGraph.config.setProperty(DEF_WINDOWS_POS_X, this.windowPosX.toString());
} else {
try {
this.windowPosX = new Integer(wPosStrX);
} catch(NumberFormatException ex) {
this.windowPosX = 800;
VisualGraph.config.setProperty(DEF_WINDOWS_POS_X, this.windowPosX.toString());
}
}
//set position Y
if(wPosStrY == null) {
this.windowPosY = 0;
VisualGraph.config.setProperty(DEF_WINDOWS_POS_Y, this.windowPosY.toString());
} else {
try {
this.windowPosY = new Integer(wPosStrY);
} catch(NumberFormatException ex) {
this.windowPosY = 0;
VisualGraph.config.setProperty(DEF_WINDOWS_POS_Y, this.windowPosY.toString());
}
}
}
}