com.dua3.meja.excelviewer.SwingExcelViewer Maven / Gradle / Ivy
/*
* Copyright 2015 Axel Howind.
*
* 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.
*/
package com.dua3.meja.excelviewer;
import com.dua3.cabe.annotations.Nullable;
import com.dua3.meja.excelviewer.ExcelViewerModel.ExcelViewer;
import com.dua3.meja.model.Sheet;
import com.dua3.meja.model.Workbook;
import com.dua3.meja.ui.swing.MejaSwingHelper;
import com.dua3.meja.ui.swing.SwingSheetView;
import com.dua3.meja.ui.swing.SwingWorkbookView;
import com.dua3.meja.util.MejaHelper;
import com.dua3.utility.swing.SwingUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;
import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Optional;
/**
* A sample Swing application that uses the Meja library to load and display
* Excel sheets or CSv data.
*
* @author axel
*/
@SuppressWarnings("serial")
public class SwingExcelViewer extends JFrame implements ExcelViewer, DropTargetListener {
private static final Logger LOG = LogManager.getLogger(SwingExcelViewer.class);
private static final int STATUS_ERROR = 1;
public static final String PROPERTY_FILE_CHANGED = "file changed";
/**
* The application name to show in title bar.
*/
public static final String APPLICATION_NAME = "Meja ExcelViewer";
public static final String AUTHOR = "Axel Howind";
public static final int YEAR = 2015;
/**
* Main method.
*
* @param args the command line arguments
*/
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public static void main(String[] args) {
SwingUtil.setNativeLookAndFeel(APPLICATION_NAME);
SwingUtilities.invokeLater(() -> {
ExcelViewerModel model = new ExcelViewerModel<>(APPLICATION_NAME, YEAR, AUTHOR);
SwingExcelViewer viewer = new SwingExcelViewer(model);
if (args.length > 1) {
System.out.println(model.getInfo());
System.exit(STATUS_ERROR);
}
File file = args.length == 1 ? new File(args[0]) : null;
viewer.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
viewer.setSize(600, 400);
viewer.setVisible(true);
if (file != null) {
try {
viewer.setWorkbook(MejaHelper.openWorkbook(file.toURI()));
} catch (IOException ex) {
LOG.error("could not load workbook from {}", file.getAbsolutePath(), ex);
}
}
});
}
private final ExcelViewerModel model;
private SwingWorkbookView workbookView;
/**
* Constructor.
*
* @param model the model
*/
public SwingExcelViewer(ExcelViewerModel model) {
super(APPLICATION_NAME);
this.model = model;
createMenu();
createContent();
pack();
setDropTarget(new DropTarget(this, this));
}
/**
* Close the application window.
*/
protected void closeApplication() {
LOG.info("closing");
dispose();
}
private void createContent() {
setLayout(new BorderLayout());
SwingWorkbookView view = new SwingWorkbookView();
add(view, BorderLayout.CENTER);
this.workbookView = view;
}
/**
* Creates the application menu bar.
*/
private void createMenu() {
JMenuBar menuBar = new JMenuBar();
// File menu
JMenu mnFile = new JMenu("File");
mnFile.add(SwingUtil.createAction("Open...", this::showOpenDialog));
mnFile.add(new AbstractAction("Save") {
{
// enable when workbook is loaded
PropertyChangeListener listener = (PropertyChangeEvent evt) -> {
if (PROPERTY_FILE_CHANGED.equals(evt.getPropertyName())) {
setEnabled(evt.getNewValue() != null);
}
};
SwingExcelViewer.this.addPropertyChangeListener(PROPERTY_FILE_CHANGED, listener);
}
@Override
public void actionPerformed(ActionEvent e) {
saveWorkbook();
}
});
mnFile.add(SwingUtil.createAction("Save as...", this::showSaveAsDialog));
mnFile.addSeparator();
mnFile.add(SwingUtil.createAction("Exit", this::closeApplication));
menuBar.add(mnFile);
// Edit menu
JMenu mnEdit = new JMenu("Edit");
mnEdit.add(SwingUtil.createAction("Adjust all column widths", e -> getCurrentView().ifPresent(model::adjustColumns)));
menuBar.add(mnEdit);
// Options menu
JMenu mnOptions = new JMenu("Options");
JMenu mnLookAndFeel = new JMenu("Look & Feel");
mnLookAndFeel.add(SwingUtil.createAction("System Default",
e -> setLookAndFeel(UIManager.getSystemLookAndFeelClassName())));
mnLookAndFeel.add(SwingUtil.createAction("Cross Platform",
e -> setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName())));
mnLookAndFeel.addSeparator();
for (final LookAndFeelInfo lAF : UIManager.getInstalledLookAndFeels()) {
mnLookAndFeel.add(SwingUtil.createAction(lAF.getName(), e -> setLookAndFeel(lAF.getClassName())));
}
mnOptions.add(mnLookAndFeel);
JMenu mnZoom = new JMenu("Zoom");
for (final int zoom : new int[]{25, 50, 75, 100, 125, 150, 200, 400}) {
mnZoom.add(SwingUtil.createAction(zoom + "%", e -> setZoom(zoom / 100.0f)));
}
mnOptions.add(mnZoom);
mnOptions.addSeparator();
mnOptions.add(SwingUtil.createAction("Freeze", e -> getCurrentView().ifPresent(model::freezeAtCurrentCell)));
menuBar.add(mnOptions);
// Help menu
JMenu mnHelp = new JMenu("Help");
mnHelp.add(SwingUtil.createAction("About ...", e -> {
String title = "About " + APPLICATION_NAME;
String msg = model.getLicenseText();
JOptionPane.showMessageDialog(this, msg, title, JOptionPane.INFORMATION_MESSAGE, null);
setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}));
menuBar.add(mnHelp);
setJMenuBar(menuBar);
}
@Override
public Optional getCurrentView() {
return workbookView.getCurrentView();
}
@Override
public Optional getViewForSheet(Sheet sheet) {
return workbookView.getViewForSheet(sheet);
}
private void saveWorkbook() {
Workbook workbook = model.getWorkbook();
if (workbook == null) {
return;
}
Optional uri = workbook.getUri();
try {
if (uri.isEmpty()) {
final Optional newUri = MejaSwingHelper.showDialogAndSaveWorkbook(this, workbook,
model.getCurrentUri());
if (newUri.isEmpty()) {
// user cancelled the dialog
LOG.debug("save-dialog was cancelled");
return;
}
workbookChanged(null /* old path was not set */, newUri.get());
} else {
model.saveWorkbook(uri.get());
}
} catch (IOException ex) {
LOG.error("exception saving workbook", ex);
JOptionPane.showMessageDialog(this, "IO-Error saving workbook.", "Workbook could not be saved.",
JOptionPane.ERROR_MESSAGE);
}
}
@Override
public void setEditable(boolean editable) {
workbookView.setEditable(editable);
}
private void setLookAndFeel(String lookAndFeelClassName) {
try {
UIManager.setLookAndFeel(lookAndFeelClassName);
} catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException
| IllegalAccessException ex) {
LOG.error("could not set look&feel", ex);
}
SwingUtilities.updateComponentTreeUI(this);
}
private void setZoom(float f) {
model.setZoom(f);
}
/**
* Show the Open dialog.
*/
private void showOpenDialog() {
try {
final Optional newWorkbook = MejaSwingHelper.showDialogAndOpenWorkbook(this,
model.getCurrentUri());
newWorkbook.ifPresent(this::setWorkbook);
} catch (IOException ex) {
LOG.error("exception loading workbook", ex);
JOptionPane.showMessageDialog(this, "Error loading workbook: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
} catch (Exception ex) {
LOG.error("unknown Exception caught, will be rethrown after message dialog: {}",
ex.getMessage());
JOptionPane.showMessageDialog(this, "Error loading workbook: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
throw ex; // rethrow
}
}
private void setWorkbook(final Workbook newWorkbook) {
final Optional oldPath = model.getUri();
model.setWorkbook(newWorkbook);
final Optional newPath = model.getUri();
workbookChanged(oldPath.orElse(null), newPath.orElse(null));
}
/**
* Show the "Save as" dialog.
*/
private void showSaveAsDialog() {
try {
Workbook workbook = model.getWorkbook();
final Optional uri = MejaSwingHelper.showDialogAndSaveWorkbook(this, workbook,
model.getCurrentUri());
uri.ifPresent(value -> {
workbook.setUri(value);
updateUri(value);
LOG.info("saved workbook to {}", value);
});
} catch (IOException ex) {
LOG.error("exception saving workbook", ex);
JOptionPane.showMessageDialog(this, "Error saving workbook: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
} catch (Exception ex) {
LOG.error("unknown exception caught, will be rethrown after message dialog: {}", ex.getMessage());
JOptionPane.showMessageDialog(this, "Error loading workbook: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
throw ex; // rethrow
}
}
private void updateUri(@Nullable URI path) {
if (path != null) {
setTitle(APPLICATION_NAME + " - " + path);
model.setUri(path);
} else {
setTitle(APPLICATION_NAME);
}
}
@Override
public void workbookChanged(@Nullable URI oldUri, @Nullable URI newUri) {
firePropertyChange(PROPERTY_FILE_CHANGED, oldUri, newUri);
workbookView.setWorkbook(model.getWorkbook());
updateUri(newUri);
}
@Override
public void dragEnter(DropTargetDragEvent dtde) {
// nop
}
@Override
public void dragOver(DropTargetDragEvent dtde) {
// nop
}
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {
// nop
}
@Override
public void dragExit(DropTargetEvent dte) {
// nop
}
@Override
public void drop(DropTargetDropEvent dtde) {
try {
Transferable tr = dtde.getTransferable();
if (tr.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
@SuppressWarnings("unchecked")
List files = (List) tr.getTransferData(DataFlavor.javaFileListFlavor);
if (files.size() == 1) {
URI uri = files.get(0).toURI();
Optional workbook = MejaSwingHelper.openWorkbook(this, uri);
if (workbook.isPresent()) {
setWorkbook(workbook.get());
dtde.getDropTargetContext().dropComplete(true);
} else {
LOG.warn("could not process dropped item '{}'", uri);
dtde.getDropTargetContext().dropComplete(false);
}
}
} else {
LOG.warn("DataFlavor.javaFileListFlavor is not supported, drop rejected");
dtde.rejectDrop();
}
} catch (Exception ex) {
LOG.warn("exception processing dropped item, drop rejected", ex);
dtde.rejectDrop();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy