summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CSVReader.java2
-rw-r--r--src/ComparisonView.java42
-rw-r--r--src/FamilyButton.java31
-rw-r--r--src/FamilyButtonListener.java61
-rw-r--r--src/FontFamily.java62
-rw-r--r--src/JSONReader.java15
-rw-r--r--src/LineGraph.java46
-rw-r--r--src/MetadataView.java35
-rw-r--r--src/Reader.java2
9 files changed, 248 insertions, 48 deletions
diff --git a/src/CSVReader.java b/src/CSVReader.java
index da11f36..62e7845 100644
--- a/src/CSVReader.java
+++ b/src/CSVReader.java
@@ -10,7 +10,7 @@ import java.util.Arrays;
* References:
*
* Date:
- * 2024-05-20
+ * 2024-05-25
*
* Purpose of class:
* Read from and interpret CSV files.
diff --git a/src/ComparisonView.java b/src/ComparisonView.java
index e1104ef..636cd18 100644
--- a/src/ComparisonView.java
+++ b/src/ComparisonView.java
@@ -16,7 +16,7 @@ import java.awt.*;
*
*
* Date:
- * 2024-05-20
+ * 2024-05-25
*
* Purpose of class:
* Provide a view for comparing font families.
@@ -28,7 +28,10 @@ public class ComparisonView extends JFrame {
private final int WINDOW_MIN_HEIGHT = 540; // A ComparisonView has a minimum width
private ArrayList<FontFamily> fonts; // A ComparisonView has a list of fonts
private Font textFont; // A ComparisonView has a preferred text font
+ private Font buttonFont; // A ComparisonView has a preferred button font
private final int TEXT_SIZE = 20; // A ComparisonView has a constant text size.
+ private FamilyButton buttons[]; // A ComparisonView has an array of buttons.
+ private final int BUTTON_MAX = 10; // A ComparisonView has a set maximum number of buttons.
/**
* Walk the file tree.
@@ -70,6 +73,10 @@ public class ComparisonView extends JFrame {
getContentPane().setFont(textFont);
UIManager.put("Label.font", textFont);
UIManager.put("Panel.font", textFont);
+ UIManager.put("TextArea.font", textFont);
+ /* Set button font to a DejaVu Sans Condensed at a smaller point size. */
+ buttonFont = new Font("DejaVu Sans Condensed", Font.PLAIN, TEXT_SIZE * 3 / 4);
+ UIManager.put("ToggleButton.font", buttonFont);
setTitle("Google Fonts Style vs. Popularity"); // Window title
@@ -121,14 +128,37 @@ public class ComparisonView extends JFrame {
fonts.add(new FontFamily(metadata, popularity, style));
}
+ /* Sort fonts by their views over the past 30 days. */
+ fonts = FontFamily.sort(fonts, "30day");
+
waiting.remove(waitingLabel); // Remove waiting message.
- JPanel author = new JPanel();
- JLabel authorLabel = new JLabel("Written by Kian Agheli");
- author.add(authorLabel);
- add(author, BorderLayout.SOUTH); // Add author panel.
+
+ /* Add panel for font family metadata. */
+ JPanel metadataPanel = new JPanel();
+ MetadataView metadataView = new MetadataView();
+ metadataPanel.add(metadataView);
+ this.add(metadataPanel, BorderLayout.WEST);
LineGraph graph = new LineGraph(fonts); // Draw a line graph of the font views metadata.
- add(graph, BorderLayout.NORTH); // Add the line graph.
+ add(graph, BorderLayout.EAST); // Add the line graph.
+
+ /* Add panel for font family metadata activation buttons. BUTTON_MAX buttons
+ in horizontal orientation. */
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new GridLayout(1, BUTTON_MAX));
+ buttons = new FamilyButton[BUTTON_MAX];
+ /* Display buttons for the top families. */
+ for (int i = 0; i < BUTTON_MAX; i++) {
+ /* Get the family associated with the given iteration's sort order. */
+ FamilyButton button = new FamilyButton(fonts.get(i));
+ /* Set the text of the button to the name of the font family. */
+ button.setText(button.getFamily().getFamilyName());
+ button.setBackground(new Color(LineGraph.getColors()[i]));
+ button.addItemListener(new FamilyButtonListener(buttons, i, metadataView));
+ buttons[i] = button;
+ buttonPanel.add(button);
+ }
+ this.add(buttonPanel, BorderLayout.SOUTH);
pack(); // Pack the window.
setVisible(true); // Re-draw the window.
diff --git a/src/FamilyButton.java b/src/FamilyButton.java
new file mode 100644
index 0000000..994e848
--- /dev/null
+++ b/src/FamilyButton.java
@@ -0,0 +1,31 @@
+import javax.swing.JToggleButton;
+
+/*
+ * @author
+ * Kian Agheli
+ *
+ * References:
+ * https://www.geeksforgeeks.org/java-swing-jtogglebutton-class/
+ *
+ * Date:
+ * 2024-05-25
+ *
+ * Purpose of class:
+ * Provide an interative button to toggle FontFamily metadata.
+ */
+
+public class FamilyButton extends JToggleButton {
+ private FontFamily family; // A FamilyButton has-a font family
+
+ public FamilyButton(FontFamily family)
+ {
+ this.family = family; // Set family to provided
+ }
+
+ /**
+ * Return the FontFamily associated with the instantiated button.
+ */
+ public FontFamily getFamily() {
+ return family;
+ }
+}
diff --git a/src/FamilyButtonListener.java b/src/FamilyButtonListener.java
new file mode 100644
index 0000000..95a4bc4
--- /dev/null
+++ b/src/FamilyButtonListener.java
@@ -0,0 +1,61 @@
+import java.awt.event.*;
+
+/*
+ * @author
+ * Kian Agheli
+ *
+ * References:
+ *
+ * Date:
+ * 2024-05-25
+ *
+ * Purpose of class:
+ * Listen for state changes in an instantiation of FamilyButton.
+ */
+public class FamilyButtonListener implements ItemListener
+{
+ private MetadataView metadataView; // A FamilyButtonListener has a metadataView
+ private FamilyButton[] buttons; // A FamilyButtonListener has an array of buttons
+ private int buttonIndex; // A FamilyButtonListener has a button at a specified index in the array
+
+ public FamilyButtonListener(FamilyButton[] buttons, int buttonIndex, MetadataView metadataView) {
+ /* Set each of the instance's fields to the given objects. */
+ this.buttons = buttons;
+ this.buttonIndex = buttonIndex;
+ this.metadataView = metadataView;
+ }
+
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ /* Get the state of the button. */
+ int state = e.getStateChange();
+ /* If the button is selected: */
+ if (state == ItemEvent.SELECTED) {
+ /* Deselect all other buttons. */
+ for (int i = 0; i < buttons.length; i++) {
+ if (i != buttonIndex) {
+ buttons[i].setSelected(false);
+ }
+ }
+
+ /* Set the metadata on display to the metadata of the FontFamily
+ associated with the selected button. */
+ metadataView.setText(buttons[buttonIndex].getFamily().toString());
+ /* If the button is deselected: */
+ } else {
+ /* Check if every button is deselected. */
+ boolean selected = true;
+ for (int i = 0; i < buttons.length; i++) {
+ if (!buttons[i].isSelected()) {
+ selected = false;
+ }
+ }
+
+ /* If every button is deselected, reset the metadata to display
+ the default text. */
+ if (!selected) {
+ metadataView.reset();
+ }
+ }
+ }
+}
diff --git a/src/FontFamily.java b/src/FontFamily.java
index 97328d8..0b7c458 100644
--- a/src/FontFamily.java
+++ b/src/FontFamily.java
@@ -1,4 +1,7 @@
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
/*
@@ -8,7 +11,7 @@ import java.util.HashMap;
* References:
*
* Date:
- * 2024-05-20
+ * 2024-05-25
*
* Purpose of class:
* Store and operate on font family metadata.
@@ -153,4 +156,61 @@ public class FontFamily {
public HashMap<String,Long> getViews() {
return views;
}
+
+ /* Sort an ArrayList by a given metric of views, in descending order. */
+ public static ArrayList<FontFamily> sort(ArrayList<FontFamily> fonts, String metric) {
+ Collections.sort(fonts, new Comparator<FontFamily>() {
+ /* If a is lesser, return 1. If b is lesser, return -1.
+ Otherwise, they are equal, return 0. */
+ public int compare (FontFamily a, FontFamily b) {
+ /* If equal, return 0. */
+ if (a.getViews().get(metric) == b.getViews().get(metric)) {
+ return 0;
+ }
+
+ /* If either is null, it is lesser. */
+ if (a.getViews().get(metric) == null) {
+ return 1;
+ }
+ if (b.getViews().get(metric) == null) {
+ return -1;
+ }
+
+ /* Neither are null, compare. */
+ if (a.getViews().get(metric) > b.getViews().get(metric)) {
+ return -1;
+ }
+
+ /* aViews must be lesser. */
+ return 1;
+ }
+ });
+
+ return fonts; // Return sorted ArrayList.
+ }
+
+ public String toString() {
+ String string = String.format("%s\nPublished %s\n", familyName, dateAdded);
+ string += "Styles:\n";
+ for (String style : styles.keySet()) {
+ string += String.format(" %s: %d%%\n", style, styles.get(style));
+ }
+ string += String.format("Designed by %s\n", designer);
+ string += String.format("Distributed under the terms of the %s\n", license);
+ string += String.format("Vaguely categorized as %s\n", category);
+ string += "Unicode subsets:\n";
+ /* Print two subsets on each line. */
+ for (int i = 0; i < subsets.length - 1; i++) {
+ if (i % 2 == 0) {
+ string += String.format(" %s", subsets[i]);
+ } else {
+ string += String.format("; %s\n", subsets[i]);
+ }
+ }
+ if (subsets.length % 2 == 0) {
+ string += '\n';
+ }
+
+ return string;
+ }
}
diff --git a/src/JSONReader.java b/src/JSONReader.java
index a4af8c9..4cc72ad 100644
--- a/src/JSONReader.java
+++ b/src/JSONReader.java
@@ -12,9 +12,10 @@ import java.io.*;
* https://stackoverflow.com/questions/3880274/how-to-convert-the-object-to-string-in-java
* https://stackoverflow.com/questions/8938498/get-the-index-of-a-pattern-in-a-string-using-regex
* https://howtodoinjava.com/java/regex/start-end-of-string/
+ * https://www.baeldung.com/java-remove-last-character-of-string
*
* Date:
- * 2024-05-20
+ * 2024-05-25
*
* Purpose of class:
* Read from and interpret JSON files.
@@ -77,9 +78,15 @@ public class JSONReader extends Reader {
/* This JSON is pretty-printed. */
int nl = json.indexOf("\n", start);
- /* Extract substring. Remove any quotation marks and commas. */
- String substring = json.substring(start, nl);
- return substring.replaceAll("[\",]", "");
+ /* Extract substring. Remove any quotation marks. */
+ String extract = json.substring(start, nl);
+ extract = extract.replaceAll("\"", "");
+
+ /* If the string ends with a comma, remove it. */
+ if (extract.endsWith(",")) {
+ extract = extract.substring(0, extract.length() - 1);
+ }
+ return extract;
}
/**
diff --git a/src/LineGraph.java b/src/LineGraph.java
index 7c4b8ac..7ef9a94 100644
--- a/src/LineGraph.java
+++ b/src/LineGraph.java
@@ -21,7 +21,7 @@ import java.util.Date;
* https://stackoverflow.com/questions/5799140/java-get-month-string-from-integer
*
* Date:
- * 2024-05-20
+ * 2024-05-25
*
* Purpose of class:
* Draw a line graph.
@@ -32,15 +32,17 @@ public class LineGraph extends JPanel {
private ArrayList<FontFamily> fonts; // A line graph has-a set of fonts
private final int WIDTH = 640; // A line graph has a preferred width
private final int HEIGHT = 480; // A line graph has a preferred height
- private final int LINES = 0x10; // A line graph has a maximum lines graphed at a time
+ private final int LINES = 10; // A line graph has a maximum lines graphed at a time
private final int LINE_WIDTH = 3; // A line graph has lines with a given pixel width
private final int TICK_HEIGHT = 10; // A line graph has ticks with a given pixel height
/* A line graph has an array of abbreviated month names. */
private final String[] ABBREVIATED_MONTH = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct", "Nov", "Dec"};
- /* A line graph has an array of unique color values to use for each of the lines. */
- private final int[] COLORS = {0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff,
- 0xff8040, 0xff4080, 0x80ff40, 0x40ff80, 0x4080ff, 0x8040ff, 0xff8080, 0x80ff80, 0x8080ff,
+ /* A line graph has an array of unique color values to use for each of the lines.
+ Made static so that it may be referenced from ComparisonView, so that the colors used for line
+ drawings and their associated buttons may match. */
+ private static final int[] COLORS = {0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff,
+ 0xff8040, 0xff4080, 0x4080ff, 0xff8080, 0x80ff80, 0x8080ff,
0xff4040, 0x40ff40, 0x4040ff};
/**
@@ -111,8 +113,6 @@ public class LineGraph extends JPanel {
graphics.drawLine(TICK_HEIGHT + xOffset - LINE_WIDTH / 3, 0, TICK_HEIGHT + xOffset -
LINE_WIDTH / 3, yMax);
- sortFonts("30day"); // Sort the list of fonts by their 30day metrics.
-
int y = 0 + metrics.getHeight();
/* Cast to double within parentheses for floating-point
division, cast back to int to remove fractional part.
@@ -187,33 +187,9 @@ public class LineGraph extends JPanel {
}
}
- /* Sort by views, in descending order. */
- private void sortFonts(String metric) {
- Collections.sort(fonts, new Comparator<FontFamily>() {
- /* If a is lesser, return 1. If b is lesser, return -1.
- Otherwise, they are equal, return 0. */
- public int compare (FontFamily a, FontFamily b) {
- /* If equal, return 0. */
- if (a.getViews().get(metric) == b.getViews().get(metric)) {
- return 0;
- }
-
- /* If either is null, it is lesser. */
- if (a.getViews().get(metric) == null) {
- return 1;
- }
- if (b.getViews().get(metric) == null) {
- return -1;
- }
-
- /* Neither are null, compare. */
- if (a.getViews().get(metric) > b.getViews().get(metric)) {
- return -1;
- }
-
- /* aViews must be lesser. */
- return 1;
- }
- });
+ /* Return the array of hex values used to color the lines on the graph.
+ The background color of each FamilyButton match the associated line on the graph. */
+ public static int[] getColors() {
+ return COLORS;
}
}
diff --git a/src/MetadataView.java b/src/MetadataView.java
new file mode 100644
index 0000000..5837aca
--- /dev/null
+++ b/src/MetadataView.java
@@ -0,0 +1,35 @@
+import javax.swing.JTextArea;
+import java.awt.*;
+
+/*
+ * @author
+ * Kian Agheli
+ *
+ * References:
+ * https://docs.oracle.com/javase/tutorial/uiswing/components/textarea.html
+ *
+ * Date:
+ * 2024-05-25
+ *
+ * Purpose of class:
+ * Provide an area to show metadata.
+ */
+
+public class MetadataView extends JTextArea {
+ // A MetadataView has-a default text.
+ private final String defaultText = "Toggle a font family using a colorful button below.\n" +
+ "Each color corresponds with a line on the graph to the right.\n" +
+ "The graph tracks monthly views.";
+
+ public MetadataView() {
+ super(); // Call parent constructor
+ setEditable(false); // Disable editing of the widget.
+ setFocusable(false); // Disable focusing of the widget.
+ setText(defaultText); // Set to the default text.
+ }
+
+ /* Reset the MetadataView. Set the text to the default. */
+ public void reset() {
+ setText(defaultText);
+ }
+}
diff --git a/src/Reader.java b/src/Reader.java
index d4a46fa..d066d6d 100644
--- a/src/Reader.java
+++ b/src/Reader.java
@@ -11,7 +11,7 @@ import java.util.List;
* https://www.baeldung.com/java-scanner
*
* Date:
- * 2024-05-20
+ * 2024-05-25
*
* Purpose of class:
* Read from a file.