Fixed XML loading FeedGroups

This commit is contained in:
Balazs Toldi 2020-11-28 16:12:55 +01:00
parent fb27934790
commit d9aad12b82
6 changed files with 435 additions and 75 deletions

View file

@ -115,6 +115,7 @@ public class Article {
this.pubDate = pubDate;
}
public void open(){
Desktop desktop;
if(Desktop.isDesktopSupported() && (desktop = Desktop.getDesktop()).isSupported(Desktop.Action.BROWSE)){
@ -132,5 +133,4 @@ public class Article {
}
}
}
}

View file

@ -71,11 +71,6 @@ public class Feed {
}
@Override
public String toString() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ -91,4 +86,13 @@ public class Feed {
public String getLink() {
return link.toString();
}
public List<Article> getArticleList() {
return articleList;
}
@Override
public String toString() {
return name;
}
}

View file

@ -6,6 +6,7 @@ import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
public class FeedData extends AbstractTableModel {
private List<Feed> feeds = new ArrayList<Feed>();
@ -96,6 +97,28 @@ public class FeedData extends AbstractTableModel {
return feeds;
}
public void removeFeed(Feed feed){
boolean found = false;
for (int i = 0; i < feeds.size(); i++) {
//Csak ha PONTOSAN megegyezik
if(feeds.get(i) == feed){
feeds.remove(i);
found =true;
break;
}
}
if(found){
List<Article> similar = new ArrayList<Article>( articleList );
List<Article> different = new ArrayList<Article>();
different.addAll( articleList );
different.addAll( feed.getArticleList() );
similar.retainAll( feed.getArticleList() );
different.removeAll( similar );
articleList = different;
}
}
@Override
public String toString() {
return "FeedData{" +

View file

@ -5,13 +5,21 @@ import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.table.TableRowSorter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
//TODO: Hírcsatornák rendezése
//TODO: Keresés cikkek között
//TODO: Automatikus frissítés
public class FeedFrame extends JFrame {
@ -22,6 +30,7 @@ public class FeedFrame extends JFrame {
private JMenuBar menubar;
private JTree feeds;
private TableRowSorter<FeedData> sorter;
private DefaultMutableTreeNode treeRoot;
public FeedFrame() {
@ -34,22 +43,10 @@ public class FeedFrame extends JFrame {
private void initData() {
FeedLoader loader = new FeedLoader();
//data = loader.loadFeedData("feeds.xml");
data = new FeedData();
FeedGroup group = new FeedGroup("Magyar hírek");
try {
group.addFeed(new Feed(new URL("https://24.hu/feed")));
group.addFeed(new Feed(new URL("https://444.hu/feed")));
group.addFeed(new Feed(new URL("https://hvg.hu/rss")));
data.addFeed(new Feed(new URL("https://www.theguardian.com/uk/rss")));
} catch (MalformedURLException e) {
e.printStackTrace();
}
data.addFeed(group);
data = loader.loadFeedData("feeds.xml");
}
private void initTable(){
private void initTable() {
table = new JTable();
scrollPane = new JScrollPane(table);
table.setModel(data);
@ -70,7 +67,7 @@ public class FeedFrame extends JFrame {
}
private void initMenuBar(){
private void initMenuBar() {
menubar = new JMenuBar();
JMenu menu1 = new JMenu("File");
JMenuItem addFeed = new JMenuItem("Add Feed");
@ -84,12 +81,33 @@ public class FeedFrame extends JFrame {
this.setJMenuBar(menubar);
}
private void initTree(){
DefaultMutableTreeNode root = data.getRootNode();
feeds = new JTree(root);
private void expandTree(JTree tree) {
DefaultMutableTreeNode root =
(DefaultMutableTreeNode) tree.getModel().getRoot();
Enumeration e = root.breadthFirstEnumeration();
while (e.hasMoreElements()) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) e.nextElement();
if (node.isLeaf()) continue;
int row = tree.getRowForPath(new TreePath(node.getPath()));
tree.expandRow(row);
}
}
private void initTree() {
treeRoot = data.getRootNode();
feeds = new JTree(treeRoot);
feeds.addMouseListener(new SwitchFeed());
feeds.setEditable(true);
add(feeds,BorderLayout.WEST);
feeds.setEditable(false);
feeds.setDragEnabled(true);
feeds.setDropMode(DropMode.ON_OR_INSERT);
feeds.setTransferHandler(new TreeTransferHandler());
feeds.getSelectionModel().setSelectionMode(
TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
expandTree(feeds);
add(feeds, BorderLayout.WEST);
}
private void initComponents() {
@ -101,6 +119,12 @@ public class FeedFrame extends JFrame {
initTree();
}
private void updateTeble(){
sorter.setModel(data);
table.setRowSorter(sorter);
table.updateUI();
}
private class AddFeed implements ActionListener {
@Override
@ -118,8 +142,10 @@ public class FeedFrame extends JFrame {
} catch (MalformedURLException malformedURLException) {
malformedURLException.printStackTrace();
}
treeRoot.add(f.getTreeNode());
data.addFeed(f);
table.updateUI();
feeds.updateUI();
} else {
System.out.println("Cancelled");
}
@ -141,19 +167,261 @@ public class FeedFrame extends JFrame {
public void mousePressed(MouseEvent e) {
int selRow = feeds.getRowForLocation(e.getX(), e.getY());
TreePath selPath = feeds.getPathForLocation(e.getX(), e.getY());
if(selRow != -1) {
if(e.getClickCount() == 1) {
if(selRow == 0) data.limitTo(null);
if (selRow != -1) {
if (e.getClickCount() == 2) {
if (selRow == 0) data.limitTo(null);
else {
data.limitTo((Feed) ((DefaultMutableTreeNode) selPath.getLastPathComponent()).getUserObject());
}
sorter.setModel(data);
table.setRowSorter(sorter);
table.updateUI();
updateTeble();
}
}
}
}
}
class TreeTransferHandler extends TransferHandler {
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
List<DefaultMutableTreeNode> nodesToRemove;
public TreeTransferHandler() {
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType +
";class=\"" +
DefaultMutableTreeNode[].class.getName() +
"\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
public boolean canImport(TransferHandler.TransferSupport support) {
if (!support.isDrop() || support.getDropAction() == COPY) {
return false;
}
support.setShowDropLocation(true);
if (!support.isDataFlavorSupported(nodesFlavor)) {
return false;
}
// Do not allow a drop on the drag source selections.
JTree.DropLocation dl =
(JTree.DropLocation) support.getDropLocation();
JTree tree = (JTree) support.getComponent();
int dropRow = tree.getRowForPath(dl.getPath());
int[] selRows = tree.getSelectionRows();
for (int i = 0; i < selRows.length; i++) {
if (selRows[i] == dropRow) {
return false;
}
}
// Do not allow MOVE-action drops if a non-leaf node is
// selected unless all of its children are also selected.
int action = support.getDropAction();
if (action == MOVE) {
return haveCompleteNode(tree);
}
// Do not allow a non-leaf node to be copied to a level
// which is less than its source level.
TreePath dest = dl.getPath();
DefaultMutableTreeNode target =
(DefaultMutableTreeNode) dest.getLastPathComponent();
TreePath path = tree.getPathForRow(selRows[0]);
DefaultMutableTreeNode firstNode =
(DefaultMutableTreeNode) path.getLastPathComponent();
if (firstNode.getChildCount() > 0 &&
target.getLevel() < firstNode.getLevel()) {
return false;
}
return true;
}
private boolean haveCompleteNode(JTree tree) {
int[] selRows = tree.getSelectionRows();
TreePath path = tree.getPathForRow(selRows[0]);
DefaultMutableTreeNode first =
(DefaultMutableTreeNode) path.getLastPathComponent();
int childCount = first.getChildCount();
// first has children and no children are selected.
if (childCount > 0 && selRows.length == 1)
return false;
// first may have children.
for (int i = 1; i < selRows.length; i++) {
path = tree.getPathForRow(selRows[i]);
DefaultMutableTreeNode next =
(DefaultMutableTreeNode) path.getLastPathComponent();
if (first.isNodeChild(next)) {
// Found a child of first.
if (childCount > selRows.length - 1) {
// Not all children of first are selected.
return false;
}
}
}
return true;
}
protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree) c;
TreePath[] paths = tree.getSelectionPaths();
if (paths != null) {
// Make up a node array of copies for transfer and
// another for/of the nodes that will be removed in
// exportDone after a successful drop.
List<DefaultMutableTreeNode> copies = new ArrayList<DefaultMutableTreeNode>();
nodesToRemove = new ArrayList<DefaultMutableTreeNode>();
DefaultMutableTreeNode node = (DefaultMutableTreeNode) paths[0].getLastPathComponent();
DefaultMutableTreeNode copy = copy(node);
copies.add(copy);
nodesToRemove.add(node);
for (int i = 1; i < paths.length; i++) {
DefaultMutableTreeNode next =
(DefaultMutableTreeNode) paths[i].getLastPathComponent();
// Do not allow higher level nodes to be added to list.
if (next.getLevel() < node.getLevel()) {
break;
} else if (next.getLevel() > node.getLevel()) { // child node
copy.add(copy(next));
// node already contains child
} else { // sibling
copies.add(copy(next));
nodesToRemove.add(next);
}
}
DefaultMutableTreeNode[] nodes =
copies.toArray(new DefaultMutableTreeNode[copies.size()]);
return new NodesTransferable(nodes);
}
return null;
}
/**
* Defensive copy used in createTransferable.
*/
private DefaultMutableTreeNode copy(DefaultMutableTreeNode node) {
return new DefaultMutableTreeNode(node.getUserObject());
}
protected void exportDone(JComponent source, Transferable data, int action) {
if ((action & MOVE) == MOVE) {
JTree tree = (JTree) source;
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
// Remove nodes saved in nodesToRemove in createTransferable.
for (int i = 0; i < nodesToRemove.size(); i++) {
model.removeNodeFromParent(nodesToRemove.get(i));
}
}
updateTeble();
}
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
public List<DefaultMutableTreeNode> getParents(DefaultMutableTreeNode[] nodes, TreePath[] paths) {
ArrayList<DefaultMutableTreeNode> results = new ArrayList<DefaultMutableTreeNode>();
for (int i = 0; i < nodes.length; i++) {
for (int j = 0; j < paths.length; j++) {
if (nodes[i].getUserObject().equals(((DefaultMutableTreeNode)paths[j].getLastPathComponent()).getUserObject())) {
results.add((DefaultMutableTreeNode) ((DefaultMutableTreeNode) paths[j].getLastPathComponent()).getParent());
}
}
}
return results;
}
public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
DefaultMutableTreeNode[] nodes = null;
try {
Transferable t = support.getTransferable();
nodes = (DefaultMutableTreeNode[]) t.getTransferData(nodesFlavor);
} catch (UnsupportedFlavorException ufe) {
System.out.println("UnsupportedFlavor: " + ufe.getMessage());
} catch (java.io.IOException ioe) {
System.out.println("I/O error: " + ioe.getMessage());
}
JTree.DropLocation dl =
(JTree.DropLocation) support.getDropLocation();
int childIndex = dl.getChildIndex();
TreePath dest = dl.getPath();
DefaultMutableTreeNode parent =
(DefaultMutableTreeNode) dest.getLastPathComponent();
JTree tree = (JTree) support.getComponent();
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
List<DefaultMutableTreeNode> parents = getParents(nodes,tree.getSelectionPaths());
int index = childIndex; // DropMode.INSERT
if (childIndex == -1) { // DropMode.ON
if (parent.getLevel() > 1) {
return false;
}
if (parent.isLeaf()) {
FeedGroup fg = new FeedGroup("New Feed Group");
fg.addFeed((Feed) parent.getUserObject());
DefaultMutableTreeNode newParent = fg.getTreeNode();
data.removeFeed((Feed) parent.getUserObject());
model.insertNodeInto(newParent, (MutableTreeNode) parent.getParent(), parent.getParent().getChildCount());
for (int i = 0; i < nodes.length; i++) {
fg.addFeed((Feed) nodes[i].getUserObject());
}
data.addFeed(fg);
model.removeNodeFromParent(parent);
parent = newParent;
}
index = parent.getChildCount();
}
for (int i = 0; i < nodes.length; i++) {
model.insertNodeInto(nodes[i], parent, index++);
if (parent != parents.get(i)) {
if (!(parents.get(i).isRoot())) {
FeedGroup fg = (FeedGroup) parents.get(i).getUserObject();
fg.removeFeed((Feed) nodes[i].getUserObject());
} else {
data.removeFeed((Feed) nodes[i].getUserObject());
}
if(parents.get(i).getChildCount() == 1){
model.removeNodeFromParent(parents.get(i));
data.limitTo(null);
data.removeFeed((Feed) parent.getUserObject());
}
}
}
return true;
}
public String toString() {
return getClass().getName();
}
public class NodesTransferable implements Transferable {
DefaultMutableTreeNode[] nodes;
public NodesTransferable(DefaultMutableTreeNode[] nodes) {
this.nodes = nodes;
}
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException {
if (!isDataFlavorSupported(flavor))
throw new UnsupportedFlavorException(flavor);
return nodes;
}
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return nodesFlavor.equals(flavor);
}
}
}
}

View file

@ -20,10 +20,21 @@ public class FeedGroup extends Feed {
}
public void addFeed(Feed feed){
feedList.add(feed);
for (int i = 0; i < feed.getArticleCount(); i++) {
articleList.add(feed.get(i));
if(!feedExists(feed)) {
feedList.add(feed);
for (int i = 0; i < feed.getArticleCount(); i++) {
articleList.add(feed.get(i));
}
}else
System.out.println("Feed exists");
}
public boolean feedExists(Feed f){
for (int i = 0; i < feedList.size(); i++) {
if(f == feedList.get(i))
return true;
}
return false;
}
@Override
@ -55,4 +66,27 @@ public class FeedGroup extends Feed {
}
return folder;
}
public void removeFeed(Feed feed){
boolean found = false;
for (int i = 0; i < feedList.size(); i++) {
//Csak ha PONTOSAN megegyezik
if(feedList.get(i) == feed){
feedList.remove(i);
found =true;
break;
}
}
if(found){
List<Article> similar = new ArrayList<Article>( articleList );
List<Article> different = new ArrayList<Article>();
different.addAll( articleList );
different.addAll( feed.getArticleList() );
similar.retainAll( feed.getArticleList() );
different.removeAll( similar );
articleList = different;
}
}
}

View file

@ -9,10 +9,8 @@ import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
@ -22,6 +20,38 @@ public class FeedLoader {
private FeedData data;
private Feed getFeed(NodeList feedProperties) throws MalformedURLException {
List<Article> articleList = new ArrayList<Article>();
String url = null;
for (int j = 1; j < feedProperties.getLength(); j+=2) {
Node node = feedProperties.item(j);
String tagName = node.getNodeName();
switch (tagName){
case "link":
url = node.getTextContent();
break;
case "articleList":
NodeList articles = node.getChildNodes();
for (int k = 0; k < articles.getLength(); k++) {
Node article = articles.item(k);
Article a = new Article(article, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
if(a.getURL() != null)
articleList.add(a);
}
}
if(url == null) return null;
}
Feed feed = new Feed(new URL(url));
System.out.println(articleList.size());
for (int k = 0; k < articleList.size(); k++) {
feed.addArticle(articleList.get(k));
}
return feed;
}
public FeedData loadFeedData(String filename) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newDefaultInstance();
data = new FeedData();
@ -29,40 +59,38 @@ public class FeedLoader {
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File(filename));
NodeList feeds = doc.getElementsByTagName("feed");
for (int i = 0; i < feeds.getLength(); i++) {
NodeList feedProperties = feeds.item(i).getChildNodes();
List<Article> articleList = new ArrayList<Article>();
String url = null;
for (int j = 0; j < feedProperties.getLength(); j++) {
Node node = feedProperties.item(j);
String tagName = node.getNodeName();
NodeList feeds = doc.getFirstChild().getChildNodes();
for (int i = 1; i < feeds.getLength(); i=i+2) {
if(feeds.item(i).getNodeName().equals("feed")) {
Feed feed = getFeed(feeds.item(i).getChildNodes());
if(feed != null)data.addFeed(feed);
}else if (feeds.item(i).getNodeName().equals("feedGroup")){
NodeList feedGroupprops = feeds.item(i).getChildNodes();
String name = null;
FeedGroup fg = null;
for (int j = 1; j < feedGroupprops.getLength(); j+=2) {
Node node = feedGroupprops.item(j);
String tagName = node.getNodeName();
switch (tagName){
case "link":
url = node.getTextContent();
break;
case "articleList":
NodeList articles = node.getChildNodes();
for (int k = 0; k < articles.getLength(); k++) {
Node article = articles.item(k);
Article a = new Article(article, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
if(a.getURL() != null)
articleList.add(a);
}
switch (tagName){
case "name":
fg = new FeedGroup(node.getTextContent());
break;
case "feedList":
if(fg == null) continue;
NodeList feedList1 = node.getChildNodes();
for (int k = 1; k < feedList1.getLength(); k+=2) {
Node f = feedList1.item(k);
Feed feed = getFeed(f.getChildNodes());
fg.addFeed(feed);
}
}
}
if(url == null) continue;
}
Feed feed = new Feed(new URL(url));
System.out.println(articleList.size());
for (int k = 0; k < articleList.size(); k++) {
System.out.println();
feed.addArticle(articleList.get(k));
}
data.addFeed(feed);
if(fg != null)
data.addFeed(fg);
}else
System.out.println(feeds.item(i).getNodeName());
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
@ -71,16 +99,19 @@ public class FeedLoader {
} catch (SAXException e) {
e.printStackTrace();
}
return data;
}
public void saveFeedData() {
XStream xStream = new XStream();
xStream.processAnnotations(Article.class);
xStream.processAnnotations(Feed.class);
xStream.processAnnotations(FeedGroup.class);
xStream.omitField(FeedData.class,"articleList");
xStream.omitField(javax.swing.event.EventListenerList.class,"listenerList");
xStream.omitField(FeedData.class, "articleList");
xStream.omitField(javax.swing.event.EventListenerList.class, "listenerList");
String xml = xStream.toXML(data.getFeeds());
BufferedWriter writer;
try {