5
\$\begingroup\$

I am working on adding a GUI to the project that I was making in some course. I am curious if the layout looks good, if there variables and methods are shared properly between particular classes, if there setters and getters are made correctly and if you see anything that I should do better.

Btw i want to add method to Controller that change language of menu. I thought the best way to do that is making a hashMap that have JComponent variable name as an argument and translation of JComponent label as a worth. Next i wanted to compare this hashMap with list of View class variables:

Class<View> c = View.class;
Field[] fields = c.getDeclaredFields();

and set labels for JComponents with setText() method, but i think it's imposible because it's impossible to invoke an object by his variable name. Or maybe i'm wrong.

public class App {

     public static void main(String[] args) throws IOException {

      Model m = new Model();
      View v = new View("Cipher_Studio");
      Controller c = new Controller(m, v);
      c.initController();
      c.changeLanguage();
      c.makeADictionaryMap(m.getDictionariesPath());
     }
    }

View:

public class View {

    private JFrame frame;
    private JTextArea JTextInput, decryptedTxt;
    private JTextField enterTheNumField ;       
    private JLabel jSource, jOperation, jCypher, lEnterTheNum;
    private JButton jGetFile, jExecute, jDirectDict;
    private JRadioButton jrCipher, jrBreak, jrCeasar, jrVigenere;
    private ButtonGroup jrChooseOperation, jrChooseCipher;
    private JMenuBar menuBar;
    private JMenu menuFile, menuEdit;
    private JMenuItem mOpenTextFile, mLoadDictionaries, mSaveFile, mExit, mMenuLangFile;    
    private ArrayList <Object> JElements;




