package org.rr.jeborker.gui; import static org.rr.commons.utils.BooleanUtils.not; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import org.apache.commons.io.FilenameUtils; import org.rr.commons.collection.TransformValueList; import org.rr.commons.log.LoggerFactory; import org.rr.commons.mufs.IResourceHandler; import org.rr.commons.swing.components.JRScrollPane; import org.rr.commons.swing.components.JRTable; import org.rr.commons.swing.components.container.ShadowPanel; import org.rr.commons.utils.StringUtil; import org.rr.jeborker.db.item.EbookPropertyItem; import org.rr.jeborker.gui.cell.MetadataDownloadTableCellEditor; import org.rr.jeborker.gui.cell.MetadataDownloadTableCellRenderer; import org.rr.jeborker.gui.model.MetadataDownloadModel; import org.rr.jeborker.gui.resources.ImageResourceBundle; import org.rr.jeborker.metadata.IMetadataReader; import org.rr.jeborker.metadata.IMetadataReader.COMMON_METADATA_TYPES; import org.rr.jeborker.metadata.download.MetadataDownloadEntry; import org.rr.jeborker.metadata.download.MetadataDownloadProviderFactory; import org.rr.jeborker.metadata.download.MetadataDownloader; import org.rr.jeborker.metadata.MetadataHandlerFactory; class MetadataDownloadView extends AbstractDialogView { private static final long serialVersionUID = -8695330707780422570L; private static final int ABORT_BUTTON_INDEX = 0; private static final int OK_BUTTON_INDEX = 1; public static final int ACTION_RESULT_OK = 0; private int actionResult = -1; private boolean hasCoverWriterSupport = true; private Map<COMMON_METADATA_TYPES, List<Entry<JCheckBox, String>>> textValues; private byte[] coverImage; private MetadataDownloadController controller; private JPanel bottomPanel; private final ActionListener abortAction = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { controller.close(); } }; private final ActionListener okAction = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetadataDownloadTableCellEditor editor = (MetadataDownloadTableCellEditor) table.stopEdit(); actionResult = ACTION_RESULT_OK; if(editor != null) { textValues = editor.getEditingValues(); if(editor.isCoverImageChecked()) { MetadataDownloadEntry editorMetadataDownloadEntry = editor.getEditorMetadataDownloadEntry(); coverImage = editorMetadataDownloadEntry.getCoverImage(); } } else { textValues = new HashMap<COMMON_METADATA_TYPES, List<Entry<JCheckBox, String>>>(); } controller.close(); } }; private final ActionListener searchAction = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final String selectedItem = (String) searchProviderCombobox.getSelectedItem(); final MetadataDownloader downloader = MetadataDownloadProviderFactory.getDownloader(selectedItem, selectedEbookPropertyItems); final MetadataDownloadModel model = new MetadataDownloadModel(downloader, searchTextField.getText()); final ShadowPanel shadowPanel = new ShadowPanel(); setGlassPane(shadowPanel); new Thread(new Runnable() { @Override public void run() { try { shadowPanel.setVisible(true); model.loadSearchResult(); //new renderer and editor instances for releasing cached resources and avoid get cached values //from the old search. table.setDefaultRenderer(MetadataDownloadEntry.class, new MetadataDownloadTableCellRenderer(hasCoverWriterSupport)); table.setDefaultEditor(MetadataDownloadEntry.class, new MetadataDownloadTableCellEditor(new MetadataDownloadTableCellRenderer(hasCoverWriterSupport))); table.setModel(model); } finally { shadowPanel.setVisible(false); } } }).start(); } }; private final List<EbookPropertyItem> selectedEbookPropertyItems = MainController.getController().getSelectedEbookPropertyItems(); private JRScrollPane scrollPane; private JRTable table; private JPanel searchPanel; private JTextField searchTextField; private JButton searchButton; private JLabel lblSearch; private JComboBox<String> searchProviderCombobox; public MetadataDownloadView(MetadataDownloadController controller, JFrame mainWindow) { super(mainWindow); setModal(true); this.controller = controller; initialize(); } protected void initialize() { super.initialize(); hasCoverWriterSupport = hasCoverWriterSupport(selectedEbookPropertyItems); GridBagLayout gridBagLayout = new GridBagLayout(); gridBagLayout.columnWidths = new int[]{0, 0}; gridBagLayout.rowHeights = new int[]{0, 0, 0, 0}; gridBagLayout.columnWeights = new double[]{1.0, Double.MIN_VALUE}; gridBagLayout.rowWeights = new double[]{0.0, 1.0, 0.0, Double.MIN_VALUE}; getContentPane().setLayout(gridBagLayout); searchPanel = new JPanel(); GridBagConstraints gbc_searchPanel = new GridBagConstraints(); gbc_searchPanel.insets = new Insets(5, 3, 5, 3); gbc_searchPanel.fill = GridBagConstraints.BOTH; gbc_searchPanel.gridx = 0; gbc_searchPanel.gridy = 0; getContentPane().add(searchPanel, gbc_searchPanel); GridBagLayout gbl_searchPanel = new GridBagLayout(); gbl_searchPanel.columnWidths = new int[]{120, 0, 114, 27, 0}; gbl_searchPanel.rowHeights = new int[]{25, 0}; gbl_searchPanel.columnWeights = new double[]{0.0, 0.0, 1.0, 0.0, Double.MIN_VALUE}; gbl_searchPanel.rowWeights = new double[]{0.0, Double.MIN_VALUE}; searchPanel.setLayout(gbl_searchPanel); searchProviderCombobox = new JComboBox<String>(new DefaultComboBoxModel<>(MetadataDownloadProviderFactory.getDownloaderNames().toArray(new String[0]))); GridBagConstraints gbc_comboBox = new GridBagConstraints(); gbc_comboBox.insets = new Insets(0, 0, 0, 5); gbc_comboBox.fill = GridBagConstraints.HORIZONTAL; gbc_comboBox.gridx = 0; gbc_comboBox.gridy = 0; searchPanel.add(searchProviderCombobox, gbc_comboBox); lblSearch = new JLabel(Bundle.getString("MetadataDownloadView.label.search") + ":"); GridBagConstraints gbc_lblSucheingabe = new GridBagConstraints(); gbc_lblSucheingabe.insets = new Insets(0, 3, 0, 5); gbc_lblSucheingabe.anchor = GridBagConstraints.EAST; gbc_lblSucheingabe.gridx = 1; gbc_lblSucheingabe.gridy = 0; searchPanel.add(lblSearch, gbc_lblSucheingabe); searchTextField = new JTextField(); GridBagConstraints gbc_searchTextField = new GridBagConstraints(); gbc_searchTextField.fill = GridBagConstraints.BOTH; gbc_searchTextField.anchor = GridBagConstraints.WEST; gbc_searchTextField.insets = new Insets(0, 0, 0, 5); gbc_searchTextField.gridx = 2; gbc_searchTextField.gridy = 0; searchPanel.add(searchTextField, gbc_searchTextField); searchTextField.setColumns(10); searchTextField.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { searchAction.actionPerformed(null); } } }); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { searchTextField.selectAll(); searchTextField.requestFocus(); } }); if(!selectedEbookPropertyItems.isEmpty()) { String searchPhrase = (StringUtil.toString(selectedEbookPropertyItems.get(0).getAuthor()) + " " + StringUtil.toString(selectedEbookPropertyItems.get(0).getTitle())).trim(); if(StringUtil.isNotEmpty(searchPhrase)) { searchTextField.setText(searchPhrase.trim()); } else { String fileName = FilenameUtils.removeExtension(selectedEbookPropertyItems.get(0).getFileName()); searchTextField.setText(fileName); } } searchButton = new JButton(ImageResourceBundle.getResourceAsImageIcon("play_16.png")); searchButton.setPreferredSize(new Dimension(27, 27)); GridBagConstraints gbc_searchButton = new GridBagConstraints(); gbc_searchButton.anchor = GridBagConstraints.NORTHEAST; gbc_searchButton.gridx = 3; gbc_searchButton.gridy = 0; searchPanel.add(searchButton, gbc_searchButton); searchButton.addActionListener(searchAction); scrollPane = new JRScrollPane(); GridBagConstraints gbc_scrollPane = new GridBagConstraints(); gbc_scrollPane.insets = new Insets(0, 3, 5, 3); gbc_scrollPane.fill = GridBagConstraints.BOTH; gbc_scrollPane.gridx = 0; gbc_scrollPane.gridy = 1; getContentPane().add(scrollPane, gbc_scrollPane); table = new JRTable(); table.setTableHeader(null); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); table.setStopEditOnSelectionChange(true); scrollPane.setViewportView(table); //bottom OK and abort button bottomPanel = createBottomButtonPanel(); GridBagConstraints gbc_panel2 = new GridBagConstraints(); gbc_panel2.insets = new Insets(5, 3, 5, 3); gbc_panel2.fill = GridBagConstraints.BOTH; gbc_panel2.gridx = 0; gbc_panel2.gridy = 2; getContentPane().add(bottomPanel, gbc_panel2); } public int getActionResult() { return this.actionResult; } /** * Test all selected resources for cover writer support. * @param selectedEbookPropertyItems Selected items to be tested. * @return <code>true</code> if all selected items have cover writer support or <code>false</code> if one * or more have not. */ private boolean hasCoverWriterSupport(final List<EbookPropertyItem> selectedEbookPropertyItems) { for(EbookPropertyItem selectedEbookPropertyItem : selectedEbookPropertyItems) { IResourceHandler resourceHandler = selectedEbookPropertyItem.getResourceHandler(); boolean hasCoverWriterSupport = MetadataHandlerFactory.hasCoverWriterSupport(resourceHandler); if(!hasCoverWriterSupport) { return false; } } return true; } /** * Get the downloaded metadata string value for the given type. * @return A list with the downloaded values for the given type. Each list entry * is a {@link Entry} with the checkbox boolean value as <code>key</code> and the * text with the <code>value</code>. */ public List<Entry<Boolean, String>> getValues(IMetadataReader.COMMON_METADATA_TYPES type) { List<Entry<JCheckBox, String>> list = textValues.get(type); if(list != null) { return new TransformValueList<Map.Entry<JCheckBox, String>, Map.Entry<Boolean,String>>(list) { @Override public Map.Entry<Boolean,String> transform(final Map.Entry<JCheckBox, String> source) { return new Map.Entry<Boolean, String>() { @Override public Boolean getKey() { JCheckBox checkbox = source.getKey(); if(checkbox == null || not(checkbox.isSelected())) { return Boolean.FALSE; } return Boolean.TRUE; } @Override public String getValue() { return source.getValue(); } @Override public String setValue(String value) { return null; } }; } }; } return Collections.<Entry<Boolean, String>> emptyList(); } /** * Get the cover image from the downloader. */ public byte[] getCoverImage() { return coverImage; } /** * get the selected index of the search provider combobox. */ int getSearchProviderIndex() { return this.searchProviderCombobox.getSelectedIndex(); } /** * Set the given index to the search provider combobox. */ void setSearchProviderIndex(int index) { try { this.searchProviderCombobox.setSelectedIndex(index); } catch(Exception e) { LoggerFactory.getLogger().log(Level.WARNING, "Failed to set search provider " + index, e); } } @Override protected int getBottomButtonCount() { return 2; } @Override protected ActionListener getBottomButtonAction(int index) { switch(index) { case ABORT_BUTTON_INDEX: return abortAction; case OK_BUTTON_INDEX: return okAction; } return null; } @Override protected String getBottomButtonLabel(int index) { switch(index) { case 0: return Bundle.getString("MetadataDownloadView.Abort"); case 1: return Bundle.getString("MetadataDownloadView.OK"); } return null; } @Override protected Dimension getDefaultDialogSize() { return new Dimension(700, 500); } @Override protected String getDialogTitle() { return Bundle.getString("MetadataDownloadView.title"); } @Override protected Dimension getDialogMinimumSize() { return new Dimension(350, 250); } @Override protected boolean isDefaultButtonAction(int idx) { return idx == OK_BUTTON_INDEX; } @Override protected boolean isAbortAction(int idx) { return idx == ABORT_BUTTON_INDEX; } }