Adding pick maintenance program source code.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,169 @@
|
||||
package pickMaint;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This is a quick routine I wrote to automatically run some SQL queries I developed to judge how well the layout/tablet programs are
|
||||
* performing. It works by figuring out what and how many rows were adjusted by Gloria/Val after the data was submitted from the tablets
|
||||
* by Chelsea/Traci.
|
||||
*
|
||||
* Spits out an excel file for all 3 shifts for each date in the DATE[] constant.
|
||||
*
|
||||
* @author Wes
|
||||
*/
|
||||
public class Analyze {
|
||||
|
||||
private static final int[] DATE = new int[]{ 141117 };
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(Analyze.class.getName());
|
||||
private static final String[] COLUMN_NAMES = new String[]{ "DATE", "SHIFT", "LOOM #", "WEAVER #", "HOURS", "PICKS", "HOURS ENTERED", "PICKS ACTUAL", "PICKS ENTERED", "HOUR ADJUSTMENT", "PICK ADJUSTMENT", "DOWN TIME CODE"};
|
||||
private static final String ROWS_CHANGED_QUERY = "SELECT lddate, "
|
||||
+ " ldshif, "
|
||||
+ " ldloom, "
|
||||
+ " ldweav, "
|
||||
+ " ldhrs, "
|
||||
+ " ldpick, "
|
||||
+ " HOURS, "
|
||||
+ " pksact, "
|
||||
+ " pksent, "
|
||||
+ " ldhrs - HOURS HRS_ADJ, "
|
||||
+ " ldpick - pksact PKS_ADJ, "
|
||||
+ " '(' "
|
||||
+ " || stmdata.iedtfl.iedtcd "
|
||||
+ " || ') ' "
|
||||
+ " || stmdata.iedtfl.iedtds dtcode "
|
||||
+ "FROM stmdata.loomds "
|
||||
+ " LEFT JOIN stmdata.pksread ON lddate = DATE AND "
|
||||
+ " ldshif = shift AND "
|
||||
+ " ldloom = loom "
|
||||
+ " LEFT JOIN stmdata.IEDTFL ON stmdata.loomds.ldreas = stmdata.iedtfl.iedtcd "
|
||||
+ "WHERE lddate = ? AND "
|
||||
+ " ldshif = ? AND "
|
||||
+ " (ldhrs != HOURS OR "
|
||||
+ " ldpick != pksact) AND "
|
||||
+ " NOT (ldweav > 699) AND "
|
||||
+ " ldloom NOT IN (SELECT ldloom "
|
||||
+ " FROM stmdata.loomds "
|
||||
+ " WHERE lddate = ? AND "
|
||||
+ " ldshif = ? AND "
|
||||
+ " ldsty1 = ' SAM') "
|
||||
+ "ORDER BY ldloom ";
|
||||
|
||||
private static final String TOTAL_ROWS = "SELECT COUNT(*) total_rows "
|
||||
+ "FROM stmdata.pksread "
|
||||
+ "WHERE date = ? AND "
|
||||
+ " shift = ? ";
|
||||
|
||||
public static void main(String[] args) throws SQLException, IOException {
|
||||
// Register AS400 DB2 driver and open a connection with the AS400
|
||||
LOGGER.info("Connecting to AS400 as user: WRAY\n");
|
||||
DriverManager.registerDriver(new com.ibm.as400.access.AS400JDBCDriver());
|
||||
Connection conn = DriverManager.getConnection("jdbc:as400://0.0.0.0", "USER", "PASS");
|
||||
|
||||
LOGGER.info("Pre-compiling SQL statements...\n");
|
||||
PreparedStatement rowsChanged = conn.prepareStatement(ROWS_CHANGED_QUERY, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||
PreparedStatement totalRows = conn.prepareStatement(TOTAL_ROWS);
|
||||
|
||||
LOGGER.info("Downloading data for all shifts for " + DATE.length + " days...\n");
|
||||
for (int date : DATE) {
|
||||
//System.out.println("Date: " + date);
|
||||
for (int shift = 1; shift < 4; shift++) {
|
||||
//System.out.println("Shift: " + shift);
|
||||
rowsChanged.setInt(1, date);
|
||||
rowsChanged.setInt(2, shift);
|
||||
rowsChanged.setInt(3, date);
|
||||
rowsChanged.setInt(4, shift);
|
||||
|
||||
totalRows.setInt(1, date);
|
||||
totalRows.setInt(2, shift);
|
||||
|
||||
ResultSet changed = rowsChanged.executeQuery();
|
||||
ResultSet total = totalRows.executeQuery();
|
||||
|
||||
LOGGER.info(((shift == 1) ? "1st" : (shift == 2) ? "2nd" : (shift == 3) ? "3rd" : "") + " shift downloaded. Dumping to Excel sheet...\n");
|
||||
|
||||
int tot = 0;
|
||||
if (total.next())
|
||||
tot = total.getInt(1);
|
||||
|
||||
FileWriter out = new FileWriter(date + "_" + shift + ".xls");
|
||||
String buffer = "";
|
||||
|
||||
for (int i = 0; i < COLUMN_NAMES.length; i++) {
|
||||
buffer += (COLUMN_NAMES[i] + "\t");
|
||||
}
|
||||
|
||||
out.write(buffer + "\n");
|
||||
buffer = "";
|
||||
|
||||
while (changed.next()) {
|
||||
for (int i = 0; i < COLUMN_NAMES.length; i++) {
|
||||
if(i == 11) {
|
||||
String dt = "" + changed.getObject(i + 1);
|
||||
if(dt.equalsIgnoreCase("null"))
|
||||
buffer += (" \t");
|
||||
else
|
||||
buffer += (dt.trim() + "\t");
|
||||
} else {
|
||||
buffer += (changed.getObject(i + 1) + "\t");
|
||||
}
|
||||
}
|
||||
out.write(buffer + "\n");
|
||||
buffer = "";
|
||||
}
|
||||
|
||||
int c = getRowCount(changed);
|
||||
|
||||
out.write("\nROWS CHANGED\tTOTAL ROWS\n");
|
||||
out.write(c + "\t" + tot + "\t \t" + "=1-(A" + (c + 4) + "/B" + (c + 4) + ")" + "\n");
|
||||
out.write(" \t \t \t=1-(A" + (c + 5) + "/B" + (c + 4) + ")" + "\n");
|
||||
|
||||
out.flush(); // Make sure everything gets written
|
||||
out.close();
|
||||
out = null;
|
||||
|
||||
changed.close();
|
||||
total.close();
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.info("Tidying up open resources and exiting...");
|
||||
rowsChanged.close();
|
||||
totalRows.close();
|
||||
rowsChanged = null;
|
||||
totalRows = null;
|
||||
conn.close();
|
||||
conn = null;
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ResultSet you pass to this method must be from a PreparedStatement created with these args:
|
||||
* prepareStatement("select * from ...", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||
*
|
||||
* This will throw an exception with FORWARD_ONLY ResultSets (as in the default one you get with no extra arguments)
|
||||
*
|
||||
* ResultSet.CONCUR_READ_ONLY may actually be something else if you so desire. TYPE_SCROLL_INSENSITIVE is what is important.
|
||||
*
|
||||
* @param set - The ResultSet to count rows in
|
||||
* @return The number of rows in the ResultSet
|
||||
* @throws SQLException
|
||||
*/
|
||||
public static int getRowCount(ResultSet set) throws SQLException {
|
||||
int rowCount;
|
||||
int currentRow = set.getRow(); // Get current row
|
||||
rowCount = set.last() ? set.getRow() : 0; // Determine number of rows
|
||||
if (currentRow == 0) // If there was no current row
|
||||
set.beforeFirst(); // We want next() to go to first row
|
||||
else // If there WAS a current row
|
||||
set.absolute(currentRow); // Restore it
|
||||
return rowCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* I grabbed this from the official Oracle JTabbedPane tutorial and slightly
|
||||
* modified how it behaves when the close button is clicked to properly remove
|
||||
* objects from the HashMaps in the Editor instance.
|
||||
*
|
||||
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle or the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package pickMaint;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.plaf.basic.BasicButtonUI;
|
||||
|
||||
/**
|
||||
* Component to be used as tabComponent;
|
||||
* Contains a JLabel to show the text and
|
||||
* a JButton to close the tab it belongs to
|
||||
*/
|
||||
public class ButtonTabComponent extends JPanel {
|
||||
private static final long serialVersionUID = -5689913156783054837L;
|
||||
private final JTabbedPane pane;
|
||||
private final Editor editor;
|
||||
|
||||
public ButtonTabComponent(final JTabbedPane pane, final Editor editor) {
|
||||
//unset default FlowLayout' gaps
|
||||
super(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
||||
if (pane == null) {
|
||||
throw new NullPointerException("TabbedPane is null");
|
||||
}
|
||||
this.pane = pane;
|
||||
this.editor = editor;
|
||||
setOpaque(false);
|
||||
|
||||
//make JLabel read titles from JTabbedPane
|
||||
JLabel label = new JLabel() {
|
||||
private static final long serialVersionUID = -3058269816351809172L;
|
||||
|
||||
public String getText() {
|
||||
int i = pane.indexOfTabComponent(ButtonTabComponent.this);
|
||||
if (i != -1) {
|
||||
return pane.getTitleAt(i);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
add(label);
|
||||
//add more space between the label and the button
|
||||
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
|
||||
//tab button
|
||||
JButton button = new TabButton();
|
||||
add(button);
|
||||
//add more space to the top of the component
|
||||
setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
|
||||
}
|
||||
|
||||
private class TabButton extends JButton implements ActionListener {
|
||||
private static final long serialVersionUID = 369894927571691780L;
|
||||
|
||||
public TabButton() {
|
||||
int size = 17;
|
||||
setPreferredSize(new Dimension(size, size));
|
||||
setToolTipText("close this tab");
|
||||
//Make the button looks the same for all Laf's
|
||||
setUI(new BasicButtonUI());
|
||||
//Make it transparent
|
||||
setContentAreaFilled(false);
|
||||
//No need to be focusable
|
||||
setFocusable(false);
|
||||
setBorder(BorderFactory.createEtchedBorder());
|
||||
setBorderPainted(false);
|
||||
//Making nice rollover effect
|
||||
//we use the same listener for all buttons
|
||||
addMouseListener(buttonMouseListener);
|
||||
setRolloverEnabled(true);
|
||||
//Close the proper tab by clicking the button
|
||||
addActionListener(this);
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int i = pane.indexOfTabComponent(ButtonTabComponent.this);
|
||||
if (i != -1) {
|
||||
String[] parse = pane.getTitleAt(i).split(" ");
|
||||
int shift = Integer.parseInt(parse[2].substring(0, 1));
|
||||
DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
|
||||
try {
|
||||
Date date = formatter.parse(parse[0]);
|
||||
editor.unloadShiftDetail(date, shift);
|
||||
//pane.remove(i);
|
||||
} catch (ParseException e1) { e1.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
|
||||
//we don't want to update UI for this button
|
||||
public void updateUI() {
|
||||
}
|
||||
|
||||
//paint the cross
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
//shift the image for pressed buttons
|
||||
if (getModel().isPressed()) {
|
||||
g2.translate(1, 1);
|
||||
}
|
||||
g2.setStroke(new BasicStroke(2));
|
||||
g2.setColor(Color.BLACK);
|
||||
if (getModel().isRollover()) {
|
||||
g2.setColor(Color.MAGENTA);
|
||||
}
|
||||
int delta = 6;
|
||||
g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1);
|
||||
g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1);
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private final static MouseListener buttonMouseListener = new MouseAdapter() {
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
Component component = e.getComponent();
|
||||
if (component instanceof AbstractButton) {
|
||||
AbstractButton button = (AbstractButton) component;
|
||||
button.setBorderPainted(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void mouseExited(MouseEvent e) {
|
||||
Component component = e.getComponent();
|
||||
if (component instanceof AbstractButton) {
|
||||
AbstractButton button = (AbstractButton) component;
|
||||
button.setBorderPainted(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,132 @@
|
||||
package pickMaint;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This represents my attempts to recreate the incentive pay calculations done on the AS400
|
||||
* This is for research purposes. Magic numbers are constants pulled from the DB.
|
||||
* @author Wes
|
||||
*/
|
||||
public class EfficiencyBonusCalc {
|
||||
|
||||
private static final int[] DATE = new int[]{ 180219, 180220, 180221, 180222 };
|
||||
private static final int WEAVER = 183;
|
||||
|
||||
private static final double[] MAX_BONUS = new double[]{ 0.0, 0.0, 0.0, 0.0, 2.5, 3.0, 3.75, 4.0, 4.25, 4.75, 7.0, 10.25, 33.0, 33.0 };
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(EfficiencyBonusCalc.class.getName());
|
||||
private static final String EFF_BONUS_BY_DATE = "SELECT y.lddate, "
|
||||
+ " y.ldshif, "
|
||||
+ " y.looms, "
|
||||
+ " y.picks, "
|
||||
+ " y.pickspossible, "
|
||||
+ " ((((CAST(y.picks AS FLOAT) / y.pickspossible) * (y.loomhours * LMRTLH)) - (y.shiftlen * LMRATE)) * lmpct) EFF_BON "
|
||||
+ "FROM (SELECT x.lddate, "
|
||||
+ " x.ldshif, "
|
||||
+ " CAST(ROUND(SUM(x.ldhrs) / max(x.ldhrs), 0) AS INT) looms, "
|
||||
+ " SUM(x.ldhrs) loomhours, "
|
||||
+ " max(x.ldhrs) shiftlen, "
|
||||
+ " sum(x.ldpick) picks, "
|
||||
+ " sum(x.maxpicks) pickspossible "
|
||||
+ " FROM (SELECT lddate, "
|
||||
+ " ldshif, "
|
||||
+ " ldloom, "
|
||||
+ " ldweav, "
|
||||
+ " ldhrs, "
|
||||
+ " ldpick, "
|
||||
+ " CAST(ROUND((lmppm * ldhrs), 0) AS INT) maxpicks "
|
||||
+ " FROM stmdata.loomds "
|
||||
+ " INNER JOIN stmdata.loomms ON stmdata.loomds.ldloom = stmdata.loomms.lmlomn "
|
||||
+ " WHERE lddate = ? AND "
|
||||
+ " ldshif = ? AND "
|
||||
+ " ldweav = ?) x "
|
||||
+ " GROUP BY x.lddate,x.ldshif) y "
|
||||
+ " LEFT JOIN stmdata.lmprir ON stmdata.lmprir.lmloom = 'D' AND "
|
||||
+ " stmdata.lmprir.lmnolm = y.looms ";
|
||||
|
||||
private static final String WEAVER_INFO = "select wvrnam, shift from stmdata.iewvms where WVR# = " + WEAVER;
|
||||
|
||||
|
||||
public static void main(String[] args) throws SQLException, IOException {
|
||||
System.out.println(EFF_BONUS_BY_DATE);
|
||||
// Register AS400 DB2 driver and open a connection with the AS400
|
||||
LOGGER.info("Connecting to AS400 as user: WRAY\n");
|
||||
DriverManager.registerDriver(new com.ibm.as400.access.AS400JDBCDriver());
|
||||
Connection conn = DriverManager.getConnection("jdbc:as400://0.0.0.0", "USER", "PASSWORD");
|
||||
|
||||
LOGGER.info("Pre-compiling SQL statements...\n");
|
||||
PreparedStatement effBonusGet = conn.prepareStatement(EFF_BONUS_BY_DATE);
|
||||
|
||||
LOGGER.info("Looking up weaver name and shift for number " + WEAVER +"...\n");
|
||||
int shift = 0;
|
||||
String name = "";
|
||||
double total = 0;
|
||||
ResultSet weavInfo = conn.createStatement().executeQuery(WEAVER_INFO);
|
||||
if(weavInfo.next()) {
|
||||
shift = weavInfo.getInt(2);
|
||||
name = weavInfo.getString(1).trim();
|
||||
} else {
|
||||
throw new RuntimeException("Weaver doesn't exist!");
|
||||
}
|
||||
|
||||
System.out.println("Efficiency Bonus Calculations for " + name + " (" + WEAVER + ") " + ((shift == 1) ? "1st" : (shift == 2) ? "2nd" : (shift == 3) ? "3rd" : "") + " shift.\n");
|
||||
|
||||
for(int d : DATE){
|
||||
effBonusGet.setInt(1, d);
|
||||
effBonusGet.setInt(2, shift);
|
||||
effBonusGet.setInt(3, WEAVER);
|
||||
|
||||
ResultSet rs = effBonusGet.executeQuery();
|
||||
if(rs.next()){
|
||||
int looms = rs.getInt(3);
|
||||
if(looms > 13)
|
||||
looms = 13;
|
||||
double bonus = rs.getDouble(6);
|
||||
bonus = Math.min(bonus, MAX_BONUS[looms]);
|
||||
|
||||
System.out.println(d + "_" + shift + " - " + looms + " looms. $" + bonus);
|
||||
total += bonus;
|
||||
rs.close();
|
||||
} else {
|
||||
System.out.println(d + "_" + shift + " - NO DATA");
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("\nTotal Efficiency Bonus: $" + total);
|
||||
|
||||
effBonusGet.close();
|
||||
effBonusGet = null;
|
||||
conn.close();
|
||||
conn = null;
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ResultSet you pass to this method must be from a PreparedStatement created with these args:
|
||||
* prepareStatement("select * from ...", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||
*
|
||||
* This will throw an exception with FORWARD_ONLY ResultSets (as in the default one you get with no extra arguments)
|
||||
*
|
||||
* ResultSet.CONCUR_READ_ONLY may actually be something else if you so desire. TYPE_SCROLL_INSENSITIVE is what is important.
|
||||
*
|
||||
* @param set - The ResultSet to count rows in
|
||||
* @return The number of rows in the ResultSet
|
||||
* @throws SQLException
|
||||
*/
|
||||
public static int getRowCount(ResultSet set) throws SQLException {
|
||||
int rowCount;
|
||||
int currentRow = set.getRow(); // Get current row
|
||||
rowCount = set.last() ? set.getRow() : 0; // Determine number of rows
|
||||
if (currentRow == 0) // If there was no current row
|
||||
set.beforeFirst(); // We want next() to go to first row
|
||||
else // If there WAS a current row
|
||||
set.absolute(currentRow); // Restore it
|
||||
return rowCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package pickMaint;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
/**
|
||||
* This class provides means to dump the contents of a JTable into a tab delimited file and then open it in Excel.
|
||||
*
|
||||
* @author Wesley Ray
|
||||
*/
|
||||
public class ExcelExporter {
|
||||
private static final Logger LOGGER = Logger.getLogger(LoomDSRecord.class.getName());
|
||||
|
||||
/**
|
||||
* Dumps the data in a JTable out to a tab delimited file.
|
||||
* @param table
|
||||
* @param outFile
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void exportJTableToFile(JTable table, String outFile) throws IOException{
|
||||
TableModel m = table.getModel();
|
||||
FileWriter out = new FileWriter(outFile);
|
||||
String buffer = "";
|
||||
|
||||
LOGGER.info("Exporting " + m.getRowCount() + " rows to tab delmited file: " + outFile);
|
||||
|
||||
for (int i = 0; i < m.getColumnCount(); i++) {
|
||||
buffer += (m.getColumnName(i) + "\t");
|
||||
}
|
||||
|
||||
out.write(buffer + "\n");
|
||||
buffer = "";
|
||||
|
||||
for (int i = 0; i < m.getRowCount(); i++) {
|
||||
for (int j = 0; j < m.getColumnCount(); j++) {
|
||||
buffer += (m.getValueAt(i, j) + "\t");
|
||||
}
|
||||
out.write(buffer + "\n");
|
||||
buffer = "";
|
||||
}
|
||||
|
||||
out.flush(); //Make sure everything gets written
|
||||
out.close(); //Close the file
|
||||
out = null; //Make sure this gets garbage collected
|
||||
}
|
||||
|
||||
/**
|
||||
* This only works on Windows. This will work with any file that you can double click to open really.
|
||||
* XLS files happen to open in excel automatically.
|
||||
*
|
||||
* @param path
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void openInExcel(String path) throws IOException{
|
||||
LOGGER.info("Invoking \"cmd.exe /c start " + path + "\"");
|
||||
Runtime.getRuntime().exec("cmd.exe /c start " + path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package pickMaint;
|
||||
|
||||
public class LoomDSKey {
|
||||
|
||||
private final int DATE;
|
||||
private final int SHIFT;
|
||||
private final int LOOM;
|
||||
private final int WEAVER;
|
||||
private final String TYPE;
|
||||
|
||||
public LoomDSKey(int date, int shift, int loom, int weaver, String type){
|
||||
this.DATE = date;
|
||||
this.SHIFT = shift;
|
||||
this.LOOM = loom;
|
||||
this.WEAVER = weaver;
|
||||
this.TYPE = type;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return DATE + "-" + SHIFT + "-" + LOOM + "-" + WEAVER + "-" + TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* All 5 components of the composite key must be equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof LoomDSKey)) return false;
|
||||
LoomDSKey key = (LoomDSKey) o;
|
||||
return DATE == key.DATE &&
|
||||
SHIFT == key.SHIFT &&
|
||||
LOOM == key.LOOM &&
|
||||
WEAVER == key.WEAVER &&
|
||||
TYPE.equalsIgnoreCase(key.TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obviously not a perfect hash; although I suspect collisions will be rare in our use case.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = DATE * SHIFT;
|
||||
hash = hash + LOOM;
|
||||
hash = hash * (WEAVER / 2);
|
||||
hash = hash + TYPE.hashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
package pickMaint;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This class is essentially just an Object representation of a single record in LOOMDS/LOOMDS2.
|
||||
*
|
||||
* The constructor takes a reference to an AS400Interface only in case we need to pull "no bonus" hours and picks from LOOMDS2.
|
||||
* See below: if(deleteCode.equalsIgnoreCase("N")) { ... }
|
||||
*
|
||||
* The bulk of the object is created using the java.sql.ResultSet that is passed to the constructor. This ResultSet is expected to be
|
||||
* generated by a particular query stored in AS400Interface.java
|
||||
*
|
||||
* The rest of the class is just getters/setters.
|
||||
*
|
||||
* @author Wesley Ray
|
||||
*/
|
||||
public class LoomDSRecord implements Comparable<Object> {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(LoomDSRecord.class.getName());
|
||||
|
||||
private Date date;
|
||||
private int shift;
|
||||
private int loomNumber;
|
||||
private int weaverNumber;
|
||||
private String weaverName;
|
||||
private String ldStyle; //TRL, BLN, or SAM
|
||||
private double hours;
|
||||
private int picks;
|
||||
private float picksPerHourBonus;
|
||||
private float picksPerHourNoBonus;
|
||||
private String downTimeCode;
|
||||
private String downTimeCodeDescription;
|
||||
private int cut;
|
||||
private String cutSuffix;
|
||||
private String typeCode;
|
||||
private String deleteCode;
|
||||
|
||||
private boolean bonus;
|
||||
private boolean changed = false; //Never ended up using this, not a bad idea though. leaving it here just in case
|
||||
|
||||
public LoomDSRecord(AS400Interface as400, ResultSet row) throws SQLException {
|
||||
date = AS400Interface.intToDate(row.getInt(1));
|
||||
loomNumber = row.getInt(2);
|
||||
shift = row.getInt(3);
|
||||
weaverNumber = row.getInt(4);
|
||||
weaverName = row.getString(5).trim();
|
||||
ldStyle = row.getString(6).trim();
|
||||
hours = row.getDouble(7);
|
||||
picks = row.getInt(8);
|
||||
picksPerHourBonus = row.getFloat(11);
|
||||
picksPerHourNoBonus = row.getFloat(12);
|
||||
downTimeCode = row.getString(13).trim();
|
||||
downTimeCodeDescription = AS400Interface.dtCodeLookup(downTimeCode);
|
||||
cut = row.getInt(14);
|
||||
cutSuffix = row.getString(15).trim();
|
||||
typeCode = row.getString(16).trim();
|
||||
deleteCode = row.getString(17);
|
||||
|
||||
bonus = !((weaverNumber > 699 && weaverNumber < 703) || (ldStyle.equalsIgnoreCase("TRL") || ldStyle.equalsIgnoreCase("BLN") || deleteCode.equalsIgnoreCase("N")));
|
||||
|
||||
if(deleteCode.equalsIgnoreCase("N")){
|
||||
LOGGER.fine(logPrefix() + "is flagged NO_BONUS need to fetch hours and picks from LOOMDS2.");
|
||||
float[] values = as400.getLoomDS2HoursPicks(AS400Interface.dateToInt(date), loomNumber, shift, weaverNumber);
|
||||
hours = values[0];
|
||||
picks = (int) values[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the weaverNumber
|
||||
*/
|
||||
public final int getWeaverNumber() {
|
||||
return weaverNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param weaverNumber the weaverNumber to set
|
||||
*/
|
||||
public final void setWeaverNumber(int weaverNumber) {
|
||||
LOGGER.info("Loom: " + loomNumber + " - " + ((shift == 1) ? "1st" : (shift == 2) ? "2nd" : (shift == 3) ? "3rd" : "") + " shift - " + new SimpleDateFormat("MM/dd/yyyy").format(date) +
|
||||
" - Changing weaver from: " + weaverName + " (" + this.weaverNumber + ") to: " + AS400Interface.weaverLookup(weaverNumber) + " (" + weaverNumber + ")");
|
||||
this.weaverNumber = weaverNumber;
|
||||
this.weaverName = AS400Interface.weaverLookup(weaverNumber);
|
||||
bonus = !((weaverNumber > 699 && weaverNumber < 703) || (ldStyle.equalsIgnoreCase("TRL") || ldStyle.equalsIgnoreCase("BLN")));
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ldStyle
|
||||
*/
|
||||
public final String getLdStyle() {
|
||||
return ldStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ldStyle the ldStyle to set
|
||||
*/
|
||||
public final void setLdStyle(String ldStyle) {
|
||||
LOGGER.info(logPrefix() + "- Changing LDSTYL from: " + this.ldStyle + " to: " + ldStyle);
|
||||
this.ldStyle = ldStyle;
|
||||
bonus = !((weaverNumber > 699 && weaverNumber < 703) || (ldStyle.equalsIgnoreCase("TRL") || ldStyle.equalsIgnoreCase("BLN")));
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the hours
|
||||
*/
|
||||
public final double getHours() {
|
||||
return hours;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hours the hours to set
|
||||
*/
|
||||
public final void setHours(double hours) {
|
||||
LOGGER.info(logPrefix() + "- Changing hours from: " + this.hours + " to: " + hours);
|
||||
this.hours = hours;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the picks
|
||||
*/
|
||||
public final int getPicks() {
|
||||
return picks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param picks the picks to set
|
||||
*/
|
||||
public final void setPicks(int picks) {
|
||||
LOGGER.info(logPrefix() + "- Changing picks from: " + this.picks + " to: " + picks);
|
||||
this.picks = picks;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
public final int getMaxPicks(){
|
||||
return (int) ((hours * (bonus ? picksPerHourBonus : picksPerHourNoBonus)) + 0.5); //The +0.5 combined with the (int) cast creates the effect of rounding up to nearest whole number
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the downTimeCode
|
||||
*/
|
||||
public final String getDownTimeCode() {
|
||||
return downTimeCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param downTimeCode the downTimeCode to set
|
||||
*/
|
||||
public final void setDownTimeCode(String downTimeCode) {
|
||||
LOGGER.info(logPrefix() + "- Changing down time code from: " + this.downTimeCode + " to: " + downTimeCode);
|
||||
this.downTimeCode = downTimeCode;
|
||||
this.downTimeCodeDescription = AS400Interface.dtCodeLookup(downTimeCode);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the typeCode
|
||||
*/
|
||||
public final String getTypeCode() {
|
||||
return typeCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param typeCode the typeCode to set
|
||||
*/
|
||||
public final void setTypeCode(String typeCode) {
|
||||
LOGGER.info(logPrefix() + "- Changing type code from: " + this.typeCode + " to: " + typeCode);
|
||||
this.typeCode = typeCode;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the date
|
||||
*/
|
||||
public final Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the shift
|
||||
*/
|
||||
public final int getShift() {
|
||||
return shift;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the loomNumber
|
||||
*/
|
||||
public final int getLoomNumber() {
|
||||
return loomNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the weaverName
|
||||
*/
|
||||
public final String getWeaverName() {
|
||||
return weaverName;
|
||||
}
|
||||
|
||||
public final String getWeaverNameDisplay(){
|
||||
return weaverName + " (" + weaverNumber + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the picksPerHourBonus
|
||||
*/
|
||||
public final float getPicksPerHourBonus() {
|
||||
return picksPerHourBonus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the picksPerHourNoBonus
|
||||
*/
|
||||
public final float getPicksPerHourNoBonus() {
|
||||
return picksPerHourNoBonus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the downTimeCodeDescription
|
||||
*/
|
||||
public final String getDownTimeCodeDescription() {
|
||||
return downTimeCodeDescription;
|
||||
}
|
||||
|
||||
public final String getformattedDowntimeReason(){
|
||||
if(downTimeCodeDescription != null)
|
||||
return "(" + downTimeCode + ") " + downTimeCodeDescription;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the cut
|
||||
*/
|
||||
public final int getCut() {
|
||||
return cut;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the cutSuffix
|
||||
*/
|
||||
public final String getCutSuffix() {
|
||||
return cutSuffix;
|
||||
}
|
||||
|
||||
public final String getFormattedCutNumber(){
|
||||
if(cut < 1)
|
||||
return "";
|
||||
if(cutSuffix.length() == 0)
|
||||
return "" + cut;
|
||||
return cut + "-" + cutSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deleteCode
|
||||
*/
|
||||
public final String getDeleteCode() {
|
||||
return deleteCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bonus
|
||||
*/
|
||||
public final boolean isBonus() {
|
||||
return bonus;
|
||||
}
|
||||
|
||||
public final boolean changed(){
|
||||
return changed;
|
||||
}
|
||||
|
||||
private String logPrefix(){
|
||||
return "Loom: " + loomNumber + " - " + ((shift == 1) ? "1st" : (shift == 2) ? "2nd" : (shift == 3) ? "3rd" : "") + " shift - "
|
||||
+ new SimpleDateFormat("MM/dd/yyyy").format(date) + " Weaver: " + weaverName + " (" + weaverNumber + ") ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
if(o instanceof LoomDSRecord){
|
||||
return loomNumber - ((LoomDSRecord) o).getLoomNumber();
|
||||
} else {
|
||||
throw new RuntimeException("Something screwed when sorting LoomDSRecord array");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package pickMaint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
/**
|
||||
* This class implements all abstract methods in AbstractTableModel as needed to display LoomDSRecords properly.
|
||||
*
|
||||
* @author Wesley Ray
|
||||
*/
|
||||
public class LoomDSTableModel extends AbstractTableModel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String [] COL_HEADERS = {"Loom", "Weaver", "Style", "Hours", "Picks", "Picks Possible", "Down Time", "Sample Cut"};
|
||||
|
||||
private LoomDSRecord[] data;
|
||||
private Integer[] sampleHighlight;
|
||||
private Integer[] zeroHighlight;
|
||||
|
||||
/**
|
||||
* Updates the data to be displayed by the table model.
|
||||
* Also builds an array of specific rows to highlight in a different color due to them being sample cut-ins
|
||||
* @param data The LoomDSRecord[] to display
|
||||
*/
|
||||
public void loadTable(LoomDSRecord[] data){
|
||||
this.data = data;
|
||||
|
||||
ArrayList<Integer> q = new ArrayList<Integer>();
|
||||
for(LoomDSRecord r : data){
|
||||
if(r.getLdStyle().trim().equalsIgnoreCase("SAM"))
|
||||
q.add(r.getLoomNumber());
|
||||
}
|
||||
sampleHighlight = q.toArray(new Integer[q.size()]);
|
||||
|
||||
q = new ArrayList<Integer>();
|
||||
for(LoomDSRecord r : data){
|
||||
float derp = (float) r.getPicks() / (float) r.getMaxPicks();
|
||||
if(derp <= 0.75 && r.getWeaverNumber() != 700 && r.getWeaverNumber() != 701 && r.getWeaverNumber() != 702)
|
||||
q.add(r.getLoomNumber());
|
||||
}
|
||||
zeroHighlight = q.toArray(new Integer[q.size()]);
|
||||
|
||||
this.fireTableDataChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given row number is to be highlighted for being a sample cut
|
||||
* @param row - the row number to check
|
||||
* @return true/false if row contains sample cut
|
||||
*/
|
||||
public boolean highlightSample(int row){
|
||||
int target = data[row].getLoomNumber();
|
||||
for(int i : sampleHighlight){
|
||||
if(i == target)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given row number is to be highlighted for having zero picks
|
||||
* @param row - the row number to check
|
||||
* @return true/false
|
||||
*/
|
||||
public boolean highlightZero(int row){
|
||||
int target = data[row].getLoomNumber();
|
||||
for(int i : zeroHighlight){
|
||||
if(i == target)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns bonus status for a given row
|
||||
* @param row - the row to check
|
||||
* @return Bonus or not?
|
||||
*/
|
||||
public boolean bonus(int row){
|
||||
return data[row].isBonus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return data.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return COL_HEADERS.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
return COL_HEADERS[column];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
switch(columnIndex){
|
||||
case 0:
|
||||
return data[rowIndex].getLoomNumber();
|
||||
case 1:
|
||||
return data[rowIndex].getWeaverNameDisplay();
|
||||
case 2:
|
||||
return data[rowIndex].getLdStyle();
|
||||
case 3:
|
||||
return data[rowIndex].getHours();
|
||||
case 4:
|
||||
return data[rowIndex].getPicks();
|
||||
case 5:
|
||||
return data[rowIndex].getMaxPicks() + " (+" + (data[rowIndex].getMaxPicks() - data[rowIndex].getPicks()) + ")";
|
||||
case 6:
|
||||
return data[rowIndex].getformattedDowntimeReason();
|
||||
case 7:
|
||||
return data[rowIndex].getFormattedCutNumber();
|
||||
}
|
||||
return null; //required to compile
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package pickMaint;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
/**
|
||||
* Convenience class to request focus on a component.
|
||||
*
|
||||
* When the component is added to a realized Window then component will request
|
||||
* focus immediately, since the ancestorAdded event is fired immediately.
|
||||
*
|
||||
* When the component is added to a non realized Window, then the focus request
|
||||
* will be made once the window is realized, since the ancestorAdded event will
|
||||
* not be fired until then.
|
||||
*
|
||||
* Using the default constructor will cause the listener to be removed from the
|
||||
* component once the AncestorEvent is generated. A second constructor allows
|
||||
* you to specify a boolean value of false to prevent the AncestorListener from
|
||||
* being removed when the event is generated. This will allow you to reuse the
|
||||
* listener each time the event is generated.
|
||||
*/
|
||||
public class RequestFocusListener implements AncestorListener {
|
||||
private boolean removeListener;
|
||||
|
||||
/*
|
||||
* Convenience constructor. The listener is only used once and then it is
|
||||
* removed from the component.
|
||||
*/
|
||||
public RequestFocusListener() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructor that controls whether this listen can be used once or
|
||||
* multiple times.
|
||||
*
|
||||
* @param removeListener when true this listener is only invoked once
|
||||
* otherwise it can be invoked multiple times.
|
||||
*/
|
||||
public RequestFocusListener(boolean removeListener) {
|
||||
this.removeListener = removeListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ancestorAdded(AncestorEvent e) {
|
||||
JComponent component = e.getComponent();
|
||||
component.requestFocusInWindow();
|
||||
|
||||
if (removeListener)
|
||||
component.removeAncestorListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ancestorMoved(AncestorEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ancestorRemoved(AncestorEvent e) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package pickMaint;
|
||||
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
/**
|
||||
* Convenience class.
|
||||
* When this FocusListener is added to a text field the contents of the text field will be highlighted
|
||||
* automagicaly when the cursor enters the field.
|
||||
* @author Wesley Ray
|
||||
*/
|
||||
public class SelectAllOnFocusListener implements FocusListener {
|
||||
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
/*
|
||||
* The following causes any existing text to be selected on focusGained. Using invokeLater to ensure
|
||||
* this happens after any other events pertaining to the text field in order to avoid any unexpected
|
||||
* behavior
|
||||
*/
|
||||
final JTextField source = (JTextField) e.getSource();
|
||||
SwingUtilities.invokeLater( new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
source.selectAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
//Required to compile
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user