Merge pull request #2 from andrewlalis/development

Development
This commit is contained in:
Andrew Lalis 2017-05-04 08:13:38 +02:00 committed by GitHub
commit 2f68f7abee
4 changed files with 209 additions and 111 deletions

View File

@ -15,6 +15,8 @@ Since Tengwar is inherently a phonetic script, converting english to Tengwar wou
![Tengwar](https://puu.sh/vtyfi/598ad704e1.png "Tengwar Characters") ![Tengwar](https://puu.sh/vtyfi/598ad704e1.png "Tengwar Characters")
To translate from Tengwar back to English is much simpler, but because Tengwar characters do use capitalization, the resulting string of text will be in only lower-case letters.
### To-Do List ### To-Do List
* Implement s-curls. * Implement s-curls.

View File

@ -4,10 +4,8 @@ import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
/** /**
* @author Andrew Lalis * @author Andrew Lalis
@ -15,8 +13,8 @@ import java.io.IOException;
*/ */
public class Main { public class Main {
public static final String TITLE = "Tengwar Typewriter"; private static final String TITLE = "Tengwar Typewriter";
public static final String ICON_PATH = "resources/icon.png"; private static final String ICON_PATH = "resources/icon.png";
public static void main(String[] args){ public static void main(String[] args){
JFrame f = new JFrame(TITLE); JFrame f = new JFrame(TITLE);
@ -31,31 +29,16 @@ public class Main {
JMenu fileMenu = new JMenu("File"); JMenu fileMenu = new JMenu("File");
//Save Item. //Save Item.
JMenuItem saveItem = new JMenuItem("Save"); JMenuItem saveItem = new JMenuItem("Save");
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK)); saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
saveItem.addActionListener(new ActionListener() { saveItem.addActionListener(e -> window.onSaveClicked());
@Override
public void actionPerformed(ActionEvent e) {
window.onSaveClicked();
}
});
fileMenu.add(saveItem); fileMenu.add(saveItem);
//Import Item. //Import Item.
JMenuItem importItem = new JMenuItem("Import"); JMenuItem importItem = new JMenuItem("Import");
importItem.addActionListener(new ActionListener() { importItem.addActionListener(e -> window.onImportClicked());
@Override
public void actionPerformed(ActionEvent e) {
window.onImportClicked();
}
});
fileMenu.add(importItem); fileMenu.add(importItem);
//Exit Item. //Exit Item.
JMenuItem exitItem = new JMenuItem("Exit"); JMenuItem exitItem = new JMenuItem("Exit");
exitItem.addActionListener(new ActionListener() { exitItem.addActionListener(e -> f.dispose());
@Override
public void actionPerformed(ActionEvent e) {
f.dispose();
}
});
fileMenu.add(exitItem); fileMenu.add(exitItem);
menuBar.add(fileMenu); menuBar.add(fileMenu);
//Edit menu. //Edit menu.
@ -63,49 +46,29 @@ public class Main {
//Live checkbox //Live checkbox
JCheckBoxMenuItem liveCheckBox = new JCheckBoxMenuItem("Live"); JCheckBoxMenuItem liveCheckBox = new JCheckBoxMenuItem("Live");
liveCheckBox.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.CTRL_MASK)); liveCheckBox.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.CTRL_MASK));
liveCheckBox.addActionListener(new ActionListener() { liveCheckBox.addActionListener(e -> window.onLiveToggled(e));
@Override
public void actionPerformed(ActionEvent e) {
window.onLiveToggled(e);
}
});
editMenu.add(liveCheckBox); editMenu.add(liveCheckBox);
menuBar.add(editMenu); menuBar.add(editMenu);
//About Menu. //About Menu.
JMenu aboutMenu = new JMenu("About"); JMenu aboutMenu = new JMenu("About");
//Tengwar Item. //Tengwar Item.
JMenuItem tengwarItem = new JMenuItem("Tengwar"); JMenuItem tengwarItem = new JMenuItem("Tengwar");
tengwarItem.addActionListener(new ActionListener() { tengwarItem.addActionListener(e -> window.onTengwarAboutClicked());
@Override
public void actionPerformed(ActionEvent e) {
window.onTengwarAboutClicked();
}
});
aboutMenu.add(tengwarItem); aboutMenu.add(tengwarItem);
//English Mode. //English Mode.
JMenuItem englishModeItem = new JMenuItem("English Mode"); JMenuItem englishModeItem = new JMenuItem("English Mode");
englishModeItem.addActionListener(new ActionListener() { englishModeItem.addActionListener(e -> window.onEnglishModeAboutClicked());
@Override
public void actionPerformed(ActionEvent e) {
window.onEnglishModeAboutClicked();
}
});
aboutMenu.add(englishModeItem); aboutMenu.add(englishModeItem);
//About the author. //About the author.
JMenuItem aboutMeItem = new JMenuItem("About the Author"); JMenuItem aboutMeItem = new JMenuItem("About the Author");
aboutMeItem.addActionListener(new ActionListener() { aboutMeItem.addActionListener(e -> window.onAboutMeClicked());
@Override
public void actionPerformed(ActionEvent e) {
window.onAboutMeClicked();
}
});
aboutMenu.add(aboutMeItem); aboutMenu.add(aboutMeItem);
menuBar.add(aboutMenu); menuBar.add(aboutMenu);
f.setJMenuBar(menuBar); f.setJMenuBar(menuBar);
f.pack(); f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
try { try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) { } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {

View File

@ -11,13 +11,13 @@ import java.awt.event.*;
import java.io.*; import java.io.*;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
public class Window { public class Window {
public static final List<String> OPEN_FILE_EXTENSIONS = new ArrayList<>(); //List of files that can be imported.
private static final List<String> OPEN_FILE_EXTENSIONS = new ArrayList<>();
static { static {
OPEN_FILE_EXTENSIONS.add("txt"); OPEN_FILE_EXTENSIONS.add("txt");
@ -39,40 +39,28 @@ public class Window {
private boolean isLive = false; private boolean isLive = false;
public Window() { Window() {
//Load the font into the system.
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Font tengwar_annatar = null;
try { try {
tengwar_annatar = Font.createFont(Font.TRUETYPE_FONT, this.getClass().getClassLoader().getResourceAsStream("resources/tngan.ttf")); ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, this.getClass().getClassLoader().getResourceAsStream("resources/tngan.ttf")));
} catch (FontFormatException e) { } catch (FontFormatException e) {
e.printStackTrace(); System.err.println("Font format exception!");
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); System.err.println("IOException!");
} }
ge.registerFont(tengwar_annatar);
//Explicit translation from english to tengwar. //Explicit translation from english to tengwar.
toTengwarButton.addActionListener(new ActionListener() { toTengwarButton.addActionListener(e -> tengwarTextArea.setText(Translator.translateToTengwar(inputTextArea.getText())));
@Override
public void actionPerformed(ActionEvent e) {
tengwarTextArea.setText(Translator.translateToTengwar(inputTextArea.getText()));
}
});
//Clear both text areas. //Clear both text areas.
clearButton.addActionListener(new ActionListener() { clearButton.addActionListener(e -> {
@Override tengwarTextArea.setText(null);
public void actionPerformed(ActionEvent e) { inputTextArea.setText(null);
tengwarTextArea.setText(null);
inputTextArea.setText(null);
}
}); });
//Translate tengwar to english. //Translate tengwar to english.
toEnglishButton.addActionListener(new ActionListener() { toEnglishButton.addActionListener(e -> inputTextArea.setText(Translator.translateToEnglish(tengwarTextArea.getText())));
@Override
public void actionPerformed(ActionEvent e) {
}
});
} }
private void createUIComponents() { private void createUIComponents() {
@ -95,26 +83,53 @@ public class Window {
} }
}); });
this.tengwarTextArea = new JTextArea(); this.tengwarTextArea = new JTextArea();
tengwarTextArea.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
onTengwarTextChanged();
}
@Override
public void removeUpdate(DocumentEvent e) {
onTengwarTextChanged();
}
@Override
public void changedUpdate(DocumentEvent e) {
onTengwarTextChanged();
}
});
this.toTengwarButton = new JButton(); this.toTengwarButton = new JButton();
this.toEnglishButton = new JButton(); this.toEnglishButton = new JButton();
this.clearButton = new JButton(); this.clearButton = new JButton();
this.inputTextArea.requestFocus(); this.inputTextArea.requestFocus();
} }
public JPanel getMainPanel(){ JPanel getMainPanel(){
return this.mainPanel; return this.mainPanel;
} }
/**
* If the english text is changed, and live is selected, then update the tengwar text.
*/
private void onEnglishTextChanged(){ private void onEnglishTextChanged(){
if (isLive) if (isLive && inputTextArea.hasFocus())
tengwarTextArea.setText(Translator.translateToTengwar(inputTextArea.getText())); tengwarTextArea.setText(Translator.translateToTengwar(inputTextArea.getText()));
} }
/**
* If tengwar text is changed, and live is selected, then update the english text.
*/
private void onTengwarTextChanged(){
if (isLive && tengwarTextArea.hasFocus())
inputTextArea.setText(Translator.translateToEnglish(tengwarTextArea.getText()));
}
/** /**
* Toggle the live button and disable translate buttons if needed. * Toggle the live button and disable translate buttons if needed.
* @param e event generated by the check box. * @param e event generated by the check box.
*/ */
public void onLiveToggled(ActionEvent e){ void onLiveToggled(ActionEvent e){
if (((JCheckBoxMenuItem) e.getSource()).getState()){ if (((JCheckBoxMenuItem) e.getSource()).getState()){
//Deactivate buttons, set live to true. //Deactivate buttons, set live to true.
toTengwarButton.setEnabled(false); toTengwarButton.setEnabled(false);
@ -131,7 +146,7 @@ public class Window {
/** /**
* What to do if the user clicks the 'import' button. * What to do if the user clicks the 'import' button.
*/ */
public void onImportClicked(){ void onImportClicked(){
JFileChooser fileChooser = new JFileChooser(System.getProperty("user.documents")); JFileChooser fileChooser = new JFileChooser(System.getProperty("user.documents"));
fileChooser.setFileFilter(new FileFilter() { fileChooser.setFileFilter(new FileFilter() {
@Override @Override
@ -139,10 +154,7 @@ public class Window {
if (f.isDirectory()) if (f.isDirectory())
return true; return true;
String extension = Utils.getExtension(f); String extension = Utils.getExtension(f);
if (extension != null) return extension != null && OPEN_FILE_EXTENSIONS.contains(extension.toLowerCase());
return OPEN_FILE_EXTENSIONS.contains(extension.toLowerCase());
else
return false;
} }
@Override @Override
@ -171,7 +183,7 @@ public class Window {
/** /**
* What to do when the user wants to save their document. * What to do when the user wants to save their document.
*/ */
public void onSaveClicked(){ void onSaveClicked(){
JFileChooser fileChooser = new JFileChooser(System.getProperty("user.documents")); JFileChooser fileChooser = new JFileChooser(System.getProperty("user.documents"));
int result = fileChooser.showSaveDialog(this.mainPanel); int result = fileChooser.showSaveDialog(this.mainPanel);
if (result == JFileChooser.APPROVE_OPTION){ if (result == JFileChooser.APPROVE_OPTION){
@ -186,7 +198,7 @@ public class Window {
/** /**
* Attempt to open the pdf in the browser. * Attempt to open the pdf in the browser.
*/ */
public void onEnglishModeAboutClicked(){ void onEnglishModeAboutClicked(){
if (Desktop.isDesktopSupported()){ if (Desktop.isDesktopSupported()){
try{ try{
Desktop.getDesktop().browse(new URI("https://github.com/andrewlalis/TengwarTranslator/blob/master/src/resources/EnglishOneToOneTengwarV2-1.pdf")); Desktop.getDesktop().browse(new URI("https://github.com/andrewlalis/TengwarTranslator/blob/master/src/resources/EnglishOneToOneTengwarV2-1.pdf"));
@ -199,7 +211,7 @@ public class Window {
/** /**
* Attempt to open Tengwar wikipedia page. * Attempt to open Tengwar wikipedia page.
*/ */
public void onTengwarAboutClicked(){ void onTengwarAboutClicked(){
if (Desktop.isDesktopSupported()){ if (Desktop.isDesktopSupported()){
try{ try{
Desktop.getDesktop().browse(new URI("https://en.wikipedia.org/wiki/Tengwar")); Desktop.getDesktop().browse(new URI("https://en.wikipedia.org/wiki/Tengwar"));
@ -212,7 +224,7 @@ public class Window {
/** /**
* Attempt to open my github page. * Attempt to open my github page.
*/ */
public void onAboutMeClicked(){ void onAboutMeClicked(){
if (Desktop.isDesktopSupported()){ if (Desktop.isDesktopSupported()){
try{ try{
Desktop.getDesktop().browse(new URI("https://github.com/andrewlalis")); Desktop.getDesktop().browse(new URI("https://github.com/andrewlalis"));

View File

@ -1,28 +1,12 @@
package net.agspace.translate; package net.agspace.translate;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* Created by Andrew's Computer on 23-Apr-17. * Created by Andrew's Computer on 23-Apr-17.
*/ */
public class Translator { public class Translator {
private enum CHAR_TYPE {
CONSONANT,
COMPOUND,
ALTERNATE,
VOWEL,
NUMBER,
CARRIER,
PUNCTUATION,
BAR,
S_CURL,
UNKNOWN,
}
//Consonant variables. //Consonant variables.
private static final char B = 'w'; private static final char B = 'w';
private static final char C = 'c'; private static final char C = 'c';
@ -184,7 +168,6 @@ public class Translator {
alternateChars.put('s', S_ALT); alternateChars.put('s', S_ALT);
alternateChars.put('z', Z_ALT); alternateChars.put('z', Z_ALT);
alternateChars.put('w', W_ALT); alternateChars.put('w', W_ALT);
//alternateChars.put('r', R_ALT); R alt is used if followed by a vowel.
alternateChars.put('y', Y_ALT); alternateChars.put('y', Y_ALT);
} }
@ -372,6 +355,92 @@ public class Translator {
return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'); return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u');
} }
/**
* Determines if a tengwar character is a vowel.
* @param c tengwar char to check.
* @return true if vowel, false if not.
*/
private static boolean isVowelTengwar(char c){
for (Character[] ch : vowelChars.values()){
for (char cha : ch){
if (cha == c)
return true;
}
}
return false;
}
/**
* Returns the english vowel representation of a tengwar vowel.
* @param tengwarVowel The tengwar vowel to decipher.
* @return english vowel char.
*/
private static char getEnglishVowel(char tengwarVowel){
if (!isVowelTengwar(tengwarVowel)){
return 0;
}
for (Character[] ch : vowelChars.values()){
for (char cha : ch){
if (cha == tengwarVowel) {
return getKeyByValue(vowelChars, ch);
}
}
}
return 0;
}
/**
* Determines if a tengwar char is a silent E.
* @param tengwarChar the tengwar char to evaluate.
* @return True if it is a silent E, false otherwise.
*/
private static boolean isSilentE(char tengwarChar){
return tengwarChar == E_UNDER_1
|| tengwarChar == E_UNDER_2
|| tengwarChar == E_UNDER_3
|| tengwarChar == E_UNDER_4
|| tengwarChar == E_LAMBE;
}
/**
* Returns a character or string that is a literal translation from tengwar.
* @param tengwarChar the tengwar char to translate.
* @return english representation of the tengwar.
*/
private static String getEnglishLiteral(char tengwarChar){
if (consonantChars.containsValue(tengwarChar)){
return getKeyByValue(consonantChars, tengwarChar).toString();
} else if (compoundChars.containsValue(tengwarChar)){
return getKeyByValue(compoundChars, tengwarChar);
} else if (alternateChars.containsValue(tengwarChar)) {
return getKeyByValue(alternateChars, tengwarChar).toString();
} else if (tengwarChar == R_ALT){
return "r";
} else if (numberChars.containsValue(tengwarChar)){
return getKeyByValue(numberChars, tengwarChar).toString();
} else if (punctuationChars.containsValue(tengwarChar)){
return getKeyByValue(punctuationChars, tengwarChar).toString();
}
return null;
}
/**
* Returns the key for a specified value in a 1 to 1 map.
* @param map The 1 to 1 map to use.
* @param value Value to return the key of.
* @param <T> Key type of the map.
* @param <E> Value type of the map.
* @return Key associated with value.
*/
private static <T, E> T getKeyByValue(Map<T, E> map, E value) {
for (Map.Entry<T, E> entry : map.entrySet()) {
if (Objects.equals(value, entry.getValue())) {
return entry.getKey();
}
}
return null;
}
/** /**
* Translate an english string to tengwar. * Translate an english string to tengwar.
* @param englishString english string. * @param englishString english string.
@ -380,19 +449,14 @@ public class Translator {
public static String translateToTengwar(String englishString){ public static String translateToTengwar(String englishString){
StringBuilder result = new StringBuilder(englishString.length()); StringBuilder result = new StringBuilder(englishString.length());
String input = englishString.toLowerCase().trim(); String input = englishString.toLowerCase().trim();
for (int i = 0; i < input.length(); i++){ for (int i = 0; i < input.length(); i++){
//Attempt to get previous, current, and next char. //Attempt to get previous, current, and next char.
char currentChar = input.charAt(i); char currentChar = input.charAt(i);
char previousChar = 0;
char nextChar = 0; char nextChar = 0;
try{
previousChar = input.charAt(i-1);
} catch (IndexOutOfBoundsException e){
}
try{ try{
nextChar = input.charAt(i+1); nextChar = input.charAt(i+1);
} catch (IndexOutOfBoundsException e){ } catch (IndexOutOfBoundsException e){
//Do nothing, since this may happen.
} }
//Test if the current char is a vowel. //Test if the current char is a vowel.
if (isVowel(currentChar)){ if (isVowel(currentChar)){
@ -429,6 +493,7 @@ public class Translator {
} }
result.append(tengwarCharToBeAdded); result.append(tengwarCharToBeAdded);
result.append(getAppropriateVowel(tengwarCharToBeAdded, currentChar)); result.append(getAppropriateVowel(tengwarCharToBeAdded, currentChar));
//Bar gets added after the vowel.
if (needsBar) if (needsBar)
result.append(bars.get(barSizes.get(tengwarCharToBeAdded))); result.append(bars.get(barSizes.get(tengwarCharToBeAdded)));
i++; i++;
@ -483,4 +548,60 @@ public class Translator {
} }
return result.toString(); return result.toString();
} }
/**
* Translates a tengwar string to english.
* @param tengwarString tengwar string.
* @return english string.
*/
public static String translateToEnglish(String tengwarString){
StringBuilder result = new StringBuilder(tengwarString.length()+tengwarString.length()/2);
for (int i = 0; i < tengwarString.length(); i++){
char currentChar = tengwarString.charAt(i);
char nextChar = 0;
char secondNextChar = 0;
try{
nextChar = tengwarString.charAt(i+1);
} catch (IndexOutOfBoundsException e){
//Do nothing, this is fine.
}
try{
secondNextChar = tengwarString.charAt(i+2);
} catch (IndexOutOfBoundsException e){
//Do nothing, this is fine.
}
String currentLiteral = getEnglishLiteral(currentChar);
//Check if the current character is a literal translation.
if (currentLiteral != null){
//Check if the next character is a vowel that should be placed before a character.
if (isVowelTengwar(nextChar) && !isSilentE(nextChar)){
result.append(getEnglishVowel(nextChar));
result.append(currentLiteral);
i++;
//Check for a double-bar, and then add whatever the current char is.
if (bars.contains(secondNextChar)){
result.append(currentLiteral);
i++;
}
} else if (bars.contains(nextChar)){
result.append(currentLiteral);
i++;
} else {
//Just append the current literal, no skipping.
result.append(currentLiteral);
}
} else {
//Current character is not a literal translation, so it is an E_UNDER, or carrier.
if (carriers.contains(currentChar)){
//If carrier, append the following vowel.
result.append(getEnglishVowel(nextChar));
i++;
} else if (isSilentE(currentChar)) {
result.append('e');
}
}
}
return result.toString();
}
} }