//Author: ^-^ Veerle ^-^ /* SPECIAL NOTES: *Thanks to Tan Nguyen for checking my code and pointing out errors I had not noticed Date Created: *04/09/2005 Version History: *04/09/2005: V0.1 I knew from the start that I wanted an upgradable currency converter that reads from a txt file. The first job *was to arrange the txt file in a way that could be read by the computer, and looked as user friendly as possible. *Origionally I created a comma separated table, but this was very messy and difficult to read. I then decided it would be better if the computer writes the changes itself, meaning the user doesn't have to use the txt file at all. *V0.2 I created the txt file, with two sections for currencies and the conversions. At the momment I'm only aiming to *allow users to change the conversion rates. Once everything is working I will add the feature to add/delete currencies. *05/09/2005: V0.3 I started creating the read and write objects. The read object reads the txt file one line at a time, and processes it by either what is the first char, or if a boolean flag is set, reads in the currencies/conversions. The write object saves the current line in strBuffer and then writes it to the txt file. *V0.5 I created objCurrencies to handle the readObject, to pass data to the main class and as a bonus, give currency symbols. *V0.8 I created the GUI, getting my inspiration from my metricImperial programme. The layout is very basic. *V1.0 After a few changes with the two for loops that read the conversion rates, the programme was up and running. *V1.2 I created currencyConverter2E, which is a separate frame to edit the conversion rates. My plan is to have a JScrollPane and inside that a table (or grid of labels and txt boxes) to illustrate the conversion matrix. Users will be able to edit the values in the txt boxes, and then save the changes, which will be written to the txt file. *06/09/2005: V1.5 currencyConverter2E needed its own readObject, and it seemed wasteful to have two classes using the same txt file, so I got rid of objCurrencies, and had currencyConverter2 gets its models and conversions from currencyConverter2E. At first, I passed a reference of currencyConverter2 to currencyConverter2E, so when a change has been made, currencyConverter2E can tell currencyConverter2 to update its combo boxes. *V1.8 I added a window listener to currencyConveter, so when it gains focus, if a change has been made then the combo boxes will be updated. This means currencyConverter2E no longer needs a reference to currencyConverter2. *V2.0 I added JOptionDialog boxes, after discovering them on the java reference site when initially looking for dialoguebox. These are simple dialogue boxes that are all setup, and just need a title, message, type of message (warning, information etc) and the options type (yes_no etc). I used these at the cmdClose button if a change has been made and the user has not saved the change. *V2.2 Added extra space at the top for a banner picture. Want to make the programme look good, though that is difficult for a simple application. *V2.3 Added extra key checking to prevent users from entering values of 3 decimal values or greater. At first this prevented users from entering further numbers if they were before the decimal point. I found getSelectionStart() which allows you to find the current cursor position. If they are left of the decimal point, they can enter numbers, but if they are right of the decimal point, and two decimal places exist, they can only use delete or backspace. *V2.5 Created the conversion table, but the layout is all messed up for some reason. I repeatidly checked the coding for logical problems but could not find any. I guessed it might be the size, forcing the grid to go onto a different line. I created another object called currencyConverter2T to put all the code relating to the table in. *V2.7 The extra class has made the programme neater, but it still is showing as a messed up layout. Also been messing about with the logic of saving the file, checking if changes have been made, restoring the origional conversion table if the save was rejected etc. All of that is working now, but got a problem with saving, java doesn't want my applet to save. V3.0 Have converted the applet into a jar, I would have had to do this anyway once I put it online. The write object works! I've changed the readObject so if it can not find the file, a default file is created with the Pound, Euro, Dollar conversion. This means all the person needs to start this programme is the jar file. I still need to add code to add your own currencies, and fix the layout problem. V3.5 Started creating the addCurrency with a series of dialogue boxes, asking for each conversion. I scrapped this idea after a) it gets annoying answering them all, b) requires to much code to make sure each input is legal etc. Instead it accepts the currency name and puts default values of 1.00f for everything, which the user can then change. Found a major error in the writeObject that was writing the last currency twice. Discovered it is because I got the switch case number wrong in the next segment. 07/09/2005: V4.0 The write object works, you can add currencies, change the values and save. I've changed the password so it now asks you for it if you try to save/ add a new currency. Added some dialogue boxes, e.g. when you have saved, to say it was sucessfull. V4.2 Now you can remove currencies. Created a new method for checking if the currency name exists, returning its index if it does, or -1 if it does not. V4.5 Added a rename currency function. setElementAt(element,index) allows you to change a specfic value in the Vector. V4.8 created backup currencyNames and conversion table so that if the user does not save, these are restored. The only problem left to fix is the table layout problem. 08/09/2005: V4.9 Neaten the code, add some comments to say what jobs some of the methods are doing. Found some methods that are now redudant since I changed how the programme restores the backup, so I removed them. V5.0 FIXED THE LAYOUT PROBLEM!!!!! While debugging, I set border colours, and noticed that the vertical currency labels show, but the row currency labels don't, also the dummy label does show. After some messing about the answer hit me, you can't add a component twice to a panel, otherwise it overrides the previous one. I created an extra set of labels, lblHeaderCurrencies and now the layout works! 13/09/2005: V5.3 Recieved an e-mail from envity1981@yahoo.co.uk, Tan Nguyen who said he could not get the currency converter to work, so commented out the read parts to get the shell to load. He also surgests I should comment my code to make it easier to read, so I've commented most of my code in the programme. As for the read problem, the programme works fine on my desktop and laptop, so will try it on the university computers later. While going through my code found some changes I could make, as well as fixing an error with the remove currency method. I've put the source code and the makecurrencyConverter2Jar.bat file in the zip file, allowing the user to compile the programme themselves, hopefully this should fix the problem. 19/09/2005: V5.4 Another e-mail from Tan, pointed out NullPointerException errors I didn't notice (if you press cancel for a dialogue box). He surgested init the String variables first, then testing if they equal null. Now the programme works gracefully. */ import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.TitledBorder; //Lets you create a border with a title on it import java.text.DecimalFormat; public class currencyConverter2 extends JPanel implements ActionListener, WindowFocusListener, FocusListener //Main programme { private DecimalFormat decFormat; //Decimal format lets you set how many decimal places, as well as thousand separaters private JButton cmdConvert, cmdConfig; private JComboBox cboxSource, cboxDes; private JLabel lblUnit, lblAnswer, lblBanner; private JTextField txtUnit; private JPanel panSource, panDes, panNorthArea, panSouthArea, panUnitArea, panButtonGrid, panConversionArea; private Color clrBackgrounds, clrForegrounds; private currencyConverter2E setupWindow; private currencyConverter2K currencyKeyListener = new currencyConverter2K(); private ImageIcon imgBanner; public static void main(String[] args) //With applications, you have to specify a main method (not with applets) { JFrame.setDefaultLookAndFeelDecorated(true); //Make it look nice JFrame frame = new JFrame("Currency Converter"); //Title frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setResizable(false); //Stops the user resizing the window JComponent paneMain = new currencyConverter2(); paneMain.setOpaque(true); paneMain.setPreferredSize(new Dimension(250, 250)); frame.setContentPane(paneMain); frame.pack(); frame.setVisible(true); } public currencyConverter2 () //Instead of init(), do not use void or any return type { cboxSource = new JComboBox(); cboxDes = new JComboBox(); cmdConvert = new JButton("Convert"); cmdConfig = new JButton("Update"); //Tool tip is when you highlight the mouse pointer over a component cmdConvert.setToolTipText("Perform the conversion between the two selected currencies"); cmdConfig.setToolTipText("Update the conversion rates"); cmdConfig.addActionListener(this); cmdConvert.addActionListener(this); setupWindow = new currencyConverter2E("Setup"); setupComboBoxes(); //Method to setup the combo box models decFormat = new DecimalFormat("#,###.00"); //Use thousand separator and 2 decimal places (# is optional, 0 is required) lblUnit = new JLabel("Amount: ", JLabel.RIGHT); lblAnswer = new JLabel("Answer: ", JLabel.CENTER); txtUnit = new JTextField("1.00", 4); txtUnit.addKeyListener(currencyKeyListener); txtUnit.addFocusListener(this); lblBanner = new JLabel("", JLabel.CENTER); try { imgBanner = dataManager.createImageIcon(this, "currencyConverter2Ban.gif", "Banner"); lblBanner.setIcon(imgBanner); } catch (Exception e) { lblBanner.setText(e.getMessage()); } panConversionArea = new JPanel(new BorderLayout()); panSource = new JPanel(); panDes = new JPanel(); panNorthArea = new JPanel(new BorderLayout()); panSouthArea = new JPanel(new BorderLayout()); panUnitArea = new JPanel(); panButtonGrid = new JPanel(new GridLayout(2,2,2,2)); //2 rows * 2 columns, 2 hgap, 2 vgap this.add(panNorthArea, BorderLayout.NORTH); panNorthArea.add(lblBanner, BorderLayout.NORTH); panNorthArea.add(panConversionArea, BorderLayout.SOUTH); panConversionArea.add(panSource, BorderLayout.WEST); panSource.add(cboxSource); panConversionArea.add(panDes, BorderLayout.EAST); panDes.add(cboxDes); this.add(panSouthArea, BorderLayout.SOUTH); panSouthArea.add(panUnitArea, BorderLayout.NORTH); panUnitArea.add(panButtonGrid); panButtonGrid.add(lblUnit); panButtonGrid.add(txtUnit); panButtonGrid.add(cmdConvert); panButtonGrid.add(cmdConfig); panSouthArea.add(lblAnswer, BorderLayout.SOUTH); clrBackgrounds = new Color(75,141,221); //Light blue this.setBackground(clrBackgrounds); panConversionArea.setBackground(clrBackgrounds); panSource.setBackground(clrBackgrounds); panDes.setBackground(clrBackgrounds); panNorthArea.setBackground(clrBackgrounds); panSouthArea.setBackground(clrBackgrounds); panUnitArea.setBackground(clrBackgrounds); panButtonGrid.setBackground(clrBackgrounds); cboxSource.setBackground(clrBackgrounds); cboxDes.setBackground(clrBackgrounds); clrForegrounds = new Color(255,255,255); //White lblUnit.setForeground(clrForegrounds); lblBanner.setForeground(clrForegrounds); cboxSource.setForeground(clrForegrounds); cboxDes.setForeground(clrForegrounds); clrForegrounds = new Color(0,0,0); //Black lblAnswer.setForeground(clrForegrounds); //The first TitledBorder is for the Hz position, the second is for the V position, centre means it is inline panSource.setBorder(new TitledBorder(BorderFactory.createLineBorder(Color.black, 1), "Convert From", TitledBorder.LEFT, TitledBorder.CENTER)); panDes.setBorder(new TitledBorder(BorderFactory.createLineBorder(Color.black, 1), "Convert To", TitledBorder.LEFT, TitledBorder.CENTER)); cboxSource.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); //North, West, South, East cboxDes.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); lblAnswer.setBorder(BorderFactory.createEmptyBorder(3,1,5,1)); panNorthArea.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); } public void setupComboBoxes () //Sets up the source and des combo boxes { setupWindow.resetCurrencies(); //Makes the currency frame read the txt file if (!setupWindow.isError()) //If an error did not occur during reading { cboxSource.setModel(setupWindow.getModel()); //Gets a DefaultComboBoxModel from the currency frame cboxDes.setModel(setupWindow.getModel()); cboxDes.setSelectedIndex(1); //Select the 2nd item } else //If an error did occur { lblAnswer.setText(setupWindow.getErrorMsg()); //Show the error cmdConvert.setEnabled(false); //Disable the command buttons so the programme can not be used cmdConfig.setEnabled(false); } } private String getSymbol (String currency) //Gets the currency symbol of the 3 basic currencies { if (currency.equalsIgnoreCase("Pound")) { return "£"; } else if (currency.equalsIgnoreCase("Euro")) { return "E"; } else if (currency.equalsIgnoreCase("Dollar")) { return "$"; } else { return ""; } } public void actionPerformed(ActionEvent e) { if (e.getSource() == cmdConfig) { setupWindow.setVisible(true); //Show frame currencies } else if (e.getSource() == cmdConvert) { String strBuffer = txtUnit.getText(); if (!strBuffer.equals("")) //If the amount is not empty { float unit = Float.parseFloat(strBuffer); //Convert to float float rate = setupWindow.getRate(cboxSource.getSelectedIndex(), cboxDes.getSelectedIndex()); //Gets the conversion rate for the selected source and des currencies lblAnswer.setText("Answer: " + getSymbol(cboxDes.getSelectedItem().toString()) + decFormat.format(unit * rate)); } else { lblAnswer.setText("Please enter an amount"); } } } public void windowGainedFocus (WindowEvent e) { if (setupWindow.hasChangesBeenMade()) //When this frame has gained focus again, if a change has been made, reset the combo boxes { setupComboBoxes(); } } public void windowLostFocus (WindowEvent e) { } public void focusGained (FocusEvent e) //When the amount box is selected, select all the text in it { txtUnit.selectAll(); } public void focusLost (FocusEvent e) { } }