    public View (String title) 
    {
        frame = new JFrame();
        frame.setSize(600,600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);          
        frame.setTitle("Cipher_Vigenere_v:0.5");            
        frame.setLayout(null);  

        menuBar = new JMenuBar();
        menuFile = new JMenu("File");
        menuEdit = new JMenu("Edit");
        mOpenTextFile = new JMenuItem("Get text");
        mLoadDictionaries = new JMenuItem("Get dictionaries");
        mSaveFile = new JMenuItem("Save");
        mExit = new JMenuItem("Close"); 
        mMenuLangFile = new JMenuItem("Load language menu file");
        frame.setJMenuBar(menuBar);

        menuBar.add(menuFile);
        menuBar.add(menuEdit);
        menuFile.add(mOpenTextFile);
        menuFile.add(mLoadDictionaries);
        menuFile.add(mSaveFile);
        menuFile.addSeparator();
        menuFile.add(mExit);    
        menuEdit.add(mMenuLangFile);

        GroupLayout layout = new GroupLayout(frame.getContentPane());
        frame.getContentPane().setLayout(layout);
        layout.setAutoCreateGaps(true);
        layout.setAutoCreateContainerGaps(true);        

        jSource = new JLabel("Source:");
        jOperation = new JLabel("Operation:");
        jCypher = new JLabel("Choose cipher:");
        lEnterTheNum = new JLabel("Enther the cipher:");
        enterTheNumField = new JTextField(10);
        enterTheNumField.setMaximumSize(enterTheNumField.getPreferredSize());

        jrChooseOperation = new ButtonGroup();
        jrCipher = new JRadioButton("Cipher", true);
        jrChooseOperation.add(jrCipher);
        jrBreak = new JRadioButton("Decipher", false);
        jrChooseOperation.add(jrBreak);

        jrChooseCipher = new ButtonGroup();     
        jrCeasar = new JRadioButton("Caesar", true);
        jrChooseCipher.add(jrCeasar);
        jrVigenere = new JRadioButton("Vigenere", false);
        jrChooseCipher.add(jrVigenere);

        jGetFile = new JButton("text");
        jExecute = new JButton("execute");
        jDirectDict = new JButton("dictionaries");
        JTextInput = new JTextArea();
        decryptedTxt = new JTextArea();



        JScrollPane scrollPane = new JScrollPane(JTextInput);
        JScrollPane spDecrypted = new JScrollPane(decryptedTxt);

        layout.setHorizontalGroup(layout.createParallelGroup(LEADING) 

                        .addComponent(scrollPane)
                        .addComponent(spDecrypted)
                        .addGroup(layout.createParallelGroup(LEADING)
                                .addGroup(layout.createSequentialGroup()
                                        .addGroup(layout.createParallelGroup(LEADING)
                                                .addComponent(jSource)
                                                .addComponent(jGetFile)
                                                .addComponent(jDirectDict)
                                                )   
                                .addGroup(layout.createParallelGroup(CENTER)
                                        .addComponent(jOperation)
                                        .addGroup(layout.createSequentialGroup()
                                                .addComponent(jrCipher)                                             
                                                .addComponent(jrBreak) 
                                                )                                                                               
                                        )                               
                                .addGroup(layout.createParallelGroup(CENTER)                                        
                                        .addGroup(layout.createSequentialGroup()
                                                .addComponent(jrCeasar)
                                                .addComponent(jrVigenere)
                                                )
                                        .addComponent(lEnterTheNum)
                                        .addComponent(jCypher))
                                .addGroup(layout.createParallelGroup(LEADING)
                                        .addComponent(enterTheNumField)                                     
                                        .addComponent(jExecute)
                                        )
                                ))
            );



            layout.setVerticalGroup(layout.createSequentialGroup()
                    .addGroup(layout.createParallelGroup(LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(CENTER)
                                    .addComponent(jSource)
                                    .addComponent(jOperation)
                                    .addComponent(jCypher)
                                        )
                                .addGroup(layout.createParallelGroup(BASELINE)
                                    .addComponent(jGetFile)
                                    .addComponent(jrCipher)
                                    .addComponent(jrBreak)
                                    .addComponent(jrCeasar)
                                    .addComponent(jrVigenere)
                                        ))
                                        )
                    .addGroup(layout.createParallelGroup(BASELINE)
                            .addComponent(jDirectDict)
                            .addComponent(lEnterTheNum)
                            .addComponent(enterTheNumField)
                            )

                    .addComponent(scrollPane)
                    .addComponent(jExecute)
                    .addComponent(spDecrypted)            

            );      
          frame.setVisible(true);


    }

    public JMenuItem getmMenuLangFile() {
        return mMenuLangFile;
    }

    public void setmMenuLangFile(JMenuItem mMenuLangFile) {
        this.mMenuLangFile = mMenuLangFile;
    }

    public ArrayList<Object> getJElements() {
        return JElements;
    }

    public void setJElements(ArrayList<Object> jElements) {
        JElements = jElements;
    }

    public JFrame getFrame() {
        return frame;
    }

    public void setFrame(JFrame frame) {
        this.frame = frame;
    }

    public JTextArea getJTextInput() {
        return JTextInput;
    }

    public void setJTextInput(JTextArea jTextInput) {
        JTextInput = jTextInput;
    }

    public JTextArea getDecryptedTxt() {
        return decryptedTxt;
    }

    public void setDecryptedTxt(JTextArea decryptedTxt) {
        this.decryptedTxt = decryptedTxt;
    }

    public JTextField getEnterTheNumField() {
        return enterTheNumField;
    }

    public void setEnterTheNumField(JTextField enterTheNumField) {
        this.enterTheNumField = enterTheNumField;
    }

    public JLabel getjSource() {
        return jSource;
    }

    public void setjSource(JLabel jSource) {
        this.jSource = jSource;
    }

    public JLabel getjOperation() {
        return jOperation;
    }

    public void setjOperation(JLabel jOperation) {
        this.jOperation = jOperation;
    }

    public JLabel getjCypher() {
        return jCypher;
    }

    public void setjCypher(JLabel jCypher) {
        this.jCypher = jCypher;
    }

    public JLabel getlEnterTheNum() {
        return lEnterTheNum;
    }

    public void setlEnterTheNum(JLabel lEnterTheNum) {
        this.lEnterTheNum = lEnterTheNum;
    }

    public JButton getjGetFile() {
        return jGetFile;
    }

    public void setjGetFile(JButton jGetFile) {
        this.jGetFile = jGetFile;
    }

    public JButton getjExecute() {
        return jExecute;
    }

    public void setjExecute(JButton jExecute) {
        this.jExecute = jExecute;
    }

    public JButton getjDirectDict() {
        return jDirectDict;
    }

    public void setjDirectDict(JButton jDirectDict) {
        this.jDirectDict = jDirectDict;
    }

    public JRadioButton getJrCipher() {
        return jrCipher;
    }

    public void setJrCipher(JRadioButton jrCipher) {
        this.jrCipher = jrCipher;
    }

    public JRadioButton getJrBreak() {
        return jrBreak;
    }

    public void setJrBreak(JRadioButton jrBreak) {
        this.jrBreak = jrBreak;
    }

    public JRadioButton getJrCeasar() {
        return jrCeasar;
    }

    public void setJrCeasar(JRadioButton jrCeasar) {
        this.jrCeasar = jrCeasar;
    }

    public JRadioButton getJrVigenere() {
        return jrVigenere;
    }

    public void setJrVigenere(JRadioButton jrVigenere) {
        this.jrVigenere = jrVigenere;
    }

    public ButtonGroup getJrChooseOperation() {
        return jrChooseOperation;
    }

    public void setJrChooseOperation(ButtonGroup jrChooseOperation) {
        this.jrChooseOperation = jrChooseOperation;
    }

    public ButtonGroup getJrChooseCipher() {
        return jrChooseCipher;
    }

    public void setJrChooseCipher(ButtonGroup jrChooseCipher) {
        this.jrChooseCipher = jrChooseCipher;
    }

    public JMenuBar getMenuBar() {
        return menuBar;
    }

    public void setMenuBar(JMenuBar menuBar) {
        this.menuBar = menuBar;
    }

    public JMenu getMenuFile() {
        return menuFile;
    }

    public void setMenuFile(JMenu menuFile) {
        this.menuFile = menuFile;
    }

    public JMenuItem getmOpenTextFile() {
        return mOpenTextFile;
    }

    public void setmOpenTextFile(JMenuItem mOpenTextFile) {
        this.mOpenTextFile = mOpenTextFile;
    }

    public JMenuItem getmLoadDictionaries() {
        return mLoadDictionaries;
    }

    public void setmLoadDictionaries(JMenuItem mLoadDictionaries) {
        this.mLoadDictionaries = mLoadDictionaries;
    }

    public JMenuItem getmSaveFile() {
        return mSaveFile;
    }

    public void setmSaveFile(JMenuItem mSaveFile) {
        this.mSaveFile = mSaveFile;
    }

    public JMenuItem getmExit() {
        return mExit;
    }

    public void setmExit(JMenuItem mExit) {
        this.mExit = mExit;
    }

}

