/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.platform.dataaccess.datasource.wizard.models;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import org.pentaho.reporting.libraries.base.util.CSVTokenizer;
import org.pentaho.ui.xul.XulEventSourceAdapter;
import org.pentaho.ui.xul.stereotype.Bindable;
public class CsvFileInfo extends XulEventSourceAdapter implements Serializable {
public static final String HEADER_ROWS_ATTRIBUTE = "headerRows"; //$NON-NLS-1$
public static final String ENCLOSURE_ATTRIBUTE = "enclosure"; //$NON-NLS-1$
public static final String DELIMITER_ATTRIBUTE = "delimiter"; //$NON-NLS-1$
public static final String TMP_FILENAME_ATTRIBUTE = "tmpFilename"; //$NON-NLS-1$
public static final String ENCODING = "encoding"; //$NON-NLS-1$
public static final String DEFAULT_COLUMN_NAME_PREFIX = "Field_"; //$NON-NLS-1$
private static final long serialVersionUID = 2498165533158482382L;
private List<String> contents;
private String delimiter = ","; //$NON-NLS-1$
private String enclosure = "\""; //$NON-NLS-1$
private String encoding; //$NON-NLS-1$
private int headerRows = 1;
private String project;
private String tmpFilename;
private String filename;
private String currencySymbol = ""; //$NON-NLS-1$
private String decimalSymbol = "."; //$NON-NLS-1$
private String groupSymbol = ","; //$NON-NLS-1$
private String ifNull = "---"; //$NON-NLS-1$
private String nullStr = ""; //$NON-NLS-1$
public static final String FRIENDLY_FILENAME_ATTRIBUTE = "friendlyFilename"; //$NON-NLS-1$
private String friendlyFilename;
private String savedEncoding;
@Bindable
public String getIfNull() {
return ifNull;
}
@Bindable
public void setIfNull( String ifNull ) {
this.ifNull = ifNull;
}
@Bindable
public String getNullStr() {
return nullStr;
}
@Bindable
public void setNullStr( String nullStr ) {
this.nullStr = nullStr;
}
@Bindable
public List<String> getContents() {
return contents;
}
@Bindable
public void setContents( List<String> contents ) {
this.contents = contents;
}
@Bindable
public String getDelimiter() {
return delimiter;
}
@Bindable
public void setDelimiter( String delimiter ) {
String previousVal = this.delimiter;
this.delimiter = delimiter;
firePropertyChange( DELIMITER_ATTRIBUTE, previousVal, delimiter );
}
@Bindable
public String getEnclosure() {
return enclosure;
}
@Bindable
public void setEnclosure( String enclosure ) {
String previousVal = this.enclosure;
this.enclosure = enclosure;
firePropertyChange( ENCLOSURE_ATTRIBUTE, previousVal, enclosure );
}
@Bindable
public int getHeaderRows() {
return headerRows;
}
@Bindable
public void setHeaderRows( int headerRows ) {
int previousVal = this.headerRows;
this.headerRows = headerRows;
firePropertyChange( HEADER_ROWS_ATTRIBUTE, previousVal, this.headerRows );
}
@Bindable
public String getProject() {
return project;
}
@Bindable
public void setProject( String project ) {
this.project = project;
}
@Bindable
public String getTmpFilename() {
return tmpFilename;
}
@Bindable
public void setTmpFilename( String filename ) {
String previousVal = this.tmpFilename;
this.tmpFilename = filename;
firePropertyChange( TMP_FILENAME_ATTRIBUTE, previousVal, filename );
}
public String getFilename() {
return this.filename;
}
public void setFilename( String file ) {
this.filename = file;
}
@Bindable
public String getCurrencySymbol() {
return currencySymbol;
}
@Bindable
public void setCurrencySymbol( String currencySymbol ) {
this.currencySymbol = currencySymbol;
}
@Bindable
public String getDecimalSymbol() {
return decimalSymbol;
}
@Bindable
public void setDecimalSymbol( String decimalSymbol ) {
this.decimalSymbol = decimalSymbol;
}
@Bindable
public String getGroupSymbol() {
return groupSymbol;
}
@Bindable
public void setGroupSymbol( String groupSymbol ) {
this.groupSymbol = groupSymbol;
}
@Bindable
public String getEncoding() {
return encoding;
}
@Bindable
public void setEncoding( String encoding ) {
String previousVal = this.encoding;
this.encoding = encoding;
firePropertyChange( ENCODING, previousVal, encoding );
}
public void setEncodingFromServer( String encoding ) {
if ( this.savedEncoding != null && !this.savedEncoding.trim().equals( "" ) ) {
setEncoding( this.savedEncoding );
this.savedEncoding = null;
} else {
setEncoding( encoding );
}
}
public void setSavedEncoding( String encoding ) {
this.savedEncoding = encoding;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( currencySymbol == null ) ? 0 : currencySymbol.hashCode() );
result = prime * result + ( ( decimalSymbol == null ) ? 0 : decimalSymbol.hashCode() );
result = prime * result + ( ( delimiter == null ) ? 0 : delimiter.hashCode() );
result = prime * result + ( ( enclosure == null ) ? 0 : enclosure.hashCode() );
result = prime * result + ( ( encoding == null ) ? 0 : encoding.hashCode() );
result = prime * result + ( ( tmpFilename == null ) ? 0 : tmpFilename.hashCode() );
result = prime * result + ( ( groupSymbol == null ) ? 0 : groupSymbol.hashCode() );
result = prime * result + headerRows;
result = prime * result + ( ( ifNull == null ) ? 0 : ifNull.hashCode() );
result = prime * result + ( ( nullStr == null ) ? 0 : nullStr.hashCode() );
result = prime * result + ( ( project == null ) ? 0 : project.hashCode() );
return result;
}
@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
CsvFileInfo other = (CsvFileInfo) obj;
if ( currencySymbol == null ) {
if ( other.currencySymbol != null ) {
return false;
}
} else if ( !currencySymbol.equals( other.currencySymbol ) ) {
return false;
}
if ( decimalSymbol == null ) {
if ( other.decimalSymbol != null ) {
return false;
}
} else if ( !decimalSymbol.equals( other.decimalSymbol ) ) {
return false;
}
if ( delimiter == null ) {
if ( other.delimiter != null ) {
return false;
}
} else if ( !delimiter.equals( other.delimiter ) ) {
return false;
}
if ( enclosure == null ) {
if ( other.enclosure != null ) {
return false;
}
} else if ( !enclosure.equals( other.enclosure ) ) {
return false;
}
if ( encoding == null ) {
if ( other.encoding != null ) {
return false;
}
} else if ( !encoding.equals( other.encoding ) ) {
return false;
}
if ( tmpFilename == null ) {
if ( other.tmpFilename != null ) {
return false;
}
} else if ( !tmpFilename.equals( other.tmpFilename ) ) {
return false;
}
if ( groupSymbol == null ) {
if ( other.groupSymbol != null ) {
return false;
}
} else if ( !groupSymbol.equals( other.groupSymbol ) ) {
return false;
}
if ( headerRows != other.headerRows ) {
return false;
}
if ( ifNull == null ) {
if ( other.ifNull != null ) {
return false;
}
} else if ( !ifNull.equals( other.ifNull ) ) {
return false;
}
if ( nullStr == null ) {
if ( other.nullStr != null ) {
return false;
}
} else if ( !nullStr.equals( other.nullStr ) ) {
return false;
}
if ( project == null ) {
if ( other.project != null ) {
return false;
}
} else if ( !project.equals( other.project ) ) {
return false;
}
return true;
}
public List<List<String>> parseSampleContents() {
String delim = getDelimiter();
if ( contents == null ) {
throw new IllegalStateException( "Sample Contents is null, nothing to parse" ); //$NON-NLS-1$
} else if ( delim == null || "".equals( delim ) ) { //$NON-NLS-1$
// use a random delimiter that will result in an un-parsed list
delim = "~!@#$%";
}
List<List<String>> sample = new ArrayList<List<String>>();
CSVTokenizer csvTokenizer;
String enclosure = null;
if ( !"".equals( getEnclosure() ) ) {
enclosure = getEnclosure();
}
for ( String line : contents ) {
csvTokenizer = new CSVTokenizer( line, delim, enclosure );
List<String> rowData = new ArrayList<String>();
while ( csvTokenizer.hasMoreTokens() ) {
// get next token and store it in the list
rowData.add( csvTokenizer.nextToken() );
}
sample.add( rowData );
}
return sample;
}
public String formatSampleContents() {
StringBuilder sb = new StringBuilder();
String padding = " ";
List<List<String>> parsed;
try {
parsed = parseSampleContents();
} catch ( IllegalStateException e ) {
// nothing to parse, formatted value is "nothing"
return "";
}
int maxColumns = getMaxColumnCount( parsed );
// create a dummy row for the header
if ( getHeaderRows() == 0 ) {
List<String> dummy = getDummyHeader( maxColumns );
parsed.add( 0, dummy );
}
int[] widths = getMaxWidths( parsed, maxColumns );
int lineNumber = 0;
StringBuilder headerMarker = new StringBuilder();
int lineWidth = 0;
// find out how big the entire line will be, including the padding between fields
for ( int w = 0; w < widths.length; w++ ) {
lineWidth += widths[ w ] + padding.length();
}
// create a string that will separate the header from the body of text
for ( int x = 0; x < lineWidth; x++ ) {
headerMarker.append( "-" );
}
// format each field, padding as required
for ( List<String> line : parsed ) {
for ( int i = 0; i < line.size(); i++ ) {
String field = line.get( i );
sb.append( padField( field, widths[ i ] ) );
sb.append( padding );
}
sb.append( "\n" );
if ( lineNumber == 0 ) {
sb.append( headerMarker.toString() );
sb.append( "\n" );
}
lineNumber++;
}
return sb.toString();
}
private List<String> getDummyHeader( int maxColumns ) {
List<String> dummy = new ArrayList<String>( maxColumns );
DecimalFormat df = new DecimalFormat( "000" );
for ( int i = 0; i < maxColumns; i++ ) {
dummy.add( DEFAULT_COLUMN_NAME_PREFIX + df.format( i + 1 ) );
}
return dummy;
}
/**
* It would be nice just to use String.format here, but it is not available in GWT.
*
* @param field
* @param totalWidth
* @return
*/
private String padField( String field, int totalWidth ) {
StringBuilder sb = new StringBuilder( field );
if ( field.length() < totalWidth ) {
for ( int i = field.length(); i < totalWidth; i++ ) {
sb.append( " " );
}
}
return sb.toString();
}
private int[] getMaxWidths( List<List<String>> parsedContents, int columns ) {
if ( parsedContents != null && parsedContents.size() > 0 ) {
int[] widths = new int[ columns ];
for ( List<String> lines : parsedContents ) {
for ( int i = 0; i < lines.size(); i++ ) {
String field = lines.get( i );
widths[ i ] = field.length() > widths[ i ] ? field.length() : widths[ i ];
}
}
return widths;
}
return null;
}
private int getMaxColumnCount( List<List<String>> parsedContents ) {
int max = 0;
for ( List<String> line : parsedContents ) {
max = line.size() > max ? line.size() : max;
}
return max;
}
@Bindable
public String getFriendlyFilename() {
return friendlyFilename;
}
@Bindable
public void setFriendlyFilename( String friendlyFilename ) {
String previousVal = this.friendlyFilename;
this.friendlyFilename = friendlyFilename;
firePropertyChange( FRIENDLY_FILENAME_ATTRIBUTE, previousVal, friendlyFilename );
}
public void clear() {
setDelimiter( "," );
setContents( null );
setCurrencySymbol( "" );
setEnclosure( "\"" );
setEncoding( "" );
setTmpFilename( null );
setFilename( null );
setFriendlyFilename( null );
setGroupSymbol( "," );
setCurrencySymbol( "" );
setDecimalSymbol( "." );
setHeaderRows( 1 );
setIfNull( "---" );
setNullStr( "" );
setProject( null );
formatSampleContents();
}
}