From f476d1e3cb958662acdce7c19579ed6248cb647c Mon Sep 17 00:00:00 2001 From: asdfasdf Date: Sun, 24 Nov 2019 18:47:03 -0800 Subject: [PATCH] Completed add and del butt --- src/main/data/WatchList.java | 52 ++++++++++++++++++++---- src/main/observer/Subject.java | 24 ----------- src/main/observer/Wobserver.java | 8 ---- src/main/ui/Gui.java | 14 +++++-- src/main/ui/Tui.java | 9 ++-- src/main/ui/guicomp/AddButt.java | 20 ++++++++- src/main/ui/guicomp/DelButt.java | 28 ++++++++++++- src/main/ui/guicomp/UpButt.java | 6 ++- src/main/ui/guicomp/WatchTableModel.java | 31 +++++++++++++- src/main/ui/guicomp/WatchTablePane.java | 23 +++++++++++ 10 files changed, 161 insertions(+), 54 deletions(-) delete mode 100644 src/main/observer/Subject.java delete mode 100644 src/main/observer/Wobserver.java create mode 100644 src/main/ui/guicomp/WatchTablePane.java diff --git a/src/main/data/WatchList.java b/src/main/data/WatchList.java index 451ef9e..05f15e5 100644 --- a/src/main/data/WatchList.java +++ b/src/main/data/WatchList.java @@ -5,12 +5,16 @@ import java.io.*; import data.StockEntry; import ui.Main; import data.exceptions.*; -import observer.Subject; +import java.util.Observable; -public class WatchList extends Subject implements Load,Save { +public class WatchList extends Observable implements Load,Save { private LinkedHashMap listdata; public static final String DEFAULT_SAVEFILE = ".jwatch.list"; + public enum Etype { + UPDATE, ADD, DEL + } + // Effects: List is empty // or loaded with save values public WatchList() { @@ -18,7 +22,7 @@ public class WatchList extends Subject implements Load,Save { if (fileExists(DEFAULT_SAVEFILE)) { load(""); } - ListOfWatchList.getList().addWatchList(this); + ListOfWatchList.getList().addWatchList(this); } // Debug constructor @@ -32,8 +36,10 @@ public class WatchList extends Subject implements Load,Save { // Requires: target doesn't already exists public void addStock(String target) { //The only implementation yet - StockType stype = StypeMap.getStype("NYSE"); + StockType stype = StypeMap.getStype("NYSE"); this.listdata.put(target, new StockEntry(stype, target)); + setChanged(); + notifyObservers(new Wevent(Etype.ADD, size())); } // Effects: Delete an entry with key==target @@ -43,7 +49,14 @@ public class WatchList extends Subject implements Load,Save { if (!listdata.containsKey(target)) { throw new StockNotExistsException(); } + int index = new ArrayList(listdata.keySet()).indexOf(target); this.listdata.remove(target); + setChanged(); + notifyObservers(new Wevent(Etype.DEL, index)); + } + + public String[] getNames() { + return listdata.keySet().toArray(new String[0]); } // Effects: Return an iterator of the list @@ -59,9 +72,9 @@ public class WatchList extends Subject implements Load,Save { return entryset.iterator(); } - //XXX index access method public StockEntry getStock(int index) { - return (StockEntry) listdata.entrySet().toArray()[index]; + String key = (String) listdata.keySet().toArray()[index]; + return (StockEntry) listdata.get(key); } // Effects: Return the size of list @@ -81,7 +94,7 @@ public class WatchList extends Subject implements Load,Save { while (iterate.hasNext()) { Map.Entry entry = (Map.Entry)iterate.next(); String outString = (String)entry.getKey(); - System.out.println("Exported: " + outString); + System.out.println("Exported: " + outString); bwriter.write(outString); bwriter.newLine(); } @@ -125,6 +138,29 @@ public class WatchList extends Subject implements Load,Save { StockEntry sentry = (StockEntry)entry.getValue(); sentry.update(); } - sendMsg(); + setChanged(); + notifyObservers(new Wevent(Etype.UPDATE)); + } + + public class Wevent { + private Etype type; + private int data; + + public Wevent(Etype type) { + this(type, 0); + } + + public Wevent(Etype type, int num) { + this.type = type; + this.data = num; + } + + public Etype getType() { + return type; + } + + public int getData() { + return data; + } } } diff --git a/src/main/observer/Subject.java b/src/main/observer/Subject.java deleted file mode 100644 index 7cacbdd..0000000 --- a/src/main/observer/Subject.java +++ /dev/null @@ -1,24 +0,0 @@ -package observer; - -import java.util.List; -import java.util.ArrayList; -import java.util.Collections; - -public abstract class Subject { - protected ArrayList obsList = new ArrayList(); - - public void addObs(Wobserver obs) { - obsList.add(obs); - } - - public void delObs(Wobserver obs) { - //Collections.singleton from https://howtodoinjava.com/java/collections/arraylist/arraylist-removeall/ - obsList.removeAll(Collections.singleton(obs)); - } - - public void sendMsg() { - for (Wobserver obs : obsList) { - obs.update(this); - } - } -} diff --git a/src/main/observer/Wobserver.java b/src/main/observer/Wobserver.java deleted file mode 100644 index f259a48..0000000 --- a/src/main/observer/Wobserver.java +++ /dev/null @@ -1,8 +0,0 @@ -package observer; - -import java.util.List; -import data.WatchList; - -public interface Wobserver { - public void update(Subject obsed); -} diff --git a/src/main/ui/Gui.java b/src/main/ui/Gui.java index 9fc8367..794b3d0 100644 --- a/src/main/ui/Gui.java +++ b/src/main/ui/Gui.java @@ -8,6 +8,8 @@ import javax.swing.GroupLayout; import java.awt.Container; import java.awt.LayoutManager; import ui.guicomp.*; +import data.WatchList; +import data.ListOfWatchList; import static data.Const.PROGRAM_NAME; import javax.swing.GroupLayout.Alignment; @@ -16,6 +18,8 @@ public class Gui extends JFrame implements Iface { private JButton addButton; private JButton delButton; private JButton upButton; + private WatchTablePane wtable; + private WatchList wlist; private Runnable init = new Runnable() { public void run() { addComponents(); @@ -27,9 +31,10 @@ public class Gui extends JFrame implements Iface { } private void addComponents() { - addButton = new AddButt(); - delButton = new DelButt(); - upButton = new UpButt(); + addButton = new AddButt(wlist); + delButton = new DelButt(wlist); + upButton = new UpButt(wlist); + wtable = new WatchTablePane(wlist); } private void createLayout() { @@ -38,12 +43,14 @@ public class Gui extends JFrame implements Iface { pane.setLayout(lman); lman.setAutoCreateContainerGaps(true); lman.setHorizontalGroup(lman.createParallelGroup(GroupLayout.Alignment.CENTER) + .addComponent(wtable.getPane()) .addGroup(lman.createSequentialGroup() .addComponent(addButton) .addComponent(delButton) .addComponent(upButton) )); lman.setVerticalGroup(lman.createSequentialGroup() + .addComponent(wtable.getPane()) .addGroup(lman.createParallelGroup(GroupLayout.Alignment.CENTER) .addComponent(addButton) .addComponent(delButton) @@ -53,6 +60,7 @@ public class Gui extends JFrame implements Iface { }; public Gui() { + wlist = ListOfWatchList.getList().getWatchList(0); SwingUtilities.invokeLater(init); setVisible(true); } diff --git a/src/main/ui/Tui.java b/src/main/ui/Tui.java index 9788846..29b3d21 100644 --- a/src/main/ui/Tui.java +++ b/src/main/ui/Tui.java @@ -9,9 +9,10 @@ import data.WatchList; import data.StockEntry; import data.ListOfWatchList; import data.exceptions.*; -import observer.*; +import java.util.Observer; +import java.util.Observable; -public class Tui implements Iface, Wobserver { +public class Tui implements Iface, Observer { private static final String SAVE_CURSOR = "\u001b[s"; private static final String RESTORE_CURSOR = "\u001b[s"; private static final String REQUEST_CURSOR = "\u001b[6n"; @@ -23,7 +24,7 @@ public class Tui implements Iface, Wobserver { stdin = new BufferedReader(new InputStreamReader(System.in)); getMax(); WatchList watch = ListOfWatchList.getList().getWatchList(0); - watch.addObs(this); + watch.addObserver(this); //XXX Start ui thread demo(); } @@ -182,7 +183,7 @@ public class Tui implements Iface, Wobserver { } @Override - public void update(Subject obsed) { + public void update(Observable obsed, Object event) { printWatchList(); } } diff --git a/src/main/ui/guicomp/AddButt.java b/src/main/ui/guicomp/AddButt.java index 9750b86..0de4675 100644 --- a/src/main/ui/guicomp/AddButt.java +++ b/src/main/ui/guicomp/AddButt.java @@ -3,17 +3,33 @@ package ui.guicomp; import javax.swing.JButton; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; +import javax.swing.JOptionPane; +import data.WatchList; public class AddButt extends JButton { - public AddButt() { + private WatchList wlist; + + public AddButt(WatchList wlist) { super("Add Stock..."); addActionListener(new AddButtList()); + this.wlist = wlist; } private class AddButtList implements ActionListener { public void actionPerformed(ActionEvent e) { - //XXX Ask for input dialogue //https://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html#input + //https://docs.oracle.com/javase/7/docs/api/javax/swing/JOptionPane.html + String userin = (String)JOptionPane.showInputDialog("Enter the identifier:"); + if ((userin != null) && (userin.length() > 0)) { + //https://stackoverflow.com/questions/12771500/best-way-of-creating-and-using-an-anonymous-runnable-class + new Thread(new Runnable() { + @Override + public void run() { + wlist.addStock(userin); + wlist.updateList(); + } + }).start(); + } } } } diff --git a/src/main/ui/guicomp/DelButt.java b/src/main/ui/guicomp/DelButt.java index 4f34756..476ac0a 100644 --- a/src/main/ui/guicomp/DelButt.java +++ b/src/main/ui/guicomp/DelButt.java @@ -3,17 +3,41 @@ package ui.guicomp; import javax.swing.JButton; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; +import javax.swing.JOptionPane; +import data.WatchList; +import data.exceptions.StockNotExistsException; public class DelButt extends JButton { - public DelButt() { + private WatchList wlist; + + public DelButt(WatchList wlist) { super("Remove Stock..."); addActionListener(new DelButtList()); + this.wlist = wlist; } private class DelButtList implements ActionListener { public void actionPerformed(ActionEvent e) { - //XXX Ask for input dialogue //https://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html#input + //https://docs.oracle.com/javase/7/docs/api/javax/swing/JOptionPane.html + String[] names = wlist.getNames(); + String userin = (String)JOptionPane.showInputDialog( + null, "Choose a stock to delete:", "Delete Stock", + JOptionPane.PLAIN_MESSAGE, null, names, null); + if ((userin != null) && (userin.length() > 0)) { + //https://stackoverflow.com/questions/12771500/best-way-of-creating-and-using-an-anonymous-runnable-class + new Thread(new Runnable() { + @Override + public void run() { + try { + wlist.delStock(userin); + } catch (StockNotExistsException e) { + //impossible + e.printStackTrace(); + } + } + }).start(); + } } } } diff --git a/src/main/ui/guicomp/UpButt.java b/src/main/ui/guicomp/UpButt.java index 419b7c0..85cffbf 100644 --- a/src/main/ui/guicomp/UpButt.java +++ b/src/main/ui/guicomp/UpButt.java @@ -3,11 +3,15 @@ package ui.guicomp; import javax.swing.JButton; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; +import data.WatchList; public class UpButt extends JButton { - public UpButt() { + private WatchList wlist; + + public UpButt(WatchList wlist) { super("Update"); addActionListener(new UpButtList()); + this.wlist = wlist; } private class UpButtList implements ActionListener { diff --git a/src/main/ui/guicomp/WatchTableModel.java b/src/main/ui/guicomp/WatchTableModel.java index 4a6d1d6..6685e07 100644 --- a/src/main/ui/guicomp/WatchTableModel.java +++ b/src/main/ui/guicomp/WatchTableModel.java @@ -4,16 +4,22 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import javax.swing.event.*; import data.WatchList; +import data.WatchList.Wevent; import data.StockEntry; +import java.util.Observer; +import java.util.Observable; +import javax.swing.SwingUtilities; // Ref: https://docs.oracle.com/javase/tutorial/uiswing/components/table.html // Ref2: https://docs.oracle.com/javase/8/docs/api/javax/swing/table/AbstractTableModel.html -public class WatchTableModel extends AbstractTableModel { +public class WatchTableModel extends AbstractTableModel implements Observer { private final String[] colnames = {"Identifier", "Price", "% change", "Status"}; + private final Object[] example = {"asdf", 0.0, "asdf", "asdf"}; private WatchList watch; public WatchTableModel(WatchList wlist) { watch = wlist; + watch.addObserver(this); } public int getColumnCount() { @@ -45,6 +51,27 @@ public class WatchTableModel extends AbstractTableModel { } public Class getColumnClass(int col) { - return getValueAt(0,col).getClass(); + return example[col].getClass(); + } + + @Override + public void update(Observable obsed, Object event) { + Wevent weve = (Wevent) event; + switch (weve.getType()) { + case UPDATE: + SwingUtilities.invokeLater(() -> { + fireTableDataChanged(); }); + break; + case ADD: + SwingUtilities.invokeLater(() -> { + fireTableRowsInserted(weve.getData(), weve.getData()); }); + break; + case DEL: + SwingUtilities.invokeLater(() -> { + fireTableRowsDeleted(weve.getData(), weve.getData()); }); + break; + default: + break; + } } } diff --git a/src/main/ui/guicomp/WatchTablePane.java b/src/main/ui/guicomp/WatchTablePane.java new file mode 100644 index 0000000..ee4f32a --- /dev/null +++ b/src/main/ui/guicomp/WatchTablePane.java @@ -0,0 +1,23 @@ +package ui.guicomp; + +import javax.swing.JTable; +import javax.swing.JScrollPane; +import javax.swing.table.TableModel; +import data.WatchList; + +//https://docs.oracle.com/javase/7/docs/api/javax/swing/JTable.html +public class WatchTablePane { + private JTable table; + private TableModel tmodel; + private JScrollPane spane; + + public WatchTablePane(WatchList wlist) { + tmodel = new WatchTableModel(wlist); + table = new JTable(tmodel); + spane = new JScrollPane(table); + } + + public JScrollPane getPane() { + return spane; + } +}