Model:

public class Model {

    private HashMap <String, HashSet<String>> listOfDictionaries;
    private HashMap<String, String> currLangMenu;
    private File[] dictionaries;
    static final String basicPath = (new java.io.File(".").getAbsolutePath()).substring(0,new java.io.File(".").getAbsolutePath().length()-2);//not sure 
    //is this should to be declared as a static final
    private String dictionariesPath, filePath, savePath, inputTextName, cypherValueForFileName, isCipheredTxt, isCaesarTxt;
    private boolean isCiphered, isRightCipher;
    static final String alphabet = "abcdefghijklmnopqrstuvqxwz";    


    public HashMap<String, HashSet<String>> getListOfDictionaries() {
        return listOfDictionaries;
    }

    public void setListOfDictionaries(HashMap<String, HashSet<String>> listOfDictionaries) {
        this.listOfDictionaries = listOfDictionaries;
    }

    public File[] getDictionaries() {
        return dictionaries;
    }

    public void setDictionaries(File[] dictionaries) {
        this.dictionaries = dictionaries;
    }

    public String getDictionariesPath() {
        dictionariesPath = (new StringBuilder(basicPath)).append("/dictionaries").toString();
        return dictionariesPath;
    }

    public void setDictionariesPath(String dictionariesPath) {
        this.dictionariesPath = dictionariesPath;
    }

