All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.darwinsys.notepad.Notepad Maven / Gradle / Ivy

package com.darwinsys.notepad;

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.prefs.Preferences;

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import javax.swing.undo.UndoManager;

import com.darwinsys.io.FileSaver;
import com.darwinsys.swingui.UtilGUI;

/**
 * Simple text editor, relying heavily on the Swing JTextArea.
 * Is it MVC? Well, the JTextArea is the Model, the
 * Actions are Controllers, and the rest is View.
 */
@SuppressWarnings("serial")
public class Notepad {

	private JFrame theFrame;

	private JTextArea ta;

	private UndoManager undoManager;

	private JFileChooser chooser;

	private String fileName;

	private static List windows = new ArrayList();

	/** True if this is not imbedded in another application */
	private boolean isStandalone = true;

	private JMenu fm, em, hm;

	private FileSaver fileSaver;

	protected boolean dirty;

	protected Preferences prefsNode = Preferences.userNodeForPackage(getClass());

	public Notepad() {
		this(true);
	}

	public Notepad(boolean isStandalone) {
		this(Preferences.userNodeForPackage(Notepad.class), isStandalone);
	}

	public Notepad(Preferences prefs) {
		this(prefs, true);
	}

	public Notepad(Preferences prefs, boolean isStandalone) {
		this.prefsNode = prefs;

		this.isStandalone = isStandalone;
		// Allow override of "isStandalone" from cmd line for testing
		String prop;
		if ((prop = System.getProperty("STANDALONE")) != null) {
			this.isStandalone = Boolean.parseBoolean(prop);
		}

		theFrame = new JFrame();
		theFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		theFrame.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				closeThisWindow();
			}
		});
		UtilGUI.monitorWindowPosition(theFrame, prefsNode);

		ta = new JTextArea(30,70);
		undoManager = new UndoManager();
		final Document document = ta.getDocument();
		document.addUndoableEditListener(undoManager);
		// all change methods set dirty = true;
		document.addDocumentListener(new DocumentListener() {
			public void changedUpdate(DocumentEvent e) {
				setDirty(true);
			}
			public void insertUpdate(DocumentEvent e) {
				setDirty(true);
			}
			public void removeUpdate(DocumentEvent e) {
				setDirty(true);
			}
		});
		ta.addKeyListener(new KeyListener() {

			public void keyPressed(KeyEvent e) {
				// null
			}

			public void keyReleased(KeyEvent e) {
				//null
			}

			public void keyTyped(KeyEvent ev) {
				if (ev.isControlDown() && ev.getKeyChar() == 19) {
					try {
						doSave();
					} catch (IOException e) {
						JOptionPane.showMessageDialog(theFrame,
							e.toString(), "Error!", JOptionPane.ERROR_MESSAGE);
					}
				}
			}

		});
		theFrame.setContentPane(new JScrollPane(ta));
		theFrame.pack();

		createMenus();

		Point loc = theFrame.getLocation();
		synchronized(windows) {
			int windowsCreated = windows.size();
			loc.x += windowsCreated * 20;
			loc.y += windowsCreated * 20;
			windows.add(this);
		}
		theFrame.setLocation(loc);
		theFrame.setVisible(true);
	}

	private void closeThisWindow() {
		final String[] options = new String[]{"Save", "Discard", "Cancel"};
		int ret = JOptionPane.showOptionDialog(theFrame,
				"You have unsaved changes", "Warning", 0, 0, null,
				options, options[0]);
		switch(ret) {
		case -1: case 2: // -1 is cancel, +2 is Cancel
			return;
		case 0:
			try {
				doSave(fileName);
			} catch (IOException ex) {
				JOptionPane.showMessageDialog(theFrame,
						"That didn't work: " + ex);
				return;
			}
			// FALLTHROUGH
		default:
			// nothing to do
		}
		theFrame.setVisible(false);
		theFrame.dispose();
		synchronized(windows) {
			windows.remove(this);
			if (windows.size() == 0) {
				if (isStandalone) {
					System.exit(0);
				} else {
					// imbedded - nothing to do.
				}
			}
		}
	}

	Action openAction = new AbstractAction("Open") {

		public void actionPerformed(ActionEvent e) {
			if (chooser == null) {
				chooser = new JFileChooser();
			}
			int returnVal = chooser.showOpenDialog(theFrame);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				File file = chooser.getSelectedFile();
				try {
					doLoad(file.getAbsolutePath());
				} catch (IOException e1) {
					error("Can't open file", e1);
				}
			}
		}
	};

	Action newAction = new AbstractAction("New") {
		public void actionPerformed(ActionEvent e) {
			new Notepad();
		}
	};

	private boolean doingSaveAs; // shared between SaveAction and SaveAsAction

	Action saveAction = new AbstractAction("Save") {
		/*
		 * This code is used both by Save and SaveAs, differentiated by doingSaveAs
		 * @param evt The action event
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent evt) {
			try {
				doSave();
			} catch (IOException e) {
				error("Can't save file", e);
			}
		}
	};

	Action saveAsAction = new SaveAsAction();
	class SaveAsAction extends AbstractAction {
		SaveAsAction() {
			super("Save As");
		}

		public void actionPerformed(ActionEvent e) {
			doingSaveAs = true;
			saveAction.actionPerformed(e);
			doingSaveAs = false;
		}
	};

	Action closeAction = new CloseAction();
	class CloseAction extends AbstractAction {
		CloseAction() {
			super("Close");
		}
		public void actionPerformed(ActionEvent e) {
			closeThisWindow();
		}
	};
	Action printAction = new PrintAction();
	class PrintAction extends AbstractAction {
		PrintAction() {
			super("Print");
		}
		public void actionPerformed(ActionEvent e) {
			try {
				doPrint();
			} catch (IOException e1) {
				error("Print failure", e1);
			} catch (PrintException e1) {
				error("Print failure", e1);
			}
		}
	};

	Action cutAction = new CutAction();
	class CutAction extends AbstractAction {
		CutAction() {
			super("Cut");
		}
		public void actionPerformed(ActionEvent e) {
			ta.cut();
		}
	}

	Action undoAction = new UndoAction();
	class UndoAction extends AbstractAction {
		UndoAction() {
			super("Undo");
		}
		public void actionPerformed(ActionEvent e) {
			undoManager.undo();
		}
	}

	Action copyAction = new CopyAction();
	class CopyAction extends AbstractAction {
		CopyAction() {
			super("Copy");
		}
		public void actionPerformed(ActionEvent e) {
			ta.copy();
		}
	}

	Action pasteAction = new PasteAction();
	class PasteAction extends AbstractAction {
		PasteAction() {
			super("Paste");
		}
		public void actionPerformed(ActionEvent e) {
			ta.paste();
		}
	}

	private void error(String message, Exception e) {
		JOptionPane.showMessageDialog(theFrame, message + "\n" + e);
		e.printStackTrace();
	}

	Action exitAction = new ExitAction();
	static class ExitAction extends AbstractAction {
		ExitAction() {
			super("Exit");
		}
		public void actionPerformed(ActionEvent e) {
			System.exit(0);
		}
	};

	Action helpAboutAction = new HelpAboutAction();
	class HelpAboutAction extends AbstractAction {
		HelpAboutAction() {
			super("About");
		}
		public void actionPerformed(ActionEvent e) {
			JOptionPane.showMessageDialog(theFrame,
				"Notepad 0.0 A simple text editor");
		}
	};

	private void createMenus() {
		JMenuBar mb = new JMenuBar();
		/** File, Help */

		JMenuItem mi;

		theFrame.setJMenuBar(mb);

		// The File Menu...
		fm = new JMenu("File");
		fm.add(openAction);
		fm.add(saveAction);
		((JMenuItem)fm.getMenuComponent(1)).setMnemonic(KeyEvent.VK_S);
		fm.add(saveAsAction);
		fm.add(closeAction);
		fm.add(newAction);
		fm.addSeparator();
		fm.add(printAction);
		fm.addSeparator();
		fm.add(exitAction);
		exitAction.setEnabled(isStandalone);
		mb.add(fm);

		// The Edit Menu...
		em = new JMenu("Edit");
		em.setMnemonic(KeyEvent.VK_E);
		em.add(cutAction);
		((JMenuItem)em.getMenuComponent(0)).setMnemonic(KeyEvent.VK_X);
		em.add(copyAction);
		((JMenuItem)em.getMenuComponent(1)).setMnemonic(KeyEvent.VK_C);
		em.add(pasteAction);
		em.add(undoAction);
		((JMenuItem)em.getMenuComponent(3)).setMnemonic(KeyEvent.VK_Z);
		em.addSeparator();
		mi = new JMenuItem("Search");
		mi.setEnabled(false);
		em.add(mi);
		mi = new JMenuItem("Replace");
		mi.setEnabled(false);
		em.add(mi);
		em.addSeparator();
		JMenuItem insertMenu = new JMenu("Insert");
		em.add(insertMenu);
		JMenuItem menuItem = new JMenuItem("Date");
		menuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				ta.insert(new Date().toString(), ta.getCaretPosition());
			}
		});
		insertMenu.add(menuItem);
		JMenuItem menuItem2 = new JMenuItem(".signature");
		menuItem2.setEnabled(false);
		insertMenu.add(menuItem2);
		JMenuItem menuItem3 = new JMenuItem("File...");
		menuItem3.setEnabled(false);
		insertMenu.add(menuItem3);
		mb.add(em);

		// The Help Menu...
		hm = new JMenu("Help");
		hm.add(helpAboutAction);
		helpAboutAction.setEnabled(isStandalone);
		mb.add(hm);
	}

	/** Print a file by name
	 * @throws IOException If any IO code does
	 * @throws PrintException If the print system does
	 */
	public final void doPrint() throws IOException, PrintException {

		System.out.println("Printing ");
		DocFlavor flavor = DocFlavor.CHAR_ARRAY.TEXT_PLAIN;
		PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
		//aset.add(MediaSizeName.NA_LETTER);
		PrintService[] pservices = PrintServiceLookup.lookupPrintServices(
				flavor, aset);
		int i;
		switch(pservices.length) {
		case 0:
			JOptionPane.showMessageDialog(theFrame,
					"Error: No PrintService Found", "Error", JOptionPane.ERROR_MESSAGE);
			return;
		case 1:
			i = 1;
			break;
		default:
			i = JOptionPane.showOptionDialog(theFrame,
					"Pick a printer", "Choice",
					JOptionPane.OK_OPTION, JOptionPane.QUESTION_MESSAGE,
					null, pservices, pservices[0]);
			break;
		}
		if (i < 0) {
			return;
		}
		DocPrintJob pj = pservices[i].createPrintJob();
		Doc doc = new MyDocument(flavor);

		pj.print(doc, aset);
	}

	/**
	 * Simple holder for document flavor.
	 */
	final class MyDocument implements Doc {

		private DocFlavor flavor;
		public MyDocument(DocFlavor flavor) {
			this.flavor = flavor;
		}

		public DocFlavor getDocFlavor() {
			return flavor;
		}

		public Object getPrintData() throws IOException {
			return ta.getText();
		}

		public DocAttributeSet getAttributes() {
			return null;
		}

		public Reader getReaderForText() throws IOException {
			return new StringReader(ta.getText());
		}

		public InputStream getStreamForBytes() throws IOException {
			return null;
		}
	}

	public final void doNew() {
		// XXX check for unsaved
		fileName = null;
		dirty = false;
		ta.setText("");
	}

	public final void doLoad(File file) throws IOException {
		doLoad(file.getAbsolutePath());
	}

	public final void doLoad(String fileName) throws IOException {
		BufferedReader is = null;
		try {
			is = new BufferedReader(new FileReader(fileName));
		} catch (FileNotFoundException e) {
			JOptionPane.showMessageDialog(theFrame,
				String.format("File %s not found, treating as New File", fileName),
				"Not found", JOptionPane.WARNING_MESSAGE);
			setFileName(fileName);
			return;
		}
		String line;
		while ((line = is.readLine()) != null) {
			ta.append(line);
			ta.append("\n");
		}
		ta.setCaretPosition(0);
		is.close();
		setFileName(fileName);
	}

	/**
	 * Thin wrapper for doSave()
	 * @throws IOException If the file fails to save
	 */
	private void doSave() throws IOException {
		if (fileName != null) {
			doSave(fileName);
			return;
		}
		doingSaveAs = fileName != null;
		if (chooser == null) {
			chooser = new JFileChooser();
		}
		int returnVal = chooser.showOpenDialog(theFrame);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File file = chooser.getSelectedFile();
			if (file.exists() && doingSaveAs) {
				int ret = JOptionPane.showConfirmDialog(theFrame,
						"File already exists, overwrite?", "File Exists",
						JOptionPane.YES_NO_OPTION);
				System.err.println(ret);
				if (ret != 0)	// "Yes" is the 0th option...
					return;
			}
			doSave(file.toPath());
		}
	}

	/**
	 * Thin wrapper for doSave(File).
	 * @param fileName The file to save to
	 * @throws IOException On error
	 */
	public final void doSave(String fileName) throws IOException {
		doSave(Path.of(fileName));
	}

	/**
	 * Save the file to disk, in such a way as to map the UNIX
	 * line-endings used inside JTextArea to the correct
	 * platform-specific line endings as generated by println().
	 * @param file The output file
	 * @throws IOException On error
	 */
	public final void doSave(Path file) throws IOException {

		// save using FileSaver class
		// XXX use doBackup.
		if (fileSaver == null || !(fileSaver.getFile().equals(file))) {
			fileSaver = new FileSaver(file);
		}
		PrintWriter w = new PrintWriter(fileSaver.getWriter());
		BufferedReader is = new BufferedReader(
			new StringReader(ta.getText()));
		String line;
		while ((line = is.readLine()) != null) {
			w.println(line);
		}
		w.close();
		fileSaver.finish();
		setFileName(file.normalize().toString());
		setDirty(false);
		doingSaveAs = false;
	}

	public final boolean isDirty() {
		return dirty;
	}

	public final void setDirty(boolean dirty) {
		this.dirty = dirty;
		theFrame.setTitle(fileName + (dirty ? " (modified)" : ""));
	}

	/**
	 * Set the fileName field and the title.
	 * @param fileName The new file name.
	 */
	private void setFileName(String fileName) {
		this.fileName = fileName;
		theFrame.setTitle(fileName);
	}

	public JMenu getFileMenu() {
		return fm;
	}

	public JMenu getHelpMenu() {
		return hm;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy