Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor PhonemeTable as to make it maintainable #21

Merged
merged 13 commits into from
Sep 19, 2024
Merged
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.oijon</groupId>
<artifactId>Susquehanna</artifactId>
<version>0.1.0</version>
<version>0.1.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/net/oijon/susquehanna/SystemInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,20 @@ public static String javafxVersion() {
}

public static String susquehannaVerNum() {
return "0.1.0";
return "0.1.1";
}

public static String susquehannaVerName() {
return "Cooperstown";
return "Index";
}

public static boolean isSnapshot() {
return false;
return true;
}

public static String buildName() {
if (isSnapshot()) {
return "24w36b";
return "24w36c";
} else {
return susquehannaVerName() + ", " + susquehannaVerNum();
}
Expand Down
277 changes: 144 additions & 133 deletions src/main/java/net/oijon/susquehanna/gui/components/PhonemeTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
private VBox container;
private boolean isEditable = true;
private ArrayList<GridPane> tableList = new ArrayList<GridPane>();
// TODO: make this a bit more efficient! This is so much better than the previous iteration, but still a bit slow...
// TODO: make refresh happen at end of build; don't rely on build to mark what's in/out

public PhonemeTable(Phonology p) {
this.p = p;
Expand All @@ -42,108 +40,65 @@
}

public void refresh() {
// FIXME: REFACTOR THIS!!! This is spaghetti right now
ArrayList<String> phonoList = new ArrayList<String>();
for (int i = 0; i < p.getList().size(); i++) {
phonoList.add(new String(p.getList().get(i)));
ArrayList<HBox> cells = generateCellList();

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead

for (int i = 0; i < cells.size(); i++) {
ArrayList<PhonemeButton> cell = getButtonsInCell(cells.get(i));

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead
ArrayList<String> phonemesInCell = getPhonemesFromButtons(cell);

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead

checkPhonemesInCell(cells.get(i), cell, phonemesInCell);
removeDuplicates(cells.get(i), cell, phonemesInCell);
}

Check warning

Code scanning / PMD

This for loop can be replaced by a foreach loop Warning

This for loop can be replaced by a foreach loop
for (int i = 0; i < tableList.size(); i++) {
GridPane gp = tableList.get(i);
ObservableList<Node> children = gp.getChildren();
for (int j = 0; j < children.size(); j++) {
Node c1 = children.get(j);
if (c1 instanceof HBox) {
ArrayList<PhonemeButton> cell = new ArrayList<PhonemeButton>();
ArrayList<String> phonemesInCell = new ArrayList<String>();
HBox hbox = (HBox) c1;

// generate list of phonemes and phonemebuttons in cell
for (int k = 0; k < hbox.getChildren().size(); k++) {
Node c2 = hbox.getChildren().get(k);
if (c2 instanceof PhonemeButton) {
PhonemeButton pb = (PhonemeButton) c2;
cell.add(pb);
phonemesInCell.add(pb.getPhoneme());
}
}

// a bit of a design flaw in the phono tables makes it so that multiple
// phonemes are in the same cell... as such, *every* phoneme needs
// their diacritics checked
for (int k = 0; k < cell.size(); k++) {
cell.get(k).setInPhono(p.getList().contains(cell.get(k).getPhoneme()));
ArrayList<String> diacritics = getListOfDiacritisizedPhonemes(cell.get(k).getPhoneme());

for (int l = 0; l < diacritics.size(); l++) {
if (!phonemesInCell.contains(diacritics.get(l))) {
PhonemeButton pb = new PhonemeButton(diacritics.get(l), this, isEditable);
pb.setInPhono(true);
hbox.getChildren().add(pb);
cell.add(pb);
phonemesInCell.add(diacritics.get(l));
}
}
}

// find duplicates not in phono, remove them
for (int k = 0; k < cell.size(); k++) {
for (int l = 0; l < cell.size(); l++) {
if (k != l) {
if (cell.get(k).getPhoneme().equals(cell.get(l).getPhoneme()) &
hbox.getChildren().contains(cell.get(k)) &
hbox.getChildren().contains(cell.get(l))) {
if (!cell.get(l).isInPhono()) {
hbox.getChildren().remove(cell.get(l));
} else if (!cell.get(k).isInPhono()) {
hbox.getChildren().remove(cell.get(k));
}
}
}
}
}
// find duplicates that are marked in phono but not, remove them
// this state happens when phonemes are edited
for (int k = 0; k < cell.size(); k++) {
int count = -1;
for (int l = 0; l < p.getList().size(); l++) {
String phonemeK = cell.get(k).getPhoneme();
String phonemeL = p.getList().get(l);
if (phonemeK.equals(phonemeL)) {
count++;
}
}

for (int l = 0; l < cell.size(); l++) {
if (k != l) {
if (cell.get(k).getPhoneme().equals(cell.get(l).getPhoneme()) &
hbox.getChildren().contains(cell.get(k)) &
hbox.getChildren().contains(cell.get(l))) {
if (count > 0) {
count--;
} else {
hbox.getChildren().remove(cell.get(l));
}
}
}
}
}
}

private void build() {
container = new VBox();
generateFromPhonosys();
}

private void checkPhonemesInCell(HBox cell, ArrayList<PhonemeButton> buttons, ArrayList<String> phonemes) {

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead
for (int i = 0; i < buttons.size(); i++) {
boolean inPhono = p.getList().contains(buttons.get(i).getPhoneme());
buttons.get(i).setInPhono(inPhono);
ArrayList<String> diacritics = getListOfDiacritisizedPhonemes(buttons.get(i).getPhoneme());

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead

for (int j = 0; j < diacritics.size(); j++) {
if (!phonemes.contains(diacritics.get(j))) {
PhonemeButton pb = new PhonemeButton(diacritics.get(j), this, isEditable);
pb.setInPhono(true);
cell.getChildren().add(pb);
phonemes.add(diacritics.get(j));
}
}

Check warning

Code scanning / PMD

This for loop can be replaced by a foreach loop Warning

This for loop can be replaced by a foreach loop
}

Check warning

Code scanning / PMD

This for loop can be replaced by a foreach loop Warning

This for loop can be replaced by a foreach loop
}

private ArrayList<String> getListOfDiacritisizedPhonemes(String phoneme) {
ArrayList<String> list = new ArrayList<String>();
List<String> phonemes = p.getList();
private void createContainer() {
container = new VBox();
for (int i = 0; i < tableList.size(); i++) {
container.getChildren().add(tableList.get(i));
}
Fixed Show fixed Hide fixed
this.getChildren().add(container);
}

private ArrayList<HBox> generateCellList() {

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead
ArrayList<HBox> cells = new ArrayList<HBox>();
Fixed Show fixed Hide fixed

String diacriticRegex = generateDiacriticRegex();
for (int i = 0; i < phonemes.size(); i++) {
if (Pattern.matches(diacriticRegex + phoneme + diacriticRegex, phonemes.get(i))) {
list.add(phonemes.get(i));
// loop through each table
for (int i = 0; i < tableList.size(); i++) {
GridPane gp = tableList.get(i);
ObservableList<Node> children = gp.getChildren();
// loop through each cell in table
for (int j = 0; j < children.size(); j++) {
Node node = children.get(j);
if (node instanceof HBox) {
HBox cell = (HBox) node;
cells.add(cell);
}
}
}
}
Fixed Show fixed Hide fixed

return list;
return cells;
}

private String generateDiacriticRegex() {
Expand All @@ -155,27 +110,15 @@
return diacriticRegex;
}

private void build() {
container = new VBox();
generateFromPhonosys();
}

private void generateFromPhonosys() {
PhonoSystem ps = p.getPhonoSystem();
for (int i = 0; i < ps.getTables().size(); i++) {
tableList.add(generateTable(ps.getTables().get(i), p));
}
refresh();
}

private void createContainer() {
container = new VBox();
for (int i = 0; i < tableList.size(); i++) {
container.getChildren().add(tableList.get(i));
}
this.getChildren().add(container);
}

private GridPane generateTable(PhonoTable pt, Phonology p) {
private GridPane generatePaneWithLabels(PhonoTable pt) {
GridPane gp = new GridPane();
// top labels
for (int i = 0; i < pt.getColumnNames().size(); i++) {
Expand All @@ -189,52 +132,120 @@
GridPane.setColumnIndex(l, i + 1);
gp.getChildren().add(l);
}
return gp;
}

private ArrayList<PhonemeButton> getButtonsInCell(HBox cell) {

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead
ArrayList<PhonemeButton> buttonList = new ArrayList<PhonemeButton>();
Fixed Show fixed Hide fixed
ObservableList<Node> children = cell.getChildren();

for (int i = 0; i < children.size(); i++) {
Node child = children.get(i);
if (child instanceof PhonemeButton) {
PhonemeButton pb = (PhonemeButton) child;
buttonList.add(pb);
}
}

return buttonList;
}

private ArrayList<String> getListOfDiacritisizedPhonemes(String phoneme) {

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead
ArrayList<String> list = new ArrayList<String>();
Fixed Show fixed Hide fixed
List<String> phonemes = p.getList();

String diacriticRegex = generateDiacriticRegex();
for (int i = 0; i < phonemes.size(); i++) {
if (Pattern.matches(diacriticRegex + phoneme + diacriticRegex, phonemes.get(i))) {
list.add(phonemes.get(i));
}
}
Fixed Show fixed Hide fixed

return list;
}

private ArrayList<String> getPhonemesFromButtons(ArrayList<PhonemeButton> buttons) {

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead
ArrayList<String> phonemes = new ArrayList<String>();
Fixed Show fixed Hide fixed

for (int i = 0; i < buttons.size(); i++) {
phonemes.add(buttons.get(i).getPhoneme());
}
Fixed Show fixed Hide fixed

return phonemes;
}

private void removeDuplicates(HBox cell, ArrayList<PhonemeButton> buttons, ArrayList<String> phonemes) {

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead

Check warning

Code scanning / PMD

Avoid using implementation types like 'ArrayList'; use the interface instead Warning

Avoid using implementation types like 'ArrayList'; use the interface instead

Check warning

Code scanning / PMD

Avoid unused method parameters such as 'p'. Warning

Avoid unused method parameters such as 'phonemes'.
for (int i = 0; i < buttons.size(); i++) {

// used to find duplicates that might still be marked as in the phonology
int count = 0;
for (int j = 0; j < p.getList().size(); j++) {
String p1 = buttons.get(i).getPhoneme();
String p2 = p.getList().get(j);
if (p1.equals(p2)) {
count++;
}
}
// counts when i == j & j == i, so count will be off by one without this
count--;

for (int j = 0; j < buttons.size(); j++) {
PhonemeButton p1 = buttons.get(i);
PhonemeButton p2 = buttons.get(j);
// checks that the phonemes are equal, both in the same cell,
// not the *exact* same button, and not a blank spacer
if (p1.getPhoneme().equals(p2.getPhoneme()) &
cell.getChildren().contains(p1) &
cell.getChildren().contains(p2) &
!p1.getPhoneme().equals("") &
Fixed Show fixed Hide fixed
i != j) {
// filter out button duplicates already marked as not in phono
if (!p2.isInPhono()) {
cell.getChildren().remove(p2);
} else if (!p1.isInPhono()) {
cell.getChildren().remove(p1);
}
// filter out button duplicates still marked as in phono
if (count > 0) {
count--;
} else {
cell.getChildren().remove(p2);
}
}
}
}
}

private GridPane generateTable(PhonoTable pt, Phonology p) {
Fixed Show fixed Hide fixed
GridPane gp = generatePaneWithLabels(pt);

for (int i = 0; i < pt.size(); i++) {

// generate row label
Label label = new Label(pt.getRow(i).getName());
// TODO: this text also does not align correctly
label.setAlignment(Pos.CENTER_RIGHT);
GridPane.setRowIndex(label, i + 1);
GridPane.setColumnIndex(label, 0);
PhonoCategory row = pt.getRow(i);
gp.getChildren().add(label);
// cell is needed as, although phonosystems have a predictable amount of sounds per category, phonologies do not

// queue prevents duplicate HBoxes from being added
Queue<PhonemeButton> thingsToAdd = new LinkedList<PhonemeButton>();
// 1 instead of 0 as to give room for side labels
int colIndicator = 1;
for (int j = 0; j < row.size(); j++) {
String sound = row.getSound(j);
if (!sound.equals("*") & !sound.equals("#")) {
PhonemeButton pb = new PhonemeButton(row.getSound(j), this, isEditable);
// search through phonology, mark as in phono if found, and add as many as
// appear in phono
Queue<PhonemeButton> addPerSound = new LinkedList<PhonemeButton>();
for (int k = 0; k < p.getList().size(); k++) {
String phoneme = p.getList().get(k);
String firstNonDiacriticChar = Character.toString(phoneme.replace(diacriticRegex, "").charAt(0));
if (phoneme.equals(sound)) {
if (pb.isInPhono()) {
PhonemeButton newPb = new PhonemeButton(pb);
addPerSound.add(newPb);
} else {
pb.setInPhono(true);
}
} else if (Pattern.matches(diacriticRegex + sound + diacriticRegex, phoneme) || firstNonDiacriticChar.equals(sound)) {
PhonemeButton newPb = new PhonemeButton(phoneme, this, isEditable);
newPb.setInPhono(true);
addPerSound.add(newPb);
}
}
thingsToAdd.add(pb);
while (addPerSound.size() > 0) {
thingsToAdd.add(addPerSound.poll());
}
thingsToAdd.add(pb);
} else {
PhonemeButton pb = new PhonemeButton("");
pb.getMainButton().setDisable(true);
thingsToAdd.add(pb);
}
if ((j + 1) % pt.dataPerCell() == 0) {
// cell is needed as, although phonosystems have a predictable amount of sounds per category, phonologies do not
HBox cell = new HBox();
while (thingsToAdd.size() > 0) {
PhonemeButton pb = thingsToAdd.poll();
Expand Down
Loading