    public String getFilePath() {
        filePath = (new StringBuilder(basicPath)).append("/messages").toString();
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public String getSavePath() {
        savePath = (new StringBuilder(basicPath)).append("/workspace").toString();
        //savePath = (new StringBuilder(basicPath)).append("/messages").toString();
        return savePath;
    }

    public void setSavePath(String savePath) {
        this.savePath = savePath;
    }

    public String getInputTextName() {
        return inputTextName;
    }

    public void setInputTextName(String inputTextName) {
        this.inputTextName = inputTextName;
    }

    public String getCypherValueForFileName() {
        return cypherValueForFileName;
    }

    public void setCypherValueForFileName(String cypherValueForFileName) {
        this.cypherValueForFileName = cypherValueForFileName;
    }


    public boolean isCiphered() {
        return isCiphered;
    }

    public void setCiphered(boolean isCiphered) {
        this.isCiphered = isCiphered;
    }

    public String getIsCipheredTxt() {
        return isCipheredTxt;
    }

    public void setIsCipheredTxt(String isCipheredTxt) {
        this.isCipheredTxt = isCipheredTxt;
    }

    public String getIsCaesarTxt() {
        return isCaesarTxt;
    }

    public void setIsCaesarTxt(String isCaesarTxt) {
        this.isCaesarTxt = isCaesarTxt;
    }

    public boolean isRightCipher() {
        return isRightCipher;
    }

    public void setRightCipher(boolean isRightCipher) {
        this.isRightCipher = isRightCipher;
    }

    public HashMap<String, String> getCurrLangMenu() {
        return currLangMenu;
    }

    public void setCurrLangMenu(HashMap<String, String> currLangMenu) {
        this.currLangMenu = currLangMenu;
    }   
}

Controller:

public class Controller {

    private Model model;
    private View view;

    public Controller(Model m, View v) {
        model = m;
        view = v;
    }

