blob: 03c6262af7ccbdc541c0c350ffc3a03d31a94270 [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.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import java.awt.BorderLayout;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.luke.app.IndexHandler;
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.FontUtils;
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.app.desktop.util.URLLabel;
import org.apache.lucene.luke.models.tools.IndexTools;
import org.apache.lucene.luke.models.tools.IndexToolsFactory;
import org.apache.lucene.luke.util.LoggerFactory;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.NamedThreadFactory;
import org.apache.lucene.util.SuppressForbidden;
/** Factory of create index dialog */
public class CreateIndexDialogFactory implements DialogOpener.DialogFactory {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static CreateIndexDialogFactory instance;
private final Preferences prefs;
private final IndexHandler indexHandler;
private final JTextField locationTF = new JTextField();
private final JButton browseBtn = new JButton();
private final JTextField dirnameTF = new JTextField();
private final JTextField dataDirTF = new JTextField();
private final JButton dataBrowseBtn = new JButton();
private final JButton clearBtn = new JButton();
private final JLabel indicatorLbl = new JLabel();
private final JButton createBtn = new JButton();
private final JButton cancelBtn = new JButton();
private final ListenerFunctions listeners = new ListenerFunctions();
private JDialog dialog;
public synchronized static CreateIndexDialogFactory getInstance() throws IOException {
if (instance == null) {
instance = new CreateIndexDialogFactory();
}
return instance;
}
private CreateIndexDialogFactory() throws IOException {
this.prefs = PreferencesFactory.getInstance();
this.indexHandler = IndexHandler.getInstance();
initialize();
}
private void initialize() {
locationTF.setPreferredSize(new Dimension(360, 30));
locationTF.setText(System.getProperty("user.home"));
locationTF.setEditable(false);
browseBtn.setText(FontUtils.elegantIconHtml("n", MessageUtils.getLocalizedMessage("button.browse")));
browseBtn.setFont(StyleConstants.FONT_BUTTON_LARGE);
browseBtn.setPreferredSize(new Dimension(120, 30));
browseBtn.addActionListener(listeners::browseLocationDirectory);
dirnameTF.setPreferredSize(new Dimension(200, 30));
dataDirTF.setPreferredSize(new Dimension(250, 30));
dataDirTF.setEditable(false);
clearBtn.setText(MessageUtils.getLocalizedMessage("button.clear"));
clearBtn.setPreferredSize(new Dimension(70, 30));
clearBtn.addActionListener(listeners::clearDataDir);
dataBrowseBtn.setText(FontUtils.elegantIconHtml("n", MessageUtils.getLocalizedMessage("button.browse")));
dataBrowseBtn.setFont(StyleConstants.FONT_BUTTON_LARGE);
dataBrowseBtn.setPreferredSize(new Dimension(100, 30));
dataBrowseBtn.addActionListener(listeners::browseDataDirectory);
indicatorLbl.setIcon(ImageUtils.createImageIcon("indicator.gif", 20, 20));
indicatorLbl.setVisible(false);
createBtn.setText(MessageUtils.getLocalizedMessage("button.create"));
createBtn.addActionListener(listeners::createIndex);
cancelBtn.setText(MessageUtils.getLocalizedMessage("button.cancel"));
cancelBtn.addActionListener(e -> dialog.dispose());
}
@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();
panel.setOpaque(false);
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.add(basicSettings());
panel.add(new JSeparator(JSeparator.HORIZONTAL));
panel.add(optionalSettings());
panel.add(new JSeparator(JSeparator.HORIZONTAL));
panel.add(buttons());
return panel;
}
private JPanel basicSettings() {
JPanel panel = new JPanel(new GridLayout(2, 1));
panel.setOpaque(false);
JPanel locPath = new JPanel(new FlowLayout(FlowLayout.LEADING));
locPath.setOpaque(false);
locPath.add(new JLabel(MessageUtils.getLocalizedMessage("createindex.label.location")));
locPath.add(locationTF);
locPath.add(browseBtn);
panel.add(locPath);
JPanel dirName = new JPanel(new FlowLayout(FlowLayout.LEADING));
dirName.setOpaque(false);
dirName.add(new JLabel(MessageUtils.getLocalizedMessage("createindex.label.dirname")));
dirName.add(dirnameTF);
panel.add(dirName);
return panel;
}
private JPanel optionalSettings() {
JPanel panel = new JPanel(new BorderLayout());
panel.setOpaque(false);
JPanel description = new JPanel();
description.setLayout(new BoxLayout(description, BoxLayout.Y_AXIS));
description.setOpaque(false);
JPanel name = new JPanel(new FlowLayout(FlowLayout.LEADING));
name.setOpaque(false);
JLabel nameLbl = new JLabel(MessageUtils.getLocalizedMessage("createindex.label.option"));
name.add(nameLbl);
description.add(name);
JTextArea descTA1 = new JTextArea(MessageUtils.getLocalizedMessage("createindex.textarea.data_help1"));
descTA1.setPreferredSize(new Dimension(550, 20));
descTA1.setBorder(BorderFactory.createEmptyBorder(2, 10, 10, 5));
descTA1.setOpaque(false);
descTA1.setLineWrap(true);
descTA1.setEditable(false);
description.add(descTA1);
JPanel link = new JPanel(new FlowLayout(FlowLayout.LEADING, 10, 1));
link.setOpaque(false);
JLabel linkLbl = FontUtils.toLinkText(new URLLabel(MessageUtils.getLocalizedMessage("createindex.label.data_link")));
link.add(linkLbl);
description.add(link);
JTextArea descTA2 = new JTextArea(MessageUtils.getLocalizedMessage("createindex.textarea.data_help2"));
descTA2.setPreferredSize(new Dimension(550, 50));
descTA2.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 5));
descTA2.setOpaque(false);
descTA2.setLineWrap(true);
descTA2.setEditable(false);
description.add(descTA2);
panel.add(description, BorderLayout.PAGE_START);
JPanel dataDirPath = new JPanel(new FlowLayout(FlowLayout.LEADING));
dataDirPath.setOpaque(false);
dataDirPath.add(new JLabel(MessageUtils.getLocalizedMessage("createindex.label.datadir")));
dataDirPath.add(dataDirTF);
dataDirPath.add(dataBrowseBtn);
dataDirPath.add(clearBtn);
panel.add(dataDirPath, BorderLayout.CENTER);
return panel;
}
private JPanel buttons() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
panel.setOpaque(false);
panel.setBorder(BorderFactory.createEmptyBorder(3, 3, 10, 20));
panel.add(indicatorLbl);
panel.add(createBtn);
panel.add(cancelBtn);
return panel;
}
private class ListenerFunctions {
void browseLocationDirectory(ActionEvent e) {
browseDirectory(locationTF);
}
void browseDataDirectory(ActionEvent e) {
browseDirectory(dataDirTF);
}
@SuppressForbidden(reason = "JFilechooser#getSelectedFile() returns java.io.File")
private void browseDirectory(JTextField tf) {
JFileChooser fc = new JFileChooser(new File(tf.getText()));
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fc.setFileHidingEnabled(false);
int retVal = fc.showOpenDialog(dialog);
if (retVal == JFileChooser.APPROVE_OPTION) {
File dir = fc.getSelectedFile();
tf.setText(dir.getAbsolutePath());
}
}
void createIndex(ActionEvent e) {
Path path = Paths.get(locationTF.getText(), dirnameTF.getText());
if (Files.exists(path)) {
String message = "The directory " + path.toAbsolutePath().toString() + " already exists.";
JOptionPane.showMessageDialog(dialog, message, "Empty index path", JOptionPane.ERROR_MESSAGE);
} else {
// create new index asynchronously
ExecutorService executor = Executors.newFixedThreadPool(1, new NamedThreadFactory("create-index-dialog"));
SwingWorker<Void, Void> task = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
setProgress(0);
indicatorLbl.setVisible(true);
createBtn.setEnabled(false);
try {
Directory dir = FSDirectory.open(path);
IndexTools toolsModel = new IndexToolsFactory().newInstance(dir);
if (dataDirTF.getText().isEmpty()) {
// without sample documents
toolsModel.createNewIndex();
} else {
// with sample documents
Path dataPath = Paths.get(dataDirTF.getText());
toolsModel.createNewIndex(dataPath.toAbsolutePath().toString());
}
indexHandler.open(path.toAbsolutePath().toString(), null, false, false, false);
prefs.addHistory(path.toAbsolutePath().toString());
dirnameTF.setText("");
closeDialog();
} catch (Exception ex) {
// cleanup
try {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
});
Files.deleteIfExists(path);
} catch (IOException ex2) {
}
log.error("Cannot create index", ex);
String message = "See Logs tab or log file for more details.";
JOptionPane.showMessageDialog(dialog, message, "Cannot create index", JOptionPane.ERROR_MESSAGE);
} finally {
setProgress(100);
}
return null;
}
@Override
protected void done() {
indicatorLbl.setVisible(false);
createBtn.setEnabled(true);
}
};
executor.submit(task);
executor.shutdown();
}
}
private void clearDataDir(ActionEvent e) {
dataDirTF.setText("");
}
private void closeDialog() {
dialog.dispose();
}
}
}