Coverage Report - com.timjohnstondev.unitconverter.view.UnitPanel
 
Classes in this File Line Coverage Branch Coverage Complexity
UnitPanel
0%
0/222
0%
0/70
1.854
 
 1  
 /**
 2  
  * Copyright 2009 Timothy Johnston Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
 3  
  * file except in compliance with the License. You may obtain a copy of the License at
 4  
  * 
 5  
  * http://www.apache.org/licenses/LICENSE-2.0
 6  
  * 
 7  
  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 8  
  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 9  
  * specific language governing permissions and limitations under the License.
 10  
  */
 11  
 package com.timjohnstondev.unitconverter.view;
 12  
 
 13  
 import java.awt.Color;
 14  
 import java.awt.Component;
 15  
 import java.awt.Font;
 16  
 import java.awt.Point;
 17  
 import java.awt.event.MouseAdapter;
 18  
 import java.awt.event.MouseEvent;
 19  
 import java.awt.event.MouseListener;
 20  
 import java.awt.event.MouseMotionListener;
 21  
 import java.util.ArrayList;
 22  
 import java.util.List;
 23  
 import java.util.ResourceBundle;
 24  
 import javax.swing.DefaultListModel;
 25  
 import javax.swing.JList;
 26  
 import javax.swing.JPanel;
 27  
 import javax.swing.ListModel;
 28  
 import javax.swing.ListSelectionModel;
 29  
 import javax.swing.UIManager;
 30  
 import javax.swing.border.LineBorder;
 31  
 import com.timjohnstondev.unitconverter.controller.LogicController;
 32  
 import com.timjohnstondev.unitconverter.controller.ModelController;
 33  
 import com.timjohnstondev.unitconverter.view.listener.FactorChangeEvent;
 34  
 import com.timjohnstondev.unitconverter.view.listener.FactorChangeListener;
 35  
 import com.timjohnstondev.unitconverter.view.listener.ReorderAdapter;
 36  
 
 37  
 /**
 38  
  * This panel contains all of the {@link com.timjohnstondev.unitconverter.model.Property Property}s with their
 39  
  * respective units. It provides a user interface to select the {@code Property}, From Unit and To Unit which are then
 40  
  * sent to all FactorChangeListeners.
 41  
  */
 42  
 public class UnitPanel extends JPanel implements MouseMotionListener, MouseListener, Configuration
 43  
 {
 44  
   private LogicController logicController;
 45  
   private ModelController modelController;
 46  
   private JList propertyList;
 47  
   private JList fromUnitList;
 48  
   private JList toUnitList;
 49  
   private MolarMassPanel molarMassPanel;
 50  
   private List <FactorChangeListener> listeners;
 51  
   private int cellHeight;
 52  
   private String propertyListName;
 53  
   private String fromUnitListName;
 54  
   private String toUnitListName;
 55  
   private String toolTipHtmlPrefix;
 56  
   private String toolTipHtmlSuffix;
 57  
   private boolean isMolUnitDivisor;
 58  
   private boolean isPropertySelected;
 59  
   private boolean isFromUnitSelected;
 60  
   private boolean isToUnitSelected;
 61  
 
 62  
   /**
 63  
    * Constructs a {@code UnitPanel} with a {@link ModelController} that provides access to the model layer.
 64  
    * 
 65  
    * @param newController the {@code Controller} to access to the model layer
 66  
    */
 67  
   public UnitPanel(final ModelController newController)
 68  0
   {
 69  0
     logicController = new LogicController();
 70  0
     modelController = newController;
 71  0
     loadResources(ResourceBundle.getBundle("com.timjohnstondev.unitconverter.view.View"));
 72  0
     listeners = new ArrayList <FactorChangeListener>();
 73  
 
 74  0
     setLayout(null);
 75  
 
 76  0
     propertyList = new JList();
 77  0
     fromUnitList = new JList();
 78  0
     toUnitList = new JList();
 79  0
     molarMassPanel = new MolarMassPanel(this);
 80  
 
 81  0
     configureList(propertyList, propertyListName);
 82  0
     configureList(fromUnitList, fromUnitListName);
 83  0
     configureList(toUnitList, toUnitListName);
 84  0
     setPropertyListData();
 85  0
     setReorderListener(propertyList);
 86  
 
 87  0
     propertyList.setBounds(10, 0, 170, 500);
 88  0
     fromUnitList.setBounds(180, 0, 105, 500);
 89  0
     toUnitList.setBounds(285, 0, 105, 500);
 90  0
     molarMassPanel.setBounds(390, 0, 105, 150);
 91  0
     molarMassPanel.setVisible(false);
 92  
 
 93  0
     add(propertyList);
 94  0
     add(fromUnitList);
 95  0
     add(toUnitList);
 96  0
     add(molarMassPanel);
 97  
 
 98  0
     addMouseListener(this);
 99  0
   }
 100  
 
 101  
   private void setReorderListener(final JList list)
 102  
   {
 103  0
     final MouseAdapter listener = new ReorderAdapter(modelController, list);
 104  0
     list.addMouseListener(listener);
 105  0
     list.addMouseMotionListener(listener);
 106  0
   }
 107  
 
 108  
   private void setPropertyListData()
 109  
   {
 110  0
     final DefaultListModel model = new DefaultListModel();
 111  0
     for (String propertyName : modelController.getPropertyNames())
 112  
     {
 113  0
       model.addElement(propertyName);
 114  
     }
 115  0
     propertyList.setModel(model);
 116  0
   }
 117  
 
 118  
   private void loadResources(final ResourceBundle resources)
 119  
   {
 120  0
     cellHeight = Integer.parseInt(resources.getString("UnitPanel.cellHeight"));
 121  0
     propertyListName = resources.getString("UnitPanel.propertyListName");
 122  0
     fromUnitListName = resources.getString("UnitPanel.fromUnitListName");
 123  0
     toUnitListName = resources.getString("UnitPanel.toUnitListName");
 124  0
     toolTipHtmlPrefix = resources.getString("UnitPanel.toolTipHtmlPrefix");
 125  0
     toolTipHtmlSuffix = resources.getString("UnitPanel.toolTipHtmlSuffix");
 126  0
   }
 127  
 
 128  
   private void configureList(final JList list, final String listName)
 129  
   {
 130  0
     list.setName(listName);
 131  0
     list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 132  0
     list.addMouseMotionListener(this);
 133  0
     list.addMouseListener(this);
 134  0
     list.setFixedCellHeight(cellHeight);
 135  0
     list.setBackground(getBackground());
 136  0
   }
 137  
 
 138  
   @Override
 139  
   public final void mouseDragged(final MouseEvent event)
 140  0
   {}
 141  
 
 142  
   @Override
 143  
   public final void mouseMoved(final MouseEvent event)
 144  
   {
 145  0
     final String originatorName = event.getComponent().getName();
 146  0
     final Point point = new Point(event.getX(), event.getY());
 147  
 
 148  0
     if (originatorName.equals(propertyListName) && !isPropertySelected && hasChangedSelection(propertyList, point))
 149  
     {
 150  0
       newPropertySelected(point);
 151  
     }
 152  0
     else if (originatorName.equals(fromUnitListName) && !isFromUnitSelected && hasChangedSelection(fromUnitList, point))
 153  
     {
 154  0
       newFromUnitSelected(point);
 155  
     }
 156  0
     else if (originatorName.equals(toUnitListName) && !isToUnitSelected && hasChangedSelection(toUnitList, point))
 157  
     {
 158  0
       newToUnitSelected(point);
 159  
     }
 160  0
   }
 161  
 
 162  
   /**
 163  
    * 
 164  
    */
 165  
   final void updateMassToMoleLabels()
 166  
   {
 167  0
     insertMol(toUnitList);
 168  0
     removeMol(fromUnitList);
 169  0
     setMolUnitPosition(fromUnitList);
 170  0
   }
 171  
 
 172  
   /**
 173  
    * 
 174  
    */
 175  
   final void updateMoleToMassLabels()
 176  
   {
 177  0
     insertMol(fromUnitList);
 178  0
     removeMol(toUnitList);
 179  0
     setMolUnitPosition(fromUnitList);
 180  0
   }
 181  
 
 182  
   private void setMolUnitPosition(final JList list)
 183  
   {
 184  0
     isMolUnitDivisor = logicController.isMolUnitDivisor(list.getModel());
 185  0
   }
 186  
 
 187  
   /**
 188  
    * @return {@code true} if the mole unit will/was appended to the divisor, else {@code false}
 189  
    */
 190  
   final boolean isMolUnitDivisor()
 191  
   {
 192  0
     return isMolUnitDivisor;
 193  
   }
 194  
 
 195  
   /**
 196  
    * 
 197  
    */
 198  
   final void clearMassMoleLabels()
 199  
   {
 200  0
     removeMol(fromUnitList);
 201  0
     removeMol(toUnitList);
 202  0
   }
 203  
 
 204  
   private void removeMol(final JList list)
 205  
   {
 206  0
     final int selectedIndex = list.getSelectedIndex();
 207  0
     final ListModel model = list.getModel();
 208  0
     final String[] newData = new String[model.getSize()];
 209  0
     for (int i = 0; i < model.getSize(); i++)
 210  
     {
 211  0
       newData[i] = removeMol(model.getElementAt(i));
 212  
     }
 213  0
     list.setListData(newData);
 214  0
     list.setSelectedIndex(selectedIndex);
 215  0
   }
 216  
 
 217  
   private void insertMol(final JList list)
 218  
   {
 219  0
     logicController.insertMol(list, modelController.getUnitSeparator());
 220  0
   }
 221  
 
 222  
   private void positionMolarMassPanel()
 223  
   {
 224  0
     if (modelController.usesMoles(getSelectedValue(propertyList)))
 225  
     {
 226  0
       final Point pointFromIndex = toUnitList.indexToLocation(toUnitList.getSelectedIndex());
 227  0
       final int y = getY(pointFromIndex.getY() + toUnitList.getY(), molarMassPanel);
 228  0
       molarMassPanel.setBounds(molarMassPanel.getX(), y, molarMassPanel.getWidth(), molarMassPanel.getHeight());
 229  
     }
 230  0
   }
 231  
 
 232  
   private void positionToUnitList()
 233  
   {
 234  0
     final int y = getY(fromUnitList.getY(), toUnitList);
 235  0
     toUnitList.setBounds(toUnitList.getX(), y, toUnitList.getWidth(), toUnitList.getModel().getSize() * cellHeight);
 236  0
   }
 237  
 
 238  
   private void populateToUnitList(final String propertyName, final String fromUnitName)
 239  
   {
 240  0
     final boolean hasMoles = logicController.hasMoles(toUnitList.getModel());
 241  0
     toUnitList.setListData(modelController.getSymbols(propertyName, fromUnitName).toArray());
 242  0
     if (hasMoles)
 243  
     {
 244  0
       insertMol(toUnitList);
 245  
     }
 246  0
   }
 247  
 
 248  
   private void showMolarMassPanel()
 249  
   {
 250  0
     if (modelController.usesMoles(getSelectedValue(propertyList)))
 251  
     {
 252  0
       molarMassPanel.showPanel(fromUnitList.getY());
 253  
     }
 254  
     else
 255  
     {
 256  0
       molarMassPanel.hidePanel();
 257  
     }
 258  0
   }
 259  
 
 260  
   private void positionFromUnitList()
 261  
   {
 262  0
     fromUnitList.setListData(modelController.getSymbols(getSelectedValue(propertyList)).toArray());
 263  0
     final Point pointFromIndex = propertyList.indexToLocation(propertyList.getSelectedIndex());
 264  0
     final int y = getY(pointFromIndex.getY(), fromUnitList);
 265  0
     fromUnitList.setBounds(fromUnitList.getX(), y, fromUnitList.getWidth(), fromUnitList.getModel().getSize()
 266  
         * cellHeight);
 267  0
   }
 268  
 
 269  
   private int getY(final double yOfEvent, final int componentHeight)
 270  
   {
 271  0
     final int panelHeight = componentHeight;
 272  0
     final int frameHeight = getHeight();
 273  0
     final int y = (int) ((yOfEvent + panelHeight) < frameHeight ? yOfEvent : (frameHeight - panelHeight));
 274  0
     return y;
 275  
   }
 276  
 
 277  
   private int getY(final double yOfEvent, final JPanel panel)
 278  
   {
 279  0
     return getY(yOfEvent, panel.getHeight());
 280  
   }
 281  
 
 282  
   private int getY(final double yOfEvent, final JList list)
 283  
   {
 284  0
     final int listHeight = list.getModel().getSize() * cellHeight;
 285  0
     return getY(yOfEvent, listHeight);
 286  
   }
 287  
 
 288  
   private void clearFactor()
 289  
   {
 290  0
     for (FactorChangeListener listener : listeners)
 291  
     {
 292  0
       listener.factorChanged(new FactorChangeEvent(this, FactorChangeEvent.CLEAR_FACTOR_ACTION));
 293  
     }
 294  0
   }
 295  
 
 296  
   /**
 297  
    * Notifies {@link com.timjohnstondev.unitconverter.view.listener.FactorChangeListener}s that a
 298  
    * {@link com.timjohnstondev.unitconverter.view.listener.FactorChangeEvent} has occurred
 299  
    */
 300  
   final void updateFields()
 301  
   {
 302  0
     final String[] conversionParts = loadConversionFactorParts();
 303  0
     if (conversionParts != null)
 304  
     {
 305  0
       final String conversion = modelController.getConversion(conversionParts[0], conversionParts[1],
 306  
           conversionParts[2]);
 307  0
       for (FactorChangeListener listener : listeners)
 308  
       {
 309  0
         listener.factorChanged(new FactorChangeEvent(this, conversion, molarMassPanel.getMolecularWeightCorrection()));
 310  
       }
 311  
     }
 312  0
   }
 313  
 
 314  
   private String[] loadConversionFactorParts()
 315  
   {
 316  0
     String[] conversionParts = null;
 317  0
     if (propertyList.getSelectedValue() != null && fromUnitList.getSelectedValue() != null
 318  
         && toUnitList.getSelectedValue() != null)
 319  
     {
 320  0
       conversionParts = new String[3];
 321  0
       conversionParts[0] = (String) propertyList.getSelectedValue();
 322  0
       conversionParts[1] = removeMol(fromUnitList.getSelectedValue());
 323  0
       conversionParts[2] = removeMol(toUnitList.getSelectedValue());
 324  
     }
 325  0
     return conversionParts;
 326  
   }
 327  
 
 328  
   private String removeMol(final Object unit)
 329  
   {
 330  0
     return ((String) unit).replaceAll(modelController.getUnitSeparator() + "mol", "");
 331  
   }
 332  
 
 333  
   private String getSelectedValue(final JList list)
 334  
   {
 335  0
     return list.getSelectedValue().toString();
 336  
   }
 337  
 
 338  
   private void setSelectedIndex(final JList list, final Point point)
 339  
   {
 340  0
     final int index = list.locationToIndex(point);
 341  0
     list.setSelectedIndex(index);
 342  0
   }
 343  
 
 344  
   private boolean hasChangedSelection(final JList list, final Point point)
 345  
   {
 346  0
     boolean changed = false;
 347  0
     final int index = list.locationToIndex(point);
 348  0
     if (index != list.getSelectedIndex())
 349  
     {
 350  0
       list.setSelectedIndex(index);
 351  0
       changed = true;
 352  
     }
 353  0
     return changed;
 354  
   }
 355  
 
 356  
   /**
 357  
    * Add a new FactorChangeListener to the listeners to notify in the event of any changes.
 358  
    * 
 359  
    * @param listener the listener to add
 360  
    */
 361  
   public final void addFactorChangeListener(final FactorChangeListener listener)
 362  
   {
 363  0
     if (!listeners.contains(listener))
 364  
     {
 365  0
       listeners.add(listener);
 366  
     }
 367  0
   }
 368  
 
 369  
   @Override
 370  
   public final void setBackgroundColor(final Color color)
 371  
   {
 372  0
     setBackground(color);
 373  0
     molarMassPanel.setBackground(color);
 374  0
     final Component[] children = getComponents();
 375  0
     for (Component child : children)
 376  
     {
 377  0
       if (child instanceof JList)
 378  
       {
 379  0
         ((JList) child).setBackground(color);
 380  0
         ((JList) child).setSelectionBackground(color.brighter());
 381  
       }
 382  
     }
 383  0
     UIManager.put("ToolTip.background", color.brighter());
 384  0
     UIManager.put("ToolTip.border", new LineBorder(color.darker(), 1, true));
 385  0
     updateUI();
 386  0
   }
 387  
 
 388  
   @Override
 389  
   public final void setForegroundColor(final Color color)
 390  
   {
 391  0
     setForeground(color);
 392  0
     molarMassPanel.setForegroundColor(color);
 393  0
     final Component[] children = getComponents();
 394  0
     for (Component child : children)
 395  
     {
 396  0
       if (child instanceof JList)
 397  
       {
 398  0
         ((JList) child).setForeground(color);
 399  0
         ((JList) child).setSelectionForeground(color);
 400  
       }
 401  
     }
 402  0
     UIManager.put("ToolTip.foreground", color);
 403  0
     updateUI();
 404  0
   }
 405  
 
 406  
   @Override
 407  
   public final void setFontSize(final float fontSize)
 408  
   {
 409  0
     final Font font = getFont().deriveFont(fontSize);
 410  0
     setFont(font);
 411  0
     molarMassPanel.setFontSize(fontSize);
 412  0
     final Component[] children = getComponents();
 413  0
     for (Component child : children)
 414  
     {
 415  0
       child.setFont(font);
 416  
     }
 417  0
     if (fontSize < 13)
 418  
     {
 419  0
       toolTipHtmlPrefix = toolTipHtmlPrefix.replace('4', '3');
 420  
     }
 421  0
     if (fontSize >= 13)
 422  
     {
 423  0
       toolTipHtmlPrefix = toolTipHtmlPrefix.replace('3', '4');
 424  
     }
 425  0
   }
 426  
 
 427  
   public void mousePressed(final MouseEvent event)
 428  0
   {}
 429  
 
 430  
   public final void mouseReleased(final MouseEvent event)
 431  
   {
 432  0
     final String originatorName = event.getComponent().getName();
 433  0
     final Point point = new Point(event.getX(), event.getY());
 434  
 
 435  0
     if (originatorName == null)
 436  
     {
 437  0
       isPropertySelected = false;
 438  0
       isFromUnitSelected = false;
 439  0
       isToUnitSelected = false;
 440  
     }
 441  0
     else if (originatorName.equals(propertyListName))
 442  
     {
 443  0
       newPropertySelected(point);
 444  0
       isPropertySelected = true;
 445  0
       isFromUnitSelected = false;
 446  0
       isToUnitSelected = false;
 447  
     }
 448  0
     else if (originatorName.equals(fromUnitListName))
 449  
     {
 450  0
       newFromUnitSelected(point);
 451  0
       isPropertySelected = true;
 452  0
       isFromUnitSelected = true;
 453  0
       isToUnitSelected = false;
 454  
     }
 455  0
     else if (originatorName.equals(toUnitListName) && toUnitList.getModel().getSize() > 0)
 456  
     {
 457  0
       newToUnitSelected(point);
 458  0
       isPropertySelected = true;
 459  0
       isFromUnitSelected = true;
 460  0
       isToUnitSelected = true;
 461  
     }
 462  0
   }
 463  
 
 464  
   public void mouseEntered(final MouseEvent event)
 465  0
   {}
 466  
 
 467  
   public void mouseExited(final MouseEvent event)
 468  0
   {}
 469  
 
 470  
   public void mouseClicked(final MouseEvent event)
 471  0
   {}
 472  
 
 473  
   private void newPropertySelected(final Point point)
 474  
   {
 475  0
     setSelectedIndex(propertyList, point);
 476  0
     clearFactor();
 477  0
     toUnitList.setListData(new Object[0]);
 478  0
     toUnitList.setToolTipText("");
 479  0
     positionFromUnitList();
 480  0
     showMolarMassPanel();
 481  0
   }
 482  
 
 483  
   private void newFromUnitSelected(final Point point)
 484  
   {
 485  0
     setSelectedIndex(fromUnitList, point);
 486  0
     clearFactor();
 487  0
     final String propertyName = getSelectedValue(propertyList);
 488  0
     final String fromUnitName = removeMol(getSelectedValue(fromUnitList));
 489  0
     fromUnitList.setToolTipText(toolTipHtmlPrefix + modelController.getUnitName(propertyName, fromUnitName)
 490  
         + toolTipHtmlSuffix);
 491  0
     populateToUnitList(propertyName, fromUnitName);
 492  0
     positionToUnitList();
 493  0
   }
 494  
 
 495  
   private void newToUnitSelected(final Point point)
 496  
   {
 497  0
     setSelectedIndex(toUnitList, point);
 498  0
     updateFields();
 499  0
     final String propertyName = getSelectedValue(propertyList);
 500  0
     final String toUnitName = removeMol(getSelectedValue(toUnitList));
 501  0
     toUnitList.setToolTipText(toolTipHtmlPrefix + modelController.getUnitName(propertyName, toUnitName)
 502  
         + toolTipHtmlSuffix);
 503  0
     positionMolarMassPanel();
 504  0
   }
 505  
 
 506  
 }