/*
* Copyright (c) 2013 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.ui.io.config;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.text.MessageFormat;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import com.ibm.icu.text.CharsetDetector;
import com.ibm.icu.text.CharsetMatch;
import de.fhg.igd.slf4jplus.ALogger;
import de.fhg.igd.slf4jplus.ALoggerFactory;
import eu.esdihumboldt.hale.common.core.io.IOProvider;
import eu.esdihumboldt.hale.common.core.io.ImportProvider;
import eu.esdihumboldt.hale.ui.io.IOWizard;
/**
* Configuration page for the character encoding.
*
* @param <W> the concrete I/O wizard type
* @param <P> the {@link IOProvider} type used in the wizard
*
* @author Simon Templer
*/
public class CharsetConfigurationPage<P extends IOProvider, W extends IOWizard<P>> extends
AbstractConfigurationPage<P, W> {
/**
* Configuration pages modes.
*/
public enum Mode {
/**
* User must specify character set manually.
*/
manual,
/**
* User can trigger detection of encoding on the stream through a
* button. Only valid for import providers.
*/
manualAllowDetect,
/**
* Detection of encoding is triggered automatically. Only valid for
* import providers.
*/
autoDetect
}
private static final ALogger log = ALoggerFactory.getLogger(CharsetConfigurationPage.class);
private Combo charsetCombo;
private Button detectButton;
private final Mode mode;
/**
* Default constructor.
*/
public CharsetConfigurationPage() {
this(Mode.manual);
}
/**
* Create a character set configuration page with a specific mode.
*
* @param mode the mode
*/
protected CharsetConfigurationPage(Mode mode) {
super("charset");
this.mode = mode;
setTitle("Character encoding");
setDescription("Select a character encoding.");
}
@Override
public void enable() {
// select I/O provider default charset
IOProvider pro = getWizard().getProvider();
if (pro != null) {
Charset cs = pro.getCharset();
if (cs != null) {
charsetCombo.setText(cs.name());
update();
}
if (detectButton != null) {
detectButton.setEnabled(pro instanceof ImportProvider);
}
}
}
@Override
public void disable() {
// nothing to do
}
@Override
protected void onShowPage(boolean firstShow) {
super.onShowPage(firstShow);
if (firstShow && mode == Mode.autoDetect) {
// try to auto detect encoding
ImportProvider pro = (ImportProvider) getWizard().getProvider();
if (pro.getSource() != null) {
try {
detectCharset(pro.getSource().getInput());
} catch (IOException e) {
log.error("Character encoding detection failed.", e);
}
}
}
}
@Override
public boolean updateConfiguration(IOProvider provider) {
try {
Charset cs = Charset.forName(charsetCombo.getText());
if (cs != null) {
provider.setCharset(cs);
return true;
}
} catch (Exception e) {
// ignore
}
return false;
}
@Override
protected void createContent(Composite page) {
boolean showDetectButton = mode == Mode.manualAllowDetect || mode == Mode.autoDetect;
GridLayoutFactory.swtDefaults().numColumns((showDetectButton) ? (3) : (2)).applyTo(page);
Label clabel = new Label(page, SWT.NONE);
clabel.setText("Charset: ");
charsetCombo = new Combo(page, SWT.NONE);
charsetCombo.setItems(Charset.availableCharsets().keySet()
.toArray(new String[Charset.availableCharsets().size()]));
charsetCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
update();
}
});
charsetCombo.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
update();
}
});
if (showDetectButton) {
detectButton = new Button(page, SWT.NONE);
detectButton.setText("Detect");
detectButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ImportProvider pro = (ImportProvider) getWizard().getProvider();
if (pro.getSource() != null) {
try {
detectCharset(pro.getSource().getInput());
} catch (IOException e1) {
log.userError("Character encoding detection failed.", e1);
}
}
else {
log.userError("Source on import provider not set, cannot detect encoding.");
}
}
});
}
update();
}
/**
* Try to detect the character encoding.
*
* @param input the input stream
* @throws IOException if the resource cannot be read
*/
protected void detectCharset(InputStream input) throws IOException {
// detect character set
CharsetDetector cd = new CharsetDetector();
cd.setText(input);
CharsetMatch cm = cd.detect();
if (cm != null) {
charsetCombo.setText(cm.getName());
update();
setMessage(MessageFormat.format(
"Character encoding {0} detected with {1}% confidence.", cm.getName(),
cm.getConfidence()), INFORMATION);
}
else {
setMessage("Character encoding detection yielded no result.", WARNING);
}
}
/**
* Update the page state.
*/
private void update() {
String name = charsetCombo.getText();
if (name != null && !name.isEmpty()) {
try {
Charset cs = Charset.forName(name);
setMessage(cs.displayName(), INFORMATION);
setPageComplete(true);
return;
} catch (UnsupportedCharsetException e) {
setMessage("Charset not supported", ERROR);
} catch (IllegalCharsetNameException e) {
setMessage("Illegal charset name", ERROR);
}
}
else {
setMessage("Please specify a character encoding", INFORMATION);
}
setPageComplete(false);
}
}