Commit 28d02811 authored by Dominik Gruntz's avatar Dominik Gruntz
Browse files

03_Observer2: Adds solution to issue 5

parent 550bd313
package patterns.observer.copyright.sol;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
@SuppressWarnings("serial")
class CopyRightGUI extends JFrame {
private static final String fhnw = "FHNW";
private static final String input = "(c)";
public static void main(String[] args) {
String given = (args.length > 0) ? args[0] : fhnw;
String typeThat = (args.length > 1) ? args[1] : input;
JFrame f = new CopyRightGUI(given, typeThat);
f.setDefaultCloseOperation(EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
CopyRightGUI(final String given, final String typeThat) {
final TextModel m1 = new TextModelWrong();
CorrectionListener cl1 = new CorrectionListener(m1);
TextListener tl1 = new TextListener();
m1.addListener(cl1);
m1.addListener(tl1);
final TextModel m2 = new TextModelCorrect1();
CorrectionListener cl2 = new CorrectionListener(m2);
TextListener tl2 = new TextListener();
m2.addListener(cl2);
m2.addListener(tl2);
int pos = 0;
for(char ch : given.toCharArray()) {
m1.insert(pos, ch);
m2.insert(pos, ch);
pos++;
}
setLayout(new GridLayout(3, 2, 8, 0));
add(new JLabel("Next change (press button)"));
add(new JLabel("Current Text"));
add(newInsertButton(typeThat, m1, m2));
add(tl1);
add(new JLabel(""));
add(tl2);
}
private JButton newInsertButton(final String typeThat, final TextModel m1, final TextModel m2) {
final JButton key = new JButton(buttonText(typeThat.charAt(0), 0));
key.addActionListener(new ActionListener() {
int pos = 0;
@Override
public void actionPerformed(ActionEvent arg0) {
char ch = typeThat.charAt(pos);
m1.insert(pos, ch);
m2.insert(pos, ch);
pos++;
if (pos >= typeThat.length()) {
key.setEnabled(false);
} else {
key.setText(buttonText(typeThat.charAt(pos), pos));
}
}
});
return key;
}
private String buttonText(char nextChar, int pos) {
return "insert \"" + nextChar + "\" at position " + pos;
}
}
package patterns.observer.copyright.sol;
public class CorrectionListener implements Listener {
private TextModel text;
public CorrectionListener(TextModel m) {
text = m;
}
@Override
public void notifyDelete(int from, int len) {
}
@Override
public void notifyInsert(int pos, char ch) {
if (pos >= 2) {
String s = text.getSubstring(pos - 2, 3).toUpperCase();
if ("(C)".equals(s)) {
System.out.println("correct on: " + text);
text.delete(pos - 2, 3);
text.insert(pos - 2, '©');
System.out.println("corrected text: " + text);
}
}
}
}
package patterns.observer.copyright.sol;
public interface Listener {
void notifyInsert(int pos, char ch);
void notifyDelete(int from, int len);
}
package patterns.observer.copyright.sol;
import javax.swing.JLabel;
@SuppressWarnings("serial")
public class TextListener extends JLabel implements Listener {
@Override
public void notifyDelete(int from, int len) {
String h = getText().substring(0, from);
String t = getText().substring(from + len);
setText(h + t);
}
@Override
public void notifyInsert(int pos, char ch) {
String h = getText().substring(0, pos);
String t = getText().substring(pos);
setText(h + ch + t);
}
}
package patterns.observer.copyright.sol;
public interface TextModel {
void addListener(Listener l);
void insert(int pos, char ch);
void delete(int from, int len);
String getSubstring(int from, int len);
}
\ No newline at end of file
package patterns.observer.copyright.sol;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
public class TextModelCorrect1 implements TextModel {
@FunctionalInterface
private static interface TextCommand {
void execute();
}
private final Deque<TextCommand> queue = new LinkedList<>();
private boolean isCommandRunning = false;
private void processQueue() {
if (!isCommandRunning) {
TextCommand cmd = queue.peekLast();
if (cmd != null) {
queue.pollLast();
cmd.execute();
}
}
}
private final StringBuilder text = new StringBuilder();
private final List<Listener> listeners = new ArrayList<>();
@Override
public void addListener(Listener l) {
listeners.add(l);
}
@Override
public void insert(final int pos, final char ch) {
queue.addFirst(() -> {
if (pos < 0 || pos > text.length())
throw new IllegalArgumentException();
text.insert(pos, ch);
isCommandRunning = true;
for (Listener l : listeners) {
l.notifyInsert(pos, ch);
}
isCommandRunning = false;
processQueue(); // invokes the next command in the queue
});
processQueue();
}
@Override
public void delete(final int from, final int len) {
queue.addFirst(() -> {
if (from < 0 || len < 0 || from + len > text.length())
throw new IllegalArgumentException();
text.delete(from, from + len);
isCommandRunning = true;
for (Listener l : listeners) {
l.notifyDelete(from, len);
}
isCommandRunning = false;
processQueue();
});
processQueue();
}
@Override
public String getSubstring(int from, int len) {
if (from < 0 || len < 0 || from + len > text.length()) throw new IllegalArgumentException();
return text.substring(from, from + len);
}
@Override
public String toString() {
return text.toString();
}
}
package patterns.observer.copyright.sol;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class TextModelCorrect2 implements TextModel {
@FunctionalInterface
private static interface TextCommand {
abstract void execute();
}
private final List<TextCommand> queue = new LinkedList<>();
private int notifyLevel = 0;
private void handle(TextCommand c) {
notifyLevel++;
if(notifyLevel > 1){
queue.add(c);
}
else {
c.execute();
while(!queue.isEmpty()){
queue.remove(0).execute();
}
}
notifyLevel--;
}
private final StringBuilder text = new StringBuilder();
private final List<Listener> listeners = new ArrayList<>();
@Override
public void addListener(Listener l) {
listeners.add(l);
}
@Override
public void insert(final int pos, final char ch) {
handle(() -> {
if (pos < 0 || pos > text.length())
throw new IllegalArgumentException();
text.insert(pos, ch);
for (Listener l : listeners) {
l.notifyInsert(pos, ch);
}
});
}
@Override
public void delete(final int from, final int len) {
handle(() -> {
if (from < 0 || len < 0 || from + len > text.length())
throw new IllegalArgumentException();
text.delete(from, from + len);
for (Listener l : listeners) {
l.notifyDelete(from, len);
}
});
}
@Override
public String getSubstring(int from, int len) {
if (from < 0 || len < 0 || from + len > text.length()) throw new IllegalArgumentException();
return text.substring(from, from + len);
}
@Override
public String toString() {
return text.toString();
}
}
package patterns.observer.copyright.sol;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingUtilities;
/*
* This solution is motivated by the stackoverflow entry
* http://stackoverflow.com/questions/3599519/in-java-swing-is-there-a-way-to-legally-attempt-to-mutate-in-notification
*/
public class TextModelCorrect3 implements TextModel {
private final StringBuilder text = new StringBuilder();
private final List<Listener> listeners = new ArrayList<>();
@Override
public void addListener(Listener l) {
listeners.add(l);
}
@Override
public void insert(final int pos, final char ch) {
if (pos < 0 || pos > text.length())
throw new IllegalArgumentException();
text.insert(pos, ch);
for (Listener l : listeners) {
SwingUtilities.invokeLater(() -> l.notifyInsert(pos, ch));
}
}
@Override
public void delete(int from, int len) {
if (from < 0 || len < 0 || from + len > text.length())
throw new IllegalArgumentException();
text.delete(from, from + len);
for (Listener l : listeners) {
SwingUtilities.invokeLater(() -> l.notifyDelete(from, len));
}
}
@Override
public String getSubstring(int from, int len) {
if (from < 0 || len < 0 || from + len > text.length()) throw new IllegalArgumentException();
return text.substring(from, from + len);
}
@Override
public String toString() {
return text.toString();
}
}
package patterns.observer.copyright.sol;
import java.util.ArrayList;
import java.util.List;
public class TextModelWrong implements TextModel {
private final StringBuilder text = new StringBuilder();
private List<Listener> listeners = new ArrayList<>();
@Override
public void addListener(Listener l) {
listeners.add(l);
}
@Override
public void insert(int pos, char ch) {
if (pos < 0 || pos > text.length()) throw new IllegalArgumentException();
text.insert(pos, ch);
for (Listener l : listeners) {
l.notifyInsert(pos, ch);
}
}
@Override
public void delete(int from, int len) {
if (from < 0 || len < 0 || from + len > text.length()) throw new IllegalArgumentException();
text.delete(from, from + len);
for (Listener l : listeners) {
l.notifyDelete(from, len);
}
}
@Override
public String getSubstring(int from, int len) {
if (from < 0 || len < 0 || from + len > text.length()) throw new IllegalArgumentException();
return text.substring(from, from + len);
}
@Override
public String toString() {
return text.toString();
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment