/*
* RecipesView.java
*/
package omnom;
import omnom.database.DatabaseHandler;
import java.awt.event.MouseEvent;
import omnom.newRecipes.AddRecipe;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.table.DefaultTableModel;
import omnom.jaxb.IngredientType;
import omnom.jaxb.RecipeType;
/**
* @author Ashton Alan Kemerling <ashtonkemerling@gmail.com>
*/
public class RecipesView extends FrameView implements MouseListener {
private DefaultListModel recipeListModel = new DefaultListModel();
private String[] ColumnHeaders = {"Ingredient", "Amount"};
private DefaultTableModel ingredientModel = new DefaultTableModel(ColumnHeaders, 2);
private JPopupMenu menu;
private int lastClicked = -1;
public RecipesView(SingleFrameApplication app) {
super(app);
initComponents();
menu = new JPopupMenu();
JMenuItem temp = new JMenuItem ("Delete Recipe");
temp.addMouseListener(this);
menu.add(temp);
temp = new JMenuItem("Edit Recipe");
temp.addMouseListener(this);
menu.add(temp);
// status bar initialization - message timeout, idle icon and busy animation, etc
ResourceMap resourceMap = getResourceMap();
int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
messageTimer = new Timer(messageTimeout, new ActionListener() {
public void actionPerformed(ActionEvent e) {
statusMessageLabel.setText("");
}
});
messageTimer.setRepeats(false);
int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
for (int i = 0; i < busyIcons.length; i++) {
busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
}
busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {
public void actionPerformed(ActionEvent e) {
busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
}
});
idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
statusAnimationLabel.setIcon(idleIcon);
// connecting action tasks to status bar via TaskMonitor
TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
public void propertyChange(java.beans.PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if ("started".equals(propertyName)) {
if (!busyIconTimer.isRunning()) {
statusAnimationLabel.setIcon(busyIcons[0]);
busyIconIndex = 0;
busyIconTimer.start();
}
} else if ("done".equals(propertyName)) {
busyIconTimer.stop();
statusAnimationLabel.setIcon(idleIcon);
} else if ("message".equals(propertyName)) {
String text = (String) (evt.getNewValue());
statusMessageLabel.setText((text == null) ? "" : text);
messageTimer.restart();
} else if ("progress".equals(propertyName)) {
int value = (Integer) (evt.getNewValue());
}
}
});
setup();
}
@Action
public void showAboutBox() {
if (aboutBox == null) {
JFrame mainFrame = RecipesApp.getApplication().getMainFrame();
aboutBox = new RecipesAboutBox(mainFrame);
aboutBox.setLocationRelativeTo(mainFrame);
}
RecipesApp.getApplication().show(aboutBox);
}
private void setup() {
ingredientTable.setModel(ingredientModel);
recipeList.setModel(recipeListModel);
boolean result = DatabaseHandler.connect();
if (result == false) {
System.out.println("Error connecting");
} else {
loadRecipes();
}
}
private void loadRecipes() {
recipeListModel.clear();
ArrayList<String> recipeTitles = DatabaseHandler.getRecipes();
for (String recipe : recipeTitles) {
if (!recipe.equals("NULL"))
recipeListModel.addElement(recipe);
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
mainPanel = new javax.swing.JPanel();
jScrollPane2 = new javax.swing.JScrollPane();
recipeList = new javax.swing.JList();
jScrollPane1 = new javax.swing.JScrollPane();
ingredientTable = new javax.swing.JTable();
jScrollPane3 = new javax.swing.JScrollPane();
instructionTextField = new javax.swing.JTextArea();
menuBar = new javax.swing.JMenuBar();
javax.swing.JMenu fileMenu = new javax.swing.JMenu();
newRecipeItem = new javax.swing.JMenuItem();
javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
javax.swing.JMenu helpMenu = new javax.swing.JMenu();
javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
statusPanel = new javax.swing.JPanel();
javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
statusMessageLabel = new javax.swing.JLabel();
statusAnimationLabel = new javax.swing.JLabel();
mainPanel.setName("mainPanel"); // NOI18N
jScrollPane2.setName("jScrollPane2"); // NOI18N
recipeList.setModel(new javax.swing.AbstractListModel() {
String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
public int getSize() { return strings.length; }
public Object getElementAt(int i) { return strings[i]; }
});
recipeList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
recipeList.setName("recipeList"); // NOI18N
recipeList.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
recipeListMouseClicked(evt);
}
});
jScrollPane2.setViewportView(recipeList);
jScrollPane1.setName("jScrollPane1"); // NOI18N
ingredientTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{null, null},
{null, null},
{null, null}
},
new String [] {
"Ingredient", "Amount"
}
));
ingredientTable.setName("ingredientTable"); // NOI18N
jScrollPane1.setViewportView(ingredientTable);
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(omnom.RecipesApp.class).getContext().getResourceMap(RecipesView.class);
ingredientTable.getColumnModel().getColumn(0).setHeaderValue(resourceMap.getString("ingredientTable.columnModel.title0")); // NOI18N
ingredientTable.getColumnModel().getColumn(1).setHeaderValue(resourceMap.getString("ingredientTable.columnModel.title2")); // NOI18N
jScrollPane3.setName("jScrollPane3"); // NOI18N
instructionTextField.setColumns(20);
instructionTextField.setRows(5);
instructionTextField.setName("instructionTextField"); // NOI18N
jScrollPane3.setViewportView(instructionTextField);
javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
mainPanel.setLayout(mainPanelLayout);
mainPanelLayout.setHorizontalGroup(
mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(mainPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 672, Short.MAX_VALUE)
.addGroup(mainPanelLayout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 309, Short.MAX_VALUE)))
.addContainerGap())
);
mainPanelLayout.setVerticalGroup(
mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(mainPanelLayout.createSequentialGroup()
.addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addGroup(mainPanelLayout.createSequentialGroup()
.addGap(11, 11, 11)
.addComponent(jScrollPane1, 0, 0, Short.MAX_VALUE))
.addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 321, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 336, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
menuBar.setName("menuBar"); // NOI18N
fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
fileMenu.setName("fileMenu"); // NOI18N
newRecipeItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_MASK));
newRecipeItem.setText("New Recipe");
newRecipeItem.setName("newRecipeItem"); // NOI18N
newRecipeItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newRecipeItemActionPerformed(evt);
}
});
fileMenu.add(newRecipeItem);
javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(omnom.RecipesApp.class).getContext().getActionMap(RecipesView.class, this);
exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
exitMenuItem.setName("exitMenuItem"); // NOI18N
exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
exitMenuItemActionPerformed(evt);
}
});
fileMenu.add(exitMenuItem);
menuBar.add(fileMenu);
helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
helpMenu.setName("helpMenu"); // NOI18N
aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
aboutMenuItem.setName("aboutMenuItem"); // NOI18N
helpMenu.add(aboutMenuItem);
menuBar.add(helpMenu);
statusPanel.setName("statusPanel"); // NOI18N
statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N
statusMessageLabel.setName("statusMessageLabel"); // NOI18N
statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N
javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
statusPanel.setLayout(statusPanelLayout);
statusPanelLayout.setHorizontalGroup(
statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 696, Short.MAX_VALUE)
.addGroup(statusPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(statusMessageLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 672, Short.MAX_VALUE)
.addComponent(statusAnimationLabel)
.addContainerGap())
);
statusPanelLayout.setVerticalGroup(
statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(statusPanelLayout.createSequentialGroup()
.addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(statusMessageLabel)
.addComponent(statusAnimationLabel))
.addGap(3, 3, 3))
);
setComponent(mainPanel);
setMenuBar(menuBar);
setStatusBar(statusPanel);
}// </editor-fold>//GEN-END:initComponents
private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
try {
DatabaseHandler.disconnect();
} catch (SQLException ex) {
Logger.getLogger(RecipesView.class.getName()).log(Level.SEVERE, null, ex);
}
}//GEN-LAST:event_exitMenuItemActionPerformed
private void newRecipeItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newRecipeItemActionPerformed
if (addRecipe == null) {
JFrame mainFrame = RecipesApp.getApplication().getMainFrame();
addRecipe = new AddRecipe(mainFrame, this);
}
addRecipe.clearFields();
RecipesApp.getApplication().show(addRecipe);
}//GEN-LAST:event_newRecipeItemActionPerformed
/**
* This is the external handle to loadRecipes, allowing other forms
* to trigger the main panel to refresh the drawn list of recipes. Usually
* used after adding a recipe (deleting recipes triggers a refresh internally).
*/
public void refreshRecipes() {
if (DatabaseHandler.isConnected()) {
loadRecipes();
clearIngredients();
}
}
private void clearIngredients() {
while (ingredientModel.getRowCount() > 0)
ingredientModel.removeRow(0);
}
private void recipeListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recipeListMouseClicked
if (evt.getButton() == 3) {
menu.show(evt.getComponent(), evt.getX(), evt.getY());
lastClicked = recipeList.locationToIndex(evt.getPoint());
recipeList.setSelectedIndex(lastClicked);
}
if (DatabaseHandler.isConnected()) {
int index = recipeList.locationToIndex(evt.getPoint());
if (index >= 0) {
RecipeType recipe = DatabaseHandler.recipeByNum(DatabaseHandler.getRecipeByName((String) recipeListModel.get(index)));
while (ingredientModel.getRowCount() > 0) {
ingredientModel.removeRow(0);
}
List<IngredientType> ingredients = recipe.getIngredients();
for (IngredientType i : ingredients) {
String[] temp = new String[2];
temp[0] = i.getName();
if (i.getNumerator() == 0) {
temp[1] = "";
} else if (i.getDenominator() == 0) {
temp[1] = "" + i.getNumerator();
} else {
temp[1] = i.getNumerator() + "/" + i.getDenominator();
}
temp[1] += " " + i.getUnit();
ingredientModel.addRow(temp);
}
int counter = 1;
String instructions = "";
for (String s : recipe.getSteps()) {
instructions += counter + ": " + s + "\n\n";
counter++;
}
instructionTextField.setText(instructions);
}
}
}//GEN-LAST:event_recipeListMouseClicked
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTable ingredientTable;
private javax.swing.JTextArea instructionTextField;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JScrollPane jScrollPane3;
private javax.swing.JPanel mainPanel;
private javax.swing.JMenuBar menuBar;
private javax.swing.JMenuItem newRecipeItem;
private javax.swing.JList recipeList;
private javax.swing.JLabel statusAnimationLabel;
private javax.swing.JLabel statusMessageLabel;
private javax.swing.JPanel statusPanel;
// End of variables declaration//GEN-END:variables
private final Timer messageTimer;
private final Timer busyIconTimer;
private final Icon idleIcon;
private final Icon[] busyIcons = new Icon[15];
private int busyIconIndex = 0;
private JDialog aboutBox;
private AddRecipe addRecipe;
public void mouseClicked(MouseEvent e) {
return;
}
public void mousePressed(MouseEvent e) {
if (e.getSource() instanceof JMenuItem) {
JMenuItem source = (JMenuItem) e.getSource();
//Must check lastClicked != -1 to avoid confusing the recipeListModel. This might not be necessary due to the try and catch.
if (source.getText().equals("Delete Recipe") && lastClicked != -1)
{
String recipeName = "";
try {
recipeName = (String) recipeListModel.get(lastClicked);
if (DatabaseHandler.deleteRecipeByName(recipeName))
refreshRecipes();
} catch (ArrayIndexOutOfBoundsException ex) {
return; //Nothing to do here. User right clicked on an empty list segment.
}
}
else if (source.getText().equals("Edit Recipe") && lastClicked != -1) {
String recipeName = "";
try {
recipeName = (String) recipeListModel.get(lastClicked);
//TODO Call newRecipes to edit a recipe.
} catch (ArrayIndexOutOfBoundsException ex) {
return;
}
}
}
}
public void mouseReleased(MouseEvent e) {
return;
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
return;
}
}