aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/model/BrowserState.java10
-rw-r--r--src/main/model/css/CssParser.java169
-rw-r--r--src/main/model/html/ElementNode.java18
-rw-r--r--src/main/model/html/HtmlParser.java206
-rw-r--r--src/main/model/html/TextNode.java18
-rw-r--r--src/main/model/layout/BlockLayout.java10
-rw-r--r--src/main/model/layout/DocumentLayout.java5
-rw-r--r--src/main/model/layout/InlineLayout.java22
-rw-r--r--src/main/model/layout/Layout.java6
-rw-r--r--src/main/ui/BrowserApp.java57
-rw-r--r--src/main/ui/BrowserBar.java75
-rw-r--r--src/main/ui/BrowserCanvas.java29
-rw-r--r--src/main/ui/BrowserWindow.java23
13 files changed, 198 insertions, 450 deletions
diff --git a/src/main/model/BrowserState.java b/src/main/model/BrowserState.java
index da21c41..7b05f8c 100644
--- a/src/main/model/BrowserState.java
+++ b/src/main/model/BrowserState.java
@@ -2,13 +2,11 @@ package model;
import java.util.ArrayDeque;
-// This BrowserState function collects the stateful portions of the browser into one modelable class.
+// This BrowserState class collects the stateful portions of the browser into one modelable class.
public class BrowserState {
private ArrayDeque<String> tabs;
private String currentTab;
- // EFFECTS: constructs a new BrowserState
- // MODIFIES: this
public BrowserState(ArrayDeque<String> tabs, String currentTab) {
this.tabs = tabs;
this.currentTab = currentTab;
@@ -22,22 +20,16 @@ public class BrowserState {
return this.currentTab;
}
- // MODIFIES: this
- // EFFECTS: Sets the current tab
public void setCurrentTab(String tab) {
this.currentTab = tab;
}
- // MODIFIES: this
- // EFFECTS: add a new tab
public void addTab(String added) {
if (!this.tabs.contains(added)) {
this.tabs.add(added);
}
}
- // MODIFIES: this
- // EFFECTS: removes a tab from the tablist
public void removeTab(String removed) {
this.tabs.remove(removed);
}
diff --git a/src/main/model/css/CssParser.java b/src/main/model/css/CssParser.java
index a382b14..8bf4059 100644
--- a/src/main/model/css/CssParser.java
+++ b/src/main/model/css/CssParser.java
@@ -60,10 +60,6 @@ public class CssParser {
* however we do keep a previousChar value for dealing with (annoying) escaped quotes.
* It should be fast - I'd say something about time complexity if I knew anything about time complexity.
* No guarantees are made about invalid CSS files. Also, no guarantees are made about valid CSS files, lol.
- * <br>
- * REQUIRES: A valid CSS file, as a raw String.
- * MODIFIES: this
- * EFFECTS: Returns a parsed CSS representation as several nested ArrayLists and Pairs of Strings.
*/
public ArrayList<Pair<String, ArrayList<Pair<String, String>>>> parseCSS(String input) {
@@ -71,77 +67,52 @@ public class CssParser {
// System.out.print(state);
// System.out.println(" " + c);
switch (state) {
- case SELECTORS: caseSelectors(c);
- break;
- case MEDIA_SELECTORS: caseMediaSelectors(c);
- break;
- case ATTRIBUTE: caseAttribute(c);
- break;
- case VALUE: caseValue(c);
- break;
- case SINGLE_QUOTES: caseSingleQuotes(c);
- break;
- case DOUBLE_QUOTES: caseDoubleQuotes(c);
- break;
+ case SELECTORS -> caseSelectors(c);
+ case MEDIA_SELECTORS -> caseMediaSelectors(c);
+ case ATTRIBUTE -> caseAttribute(c);
+ case VALUE -> caseValue(c);
+ case SINGLE_QUOTES -> caseSingleQuotes(c);
+ case DOUBLE_QUOTES -> caseDoubleQuotes(c);
}
}
return result;
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the SELECTORS state.
- * See also: the (slightly wrong) context-free grammar commented at the start of this file.
- * MODIFIES: this
- */
+ // Handles and updates parser state/buffers for a single character while in the SELECTORS state.
+ // See also: the (slightly wrong) context-free grammar commented at the start of this file.
private void caseSelectors(char c) {
switch (c) {
- case '@':
+ case '@' -> {
if (currentSelector.equals("")) {
state = ParserState.MEDIA_SELECTORS;
} else {
currentSelector += c;
}
- break;
- case '{':
- state = ParserState.ATTRIBUTE;
- break;
- case ' ': case '\n':
- break;
+ }
+ case '{' -> state = ParserState.ATTRIBUTE;
+ case ' ', '\n' -> {}
// todo: do better than blindly create a string; pattern match on css selectors
- default:
- currentSelector += c;
- break;
+ default -> currentSelector += c;
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the MEDIA_SELECTORS state.
- * MODIFIES: this
- */
+ // Handles and updates parser state/buffers for a single character while in the MEDIA_SELECTORS state.
private void caseMediaSelectors(char c) {
switch (c) {
// todo: don't entirely disregard media queries, also split between @media/@...
- case '{':
+ case '{' -> {
state = ParserState.SELECTORS;
- // discard currentSelector
currentSelector = "";
- break;
- default:
- currentSelector += c;
- break;
+ }
+ default -> currentSelector += c;
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the ATTRIBUTE state.
- * MODIFIES: this
- */
+ // Handles and updates parser state/buffers for a single character while in the ATTRIBUTE state.
private void caseAttribute(char c) {
switch (c) {
- case ':':
- state = ParserState.VALUE;
- break;
- case '}':
+ case ':' -> state = ParserState.VALUE;
+ case '}' -> {
state = ParserState.SELECTORS;
if (!currentValue.equals("") || !currentProperty.equals("")) {
// System.out.println("something's wrong");
@@ -151,26 +122,20 @@ public class CssParser {
result.add(new Pair<>(currentSelector, currentRule));
currentSelector = "";
currentRule = new ArrayList<>();
- break;
- case ' ': case '\n':
- break;
- default:
- currentProperty += c;
- break;
+ }
+ case ' ', '\n' -> {}
+ default -> currentProperty += c;
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the VALUE state.
- * MODIFIES: this
- */
+ // Handles and updates parser state/buffers for a single character while in the VALUE state.
private void caseValue(char c) {
switch (c) {
- case ';':
+ case ';' -> {
state = ParserState.ATTRIBUTE;
updateCurrentRule();
- break;
- case '}':
+ }
+ case '}' -> {
state = ParserState.SELECTORS;
if (!currentValue.equals("") || !currentProperty.equals("")) {
updateCurrentRule();
@@ -178,25 +143,22 @@ public class CssParser {
result.add(new Pair<>(currentSelector, currentRule));
currentSelector = "";
currentRule = new ArrayList<>();
- break;
+ }
// todo: handle spaces better: they're actually important inside values
- case ' ': case '\n': break; // believe me, i think this is ugly too but it passes checkstyle
- case '\'':
+ case ' ', '\n' -> {}
+ case '\'' -> {
state = ParserState.SINGLE_QUOTES;
currentValue += c;
- break;
- // intentional use of TERRIBLE SMOKING FOOTGUN behavior to check boxes
- case '\"': state = ParserState.DOUBLE_QUOTES;
- default: currentValue += c;
- break;
+ }
+ case '\"' -> {
+ state = ParserState.DOUBLE_QUOTES;
+ currentValue += c;
+ }
+ default -> currentValue += c;
}
}
- /**
- * Helper function to check method length boxes.
- * EFFECTS: Adds a new property to the current rule.
- * MODIFIES: this
- */
+ // Helper function to check method length boxes.
private void updateCurrentRule() {
currentRule.add(new Pair<>(currentProperty, currentValue));
currentProperty = "";
@@ -205,13 +167,10 @@ public class CssParser {
// todo: handle additional escaped characters, though what we have right now isn't bad
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the SINGLE_QUOTES state.
- * MODIFIES: this
- */
+ // Handles and updates parser state/buffers for a single character while in the SINGLE_QUOTES state.
private void caseSingleQuotes(char c) {
switch (c) {
- case '\'':
+ case '\'' -> {
if (previousChar != '\\') {
state = ParserState.VALUE;
// quotes in css are exclusively? for paths: so we want to include the quotes themselves
@@ -223,21 +182,18 @@ public class CssParser {
currentValue += c;
previousChar = c;
}
- break;
- default:
+ }
+ default -> {
currentValue += c;
previousChar = c;
- break;
+ }
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the DOUBLE_QUOTES state.
- * MODIFIES: this
- */
+ // Handles and updates parser state/buffers for a single character while in the DOUBLE_QUOTES state.
private void caseDoubleQuotes(char c) {
switch (c) {
- case '\"':
+ case '\"' -> {
if (previousChar != '\\') {
state = ParserState.VALUE;
currentValue += c;
@@ -247,11 +203,11 @@ public class CssParser {
currentValue += c;
previousChar = c;
}
- break;
- default:
+ }
+ default -> {
currentValue += c;
previousChar = c;
- break;
+ }
}
}
@@ -260,8 +216,8 @@ public class CssParser {
* When given an invalid string (i.e. "12p53x"), it will produce an invalid result instead of throwing.
* However, it should parse every valid string correctly.
* <br>
- * REQUIRES: A string of the form [NUMBER][VALIDUNIT]
- * EFFECTS: Returns a number, in pixels, that has been converted appropriately
+ * Takes a string of the form [NUMBER][VALIDUNIT]
+ * Returns a number, in pixels, that has been converted appropriately
*/
public static double parseUnits(String input) {
String numbers = "";
@@ -286,26 +242,23 @@ public class CssParser {
}
/**
- * REQUIRES: a String that is a unit, otherwise defaults to pixels
- * EFFECTS: converts a value in some units to a value in pixels
+ * Takes a String that is a unit, otherwise defaults to pixels
+ * Converts the value in some units to a value in pixels
*/
private static double convertUnits(String units, double value) {
- // god case/break is such a fault-provoking design i hate it
- // good thing we avoid breaks entirely here lmao
- switch (units) {
+ return switch (units) {
// absolute units
- case "px": return value;
- case "pc": return value * 16;
- case "pt": return value * (4.0 / 3.0);
- case "cm": return value * 37.8;
- case "mm": return value * 378;
- case "Q": return value * 1512;
- case "in": return value * 96;
+ case "px" -> value;
+ case "pc" -> value * 16;
+ case "pt" -> value * (4.0 / 3.0);
+ case "cm" -> value * 37.8;
+ case "mm" -> value * 378;
+ case "Q" -> value * 1512;
+ case "in" -> value * 96;
// not handled: % em ex ch rem lh rlh vw vh vmin vmax vb vi svw svh lvw lvh dvw dvh
- default:
+ default -> value;
// System.out.printf("Unit %s not implemented, defaulting to %s in pixels...%n", units, value);
- return value;
- }
+ };
}
}
diff --git a/src/main/model/html/ElementNode.java b/src/main/model/html/ElementNode.java
index 6f0a556..3faf4ae 100644
--- a/src/main/model/html/ElementNode.java
+++ b/src/main/model/html/ElementNode.java
@@ -8,15 +8,11 @@ import java.util.ArrayList;
* This ElementNode class represents an HTML tag and nested tags.
*/
public class ElementNode implements Node {
- private String tag;
- private ArrayList<Pair<String,String>> attributes;
+ private final String tag;
+ private final ArrayList<Pair<String,String>> attributes;
- private ArrayList<Node> children;
+ private final ArrayList<Node> children;
- /**
- * EFFECTS: Constructs a new ElementNode from the arguments provided.
- * MODIFIES: this
- */
public ElementNode(String tag, ArrayList<Pair<String, String>> attributes, ArrayList<Node> children) {
this.tag = tag;
this.attributes = attributes;
@@ -25,8 +21,6 @@ public class ElementNode implements Node {
/**
* Overloads the constructor for ease of use. We often don't provide children, at first.
- * EFFECTS: Constructs a new ElementNode from the arguments provided.
- * MODIFIES: this
*/
public ElementNode(String tag, ArrayList<Pair<String, String>> attributes) {
this(tag, attributes, new ArrayList<>());
@@ -34,17 +28,11 @@ public class ElementNode implements Node {
/**
* Overloads the constructor for ease of use. Should probably only be used for tests.
- * EFFECTS: Constructs a new ElementNode from the arguments provided.
- * MODIFIES: this
*/
public ElementNode(String tag) {
this(tag, new ArrayList<>(), new ArrayList<>());
}
- /**
- * EFFECTS: Adds a child to the children ArrayList.
- * MODIFIES: this
- */
public void addChild(Node child) {
this.children.add(child);
}
diff --git a/src/main/model/html/HtmlParser.java b/src/main/model/html/HtmlParser.java
index e50f713..5e5e7ce 100644
--- a/src/main/model/html/HtmlParser.java
+++ b/src/main/model/html/HtmlParser.java
@@ -43,8 +43,6 @@ public class HtmlParser {
private ParserState state;
- // EFFECTS: constructs a new HTML parser.
- // MODIFIES: this
public HtmlParser() {
result = new ArrayList<>();
unfinished = new ArrayDeque<>();
@@ -65,118 +63,76 @@ public class HtmlParser {
// System.out.print(state);
// System.out.println(" " + c + " " + currentText);
switch (state) {
- case HTML: caseHtml(c);
- break;
- case UNKNOWN_TAG: caseUnknownTag(c);
- break; // FOOTGUN LANGUAGE DESIGN STRIKES AGAIN
- case IGNORED: caseIgnored(c);
- break;
- case OPENING_TAG: caseOpeningTag(c);
- break;
- case CLOSING_TAG: caseClosingTag(c);
- break;
- case KEY: caseKey(c);
- break;
- case VALUE: caseValue(c);
- break;
- case SINGLE_QUOTES: caseSingleQuotes(c);
- break;
- case DOUBLE_QUOTES: caseDoubleQuotes(c);
- break;
+ case HTML -> caseHtml(c);
+ case UNKNOWN_TAG -> caseUnknownTag(c);
+ case IGNORED -> caseIgnored(c);
+ case OPENING_TAG -> caseOpeningTag(c);
+ case CLOSING_TAG -> caseClosingTag(c);
+ case KEY -> caseKey(c);
+ case VALUE -> caseValue(c);
+ case SINGLE_QUOTES -> caseSingleQuotes(c);
+ case DOUBLE_QUOTES -> caseDoubleQuotes(c);
}
}
return result;
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the HTML state.
- * MODIFIES: this
- */
private void caseHtml(char c) {
switch (c) {
- case '<':
+ case '<' -> {
state = ParserState.UNKNOWN_TAG;
if (!currentText.equals("")) {
addNewTextNode();
}
- break; // FOOTGUN LANGUAGE DESIGN
- case ' ': case '\n':
+ }
+ case ' ', '\n' -> {
if (previousChar != ' ') {
currentText += ' ';
}
previousChar = ' ';
- break;
- default:
+ }
+ default -> {
currentText += c;
previousChar = c;
- break;
+ }
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the UNKNOWN_TAG state.
- * MODIFIES: this
- */
private void caseUnknownTag(char c) {
switch (c) {
- case '/':
- state = ParserState.CLOSING_TAG;
- break;
- case '>': // Why would you put <> in your HTML??? go away
+ case '/' -> state = ParserState.CLOSING_TAG;
+ case '>' -> { // Why would you put <> in your HTML??? go away
state = ParserState.HTML;
currentText += "<>";
- break;
- // For now, we'll straight-up ignore anything matching the <!...> syntax:
+ }
+ // For now, we'll straight up ignore anything matching the <!...> syntax:
// i.e. comments, and <!DOCTYPE html>
- case '!':
- state = ParserState.IGNORED;
- break;
- default:
+ case '!' -> state = ParserState.IGNORED;
+ default -> {
state = ParserState.OPENING_TAG;
currentTag += c;
- break;
+ }
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the IGNORED state.
- * MODIFIES: this
- */
private void caseIgnored(char c) {
switch (c) {
- case '>':
- state = ParserState.HTML;
- break;
- default:
- break;
+ case '>' -> state = ParserState.HTML;
+ default -> {}
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the OPENING_TAG state.
- * MODIFIES: this
- */
private void caseOpeningTag(char c) {
switch (c) {
- case '>':
- addNewElementNode();
- break;
- case ' ': case '\n':
- state = ParserState.KEY;
- break;
- default:
- currentTag += c;
- break;
+ case '>' -> addNewElementNode();
+ case ' ', '\n' -> state = ParserState.KEY;
+ default -> currentTag += c;
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the CLOSING_TAG state.
- * MODIFIES: this
- */
private void caseClosingTag(char c) {
switch (c) {
- case '>':
+ case '>' -> {
state = ParserState.HTML;
// IMPORTANT: we don't validate that closing tags correspond to an open tag
if (!isSelfClosingTag(currentTag)) {
@@ -185,72 +141,46 @@ public class HtmlParser {
}
}
currentTag = "";
- break;
- case ' ': case '\n':
- break;
- default:
- currentTag += c;
- break;
+ }
+ case ' ', '\n' -> {}
+ default -> currentTag += c;
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the KEY state.
- * MODIFIES: this
- */
private void caseKey(char c) {
switch (c) {
- case '>':
- addNewElementNode();
- break;
- case '=':
- state = ParserState.VALUE;
- break;
- case ' ': case '\n':
- break;
- default:
- currentKey += c;
- break;
+ case '>' -> addNewElementNode();
+ case '=' -> state = ParserState.VALUE;
+ case ' ', '\n' -> {}
+ default -> currentKey += c;
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the VALUE state.
- * MODIFIES: this
- */
private void caseValue(char c) {
switch (c) {
- case '\'': state = ParserState.SINGLE_QUOTES;
- break;
- case '\"': state = ParserState.DOUBLE_QUOTES;
- break;
- case ' ': case '\n':
+ case '\'' -> state = ParserState.SINGLE_QUOTES;
+ case '\"' -> state = ParserState.DOUBLE_QUOTES;
+ case ' ', '\n' -> {
state = ParserState.KEY;
currentAttributes.add(new Pair<>(currentKey, currentValue));
currentKey = "";
currentValue = "";
- break; // THE FOOTGUN DESIGN STRIKES AGAIN
- case '>':
+ }
+ case '>' -> {
if (!currentKey.equals("") || !currentValue.equals("")) {
currentAttributes.add(new Pair<>(currentKey, currentValue));
currentKey = "";
currentValue = "";
}
addNewElementNode();
- break;
- default:
- currentValue += c;
- break;
+ }
+ default -> currentValue += c;
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the SINGLE_QUOTES state.
- * MODIFIES: this
- */
private void caseSingleQuotes(char c) {
switch (c) {
- case '\'':
+ case '\'' -> {
if (previousChar != '\\') {
state = ParserState.VALUE;
previousChar = '\0';
@@ -259,21 +189,17 @@ public class HtmlParser {
currentValue += c;
previousChar = c;
}
- break;
- default:
+ }
+ default -> {
currentValue += c;
previousChar = c;
- break;
+ }
}
}
- /**
- * EFFECTS: Handles and updates parser state/buffers for a single character while in the DOUBLE_QUOTES state.
- * MODIFIES: this
- */
private void caseDoubleQuotes(char c) {
switch (c) {
- case '\"':
+ case '\"' -> {
if (previousChar != '\\') {
state = ParserState.VALUE;
previousChar = '\0';
@@ -282,19 +208,15 @@ public class HtmlParser {
currentValue += c;
previousChar = c;
}
- break; // FOOTGUN LANGUAGE DESIGN
- default:
+ }
+ default -> {
currentValue += c;
previousChar = c;
- break;
+ }
}
}
- /**
- * Helper function to remove code duplication.
- * EFFECTS: Creates and adds a new ElementNode from the current buffers to the unfinished and result stacks
- * MODIFIES: this
- */
+ // Helper function to remove code duplication.
private void addNewElementNode() {
state = ParserState.HTML;
ElementNode node = new ElementNode(currentTag, currentAttributes);
@@ -313,11 +235,7 @@ public class HtmlParser {
currentAttributes = new ArrayList<>();
}
- /**
- * Helper function to check method length boxes.
- * EFFECTS: Creates and adds a new TextNode from the current buffers to the unfinished and result stacks
- * MODIFIES: this
- */
+ // Helper function to check method length boxes.
private void addNewTextNode() {
if (unfinished.size() != 0) {
unfinished.getLast().addChild(new TextNode(currentText));
@@ -328,21 +246,13 @@ public class HtmlParser {
previousChar = '\0';
}
- /**
- * Simple helper function to check if a tag is self-closing.
- * EFFECTS: Returns whether a String tag is a self-closing tag.
- */
+ // Simple helper function to check if a tag is self-closing.
private static boolean isSelfClosingTag(String tag) {
- switch (tag) {
- case "input": case "param":
- case "br": case "hr": case "wbr":
- case "img": case "embed": case "area":
- case "meta": case "base": case "link":
- case "source": case "track": case "col":
- return true;
- default:
- return false;
- }
+ return switch (tag) {
+ case "input", "param", "br", "hr", "wbr", "img", "embed", "area",
+ "meta", "base", "link", "source", "track", "col" -> true;
+ default -> false;
+ };
}
}
diff --git a/src/main/model/html/TextNode.java b/src/main/model/html/TextNode.java
index 464180f..c50ce0f 100644
--- a/src/main/model/html/TextNode.java
+++ b/src/main/model/html/TextNode.java
@@ -3,23 +3,9 @@ package model.html;
/**
* This TextNode class represents raw text, with no nested tags.
*/
-public class TextNode implements Node {
- private String text = "";
-
- /**
- * EFFECTS: Creates a new TextNode from the provided String value.
- * MODIFIES: this
- */
- public TextNode(String text) {
- this.text = text;
- }
-
- public String getText() {
- return this.text;
- }
-
+public record TextNode(String text) implements Node {
// We implement this method for easy debugging.
public String getData() {
- return getText();
+ return text();
}
}
diff --git a/src/main/model/layout/BlockLayout.java b/src/main/model/layout/BlockLayout.java
index f011847..9204b61 100644
--- a/src/main/model/layout/BlockLayout.java
+++ b/src/main/model/layout/BlockLayout.java
@@ -4,17 +4,13 @@ import model.html.Node;
import java.awt.*;
-// A block style layout.
public class BlockLayout extends Layout {
- // MODIFIES: this
- // EFFECTS: constructs a new BlockLayout
public BlockLayout(Node node, Layout parent) {
super(node, parent);
}
- // MODIFIES: this
- // EFFECTS: recursively constructs the layout tree
+ // recursively construct the layout tree
public void layout() {
this.setLocation(this.getParent().getLocation());
this.getPreviousSibling().ifPresent(
@@ -28,8 +24,8 @@ public class BlockLayout extends Layout {
child.layout();
this.setHeight(this.getHeight() + child.getHeight());
}
- System.out.println(this.getAssociatedNode().getData() + this.getLocation());
- System.out.println(System.identityHashCode(this.getLocation()));
+// System.out.println(this.getAssociatedNode().getData() + this.getLocation());
+// System.out.println(System.identityHashCode(this.getLocation()));
// System.out.println(this.getAssociatedNode().getData() + this.getDimension());
}
}
diff --git a/src/main/model/layout/DocumentLayout.java b/src/main/model/layout/DocumentLayout.java
index 92c0b00..2e9d778 100644
--- a/src/main/model/layout/DocumentLayout.java
+++ b/src/main/model/layout/DocumentLayout.java
@@ -1,9 +1,7 @@
package model.layout;
import java.awt.*;
-import java.util.ArrayList;
-// root document layout style
public class DocumentLayout extends Layout {
/*
@@ -15,8 +13,7 @@ public class DocumentLayout extends Layout {
super(null, null);
}
- // MODIFIES: this
- // EFFECTS: recursively constructs the layout tree
+ // recursively construct the layout tree
public void layout() {
this.setLocation(new Point(10, 20));
this.setDimension(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
diff --git a/src/main/model/layout/InlineLayout.java b/src/main/model/layout/InlineLayout.java
index 8e375d5..c4c51b5 100644
--- a/src/main/model/layout/InlineLayout.java
+++ b/src/main/model/layout/InlineLayout.java
@@ -6,19 +6,16 @@ import model.html.TextNode;
import java.awt.*;
-// Inline layout style
public class InlineLayout extends Layout {
private Point cursor;
- // Constructs a new InlineLayout
public InlineLayout(Node node, Layout parent) {
super(node, parent);
cursor = new Point();
}
- // MODIFIES: this
- // EFFECTS: recursively constructs the layout tree
+ // recursively construct the layout tree
public void layout() {
this.setLocation(this.getParent().getLocation());
this.getPreviousSibling().ifPresent(
@@ -28,14 +25,17 @@ public class InlineLayout extends Layout {
this.setCursor(this.getX(), this.getY());
Node node = this.getAssociatedNode();
- if (node instanceof TextNode) {
- if (node.getData().length() > 5) {
- this.setHeight(20);
-// this.setWidth(this.getWidth() + node.getData().length());
+ switch (node) {
+ case ElementNode e -> {
+ if (e.getTag().equals("a")) {
+ this.setX(this.getX() + this.getParent().getWidth());
+ }
}
- } else if (node instanceof ElementNode) {
- if (((ElementNode) node).getTag().equals("a")) {
- this.setX(this.getX() + this.getParent().getWidth());
+ default -> {
+ if (node.getData().length() > 5) {
+ this.setHeight(20);
+// this.setWidth(this.getWidth() + node.getData().length());
+ }
}
}
diff --git a/src/main/model/layout/Layout.java b/src/main/model/layout/Layout.java
index 4d9f48f..5a19302 100644
--- a/src/main/model/layout/Layout.java
+++ b/src/main/model/layout/Layout.java
@@ -31,8 +31,6 @@ public abstract class Layout {
// the big function
public abstract void layout();
- // MODIFIES: this
- // EFFECTS: recursively constructs the layout tree
public Layout(Node node, Layout parent) {
this.associatedNode = node;
@@ -47,8 +45,6 @@ public abstract class Layout {
// eh, probably the best place to put this
// parent MAY BE nil: a handy call to Optional.ofNullable allows this
- // MODIFIES: this
- // EFFECTS: recursively constructs the layout tree
public static ArrayList<Layout> constructTree(ArrayList<Node> html, Layout parent) {
ArrayDeque<Layout> result = new ArrayDeque<>();
for (Node node : html) {
@@ -74,8 +70,6 @@ public abstract class Layout {
return new ArrayList<>(result); // haha
}
- // MODIFIES: this
- // EFFECTS: recursively constructs the layout tree
public static DocumentLayout constructTree(ArrayList<Node> html) {
DocumentLayout result = new DocumentLayout();
result.setChildren(constructTree(html, result));
diff --git a/src/main/ui/BrowserApp.java b/src/main/ui/BrowserApp.java
index 520cac8..36f2005 100644
--- a/src/main/ui/BrowserApp.java
+++ b/src/main/ui/BrowserApp.java
@@ -1,9 +1,6 @@
package ui;
-import model.html.ElementNode;
-import model.html.HtmlParser;
-import model.html.TextNode;
-import model.html.Node;
+import model.html.*;
import java.nio.file.*;
import java.util.*;
@@ -18,24 +15,15 @@ public class BrowserApp {
private ArrayList<Node> parsed;
private ArrayDeque<String> tabs;
- /**
- * EFFECTS: Renders an arbitrary HTML page and arbitrary HTML input.
- */
+ // Renders an arbitrary HTML page and arbitrary HTML input.
public BrowserApp() {
println("apus: currently a barebones html/css renderer");
this.input = new Scanner(System.in);
this.tabs = new ArrayDeque<>();
- mainLoop();
- }
- /**
- * EFFECTS: Runs the main loop
- */
- private void mainLoop() {
while (true) {
try {
- Path path = Paths.get(pathString);
- String file = new String(Files.readAllBytes(path));
+ String file = Files.readString(Path.of(pathString));
HtmlParser parser = new HtmlParser();
parsed = parser.parseHtml(file);
println(border);
@@ -52,43 +40,38 @@ public class BrowserApp {
}
}
- /**
- * EFFECTS: Barebones HTML rendering. Iterates through a list of Nodes and their children and prints any text.
- */
+ // Barebones HTML rendering. Iterates through a list of Nodes and their children and prints any text.
private void renderHtml(ArrayList<Node> html) {
for (Node node: html) {
- if (node instanceof TextNode) {
- println(node.getData());
- } else {
- renderHtml(((ElementNode) node).getChildren());
+ switch (node) {
+ case ElementNode e -> {
+ renderHtml(e.getChildren());
+ }
+ default -> {
+ println(node.getData());
+ }
}
}
}
- /**
- * EFFECTS: Handles user input after rendering an initial site
- */
+ // Handles user input after rendering an initial site
private void handleInput(String input) {
switch (input) {
- case "newuri":
+ case "newuri" -> {
println("please provide a path to a file (examples located in data/*):");
pathString = this.input.next();
- break;
- case "newtab":
+ }
+ case "newtab" -> {
this.tabs.add(pathString);
println("please provide a path to a file (examples located in data/*):");
pathString = this.input.next();
- break;
- case "nexttab":
+ }
+ case "nexttab" -> {
this.tabs.add(pathString);
pathString = this.tabs.removeFirst();
- break;
- case "quit":
- System.exit(0);
- break;
- default:
- println("Sorry, I didn't quite get that. Please try again.");
- break;
+ }
+ case "quit" -> System.exit(0);
+ default -> println("Sorry, I didn't quite get that. Please try again.");
}
}
diff --git a/src/main/ui/BrowserBar.java b/src/main/ui/BrowserBar.java
index e9db3c3..131fe19 100644
--- a/src/main/ui/BrowserBar.java
+++ b/src/main/ui/BrowserBar.java
@@ -2,19 +2,17 @@ package ui;
import javax.swing.*;
import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
+import java.awt.event.*;
import java.util.*;
-// BrowserBar
public class BrowserBar extends JToolBar {
- private BrowserWindow parent;
+ private final BrowserWindow parent;
- private JPopupMenu tabMenu;
- private JToggleButton tabButton;
- private JTextField uriInput;
-// private JButton saveTabsButton;
- private JButton openUriButton;
+ private final JPopupMenu tabMenu;
+ private final JToggleButton tabButton;
+ private final JTextField uriInput;
+// private final JButton saveTabsButton;
+ private final JButton openUriButton;
public BrowserBar(BrowserWindow parent) {
this.parent = parent;
@@ -34,36 +32,28 @@ public class BrowserBar extends JToolBar {
}
- // EFFECTS: opens the content of the text field in the current tab
private ActionListener openTab() {
- return new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent actionEvent) {
- String uri = uriInput.getText();
- parent.render(uri);
- addTab(uri);
- }
+ return actionEvent -> {
+ String uri = uriInput.getText();
+ parent.render(uri);
+ addTab(uri);
};
}
- // EFFECTS: adds a new tab pointing to URI in the background
public void addTab(String tab) {
JToggleButton tabButton = new JToggleButton(tab);
- tabButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent actionEvent) {
- int action = JOptionPane.showOptionDialog(null,
- "Open or close this tab?", "apus",
- JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE,
- null, new String[]{"Open", "Close"}, "Open");
- if (action == 0) {
- parent.render(tab);
- } else {
- tabMenu.remove(tabButton);
- tabMenu.setVisible(false);
- parent.getBrowserState().removeTab(tab);
- }
+ tabButton.addActionListener(actionEvent -> {
+ int action = JOptionPane.showOptionDialog(null,
+ "Open or close this tab?", "apus",
+ JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE,
+ null, new String[]{"Open", "Close"}, "Open");
+ if (action == 0) {
+ parent.render(tab);
+ } else {
+ tabMenu.remove(tabButton);
+ tabMenu.setVisible(false);
+ parent.getBrowserState().removeTab(tab);
}
});
@@ -71,20 +61,15 @@ public class BrowserBar extends JToolBar {
parent.getBrowserState().addTab(tab);
}
- // MODIFIES: this
- // EFFECTS: toggles the tab menu
private ActionListener toggleTabMenu() {
- return new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent actionEvent) {
- if (tabButton.isSelected()) {
- Point location = tabButton.getLocationOnScreen();
- location.translate(0, 30); // fuck this method lol
- tabMenu.setLocation(location);
- tabMenu.setVisible(true);
- } else {
- tabMenu.setVisible(false);
- }
+ return actionEvent -> {
+ if (tabButton.isSelected()) {
+ Point location = tabButton.getLocationOnScreen();
+ location.translate(0, 30); // fuck this method lol
+ tabMenu.setLocation(location);
+ tabMenu.setVisible(true);
+ } else {
+ tabMenu.setVisible(false);
}
};
}
diff --git a/src/main/ui/BrowserCanvas.java b/src/main/ui/BrowserCanvas.java
index a58f6e1..43481ef 100644
--- a/src/main/ui/BrowserCanvas.java
+++ b/src/main/ui/BrowserCanvas.java
@@ -1,24 +1,17 @@
package ui;
-import model.html.ElementNode;
-import model.html.TextNode;
-import model.html.Node;
-import model.layout.DocumentLayout;
-import model.layout.Layout;
+import model.html.*;
+import model.layout.*;
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class BrowserCanvas extends JPanel {
- private ArrayList<Node> html;
- private DocumentLayout currentLayout;
+ private final DocumentLayout currentLayout;
- // MODIFIES: this
- // EFFECTS: constructs a BrowserCanvas object
public BrowserCanvas(ArrayList<Node> html) {
super();
- this.html = html;
this.currentLayout = Layout.constructTree(html);
printTree(this.currentLayout.getChildren());
}
@@ -30,7 +23,6 @@ public class BrowserCanvas extends JPanel {
}
}
- // EFFECTS: paints a component onto a canvas
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
@@ -38,20 +30,6 @@ public class BrowserCanvas extends JPanel {
renderHtml(this.currentLayout.getChildren(), g, location);
}
- // EFFECTS: naively renders our html file by printing text nodes
- /*private void renderHtml(ArrayList<Node> html, Graphics g, Point location) {
- for (Node node : html) {
- if (node instanceof TextNode) {
- if (node.getData().length() > 5) {
- g.drawString(node.getData(), location.x, location.y);
- location.translate(0, 20);
- }
- } else {
- renderHtml(((ElementNode) node).getChildren(), g, location);
- }
- }
- }*/
-
private void renderHtml(ArrayList<Layout> tree, Graphics g, Point location) {
for (Layout layout : tree) {
// System.out.println(layout.getLocation());
@@ -67,5 +45,4 @@ public class BrowserCanvas extends JPanel {
}
}
}
-
}
diff --git a/src/main/ui/BrowserWindow.java b/src/main/ui/BrowserWindow.java
index bd1cf7f..94bd2d8 100644
--- a/src/main/ui/BrowserWindow.java
+++ b/src/main/ui/BrowserWindow.java
@@ -5,11 +5,8 @@ import model.html.HtmlParser;
import javax.swing.*;
import java.awt.*;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
+import java.nio.file.*;
+import java.util.*;
// Broad JFrame usage taken from here: https://docs.oracle.com/javase/tutorial/uiswing/components/frame.html
public class BrowserWindow extends JFrame {
@@ -17,43 +14,33 @@ public class BrowserWindow extends JFrame {
public static final int HEIGHT = 800;
private BrowserCanvas canvas;
- private BrowserBar browserBar;
+ private final BrowserBar browserBar;
+ private final BrowserState state;
- private BrowserState state;
-
- // MODIFIES: this
- // EFFECTS: creates a new BrowserWindow program for rendering pages
public BrowserWindow() {
super("apus");
state = new BrowserState(new ArrayDeque<>(), "");
canvas = new BrowserCanvas(new ArrayList<>());
-// render("data/example.html");
browserBar = new BrowserBar(this);
getContentPane().add(browserBar, BorderLayout.SOUTH);
-// pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(WIDTH, HEIGHT);
render("/home/apropos/Projects/website/j-james/index.html");
-// render("data/example.hctml");
// browserBar.addTab("/home/apropos/Projects/website/j-james/index.html");
setVisible(true);
}
- // MODIFIES: this
- // EFFECTS: Renders an arbitrary page
public void render(String uri) {
state.setCurrentTab(uri);
remove(canvas);
// System.out.println(state.getCurrentTab());
try {
- Path path = Paths.get(state.getCurrentTab());
- String file = new String(Files.readAllBytes(path));
+ String file = Files.readString(Path.of(state.getCurrentTab()));
HtmlParser parser = new HtmlParser();
canvas = new BrowserCanvas(parser.parseHtml(file));
} catch (Exception e) {
System.out.println("Could not read file, rendering empty page: " + e.getMessage());
-
canvas = new BrowserCanvas(new ArrayList<>());
}
add(canvas);