org.datacleaner.windows.DataSetWindow Maven / Gradle / Ivy
/**
* DataCleaner (community edition)
* Copyright (C) 2014 Neopost - Customer Information Management
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.datacleaner.windows;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Image;
import java.util.concurrent.Callable;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.border.MatteBorder;
import javax.swing.table.TableModel;
import org.apache.metamodel.DataContext;
import org.apache.metamodel.data.DataSet;
import org.apache.metamodel.data.DataSetTableModel;
import org.apache.metamodel.query.Query;
import org.datacleaner.bootstrap.WindowContext;
import org.datacleaner.panels.DCPanel;
import org.datacleaner.util.ErrorUtils;
import org.datacleaner.util.IconUtils;
import org.datacleaner.util.ImageManager;
import org.datacleaner.util.WidgetFactory;
import org.datacleaner.util.WidgetUtils;
import org.datacleaner.widgets.LoadingIcon;
import org.datacleaner.widgets.table.DCTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Strings;
/**
* A window that presents a tabular dataset to the end user. The dataset may be
* based on queried data, transformed data, a record sample or other such
* source.
*/
public class DataSetWindow extends AbstractWindow {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(DataSetWindow.class);
private final Query _query;
private final int _pageSize;
private final String _title;
private final Callable _tableModelCallable;
private final DCTable _table;
private final LoadingIcon _loadingIcon = new LoadingIcon();
private JButton _previousPageButton;
private JButton _nextPageButton;
public DataSetWindow(final Query query, final DataContext dataContext, final WindowContext windowContext) {
this(query, dataContext, -1, windowContext);
}
public DataSetWindow(final Query query, final DataContext dataContext, final int pageSize,
final WindowContext windowContext) {
super(windowContext);
_table = new DCTable();
_query = query;
_pageSize = pageSize;
_title = "DataSet: " + _query.toSql();
_tableModelCallable = () -> {
final DataSet dataSet = dataContext.executeQuery(_query);
return new DataSetTableModel(dataSet);
};
_previousPageButton = WidgetFactory.createDefaultButton("Previous page", IconUtils.ACTION_BACK);
_previousPageButton.setEnabled(false);
_nextPageButton = WidgetFactory.createDefaultButton("Next page", IconUtils.ACTION_FORWARD);
_nextPageButton.setHorizontalTextPosition(SwingConstants.LEFT);
_nextPageButton.setEnabled(false);
}
public DataSetWindow(final String title, final Callable tableModelCallable,
final WindowContext windowContext) {
super(windowContext);
_table = new DCTable();
_query = null;
_pageSize = -1;
_title = title;
_tableModelCallable = tableModelCallable;
_previousPageButton = null;
_nextPageButton = null;
}
@Override
public String getWindowTitle() {
return _title;
}
@Override
protected boolean isWindowResizable() {
return true;
}
@Override
public Image getWindowIcon() {
return ImageManager.get().getImage(IconUtils.ACTION_PREVIEW);
}
@Override
protected JComponent getWindowContent() {
updateTable();
_table.setColumnControlVisible(false);
final DCPanel tablePanel = _table.toPanel();
final DCPanel pagingButtonPanel = createPagingButtonPanel();
final DCPanel panel = new DCPanel();
panel.setLayout(new BorderLayout());
_loadingIcon.setPreferredSize(700, 300);
panel.add(_loadingIcon, BorderLayout.NORTH);
panel.add(tablePanel, BorderLayout.CENTER);
if (pagingButtonPanel != null) {
panel.add(pagingButtonPanel, BorderLayout.SOUTH);
}
return panel;
}
private void updateTable() {
_loadingIcon.setVisible(true);
_table.setVisible(false);
if (_query != null) {
if (_pageSize > 0) {
_query.setMaxRows(_pageSize);
}
}
new SwingWorker() {
protected TableModel doInBackground() throws Exception {
final TableModel tableModel = _tableModelCallable.call();
touchTableModel(tableModel);
return tableModel;
}
protected void done() {
try {
final TableModel tableModel = get();
_table.setModel(tableModel);
final int columnCount = _table.getColumnCount();
if (columnCount > 10) {
_table.setHorizontalScrollEnabled(true);
}
updatePagingButtons();
_loadingIcon.setVisible(false);
_table.setVisible(true);
} catch (Throwable e) {
e = ErrorUtils.unwrapForPresentation(e);
logger.error("Unexpected error occurred while building DataSetWindow contents", e);
DataSetWindow.this.dispose();
final String exceptionMessage = e.getMessage();
if (Strings.isNullOrEmpty(exceptionMessage)) {
WidgetUtils.showErrorMessage("Unexpected error",
"An unexpected error occurred while building data set.\n\nSee logs for details.");
} else {
WidgetUtils.showErrorMessage("Unexpected error",
"An unexpected error occurred while building data set:\n" + exceptionMessage
+ "\n\nSee logs for details.");
}
}
}
}.execute();
}
/**
* Touches the table model values in order to ensure that it will be able to
* retrieve values. This is a bit of a silly thing to do, but it ensures
* that errors during {@link TableModel#getValueAt(int, int)} will not
* affect the user at rendering time. If errors occur, we encounter them
* early by invoking this method
*
* @param tableModel
*/
private void touchTableModel(final TableModel tableModel) {
for (int row = 0; row < tableModel.getRowCount(); row++) {
for (int col = 0; col < tableModel.getColumnCount(); col++) {
tableModel.getValueAt(row, col);
}
}
}
private DCPanel createPagingButtonPanel() {
if (_query == null) {
return null;
}
final Integer maxRows = _query.getMaxRows();
if (maxRows == null) {
// no paging needed when there are no max rows property
return null;
}
_previousPageButton.addActionListener(e -> {
int newFirstRow = getFirstRow() - maxRows;
if (newFirstRow <= 0) {
newFirstRow = 1;
}
_query.setFirstRow(newFirstRow);
updateTable();
});
_nextPageButton.addActionListener(e -> {
final int newFirstRow = getFirstRow() + maxRows;
_query.setFirstRow(newFirstRow);
updateTable();
});
final DCPanel buttonPanel = new DCPanel(WidgetUtils.COLOR_DEFAULT_BACKGROUND);
buttonPanel.setBorder(new MatteBorder(1, 0, 0, 0, WidgetUtils.BG_COLOR_LESS_BRIGHT));
buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 4, 10));
buttonPanel.add(_previousPageButton);
buttonPanel.add(_nextPageButton);
return buttonPanel;
}
private void updatePagingButtons() {
if (_nextPageButton != null) {
if (_table.getRowCount() < _query.getMaxRows()) {
_nextPageButton.setEnabled(false);
} else {
_nextPageButton.setEnabled(true);
}
}
if (_previousPageButton != null) {
if (getFirstRow() <= 1) {
_previousPageButton.setEnabled(false);
} else {
_previousPageButton.setEnabled(true);
}
}
}
private int getFirstRow() {
return _query.getFirstRow() == null ? 1 : _query.getFirstRow();
}
@Override
public Dimension getPreferredSize() {
final Dimension preferredSize = super.getPreferredSize();
if (preferredSize.width < 300) {
preferredSize.width = 300;
}
if (preferredSize.height < 200) {
preferredSize.height = 200;
}
return preferredSize;
}
@Override
protected boolean isCentered() {
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy