1 /* 2 * 3 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * - Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * - Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * - Neither the name of Oracle nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 34 import java.awt.BorderLayout; 35 import java.awt.Color; 36 import java.awt.Component; 37 import java.awt.FileDialog; 38 import java.awt.Frame; 39 import java.awt.Graphics; 40 import java.awt.GraphicsEnvironment; 41 import java.awt.event.ActionEvent; 42 import java.awt.event.ActionListener; 43 import java.io.File; 44 import java.io.FileInputStream; 45 import java.io.FileOutputStream; 46 import java.io.IOException; 47 import java.io.ObjectInputStream; 48 import java.io.ObjectOutput; 49 import java.io.ObjectOutputStream; 50 import java.lang.reflect.InvocationTargetException; 51 import java.util.MissingResourceException; 52 import java.util.ResourceBundle; 53 import java.util.logging.Level; 54 import java.util.logging.Logger; 55 import javax.swing.AbstractAction; 56 import javax.swing.Action; 57 import javax.swing.Icon; 58 import javax.swing.JButton; 59 import javax.swing.JComboBox; 60 import javax.swing.JFrame; 61 import javax.swing.JMenu; 62 import javax.swing.JMenuItem; 63 import javax.swing.JTextPane; 64 import javax.swing.SwingUtilities; 65 import javax.swing.text.DefaultStyledDocument; 66 import javax.swing.text.Document; 67 import javax.swing.text.JTextComponent; 68 import javax.swing.text.StyleContext; 69 import javax.swing.text.StyledEditorKit; 70 import javax.swing.text.TextAction; 71 72 73 /** 74 * Sample application using JTextPane. 75 * 76 * @author Timothy Prinzing 77 */ 78 @SuppressWarnings("serial") 79 public class Stylepad extends Notepad { 80 81 private static ResourceBundle resources; 82 private FileDialog fileDialog; 83 84 private static final String[] MENUBAR_KEYS = {"file", "edit", "color", 85 "font", "debug"}; 86 private static final String[] FONT_KEYS = {"family1", "family2", "family3", 87 "family4", "-", "size1", "size2", "size3", "size4", "size5", "-", 88 "bold", "italic", "underline"}; 89 private static final String[] TOOLBAR_KEYS = {"new", "open", "save", "-", 90 "cut", "copy", "paste", "-", "bold", "italic", "underline", "-", 91 "left", "center", "right"}; 92 93 94 static { 95 try { 96 properties.load(Stylepad.class.getResourceAsStream( 97 "resources/StylepadSystem.properties")); 98 resources = ResourceBundle.getBundle("resources.Stylepad"); 99 } catch (MissingResourceException | IOException mre) { 100 System.err.println("Stylepad.properties or StylepadSystem.properties not found"); 101 System.exit(0); 102 } 103 } 104 105 public Stylepad() { 106 super(); 107 } 108 109 public static void main(String[] args) { 110 try { 111 SwingUtilities.invokeAndWait(new Runnable() { 112 113 public void run() { 114 JFrame frame = new JFrame(); 115 frame.setTitle(resources.getString("Title")); 116 frame.setBackground(Color.lightGray); 117 frame.getContentPane(). 118 setLayout(new BorderLayout()); 119 Stylepad stylepad = new Stylepad(); 120 frame.getContentPane().add("Center", stylepad); 121 frame.setJMenuBar(stylepad.createMenubar()); 122 frame.addWindowListener(new AppCloser()); 123 frame.pack(); 124 frame.setSize(600, 480); 125 frame.setVisible(true); 126 } 127 }); 128 } catch (InterruptedException ex) { 129 Logger.getLogger(Stylepad.class.getName()).log(Level.SEVERE, null, 130 ex); 131 } catch (InvocationTargetException ex) { 132 Logger.getLogger(Stylepad.class.getName()).log(Level.SEVERE, null, 133 ex); 134 } 135 } 136 137 /** 138 * Fetch the list of actions supported by this 139 * editor. It is implemented to return the list 140 * of actions supported by the superclass 141 * augmented with the actions defined locally. 142 */ 143 @Override 144 public Action[] getActions() { 145 Action[] defaultActions = { 146 new NewAction(), 147 new OpenAction(), 148 new SaveAction(), 149 new StyledEditorKit.FontFamilyAction("font-family-SansSerif", 150 "SansSerif"), }; 151 Action[] a = TextAction.augmentList(super.getActions(), defaultActions); 152 return a; 153 } 154 155 /** 156 * Try and resolve the resource name in the local 157 * resource file, and if not found fall back to 158 * the superclass resource file. 159 */ 160 @Override 161 protected String getResourceString(String nm) { 162 String str; 163 try { 164 str = Stylepad.resources.getString(nm); 165 } catch (MissingResourceException mre) { 166 str = super.getResourceString(nm); 167 } 168 return str; 169 } 170 171 /** 172 * Create an editor to represent the given document. 173 */ 174 @Override 175 protected JTextComponent createEditor() { 176 StyleContext sc = new StyleContext(); 177 DefaultStyledDocument doc = new DefaultStyledDocument(sc); 178 initDocument(doc, sc); 179 JTextPane p = new JTextPane(doc); 180 p.setDragEnabled(true); 181 182 //p.getCaret().setBlinkRate(0); 183 184 return p; 185 } 186 187 /** 188 * Create a menu for the app. This is redefined to trap 189 * a couple of special entries for now. 190 */ 191 @Override 192 protected JMenu createMenu(String key) { 193 if (key.equals("color")) { 194 return createColorMenu(); 195 } 196 return super.createMenu(key); 197 } 198 199 @Override 200 protected String[] getItemKeys(String key) { 201 switch (key) { 202 case "font": 203 return FONT_KEYS; 204 default: 205 return super.getItemKeys(key); 206 } 207 } 208 209 @Override 210 protected String[] getMenuBarKeys() { 211 return MENUBAR_KEYS; 212 } 213 214 @Override 215 protected String[] getToolBarKeys() { 216 return TOOLBAR_KEYS; 217 } 218 219 // this will soon be replaced 220 JMenu createColorMenu() { 221 ActionListener a; 222 JMenuItem mi; 223 JMenu menu = new JMenu(getResourceString("color" + labelSuffix)); 224 mi = new JMenuItem(resources.getString("Red")); 225 mi.setHorizontalTextPosition(JButton.RIGHT); 226 mi.setIcon(new ColoredSquare(Color.red)); 227 a = 228 new StyledEditorKit.ForegroundAction("set-foreground-red", 229 Color.red); 230 //a = new ColorAction(se, Color.red); 231 mi.addActionListener(a); 232 menu.add(mi); 233 mi = new JMenuItem(resources.getString("Green")); 234 mi.setHorizontalTextPosition(JButton.RIGHT); 235 mi.setIcon(new ColoredSquare(Color.green)); 236 a = new StyledEditorKit.ForegroundAction("set-foreground-green", 237 Color.green); 238 //a = new ColorAction(se, Color.green); 239 mi.addActionListener(a); 240 menu.add(mi); 241 mi = new JMenuItem(resources.getString("Blue")); 242 mi.setHorizontalTextPosition(JButton.RIGHT); 243 mi.setIcon(new ColoredSquare(Color.blue)); 244 a = new StyledEditorKit.ForegroundAction("set-foreground-blue", 245 Color.blue); 246 //a = new ColorAction(se, Color.blue); 247 mi.addActionListener(a); 248 menu.add(mi); 249 250 return menu; 251 } 252 253 void initDocument(DefaultStyledDocument doc, StyleContext sc) { 254 Wonderland w = new Wonderland(doc, sc); 255 w.loadDocument(); 256 } 257 258 JComboBox createFamilyChoices() { 259 JComboBox b = new JComboBox(); 260 String[] fontNames = GraphicsEnvironment.getLocalGraphicsEnvironment(). 261 getAvailableFontFamilyNames(); 262 for (String fontName : fontNames) { 263 b.addItem(fontName); 264 } 265 return b; 266 } 267 268 269 /** 270 * Trys to read a file which is assumed to be a 271 * serialization of a document. 272 */ 273 class OpenAction extends AbstractAction { 274 275 OpenAction() { 276 super(openAction); 277 } 278 279 @Override 280 public void actionPerformed(ActionEvent e) { 281 Frame frame = getFrame(); 282 if (fileDialog == null) { 283 fileDialog = new FileDialog(frame); 284 } 285 fileDialog.setMode(FileDialog.LOAD); 286 fileDialog.setVisible(true); 287 288 String file = fileDialog.getFile(); 289 if (file == null) { 290 return; 291 } 292 String directory = fileDialog.getDirectory(); 293 File f = new File(directory, file); 294 if (f.exists()) { 295 try { 296 FileInputStream fin = new FileInputStream(f); 297 ObjectInputStream istrm = new ObjectInputStream(fin); 298 Document doc = (Document) istrm.readObject(); 299 if (getEditor().getDocument() != null) { 300 getEditor().getDocument().removeUndoableEditListener( 301 undoHandler); 302 } 303 getEditor().setDocument(doc); 304 doc.addUndoableEditListener(undoHandler); 305 resetUndoManager(); 306 frame.setTitle(file); 307 validate(); 308 } catch (IOException io) { 309 // should put in status panel 310 System.err.println("IOException: " + io.getMessage()); 311 } catch (ClassNotFoundException cnf) { 312 // should put in status panel 313 System.err.println("Class not found: " + cnf.getMessage()); 314 } 315 } else { 316 // should put in status panel 317 System.err.println("No such file: " + f); 318 } 319 } 320 } 321 322 323 /** 324 * Trys to write the document as a serialization. 325 */ 326 class SaveAction extends AbstractAction { 327 328 SaveAction() { 329 super(saveAction); 330 } 331 332 @Override 333 public void actionPerformed(ActionEvent e) { 334 Frame frame = getFrame(); 335 if (fileDialog == null) { 336 fileDialog = new FileDialog(frame); 337 } 338 fileDialog.setMode(FileDialog.SAVE); 339 fileDialog.setVisible(true); 340 String file = fileDialog.getFile(); 341 if (file == null) { 342 return; 343 } 344 String directory = fileDialog.getDirectory(); 345 File f = new File(directory, file); 346 try { 347 FileOutputStream fstrm = new FileOutputStream(f); 348 ObjectOutput ostrm = new ObjectOutputStream(fstrm); 349 ostrm.writeObject(getEditor().getDocument()); 350 ostrm.flush(); 351 frame.setTitle(f.getName()); 352 } catch (IOException io) { 353 // should put in status panel 354 System.err.println("IOException: " + io.getMessage()); 355 } 356 } 357 } 358 359 360 /** 361 * Creates an empty document. 362 */ 363 class NewAction extends AbstractAction { 364 365 NewAction() { 366 super(newAction); 367 } 368 369 @Override 370 public void actionPerformed(ActionEvent e) { 371 if (getEditor().getDocument() != null) { 372 getEditor().getDocument().removeUndoableEditListener(undoHandler); 373 } 374 getEditor().setDocument(new DefaultStyledDocument()); 375 getEditor().getDocument().addUndoableEditListener(undoHandler); 376 resetUndoManager(); 377 getFrame().setTitle(resources.getString("Title")); 378 validate(); 379 } 380 } 381 382 383 class ColoredSquare implements Icon { 384 385 Color color; 386 387 public ColoredSquare(Color c) { 388 this.color = c; 389 } 390 391 @Override 392 public void paintIcon(Component c, Graphics g, int x, int y) { 393 Color oldColor = g.getColor(); 394 g.setColor(color); 395 g.fill3DRect(x, y, getIconWidth(), getIconHeight(), true); 396 g.setColor(oldColor); 397 } 398 399 @Override 400 public int getIconWidth() { 401 return 12; 402 } 403 404 @Override 405 public int getIconHeight() { 406 return 12; 407 } 408 } 409 }