    public void initController() {
        view.getjGetFile().addActionListener(e -> loadFiles());
        view.getmOpenTextFile().addActionListener(e -> loadFiles());
        view.getjExecute().addActionListener(e -> execute());
        view.getjDirectDict().addActionListener(e -> makeADictionaryMap());
        view.getmLoadDictionaries().addActionListener(e -> makeADictionaryMap());
        view.getmSaveFile().addActionListener(e -> saveFiles());
        view.getmMenuLangFile().addActionListener(e -> makeLangMenuMap());
        view.getmExit().addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                view.getFrame().dispose();
            }
        });
    }

    public void makeLangMenuMap()  { //making hashMap from txt file that translating JComponents labels 

        JFileChooser jGet = new JFileChooser();
        File file = new File(Model.basicPath);
        jGet.setCurrentDirectory(file);
        HashMap <String,String> map = new HashMap<>();

        if (jGet.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) 
        {
            file = jGet.getSelectedFile();
            try {
                Scanner scanner = new Scanner(file);
                while (scanner.hasNextLine()) {
                    String line = scanner.nextLine();
                    String parts[] = line.split("-", 2);
                    map.put(parts[0], parts[1]);
                }
            } catch (FileNotFoundException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
        model.setCurrLangMenu(map);
         map.entrySet().forEach(entry->{
                System.out.println(entry.getKey() + " " + entry.getValue());  
             });
        }

    public void changeLanguage() {
        Class<View> c = View.class;
        Field[] fields = c.getDeclaredFields();
        // Here i want to compare "fields[]" with hashmap langMenu and set label name
        // for each visible JComponent in menu according
        // with hashMap worth
    }

    private void saveFiles() {
        JFileChooser jGet = new JFileChooser();
        File file = new File(model.getSavePath());

        jGet.setCurrentDirectory(file);
        jGet.setDialogTitle("Save results:");
        jGet.setName(view.getEnterTheNumField().getText());
        jGet.setApproveButtonText("Save");
        String s = model.getIsCipheredTxt() + model.getIsCaesarTxt() + "_key_value:_"
                + model.getCypherValueForFileName() + "_" + model.getInputTextName(); // setting suggested file name
        jGet.setSelectedFile((new File(s)));

        if (jGet.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) 
        {
            file = jGet.getSelectedFile();
            try {
                PrintWriter pw = new PrintWriter(file);
                Scanner scanner = new Scanner(view.getDecryptedTxt().getText());
                while (scanner.hasNext()) {
                    pw.println(scanner.nextLine());
                }
                pw.close();
            } catch (FileNotFoundException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
    }

    private void loadFiles() {
        JFileChooser jGet = new JFileChooser();
        File file = new File(model.getFilePath());
        jGet.setCurrentDirectory(file);

        if (jGet.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) // jeśli wybierzemy juz jakis plik
        {
            view.getJTextInput().setText(null);
            view.getDecryptedTxt().setText(null);

            file = jGet.getSelectedFile();
            model.setInputTextName(file.getName());
            try {
                Scanner scanner = new Scanner(file);
                while (scanner.hasNext()) {
                    view.getJTextInput().append(scanner.nextLine() + "\n");
                }
            } catch (FileNotFoundException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
    }

    private void execute() { //depends on radio buttons settings it decrypt or encrypt text for Ceasar or Vigenere cipher

        view.getDecryptedTxt().setText(null);
        String input = view.getJTextInput().getText();
        String output = "";

        if (view.getJrCipher().isSelected()) {
            String sCipher = view.getEnterTheNumField().getText();

            if (view.getJrCeasar().isSelected()) {
                try {
                    int sCipherNum = Integer.parseInt(sCipher);
                    CaesarCipher caesar = new CaesarCipher(sCipherNum);
                    output = caesar.encrypt(input);
                } catch (Exception e) {
                    JOptionPane.showMessageDialog(null, "Enter the number between 0 and 26");
                    // TODO: handle exception
                }
            } else

            {
                int[] array = new int[sCipher.length()];

                for (int i = 0; i < sCipher.length(); i++) {
                    char curChar = sCipher.charAt(i);
                    if (model.alphabet.indexOf(curChar) == -1) {
                        JOptionPane.showMessageDialog(null,
                                "Only latin letters allowed");
                        Arrays.fill(array, 0);
                        break;
                    } else {
                        array[i] = model.alphabet.indexOf(curChar);
                    }

                }
                VigenereCipher vc = new VigenereCipher(array);
                output = vc.encrypt(input);
            }
        }

        else {
            if (view.getJrCeasar().isSelected()) {
                CaesarCracker cc = new CaesarCracker();
                output = cc.decrypt(input);
            } else {
                VigenereBreaker vb = new VigenereBreaker();
                output = vb.breakForAllLanguages(input, model.getListOfDictionaries());
            }
        }
        model.setCypherValueForFileName(view.getEnterTheNumField().getText());
        if (view.getJrCipher().isSelected()) {
            model.setCiphered(true);
            model.setIsCipheredTxt("Encrypt_");
        } else {
            model.setCiphered(false);
            model.setIsCipheredTxt("Decrypt_");
        }
        if (view.getJrCeasar().isSelected()) {
            model.setIsCaesarTxt("Caesar_Cipher_");
        } else {
            model.setIsCaesarTxt("Vigenere_Cipher_");
        }
        view.getDecryptedTxt().append(output);
    }

    private void makeADictionaryMap() {
        VigenereBreaker vb = new VigenereBreaker();

        JFileChooser chooser = new JFileChooser();
        File file = new File(model.getDictionariesPath());
        chooser.setCurrentDirectory(file);
        chooser.setMultiSelectionEnabled(true);
        chooser.showOpenDialog(null);
        model.setDictionaries(chooser.getSelectedFiles());
        model.setListOfDictionaries(vb.makeDictionaryMap(model.getDictionaries()));
    }

    public void makeADictionaryMap(String dictionaryAdress) {
        VigenereBreaker vb = new VigenereBreaker();

        File[] fileList = new File(dictionaryAdress).listFiles();

        model.setDictionaries(fileList);
        model.setListOfDictionaries(vb.makeDictionaryMap(model.getDictionaries()));
    }
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

The View class is a mess. Trying to build Swing user interfaces in Java code descends very easily into a food fight in an italian restaurant. I've been there too. I have no idea what the UI is supposed to look like (and I'm not going to bother running the code to find out), but if there are separate logical components within the view, refactor them into custom components and place those in the View. This reduces the number of direct dependencies you have to declare in the View class and makes it easier to manage and maintain. If there is a tool that lets you define the layout constraints in XML or similar resource, use it.

public JLabel getjCypher() {
    return jCypher;
}

public void setjCypher(JLabel jCypher) {
    this.jCypher = jCypher;
}

You expose a lot of the internal components through getters and setters. Did you just autogenerate these for all of the fields with your IDE? If so, that was a mistake. A view should almost never need to expose it's sub-components to anyone. Especially not in this extent. The need to expose the internals is a sign that the View class is being loaded with responsibilities that should be divided into separate classes. The setters themselves seem to provide no functionality other than allowing external parties to break the internal state of the View. They need to go.

\$\endgroup\$
1
  • \$\begingroup\$ Ok. I think You're right with everything . Every changes in View should be saved as a variables keeping in Model and yep, i used Eclipse tools to create setters and getters and for now i know that was wrong. But i still don't know, what is the best way to change the look of menu. I think the method should be in Controller and in View have to have some setters to change text in labels or colour theme. Or not? \$\endgroup\$
    – KarolC
    Commented Aug 15, 2019 at 17:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.