Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
TDDD13/TDDC73 Lecture 3 Nov 11, 11 9:06 Concurrent.java Page 1/1 Nov 11, 11 8:52 BlockingSwingThread.java package lecture3.concurrent; package lecture3.threads; import import import import import import import import import import import import import import java.awt.BorderLayout; java.awt.Container; java.awt.event.ActionEvent; java.awt.event.ActionListener; java.util.ArrayList; java.util.List; java.util.concurrent.TimeUnit; import import import import javax.swing.JButton; javax.swing.JFrame; javax.swing.SwingUtilities; javax.swing.WindowConstants; java.util.Map; java.util.Queue; java.util.concurrent.ConcurrentHashMap; java.util.concurrent.ConcurrentLinkedQueue; java.util.concurrent.Semaphore; java.util.concurrent.locks.Lock; java.util.concurrent.locks.ReentrantLock; import javax.swing.SwingUtilities; /** * Examples of what you can do with concurrency in java. Does not run, and is * not intended to. * * @author jernlas */ public class Concurrent { Object that; volatile int number = 0; static Runnable runnable; public static void main(String[] args) { Lock lock = new ReentrantLock(); lock.lock(); // critical section lock.unlock(); Semaphore sema = new Semaphore(3); sema.acquireUninterruptibly(); // critical section sema.release(); Page 1/2 import lab3.given.FemaleNamesSearchProvider; import lecture1.painting.Counter; /** * <p> * Creates a window that has a button and a counter. When the button is clicked * the counter searches through a list of names and counts the number of a:s. * </p> * <p> * The point here is to show what occurs when heavy processing is done on the * swing thread. To be extra obviuos the list is searched a thousand times over. * </p> * * @author jernlas */ public class BlockingSwingThread { public static void main(String[] args) { new BlockingSwingThread(); } Map<String, String> map = new ConcurrentHashMap<String, String>(); map.put("key", "value"); Queue<String> queue = new ConcurrentLinkedQueue<String>(); queue.add("element"); SwingUtilities.isEventDispatchThread(); SwingUtilities.invokeLater(runnable); try { SwingUtilities.invokeAndWait(runnable); } catch (Exception e) { // ignore } } public synchronized void critical() { // critical section } public void partlyCritical() { // do something synchronized (this) { // critical section // synchronized on this instance } synchronized (that) { // critical section // synchronized on other object (that) } // do something } } Friday November 11, 2011 public BlockingSwingThread() { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } protected void createAndShowGUI() { final JFrame frame = new JFrame("Blocking calls"); final JButton countButton = new JButton("Count ’a’s in the name list!"); final Counter counter = new Counter(); Container pane = frame.getContentPane(); pane.setLayout(new BorderLayout()); pane.add(countButton, BorderLayout.NORTH); pane.add(counter, BorderLayout.CENTER); FemaleNamesSearchProvider provider = FemaleNamesSearchProvider .getInstance(); final List<String> names = new ArrayList<String>(); for (int i = 0; i < 1000; i++) { names.addAll(provider.getData()); } countButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { counter.setValue(0); for (String name : names) { for (int pos = 0; pos < name.length(); pos++) { if (name.charAt(pos) == ’a’) { counter.setValue(counter.getValue() + 1); lecture3/concurrent/Concurrent.java, lecture3/threads/BlockingSwingThread.java 1/12 TDDD13/TDDC73 Lecture 3 BlockingSwingThread.java Nov 11, 11 8:52 Page 2/2 try { TimeUnit.MILLISECONDS.sleep(1); } catch (InterruptedException e1) { // TODO Auto−generated catch block e1.printStackTrace(); } } } } Nov 11, 11 8:52 NotBlockingSwingThread.java Page 1/2 package lecture3.threads; import import import import import import import java.awt.BorderLayout; java.awt.Container; java.awt.event.ActionEvent; java.awt.event.ActionListener; java.util.ArrayList; java.util.List; java.util.concurrent.TimeUnit; import import import import javax.swing.JButton; javax.swing.JFrame; javax.swing.SwingUtilities; javax.swing.WindowConstants; } }); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.pack(); frame.setVisible(true); } } import lab3.given.FemaleNamesSearchProvider; import lecture1.painting.Counter; /** * <p> * Creates a window that has a button and * the counter searches through a list of * </p> * <p> * This implementation is better than the * during searching and the user will not * though. * </p> * * @author jernlas */ public class NotBlockingSwingThread { a counter. When the button is clicked names and counts the number of a:s. blocking one, it can still be used be agitated. It is still pretty ugly public static void main(String[] args) { new NotBlockingSwingThread(); } public NotBlockingSwingThread() { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } protected void createAndShowGUI() { final JFrame frame = new JFrame("Blocking calls"); final JButton countButton = new JButton("Count ’a’s in the name list!"); final Counter counter = new Counter(); Container pane = frame.getContentPane(); pane.setLayout(new BorderLayout()); pane.add(countButton, BorderLayout.NORTH); pane.add(counter, BorderLayout.CENTER); FemaleNamesSearchProvider provider = FemaleNamesSearchProvider .getInstance(); final List<String> names = new ArrayList<String>(); for (int i = 0; i < 1000; i++) { names.addAll(provider.getData()); } countButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { counter.setValue(0); Runnable runnable = new Runnable() { private volatile int value = 0; Friday November 11, 2011 lecture3/threads/BlockingSwingThread.java, lecture3/threads/NotBlockingSwingThread.java 2/12 TDDD13/TDDC73 Lecture 3 Nov 11, 11 8:52 NotBlockingSwingThread.java Page 2/2 @Override public void run() { for (String name : names) { for (int pos = 0; pos < name.length(); pos++) { if (name.charAt(pos) == ’a’) { value++; try { TimeUnit.MILLISECONDS.sleep(1); } catch (InterruptedException e1) { // TODO Auto−generated catch block e1.printStackTrace(); } } } } SwingUtilities.invokeLater(new Runnable() { public void run() { counter.setValue(value); } }); } }; new Thread(runnable).start(); } }); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.pack(); frame.setVisible(true); } } Nov 11, 11 8:52 SwingWorkerThread.java Page 1/2 package lecture3.threads; import import import import import import import java.awt.BorderLayout; java.awt.Container; java.awt.event.ActionEvent; java.awt.event.ActionListener; java.util.ArrayList; java.util.List; java.util.concurrent.TimeUnit; import import import import import javax.swing.JButton; javax.swing.JFrame; javax.swing.SwingUtilities; javax.swing.SwingWorker; javax.swing.WindowConstants; import lab3.given.FemaleNamesSearchProvider; import lecture1.painting.Counter; /** * <p> * Creates a window that has a button and a counter. When the button is clicked * the counter searches through a list of names and counts the number of a:s. * </p> * <p> * This implementation is better than the non−blocking one, it will be updated * continously and can be used during searching. * </p> * * @author jernlas */ public class SwingWorkerThread { /** * Swing worker that counts all ’a’s in the list, updating the count as it * goes along. * * @author jernlas */ private class CounterWorker extends SwingWorker<Integer, Integer> { /** * The main work, done in a separate thread. */ @Override protected Integer doInBackground() throws Exception { int value = 0; for (String name : names) { for (int pos = 0; pos < name.length(); pos++) { if (name.charAt(pos) == ’a’) { publish(value++); TimeUnit.MILLISECONDS.sleep(1); } } } return value; } /** * Called when doInBackground() completes. Executed in swing−thread. */ @Override protected void done() { try { counter.setValue(get()); } catch (Exception e) { // ignore } } Friday November 11, 2011 lecture3/threads/NotBlockingSwingThread.java, lecture3/threads/SwingWorkerThread.java 3/12 TDDD13/TDDC73 Lecture 3 Nov 11, 11 8:52 SwingWorkerThread.java Page 2/2 Nov 11, 11 8:52 SearchClient.java Page 1/1 package lecture3.given; /** * Called after every few calls to publish(). Executed in swing−thread. * * @param updates The list of published values since last called. */ @Override protected void process(List<Integer> updates) { counter.setValue(updates.get(updates.size() − 1)); } } public static void main(String[] args) { new SwingWorkerThread(); } import java.util.List; import lab3.given.SearchProvider; /** * This interface describes an asyncronous callback for searching lists of strin gs. * @author Johan JernlÃ¥s * @version 1.0.0 * @see SearchProvider */ public interface SearchClient { /** * Callback from a search operation to report the search results. * @param searchId The ID of the search this result pertains to * @param response The matches returned for this search */ void searchResultUpdate(long searchId, List<String> response); private final Counter counter = new Counter(); final List<String> names = new ArrayList<String>(); public SwingWorkerThread() { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } } protected void createAndShowGUI() { final JFrame frame = new JFrame("Blocking calls"); final JButton countButton = new JButton("Count ’a’s in the name list!"); Container pane = frame.getContentPane(); pane.setLayout(new BorderLayout()); pane.add(countButton, BorderLayout.NORTH); pane.add(counter, BorderLayout.CENTER); FemaleNamesSearchProvider provider = FemaleNamesSearchProvider .getInstance(); for (int i = 0; i < 1000; i++) { names.addAll(provider.getData()); } countButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { new CounterWorker().execute(); } }); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.pack(); frame.setVisible(true); } } Friday November 11, 2011 lecture3/threads/SwingWorkerThread.java, lecture3/given/SearchClient.java 4/12 TDDD13/TDDC73 Lecture 3 Nov 11, 11 8:52 SearchProvider.java Page 1/1 package lecture3.given; import java.util.List; import lab3.given.SearchClient; /** * This interface describes an asyncronous search service. It uses an internal * thread pool for servicing several requests simultaneously. To use it the * client must follow the following steps: * <nl> * <li>Call addObserver to register a SearchClient as an observer</li> * <li>Call newAsyncSearch to run an new search</li> * </nl> * If completed properly the SearchProvider will return a response in a finite * amount of time. It does not, however, guarantee that responses arrive in the * same order as requests. * * @author Johan JernlÃ¥s * @version 1.0.0 * @see SearchClient */ public interface SearchProvider { /** * Adds an observer that registers search results. * * @param t * The observer. May not be NULL or already registered. */ public void addObserver(SearchClient t); /** * A convenience method that dumps the whole dataset. It is only intended for * testing and general sanity checks. * * @return The data that is searched by the newAsyncSearch method */ public List<String> getData(); /** * Creates a new search for a number of matching strings. The response can * not have more elements than the requested number, but it might have fewer. * * @param text * The text to search for * @param number * The desired number of strings in the result. * @return The ID for this search */ public long newAsyncSearch(String text, int number); } Nov 11, 11 8:54 ExampleWindow.java Page 1/2 package se.jernlas.gemexample; import java.awt.Dimension; import java.awt.FlowLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextArea; import se.jernlas.swing.gem.Gem; import se.jernlas.swing.gem.types.TextType; /** * A simple example application meant to examplify how to use the Gem−component. * * @author jernlas */ class ExampleWindow extends JFrame { /** * Horizontal gap between components */ private static final int H_GAP = 4; /** * Vertical gap between components */ private static final int V_GAP = 4; /** * Serial version */ private static final long serialVersionUID = 20101126L; /** * The TextField containing the text that is to be analyzed by the gem. */ private final JTextArea textToAnalyze = new JTextArea(); /** * A label prompting the user to start typing in <code>textToAnalyze</code> */ private final JLabel textToAnalyzePrompt = new JLabel("Skriv nÃ¥got:"); /** * The actual gem that gives the user feedback on his typing */ private final Gem gemAnalyzer = new Gem(textToAnalyze .getDocument()); /** * Creates a standard example frame with a simple * textfield component that is analyzed by a gem. */ public ExampleWindow() { setDefaultCloseOperation(DISPOSE_ON_CLOSE); setLayout(new FlowLayout(FlowLayout.LEFT, H_GAP, V_GAP)); add(textToAnalyzePrompt); add(textToAnalyze); textToAnalyze.setPreferredSize(new Dimension(100, 10*(int)textToAnalyze.ge tPreferredSize().getHeight())); add(gemAnalyzer); gemAnalyzer.setPreferredSize(new Dimension(50, 50)); gemAnalyzer.addTextType(TextType.FORMAL_LETTER); gemAnalyzer.addTextType(TextType.INFORMAL_LETTER); Friday November 11, 2011 lecture3/given/SearchProvider.java, jernlas/gemexample/ExampleWindow.java 5/12 TDDD13/TDDC73 Lecture 3 Nov 11, 11 8:54 pack(); setVisible(true); } } ExampleWindow.java Page 2/2 Nov 11, 11 8:54 Main.java Page 1/1 package se.jernlas.gemexample; import javax.swing.SwingUtilities; /** * Convenience class for initializing the Gem−example application. Contains no * logic except for starting the application. * * @author jernlas */ public class Main { /** * Entry point method, runs a Gem−example application. * * @param args * Declared pro forma, all arguments are ignored. */ public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new ExampleWindow(); } }); } } Friday November 11, 2011 jernlas/gemexample/ExampleWindow.java, jernlas/gemexample/Main.java 6/12 TDDD13/TDDC73 Lecture 3 Nov 11, 11 8:54 AnalyzableDocumentAdapter.java Page 1/2 Nov 11, 11 8:54 package se.jernlas.swing.gem; import java.util.ArrayList; import java.util.Collections; import java.util.List; import import import import AnalyzableDocumentAdapter.java Page 2/2 @Override public void addAnalyzer(TextAnalyzer a) { analyzers.add(a); } /** * Fires analyzeText for all TextAnalyzers observing this class. The list of * observers is defensively copied before calling so that no errors will * occur if the observer removes itself from the original list during * execution of analyzeText(). */ private void fireAnalyseTextEvent() { List<TextAnalyzer> tmpList = Collections.unmodifiableList(analyzers); for (TextAnalyzer textAnalyzer : tmpList) { textAnalyzer.analyzeText(this); } javax.swing.event.DocumentEvent; javax.swing.event.DocumentListener; javax.swing.text.BadLocationException; javax.swing.text.Document; /** * Adapter class, adapting a Document (the model for most text based swing * components) to appear as an AnalyzableText. * * @author jernlas * @see javax.swing.text.Document */ public class AnalyzableDocumentAdapter implements AnalyzableText { } @Override public String getText() { try { return doc.getText(0, doc.getLength()); } catch (BadLocationException e) { e.printStackTrace(); return ""; } } /** * The backing Document that is used as a source for change events and text * content. The document may not be changed once set by the constructor, * since this would most likely result in unexpected behaviour. */ private final Document doc; /** * A list of TextAnalyzers observing this AnalyzableText. */ private final List<TextAnalyzer> analyzers = new ArrayList<TextAnalyzer>(); /** * Creates a new AnalyzableDocument, wrapping around the supplied Document * object. * * @param doc * The document to use. */ public AnalyzableDocumentAdapter(Document doc) { @Override public void removeAnalyzer(TextAnalyzer a) { analyzers.remove(a); } } if (doc == null) { throw new IllegalArgumentException("The document may not be NULL."); } this.doc = doc; /* Use an anonymous subclass of DocumentListener to capture changes in the * underlying Document and refire them as analyseText. * */ doc.addDocumentListener(new DocumentListener() { @Override public void changedUpdate(DocumentEvent e) { fireAnalyseTextEvent(); } @Override public void insertUpdate(DocumentEvent e) { fireAnalyseTextEvent(); } @Override public void removeUpdate(DocumentEvent e) { fireAnalyseTextEvent(); } }); } Friday November 11, 2011 jernlas/swing/gem/AnalyzableDocumentAdapter.java 7/12 TDDD13/TDDC73 Lecture 3 Nov 11, 11 8:54 AnalyzableText.java Page 1/1 package se.jernlas.swing.gem; /** * * Any text that can be analyzed by a <code>TextAnalyzer</code>. This interface * provides two vital functions: * <ul> * <li>A uniform interface for getting the text to analyze * (<code>getText()</code>).</li> * <li>Forces the client to accept TextAnalyzers, resembling the * Observer in the well known Observable design pattern.</li> * </ul> * * @author jernlas * */ public interface AnalyzableText { /** * Adds a new TextAnalyzer * @param analyzer The analyzer to add */ public void addAnalyzer(TextAnalyzer analyzer); /** * Removes a TextAnalyzer from the internal list of analyzers. * This operation should allways be allowed (ie. all implementers must * defensively copy the list before calling external code). * @param analyzer The analyzer to remove */ public void removeAnalyzer(TextAnalyzer analyzer); /** * Gets the text that is to be used for any analysis by the TextAnalyzers. * @return The text selected for analysis. */ public String getText(); Gem.java Nov 11, 11 8:54 Page 1/5 package se.jernlas.swing.gem; import java.awt.Color; import java.awt.Component; import java.awt.Frame; import java.awt.Graphics; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import import import import import import import import import import javax.swing.BorderFactory; javax.swing.BoxLayout; javax.swing.JButton; javax.swing.JComponent; javax.swing.JPanel; javax.swing.JWindow; javax.swing.border.BevelBorder; javax.swing.event.AncestorEvent; javax.swing.event.AncestorListener; javax.swing.text.Document; import se.jernlas.swing.gem.types.TextType; /** * A swing−component that helps the user to create text−documents * by analyzing what the user writes and presenting helpful suggestions. * * @author jernlas * */ public class Gem extends JComponent implements TextAnalyzer, AncestorListener { } private static final long serialVersionUID = −1449696234370220313L; /** * Last shown suggestions. */ private final Set<TextType> lastShownSuggestions = new HashSet<TextType>(); /** * The types of document to try and identify. */ private final List<TextType> types = new ArrayList<TextType>(); /** * The window containing the list of suggestions */ private JWindow tipWindow = null; /** * Indicates whether there are tips to display */ private volatile boolean hasTips = false; /** * The color of the gem when there are no tips available */ private Color inactiveColor = Color.YELLOW; /** * The color of the gem when there are tips available Friday November 11, 2011 jernlas/swing/gem/AnalyzableText.java, jernlas/swing/gem/Gem.java 8/12 TDDD13/TDDC73 Lecture 3 Nov 11, 11 8:54 */ private Color Gem.java activeColor Page 2/5 = Color.GREEN; t. * @param text The text to register as an analyzer for. */ public Gem(AnalyzableText text) { this(); text.addAnalyzer(this); } /** * Convenience constructor. * Same as the one accepting a AnalyzableText parameter, * only it accepts a Document, which is wrapped in an AnalyzableDocumentAdapt @Override public void addTextType(TextType t) { types.add(t); } @Override public void analyzeText(AnalyzableText text) { final String currentText = text.getText(); List<TextType> matchingTypes = new LinkedList<TextType>(); for (TextType t : types) { if (t.isThisType(currentText)) { matchingTypes.add(t); } } hasTips = (matchingTypes.size() > 0); if (hasTips) { displaySuggestions(matchingTypes); } else { hideSuggestions(); } repaint(); } boolean hasAll = lastShownSuggestions.containsAll(matchingTypes); boolean noExtra = lastShownSuggestions.size() == matchingTypes.size(); // If displaying the same suggestions, don’t redraw. if(hasAll && noExtra){ return; } else { lastShownSuggestions.clear(); lastShownSuggestions.addAll(matchingTypes); } // If there is already a window, dispose of it. if (tipWindow != null) { tipWindow.dispose(); } // Create a new window and populate it with components generated // from the selected TextTypes. tipWindow = new JWindow(getFrame(null)); JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS)); tipWindow.setContentPane(p); p.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); for (TextType textType : matchingTypes) { p.add(textType.getTip()); } final JButton b = new JButton("No thanks..."); b.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { hideSuggestions(); } }); p.add(b); // Make the pop−up window behave as part of the component. getFrame(null).addWindowFocusListener(new WindowAdapter() { @Override public void windowGainedFocus(WindowEvent evt) { if (tipWindow != null && !lastShownSuggestions.isEmpty()) { tipWindow.setVisible(true); } } @Override public void ancestorAdded(AncestorEvent event) { hideSuggestions(); } @Override public void ancestorMoved(AncestorEvent event) { if (event.getSource() != tipWindow) { placePopup(); } } Friday November 11, 2011 Page 3/5 /** * Displays a list of Suggestions. * @param matchingTypes The TextTypes that matches the text. */ private void displaySuggestions(Collection<TextType> matchingTypes) { /** * Creates a default gem and registers it as an analyzer for the supplied tex * to make it analyzable. * @param document The document to analyze. */ public Gem(Document document) { this(new AnalyzableDocumentAdapter(document)); } Gem.java @Override public void ancestorRemoved(AncestorEvent event) { hideSuggestions(); } /** * Creates a default gem without associating it with a text. * This can be done later by calling addAnalyzer() on the text. */ public Gem() { addAncestorListener(this); setOpaque(false); } er Nov 11, 11 8:54 @Override public void windowLostFocus(WindowEvent evt) { if (tipWindow != null && lastShownSuggestions.isEmpty()) { tipWindow.setVisible(false); } } }); // Pack, show and position the pop−up window jernlas/swing/gem/Gem.java 9/12 TDDD13/TDDC73 Lecture 3 Nov 11, 11 8:54 Gem.java Page 4/5 tipWindow.pack(); tipWindow.toFront(); tipWindow.setVisible(true); placePopup(); tipWindow.requestFocusInWindow(); Nov 11, 11 8:54 Gem.java Page 5/5 public void removeTextType(TextType t) { types.remove(t); } } } /** * Recursively gets the root Frame. * @param c The component to start from, if null this is used. * @return The root Frame. */ private Frame getFrame(Component c) { if (c == null) { c = this; } if (c.getParent() instanceof Frame) { return (Frame) c.getParent(); } return getFrame(c.getParent()); } /** * Disables the pop−up suggestions. */ private void hideSuggestions() { if (tipWindow != null) { tipWindow.setVisible(false); lastShownSuggestions.clear(); } } @Override public void paint(Graphics g) { if (isOpaque()) { g.setColor(getBackground()); g.drawRect(0, 0, getWidth() − 1, getHeight() − 1); } if (hasTips) { g.setColor(activeColor); } else { g.setColor(inactiveColor); } g.fillOval(0, 0, getWidth() − 1, getHeight() − 1); g.setColor(getForeground()); g.drawOval(0, 0, getWidth() − 1, getHeight() − 1); g.setColor(Color.WHITE); g.fillOval((int)(0.7*getWidth()), (int)(0.25*getHeight()), (int)(0.15*(get Width()−1)), (int)(0.15*(getHeight()−1))); } /** * Correctly position the pop−up, depending on the position of the main compo nent. */ private void placePopup() { if (tipWindow != null) { Point pt = this.getLocationOnScreen(); pt.translate(0, this.getHeight()); tipWindow.setLocation(pt); } } @Override Friday November 11, 2011 jernlas/swing/gem/Gem.java 10/12 TDDD13/TDDC73 Lecture 3 Nov 11, 11 8:54 TextAnalyzer.java Page 1/1 Nov 11, 11 8:54 FormalLetterType.java package se.jernlas.swing.gem; package se.jernlas.swing.gem.types; import se.jernlas.swing.gem.types.TextType; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.regex.Pattern; /** * Analyzes an AnalyzableText in order to identify matching TextTypes. * * @author jernlas */ public interface TextAnalyzer { /** * Adds a TextType to the list of TextTypes to identify. * @param type The TextType to add */ public void addTextType(TextType type); Page 1/1 import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JOptionPane; /** * A formal letter TextType. Singleton. Not intended for direct use, accessed as * a static field in TextType. * * @author jernlas */ class FormalLetterType extends TextType { /** * Perform the actual analysis. * @param text The AnalyzableText to analyze */ public void analyzeText(AnalyzableText text); /** * The singleton instance */ private final static FormalLetterType instance = new FormalLetterType(); /** * Removes a TextType from the list of identifiable types. * @param type The TextType to remove. */ public void removeTextType(TextType type); /** * Prevent others from instantiating. */ private FormalLetterType() { } @Override public JComponent getTip() { final JButton b = new JButton( "Det verkar som att du vill skriva ett formellt brev..."); b.addActionListener(new ActionListener() { } @Override public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(b, "This is only an example application..."); } }); return b; } @Override public boolean isThisType(String text) { return Pattern.matches("^Hej.*", text); } /** * Gets the singleton instance. * * @return the instance. */ public static FormalLetterType getInstance() { return instance; } } Friday November 11, 2011 jernlas/swing/gem/TextAnalyzer.java, jernlas/swing/gem/types/FormalLetterType.java 11/12 TDDD13/TDDC73 Lecture 3 Nov 11, 11 8:54 InformalLetterType.java Page 1/1 Nov 11, 11 8:54 TextType.java package se.jernlas.swing.gem.types; package se.jernlas.swing.gem.types; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.regex.Pattern; import javax.swing.JComponent; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JOptionPane; /** * An informal letter TextType. Singleton. Not intended for direct use, accessed * as a static field in TextType. * * @author jernlas */ class InformalLetterType extends TextType { /** * The singleton instance */ private final static InformalLetterType instance = new InformalLetterType(); /** * A type of text that can be identified from a string and generate a * Tip in the shape of a swing component. * * @author jernlas */ public abstract class TextType { /** * Identifies a formal letter */ public static final TextType FORMAL_LETTER = FormalLetterType.getInstance(); /** * Identifies an informal letter */ public static final TextType INFORMAL_LETTER = InformalLetterType.getInstance (); /** * Prevent others from instantiating. */ private InformalLetterType() { } /** * Generates a swing component that represents this tip. * @return The component. */ public abstract JComponent getTip(); @Override public JComponent getTip() { final JButton b = new JButton( "Det verkar som att du vill skriva ett informellt brev..."); b.addActionListener(new ActionListener() { /** * Check if the string matches this document type. * @param text The text to check * @return true if the text matches this type of document. */ public abstract boolean isThisType(String text); @Override public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(b, "This is only an example application..."); } Page 1/1 } }); return b; } @Override public boolean isThisType(String text) { return Pattern.matches("^Hejsan.*", text); } /** * Gets the singleton instance. * * @return the instance. */ public static InformalLetterType getInstance() { return instance; } } Friday November 11, 2011 jernlas/swing/gem/types/InformalLetterType.java, jernlas/swing/gem/types/TextType.java 12/12