/*
* Software Name : ATK
*
* Copyright (C) 2007 - 2012 France Télécom
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ------------------------------------------------------------------
* File Name : CheckListTable.java
*
* Created : 07/03/2007
* Author(s) : Nicolas MOTEAU
*/
package com.orange.atk.atkUI.coregui;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.io.File;
import java.io.FilenameFilter;
import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Vector;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import org.apache.log4j.Logger;
import com.orange.atk.atkUI.corecli.Campaign;
import com.orange.atk.atkUI.corecli.Configuration;
import com.orange.atk.atkUI.corecli.IProgressMonitor;
import com.orange.atk.atkUI.corecli.Step;
import com.orange.atk.atkUI.corecli.Step.Verdict;
/**
* This class define the concept of CheckListTable and the API to handle it.
* It is a kind of JPanel that aims to present in a table a list of <code>Step</code>.
* The composite Design pattern may be used for checklist tables if composite
* checklist table are needed.
* @author Nicolas MOTEAU
* @since JDK5.0
*/
public abstract class CheckListTable extends AbstractCheckListTable {
private static final long serialVersionUID = 1L;
public static int COLUMN_NBROW = 0;
public static final int COLUMN_TESTNAME = 1;
public static final int COLUMN_PHONECONFIG = COLUMN_TESTNAME + 1;
public static final int COLUMN_MODIFIED = COLUMN_PHONECONFIG + 1;
public static final int COLUMN_VERDICT = COLUMN_MODIFIED + 1;
/**
* The campaign specific to a checklist (java, flash, ...)
*/
protected Campaign campaign;
protected CheckListTableModel model;
/* ToolTips*/
public Vector<String> toolTipFlashFile;
public Vector<String> toolTipModified;
// -- Table management --
protected JTable table;
protected TableColumn nbStepColumn;
protected TableColumn flashfileColumn;
protected TableColumn modifiedColumn;
protected TableColumn verdictColumn;
protected TableColumn phoneconfigColumn;
protected JScrollPane tablePane;
protected Vector<String> toolTipReport;
protected Vector<Step> copiedItems = new Vector<Step>();
protected JComboBox comboBoxPhoneConfig;
public static final String ADD_NEW_CONFIG_FILE = "Create a new config file...";
public static final String NOT_SELECTED = "NOT SELECTED";
protected CheckListTable() {
super();
table = new JTable(model) {
/**
*
*/
private static final long serialVersionUID = 1L;
public boolean getScrollableTracksViewportHeight(){
if (getParent() instanceof JViewport){
return (((JViewport)getParent()).getHeight() > getPreferredSize().height);
}
return false;
}
};
//set ToolTip to column headers
JTableHeader header = table.getTableHeader();
ColumnHeaderToolTips tips = new ColumnHeaderToolTips();
for (int c=0; c<table.getColumnCount(); c++){
TableColumn col = table.getColumnModel().getColumn(c);
if (c == COLUMN_MODIFIED){
tips.setToolTip(col, "An 'M' flag appears if the step has been modified since the last execution of this step.");
}else{
tips.setToolTip(col, "");
}
}
header.addMouseMotionListener(tips);
header.addMouseListener(new MouseListener(){
public void mouseClicked(MouseEvent e) {
int numCol = table.columnAtPoint(e.getPoint());
if (numCol == COLUMN_NBROW){
sortAllRowsBy(numCol, true);
}else{
sortAllRowsBy(numCol, false);
}
model.fireTableStructureChanged();
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
});
//Create the combobox and initialize the values
Vector<String> readListPhoneConfig = readListPhoneConfig();
comboBoxPhoneConfig = (readListPhoneConfig == null) ? new JComboBox() : new JComboBox(readListPhoneConfig);
comboBoxPhoneConfig.addItem(ADD_NEW_CONFIG_FILE);
comboBoxPhoneConfig.addItem(NOT_SELECTED);
comboBoxPhoneConfig.setSelectedItem(NOT_SELECTED);
toolTipFlashFile = new Vector<String>();
toolTipReport = new Vector<String>();
toolTipModified = new Vector<String>();
}
protected void constructTable(){
//set ToolTip to column headers
JTableHeader header = table.getTableHeader();
ColumnHeaderToolTips tips = new ColumnHeaderToolTips();
for (int c=0; c<table.getColumnCount(); c++){
TableColumn col = table.getColumnModel().getColumn(c);
if (c == COLUMN_MODIFIED){
tips.setToolTip(col, "An 'M' flag appears if the step has been modified since the last execution of this step.");
}else{
tips.setToolTip(col, "");
}
}
header.addMouseMotionListener(tips);
header.addMouseListener(new MouseListener(){
public void mouseClicked(MouseEvent e) {
int numCol = table.columnAtPoint(e.getPoint());
if (numCol == COLUMN_NBROW){
sortAllRowsBy(numCol, true);
}else{
sortAllRowsBy(numCol, false);
}
model.fireTableStructureChanged();
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
});
table.getTableHeader().setReorderingAllowed(false);
table.setAutoCreateColumnsFromModel(false);
}
/**
* Returns the table object.
* @return the table object
*/
public JTable getTable() {
return table;
}
/**
* Returns a campaign containing all steps.
* @return a campaign with all steps
*/
public Campaign getCampaign() {
return campaign;
}
/**
* Selects all step of this checklisttable.
*/
public void selectAll() {
table.selectAll();
}
/**
* Returns the number of steps in this checklisttable.
* @return the number of steps
*/
public int getStepNumber() {
return table.getRowCount();
}
/**
* Returns the number of selected steps
*/
public int getSelectedRowCount() {
return table.getSelectedRowCount();
}
/**
* Create a new check-list
*/
public void newCheckList() {}
/**
* Adds a new row corresponding to the given "Step" object and at the row given in parameter.
* @param step The "Step" object to add in the corresponding table.
* @param rowNumberInGUI The number of row where the new step must be inserted.
* @param selectIt whether to select the new row in the table or not.
* @param checkPreviousResult if false, do not attemps to look for a previous result.
* if false, a check list update (updateModified operation) has to be performed to load previous results
*/
public abstract void addRow(Step step, int rowNumberInGUI, boolean selectIt, boolean checkPreviousResult);
/**
* Copy selected rows.
*/
public void copySelection() {
copiedItems = new Vector<Step>();
int [] selectedRows = table.getSelectedRows();
for (int i=0; i<selectedRows.length;i++){
int numRow = selectedRows[i];
String rowNumber = (String)model.getValueAt(numRow, COLUMN_NBROW);
int numInCampaign = new Integer(rowNumber).intValue()-1;
Step cmdLine = campaign.get(numInCampaign);
copiedItems.add(cmdLine);
}
CoreGUIPlugin.mainFrame.updateButtons();
}
/**
* Paste copied rows under the selected rows
*/
public void pasteUnder() {
int nbSelectedRow = table.getSelectedRowCount();
int [] selectedRows = table.getSelectedRows();
int lastRowSelected = selectedRows[nbSelectedRow -1];
int currentRow = lastRowSelected + 1;
for (Step step : copiedItems) {
Step cmdLine = (Step)step;
Step newCmdLine = (Step)cmdLine.getClone();
newCmdLine.setOutFilePath("");
newCmdLine.setVerdict(Verdict.NONE);
newCmdLine.setUserVerdict(Verdict.NONE);
newCmdLine.setSkippedMessage("");
newCmdLine.setUserComment("");
addRow(newCmdLine, currentRow, true, true);
currentRow++;
}
CoreGUIPlugin.mainFrame.updateButtons();
CoreGUIPlugin.mainFrame.setModified(true);
CoreGUIPlugin.mainFrame.updateContentTabsTitle();
}
/**
* Removes the selected steps of this checklisttable.
* @param mon a progress monitor
* @param updateTable whether to update the table now or not
*/
public void removeSelection(IProgressMonitor mon, boolean updateTable) {
if (table.getSelectedRowCount()!=0){
CoreGUIPlugin.mainFrame.setModified(true);
}
// vector of campaign indexes of removed rows.
Vector<Integer> campaignIndexRemovedRows = new Vector<Integer>();
while ( ((mon!=null)&&(!mon.isStop())) &&(table.getSelectedRowCount()!=0)) {
int numRow = table.getSelectedRow();
campaignIndexRemovedRows.add( getNumCampaign(numRow) );
model.removeRow(numRow);
mon.increment();
}
if (updateTable) {
updateAllAfterRemoving(campaignIndexRemovedRows);
}
}
/**
* Remove the row having the given model index
* @param rowsToRemove
*/
public void removeRow(int rowToRemove) {
model.removeRow(rowToRemove);
}
public void opyoneRow(int row) {
copiedItems = new Vector<Step>();
int numRow = row;
String rowNumber = (String)model.getValueAt(numRow, COLUMN_NBROW);
int numInCampaign = new Integer(rowNumber).intValue()-1;
Step cmdLine = campaign.get(numInCampaign);
copiedItems.add(cmdLine);
}
public void pasteatEnd() {
// int nbSelectedRow = table.getSelectedRowCount();
// int [] selectedRows = table.getSelectedRows();
// int lastRowSelected = selectedRows[nbSelectedRow -1];
// int currentRow = lastRowSelected + 1;
int currentRow =table.getRowCount();
for (Step step : copiedItems) {
Step cmdLine = (Step)step;
Step newCmdLine = (Step)cmdLine.getClone();
newCmdLine.setOutFilePath("");
newCmdLine.setVerdict(Verdict.NONE);
newCmdLine.setUserVerdict(Verdict.NONE);
newCmdLine.setSkippedMessage("");
newCmdLine.setUserComment("");
addRow(newCmdLine, currentRow, true, true);
currentRow++;
}
CoreGUIPlugin.mainFrame.updateButtons();
CoreGUIPlugin.mainFrame.setModified(true);
CoreGUIPlugin.mainFrame.updateContentTabsTitle();
}
public void mixAll() {
//Get Ramdom Size
int rownb =table.getRowCount();
for(int i=0;i<rownb*5;i++)
{
//get random int
Random random = new java.util.Random();
int randomnum=random.nextInt(rownb);
Logger.getLogger(this.getClass() ).debug("random"+randomnum);
random=null;
// selectRows(randomnum,randomnum);
opyoneRow(randomnum);
Vector<Integer> campaignIndexRemovedRows = new Vector<Integer>();
campaignIndexRemovedRows.add( getNumCampaign(randomnum) );
model.removeRow(randomnum);
updateAllAfterRemoving(campaignIndexRemovedRows);
pasteatEnd();
CoreGUIPlugin.mainFrame.updateButtons();
CoreGUIPlugin.mainFrame.setModified(true);
CoreGUIPlugin.mainFrame.updateContentTabsTitle();
}
}
/**
* Update campaign associated with the checklist table and all tool tips
* @param removedRows (campaign indexes)
*/
public abstract void updateAllAfterRemoving(Vector<Integer> campRemovedRows);
/**
* Update the first column of the table.
* @param campRemovedRows list of removed rows (campaign indexes)
*/
protected void updateTableAfterRemoving(Vector<Integer> campRemovedRows) {
int nbRow = table.getRowCount();
for (int i=0; i<nbRow; i++){
int numInFirstColumn = new Integer((String)model.getValueAt(i, COLUMN_NBROW));
int nbRemovedRowLower = calculateNbRemovedRowLower(campRemovedRows, numInFirstColumn);
model.setValueAt(Integer.valueOf(numInFirstColumn - nbRemovedRowLower).toString(), i, COLUMN_NBROW);
}
}
/**
* Calculates the number of removed rows (among the given Vector) with an index lower than the given one.
* @param removedRows list of campaign index of removed rows
* @param numInFirstColumn
* @return
*/
private int calculateNbRemovedRowLower(Vector<Integer> removedRows, int numInFirstColumn) {
int nb = 0;
for(Integer nbInVector : removedRows) {
if (nbInVector<numInFirstColumn) {
nb++;
}
}
return nb;
}
/**
* Remove all campaign elements whose model index is in the 'removedRows' vector.
* @param removedRows
*/
protected void updateCampaign(Vector<Integer> campRemovedRows) {
Iterator<Integer> it = campRemovedRows.iterator();
while (it.hasNext()){
int numToRemove = it.next();
campaign.set(numToRemove, null);
}
Campaign newCampaign = new Campaign();
for (Step step : campaign) {
if (step!= null) newCampaign.add(step);
}
campaign = newCampaign;
}
/**
* Remove all elements whose index is in the 'removedRows' vector.
* @param toModify the vector to update
* @param removedRows the indexes of removed row (in correspondance with the toModify vector)
* @return the updated vector
*/
protected Vector<String> updateVector(Vector<String> toModify, Vector<Integer> removedRows) {
Iterator<Integer> it = removedRows.iterator();
while (it.hasNext()){
int numToRemove = it.next();
toModify.set(numToRemove, null);
}
Vector<String> newVector = new Vector<String>();
for (String s : toModify) {
if (s != null) {
newVector.add(s);
}
}
//toModify = newVector;
return newVector;
}
/**
* Clear the current check-list
*/
public abstract void clear();
public abstract String getValueAt(int numRow);
/**
* Returns the index of step in campaign from its index in the model.
* This is usefull since the table may be ordered differently.
* @param indexRow model index (starting at 0)
* @return campaign index (starting at 0)
*/
public int getNumCampaign(int indexRow) {
//NB: index displayed in table starts at '1'
return new Integer((String)model.getValueAt(indexRow, COLUMN_NBROW)) -1 ;
}
public Vector<Step> getCopiedItems() {
return copiedItems;
}
/**
* Returns a campaign containing all seleceted steps
* @return
*/
public Campaign getSelectedCampaign() {
Campaign selection = new Campaign();
int [] selectedRows = table.getSelectedRows();
for (int i=0; i<selectedRows.length;i++){
int numRow = selectedRows[i];
String rowNumber = (String)model.getValueAt(numRow, COLUMN_NBROW);
int numInCampaign = new Integer(rowNumber).intValue()-1;
Step step = campaign.get(numInCampaign);
selection.add(step);
}
return selection;
}
/**
* Returns the first selected Step, null if no Step is selected
* @return the first selected Step or null
*/
public Step getSelectedStep() {
return campaign.get(table.getSelectedRow());
}
/**
* Returns the index of the first selected row, -1 if no row selected
* @return the index of the first selected row or -1
*/
public int getSelectedRow() {
return table.getSelectedRow();
}
protected Rectangle getRowBounds(int row){
Rectangle result = table.getCellRect(row, -1, true);
Insets i = table.getInsets();
result.x = i.left;
result.width = table.getWidth() - i.left - i.right;
return result;
}
/**
* Gets back model index from capaign index
* @param indexInCampaign campaign index
* @return model index
*/
public int getIndexInTable(int indexInCampaign) {
for (int i=0; i<table.getRowCount(); i++){
//int numCampaignInTable = new Integer((String)model.getValueAt(i, COLUMN_NBROW)).intValue() -1;
if (indexInCampaign == getNumCampaign(i)) {
// if (indexInCampaign == numCampaignInTable) {
return i;
}
}
return -1;
}
public void centerRow(int numCampaign) {
int i=0;
int row = 0;
boolean finish = false;
while (i<table.getRowCount() && !finish){
int numCampaignInTable = new Integer((String)model.getValueAt(i, COLUMN_NBROW)).intValue() -1;
if (numCampaign == numCampaignInTable){
row = i;
finish = true;
}
i++;
}
Scrolling.centerVertically(table, getRowBounds(row), false);
}
/**
* Update the given step.
* @param step step to update.
*/
public abstract void updateStep(Step step);
/**
* Select a row
* @param row index of the row to select
*/
public void selectARow(int row) {
selectRows(row, row);
}
/**
* Select several rows
* @param rowstart start index
* @param rowend end index
*/
public void selectRows(int rowstart, int rowend) {
table.setRowSelectionInterval(rowstart, rowend);
}
protected void sortAllRowsBy(int colIndex, boolean integer) {
Vector data = model.getDataVector();
Collections.sort(data, new ColumnSorter(colIndex, integer));
model.fireTableStructureChanged();
}
private static class ColumnSorter implements Comparator, Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
int colIndex;
boolean integer;
ColumnSorter(int colIndex, boolean integer) {
this.colIndex = colIndex;
this.integer = integer;
}
public int compare(Object a, Object b) {
Vector v1 = (Vector)a;
Vector v2 = (Vector)b;
Object o1 = v1.get(colIndex);
Object o2 = v2.get(colIndex);
// Treat empty strains like nulls
if (o1 instanceof String && ((String)o1).length() == 0) {
o1 = null;
}
if (o2 instanceof String && ((String)o2).length() == 0) {
o2 = null;
}
// Sort nulls so they appear last, regardless
// of sort order
if (o1 == null && o2 == null) {
return 0;
} else if (o1 == null) {
return 1;
} else if (o2 == null) {
return -1;
} else if (o1 instanceof Comparable) {
if (integer){
return ((Comparable<Integer>)new Integer((String)o1)).compareTo(new Integer((String)o2));
}else{
return ((Comparable<Object>)o1).compareTo(o2);
}
} else {
return o1.toString().compareTo(o2.toString());
}
}
}
public static class ColumnHeaderToolTips extends MouseMotionAdapter {
// Current column whose tooltip is being displayed.
// This variable is used to minimize the calls to setToolTipText().
TableColumn curCol;
// Maps TableColumn objects to tooltips
Map<TableColumn,String> tips = new HashMap<TableColumn,String>();
// If tooltip is null, removes any tooltip text.
public void setToolTip(TableColumn col, String tooltip) {
if (tooltip == null) {
tips.remove(col);
} else {
tips.put(col, tooltip);
}
}
public void mouseMoved(MouseEvent evt) {
TableColumn col = null;
JTableHeader header = (JTableHeader)evt.getSource();
JTable table = header.getTable();
TableColumnModel colModel = table.getColumnModel();
int vColIndex = colModel.getColumnIndexAtX(evt.getX());
// Return if not clicked on any column header
if (vColIndex >= 0) {
col = colModel.getColumn(vColIndex);
}
if (col != curCol) {
header.setToolTipText(tips.get(col));
curCol = col;
}
}
}
/**
* Returns the table's model.
* @return the model
*/
public CheckListTableModel getModel() {
return model;
}
public boolean areRowModified(int[] rows) {
boolean modified=false;
int i=0;
while ((!modified)&&(i<rows.length)) {
modified = isRowModified(i);
i++;
}
return modified;
}
public abstract boolean isRowModified(int row);
/**
* Confirm the verdict of selected rows
*/
public void confirmVerdict() {
int [] selectedRows = table.getSelectedRows();
for (int i=0; i<selectedRows.length;i++){
int numRow = selectedRows[i];
String rowNumber = (String)model.getValueAt(numRow, COLUMN_NBROW);
int numInCampaign = new Integer(rowNumber).intValue()-1;
Step cmdLine = campaign.get(numInCampaign);
if (cmdLine.getVerdict() != Verdict.NONE){
cmdLine.setUserVerdict(cmdLine.getVerdict());
model.setValueAt(Step.verdictAsString.get(cmdLine.getVerdict()), numRow, getNumColumnVerdict());
//TODO DB
/*if (CoreGUI.connectedToDB){
try {
CoreGUI.configuration.getArchivingDB().updateJavaVerdict(cmdLine.idBDD, Step.verdicts[cmdLine.verdict], Step.verdicts[cmdLine.userVerdict]);
} catch (Alert e) {
Out.log.println("An error occurs during database update : " + e.getMessage() );
e.printStackTrace(Out.log);
}
}*/
CoreGUIPlugin.mainFrame.setModified(true);
}
}
}
/**
* Give the number of the column which contains verdict
* @return
*/
public abstract int getNumColumnVerdict();
/**
* Modify verdict of selected rows
*/
public void modifyVerdict() {
int [] selectedRows = table.getSelectedRows();
Object [] possibilities = {Step.verdictAsString.get(Verdict.PASSED),
Step.verdictAsString.get(Verdict.FAILED),
Step.verdictAsString.get(Verdict.SKIPPED)};
String s = null;
if (selectedRows.length == 1) {
s = (String)JOptionPane.showInputDialog(CoreGUIPlugin.mainFrame, "New verdict: ", "Modify the verdict",
JOptionPane.PLAIN_MESSAGE,
null,
possibilities,
model.getValueAt(table.getSelectedRow(), getNumColumnVerdict())
);
} else {
s = (String)JOptionPane.showInputDialog(CoreGUIPlugin.mainFrame, "New verdict: ", "Modify the verdict",
JOptionPane.PLAIN_MESSAGE,
null,
possibilities,
Step.verdictAsString.get(Verdict.PASSED)
);
}
for (int i=0; i<selectedRows.length; i++) {
int numRow = selectedRows[i];
String rowNumber = (String)model.getValueAt(numRow, COLUMN_NBROW);
int numInCampaign = new Integer(rowNumber).intValue()-1;
Step step = campaign.get(numInCampaign);
if ((s!=null) && (s.length()>0)) {
if (step.getVerdict() != Verdict.NONE) {
model.setValueAt(s, numRow, getNumColumnVerdict());
if (s.equals(Step.verdictAsString.get(Verdict.PASSED))) {
step.setUserVerdict(Verdict.PASSED);
} else if (s.equals(Step.verdictAsString.get(Verdict.FAILED))) {
step.setUserVerdict(Verdict.FAILED);
} else {
step.setUserVerdict(Verdict.SKIPPED);
}
// TODO DB
/*if (CoreGUI.connectedToDB){
try {
CoreGUI.configuration.getArchivingDB().updateFlashVerdict(step.idBDD, Step.verdicts[step.verdict], Step.verdicts[step.userVerdict]);
} catch (Alert e) {
Out.log.println("An error occurs during database update : " + e.getMessage() );
e.printStackTrace(Out.log);
}
}*/
CoreGUIPlugin.mainFrame.setModified(true);
}
}
}
}
public static Vector<String> readListPhoneConfig() {
File folder = new File(Configuration.getMonitoringConfigDir());
if(!folder.exists()){
if(!folder.mkdir())
Logger.getLogger("CheckListTable").debug("Didn't manage to create the folder");
return null;
}
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".xml");
}
};
String[] listFiles = folder.list(filter);
folder = new File(Configuration.getMonitoringConfigDir());
Logger.getLogger("CheckListTable").debug("defaultPhoneConfigPath="+folder.getAbsolutePath());
String[] defaultFiles = folder.list(filter);
Vector<String> resultFiles = new Vector<String>();
for (int i=0; i<defaultFiles.length; i++)
resultFiles.add(defaultFiles[i]);
if(listFiles != null){
for (int i=0; i<listFiles.length; i++) {
if (!resultFiles.contains(listFiles[i])) resultFiles.add(listFiles[i]);
}
}
Collections.sort(resultFiles,String.CASE_INSENSITIVE_ORDER);
return resultFiles;
}
/**
* Loads external tools definitions and updates popup menu
*/
public abstract void enableUserActions(boolean b);
public abstract boolean isEnableUserActions();
public void updateHopperTestParam() {
// TODO Auto-generated method stub
}
public JComboBox getComboBoxPhoneConfig() {
return comboBoxPhoneConfig;
}
}