blob: c091bea5c47dd4f24e1ddcd6b70d2e273c36e308 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.lucene.luke.app.desktop.components.dialog.menubar;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Stream;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.luke.app.IndexHandler;
import org.apache.lucene.luke.app.IndexObserver;
import org.apache.lucene.luke.app.LukeState;
import org.apache.lucene.luke.app.desktop.Preferences;
import org.apache.lucene.luke.app.desktop.PreferencesFactory;
import org.apache.lucene.luke.app.desktop.util.DialogOpener;
import org.apache.lucene.luke.app.desktop.util.ImageUtils;
import org.apache.lucene.luke.app.desktop.util.MessageUtils;
import org.apache.lucene.luke.app.desktop.util.StyleConstants;
import org.apache.lucene.luke.models.LukeException;
import org.apache.lucene.luke.models.tools.IndexTools;
import org.apache.lucene.luke.models.tools.IndexToolsFactory;
import org.apache.lucene.luke.models.util.IndexUtils;
import org.apache.lucene.luke.util.LoggerFactory;
import org.apache.lucene.util.NamedThreadFactory;
import org.apache.lucene.util.SuppressForbidden;
/**
* Factory of export terms dialog
*/
public final class ExportTermsDialogFactory implements DialogOpener.DialogFactory {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static ExportTermsDialogFactory instance;
private final IndexToolsFactory indexToolsFactory = new IndexToolsFactory();
private final Preferences prefs;
private final IndexHandler indexHandler;
private final JComboBox<String> fieldCombo = new JComboBox<String>();
private final JComboBox<String> delimiterCombo = new JComboBox<String>();
private final JTextField destDir = new JTextField();
private final JLabel statusLbl = new JLabel();
private final JLabel indicatorLbl = new JLabel();
private final ListenerFunctions listeners = new ListenerFunctions();
private JDialog dialog;
private IndexTools toolsModel;
private String selectedDelimiter;
public synchronized static ExportTermsDialogFactory getInstance() throws IOException {
if (instance == null) {
instance = new ExportTermsDialogFactory();
}
return instance;
}
private ExportTermsDialogFactory() throws IOException {
this.prefs = PreferencesFactory.getInstance();
this.indexHandler = IndexHandler.getInstance();
indexHandler.addObserver(new Observer());
Stream.of(Delimiter.values()).forEachOrdered(delimiterVal -> delimiterCombo.addItem(delimiterVal.getDescription()));
delimiterCombo.setSelectedItem(Delimiter.COMMA.getDescription());//Set default delimiter
}
@Override
public JDialog create(Window owner, String title, int width, int height) {
dialog = new JDialog(owner, title, Dialog.ModalityType.APPLICATION_MODAL);
dialog.add(content());
dialog.setSize(new Dimension(width, height));
dialog.setLocationRelativeTo(owner);
dialog.getContentPane().setBackground(prefs.getColorTheme().getBackgroundColor());
return dialog;
}
private JPanel content() {
JPanel panel = new JPanel(new GridLayout(5, 1));
panel.setOpaque(false);
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
panel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
panel.add(currentOpenIndexPanel());
panel.add(fieldComboPanel());
panel.add(destinationDirPanel());
panel.add(delimiterComboPanel());
panel.add(statusPanel());
panel.add(actionButtonsPanel());
return panel;
}
private JPanel currentOpenIndexPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEADING));
panel.setBorder(BorderFactory.createEmptyBorder());
panel.setOpaque(false);
JLabel label = new JLabel(MessageUtils.getLocalizedMessage("export.terms.label.index_path"));
JLabel value = new JLabel(indexHandler.getState().getIndexPath());
value.setToolTipText(indexHandler.getState().getIndexPath());
panel.add(label);
panel.add(value);
return panel;
}
private JPanel delimiterComboPanel() {
JPanel panel = new JPanel(new GridLayout(2, 1));
panel.setOpaque(false);
panel.add(new JLabel("Select Delimiter: "));
panel.add(delimiterCombo);
return panel;
}
private JPanel fieldComboPanel() {
JPanel panel = new JPanel(new GridLayout(2, 1));
panel.setOpaque(false);
panel.add(new JLabel(MessageUtils.getLocalizedMessage("export.terms.field")));
panel.add(fieldCombo);
return panel;
}
private JPanel destinationDirPanel() {
JPanel panel = new JPanel(new GridLayout(2, 1));
panel.setOpaque(false);
panel.add(new JLabel(MessageUtils.getLocalizedMessage("export.terms.label.output_path")));
JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
inputPanel.setBorder(BorderFactory.createEmptyBorder());
inputPanel.setOpaque(false);
destDir.setText(System.getProperty("user.home"));
destDir.setColumns(60);
destDir.setPreferredSize(new Dimension(200, 30));
destDir.setFont(StyleConstants.FONT_MONOSPACE_LARGE);
destDir.setEditable(false);
destDir.setBackground(Color.white);
inputPanel.add(destDir);
JButton browseBtn = new JButton(MessageUtils.getLocalizedMessage("export.terms.button.browse"));
browseBtn.setFont(StyleConstants.FONT_BUTTON_LARGE);
browseBtn.setMargin(new Insets(3, 0, 3, 0));
browseBtn.addActionListener(listeners::browseDirectory);
inputPanel.add(browseBtn);
panel.add(inputPanel);
return panel;
}
private JPanel actionButtonsPanel() {
// Buttons
JPanel execButtons = new JPanel(new FlowLayout(FlowLayout.TRAILING));
execButtons.setOpaque(false);
JButton exportBtn = new JButton(MessageUtils.getLocalizedMessage("export.terms.button.export"));
exportBtn.setMargin(new Insets(3, 0, 3, 0));
exportBtn.addActionListener(listeners::export);
execButtons.add(exportBtn);
JButton closeBtn = new JButton(MessageUtils.getLocalizedMessage("button.close"));
closeBtn.setMargin(new Insets(3, 0, 3, 0));
closeBtn.addActionListener(e -> dialog.dispose());
execButtons.add(closeBtn);
return execButtons;
}
private JPanel statusPanel() {
JPanel status = new JPanel(new FlowLayout(FlowLayout.LEADING));
status.setOpaque(false);
indicatorLbl.setIcon(ImageUtils.createImageIcon("indicator.gif", 20, 20));
indicatorLbl.setVisible(false);
status.add(statusLbl);
status.add(indicatorLbl);
return status;
}
private class ListenerFunctions {
@SuppressForbidden(reason = "JFilechooser#getSelectedFile() returns java.io.File")
void browseDirectory(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChooser.setFileHidingEnabled(false);
int retVal = fileChooser.showOpenDialog(dialog);
if (retVal == JFileChooser.APPROVE_OPTION) {
File f = fileChooser.getSelectedFile();
destDir.setText(f.getAbsolutePath());
}
}
void export(ActionEvent e) {
ExecutorService executor = Executors.newSingleThreadExecutor(new NamedThreadFactory("export-terms-dialog"));
SwingWorker<Void, Void> task = new SwingWorker<Void, Void>() {
String filename;
@Override
protected Void doInBackground() {
setProgress(0);
statusLbl.setText("Exporting...");
indicatorLbl.setVisible(true);
String field = (String) fieldCombo.getSelectedItem();
selectedDelimiter = Delimiter.getSelectedDelimiterValue((String) delimiterCombo.getSelectedItem());
String directory = destDir.getText();
try {
filename = toolsModel.exportTerms(directory, field, selectedDelimiter);
} catch (LukeException e) {
log.error("Error while exporting terms from field {}", field, e);
statusLbl.setText(MessageUtils.getLocalizedMessage("export.terms.label.error", e.getMessage()));
} catch (Exception e) {
log.error("Error while exporting terms from field {}", field, e);
statusLbl.setText(MessageUtils.getLocalizedMessage("message.error.unknown"));
throw e;
} finally {
setProgress(100);
}
return null;
}
@Override
protected void done() {
indicatorLbl.setVisible(false);
if (filename != null) {
statusLbl.setText(MessageUtils.getLocalizedMessage("export.terms.label.success", filename, "[term]" + selectedDelimiter + "[doc frequency]"));
}
}
};
executor.submit(task);
executor.shutdown();
}
}
private class Observer implements IndexObserver {
@Override
public void openIndex(LukeState state) {
toolsModel = indexToolsFactory.newInstance(state.getIndexReader(), state.useCompound(), state.keepAllCommits());
IndexUtils.getFieldNames(state.getIndexReader()).stream().sorted().forEach(fieldCombo::addItem);
}
@Override
public void closeIndex() {
fieldCombo.removeAllItems();
toolsModel = null;
}
}
/**
* Delimiters that can be selected
*/
private enum Delimiter {
COMMA("Comma", ","), WHITESPACE("Whitespace", " "), TAB("Tab", "\t");
private final String description;
private final String separator;
private Delimiter(final String description, final String separator) {
this.description = description;
this.separator = separator;
}
String getDescription() {
return this.description;
}
String getSeparator() {
return this.separator;
}
static String getSelectedDelimiterValue(String delimiter) {
return Arrays.stream(Delimiter.values())
.filter(e -> e.description.equals(delimiter))
.findFirst()
.orElse(COMMA)
.getSeparator();
}
}
}