package org.rr.jeborker.gui;
import static org.apache.commons.lang.ObjectUtils.notEqual;
import static org.rr.commons.utils.StringUtil.EMPTY;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URI;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.DefaultListSelectionModel;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.tree.TreePath;
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.AbstractLayerUI;
import org.rr.commons.collection.FilterList;
import org.rr.commons.collection.FilterList.Filter;
import org.rr.commons.log.LoggerFactory;
import org.rr.commons.mufs.IResourceHandler;
import org.rr.commons.mufs.ResourceHandlerFactory;
import org.rr.commons.mufs.VirtualStaticResourceDataLoader;
import org.rr.commons.swing.SwingUtils;
import org.rr.commons.swing.components.JRScrollPane;
import org.rr.commons.swing.components.JRTable;
import org.rr.commons.swing.components.button.JMenuButton;
import org.rr.commons.swing.components.container.ShadowPanel;
import org.rr.commons.swing.components.tree.JRTree;
import org.rr.commons.swing.components.tree.TreeUtil;
import org.rr.commons.swing.components.util.EnablePropertyChangeHighlighterSupport;
import org.rr.commons.swing.dnd.DragAndDropUtils;
import org.rr.commons.swing.dnd.FileTransferable;
import org.rr.commons.swing.image.SimpleImageViewer;
import org.rr.commons.swing.layout.EqualsLayout;
import org.rr.commons.utils.CommonUtils;
import org.rr.commons.utils.ReflectionUtils;
import org.rr.commons.utils.StringUtil;
import org.rr.jeborker.Jeboorker;
import org.rr.jeborker.app.preferences.APreferenceStore;
import org.rr.jeborker.app.preferences.JeboorkerPreferenceListener;
import org.rr.jeborker.app.preferences.PreferenceStoreFactory;
import org.rr.jeborker.db.item.EbookPropertyItem;
import org.rr.jeborker.db.item.EbookPropertyItemUtils;
import org.rr.jeborker.event.ApplicationEvent;
import org.rr.jeborker.event.EventManager;
import org.rr.jeborker.gui.action.ActionFactory;
import org.rr.jeborker.gui.action.ActionUtils;
import org.rr.jeborker.gui.action.PasteFromClipboardAction;
import org.rr.jeborker.gui.cell.BasePathTreeCellEditor;
import org.rr.jeborker.gui.cell.BasePathTreeCellRenderer;
import org.rr.jeborker.gui.cell.DatePropertyCellEditor;
import org.rr.jeborker.gui.cell.DatePropertyCellRenderer;
import org.rr.jeborker.gui.cell.DefaultPropertyCellEditor;
import org.rr.jeborker.gui.cell.DefaultPropertyRenderer;
import org.rr.jeborker.gui.cell.EbookTableCellEditor;
import org.rr.jeborker.gui.cell.EbookTableCellRenderer;
import org.rr.jeborker.gui.cell.FileSystemTreeCellEditor;
import org.rr.jeborker.gui.cell.FileSystemTreeCellRenderer;
import org.rr.jeborker.gui.cell.MultiListPropertyEditor;
import org.rr.jeborker.gui.cell.MultiListPropertyRenderer;
import org.rr.jeborker.gui.cell.StarRatingPropertyEditor;
import org.rr.jeborker.gui.cell.StarRatingPropertyRenderer;
import org.rr.jeborker.gui.model.BasePathTreeModel;
import org.rr.jeborker.gui.model.EbookPropertyDBTableModel;
import org.rr.jeborker.gui.model.EbookSheetPropertyModel;
import org.rr.jeborker.gui.model.EbookSheetPropertyMultiSelectionModel;
import org.rr.jeborker.gui.model.EmptyListModel;
import org.rr.jeborker.gui.model.FileSystemNode;
import org.rr.jeborker.gui.model.FileSystemTreeModel;
import org.rr.jeborker.gui.model.MetadataAddListModel;
import org.rr.jeborker.gui.resources.ImageResourceBundle;
import org.rr.jeborker.metadata.IMetadataReader;
import org.rr.jeborker.metadata.MetadataProperty;
import com.j256.ormlite.stmt.Where;
import com.l2fprod.common.propertysheet.Property;
import com.l2fprod.common.propertysheet.PropertyEditorRegistry;
import com.l2fprod.common.propertysheet.PropertyRendererRegistry;
import com.l2fprod.common.propertysheet.PropertySheet;
import com.l2fprod.common.propertysheet.PropertySheetPanel;
import com.l2fprod.common.propertysheet.PropertySheetTableModel;
import com.l2fprod.common.propertysheet.PropertySheetTableModel.Item;
import net.miginfocom.swing.MigLayout;
import skt.swing.StringConvertor;
class MainView extends JFrame {
private static final long serialVersionUID = 6837919427429399376L;
private class MainViewPreferenceListener extends JeboorkerPreferenceListener {
@Override
public void treeAutoScrollingChanged(boolean value) {
Component[] allComponents = SwingUtils.getAllComponents(JRTree.class, MainView.this.getRootPane());
for(Component c : allComponents) {
((JRTree)c).setAutoMoveHorizontalSliders(value);
}
}
}
/**
* ListSelectionListener which is invoked by changing the selection in the main table. It saves and sets the metadata properties of
* the {@link PropertySheet}.
*/
private class PropertySheetListSelectionListener implements ListSelectionListener {
@Override
public void valueChanged(ListSelectionEvent e) {
if(!e.getValueIsAdjusting()) {
Property selectedMetadataProperty = getSelectedMetadataProperty();
refreshSheetProperties();
setSelectedMetadataProperty(selectedMetadataProperty);
}
}
}
/**
* Mouse listener which handles the right click / popup menu on the main table.
*/
private class MainTablePopupMouseListener extends MouseAdapter {
public void mouseReleased(MouseEvent event) {
if (event.getButton() == MouseEvent.BUTTON3) {
final int rowAtPoint = mainTable.rowAtPoint(event.getPoint());
//set selection for the right click
if(mainTable.getSelectedRowCount() <= 1 ) {
mainTable.getSelectionModel().setSelectionInterval(rowAtPoint, rowAtPoint);
}
showMainTablePopupMenu(event.getPoint(), mainTable);
}
}
}
/**
* Mouse listener which handles the right click / popup menu on the main table.
*/
private class FileSystemTreePopupMouseListener extends MouseAdapter {
public void mouseReleased(MouseEvent event) {
if (event.getButton() == MouseEvent.BUTTON3) {
final TreePath rowAtPoint = fileSystemTree.getPathForLocation(event.getX(), event.getY());
//set selection for the right click
if(fileSystemTree.getSelectionCount() <= 1 ) {
fileSystemTree.setSelectionPath(rowAtPoint);
}
showFileSystemTreePopupMenu(event.getPoint(), fileSystemTree);
}
}
}
/**
* Mouse listener which handles the right click / popup menu on the main table.
*/
private class CoverPopupMouseListener extends MouseAdapter {
public void mouseReleased(MouseEvent event) {
if (event.getButton() == MouseEvent.BUTTON3) {
showCoverPopupMenu(event.getPoint(), imageViewer);
}
}
}
/**
* Mouse listener which handles the right click / popup menu on the main table.
*/
private class BasePathTreePopupMouseListener extends MouseAdapter {
public void mouseReleased(MouseEvent event) {
if (event.getButton() == MouseEvent.BUTTON3) {
Point location = event.getPoint();
int row = basePathTree.getRowForLocation((int)location.getX(), (int)location.getY());
if(row >= 0) {
basePathTree.setSelectionRow(row);
showBasePathTreePopupMenu(event.getPoint(), basePathTree);
}
}
}
}
private final APreferenceStore preferenceStore = PreferenceStoreFactory.getPreferenceStore(PreferenceStoreFactory.DB_STORE);
private JRTable mainTable;
private JXLayer<JRTable> mainTableLayer;
private JProgressBar progressBar;
private JSplitPane mainSplitPane;
private JSplitPane propertySheetImageSplitPane;
private SimpleImageViewer imageViewer;
private PropertySheetPanel propertySheet;
private JMenuButton addMetadataButton;
private JButton removeMetadataButton;
private JButton saveMetadataButton;
private SortColumnComponent sortColumnComponent;
private FilterPanelComponent filterFieldComponent;
private JSplitPane treeMainTableSplitPane;
private JRTree basePathTree;
private JRTree fileSystemTree;
private JRScrollPane mainTableScrollPane;
private JTabbedPane treeTabbedPane;
private JPanel buttonPanel;
private MainViewTreeComponentHandler treeComponentHandler;
private MainViewPropertySheetHandler propertySheetHandler;
private MainViewEbookTableComponentHandler ebookTableHandler;
private MainTablePopupMouseListener mainTablePopupMouseListener;
private MainController controller;
/**
* Create the application.
*/
public MainView(MainController controller) {
this.controller = controller;
}
private void initializeGlobalKeystrokes() {
final InputMap inputMap = this.getRootPane().getInputMap(JButton.WHEN_IN_FOCUSED_WINDOW);
final ActionMap actionMap = this.getRootPane().getActionMap();
inputMap.put(MainViewMenuUtils.QUIT_KEY, "QUIT");
actionMap.put("QUIT", ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.QUIT_ACTION, null));
inputMap.put(MainViewMenuUtils.SAVE_KEY, "SAVE");
actionMap.put("SAVE", ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.SAVE_METADATA_ACTION, null));
inputMap.put(MainViewMenuUtils.FIND_KEY, "FIND");
actionMap.put("FIND", ActionFactory.getTableFindAction(mainTable));
}
/**
* Initialize the contents of the frame.
*/
void initialize() {
this.setTitle(Jeboorker.APP + " " + Jeboorker.getAppVersion());
this.setIconImage(ImageResourceBundle.getResourceAsImageIcon("logo_16.png").getImage());
this.setBounds(100, 100, 792, 622);
this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.QUIT_ACTION, null).invokeAction();
}
});
this.setGlassPane(new ShadowPanel());
JPanel contentPane = new JPanel(new MigLayout("insets 3 5 3 5")); // T, L, B, R.
contentPane.setOpaque(true);
mainSplitPane = new JSplitPane();
mainSplitPane.setAlignmentX(Component.RIGHT_ALIGNMENT);
mainSplitPane.setOneTouchExpandable(true);
mainSplitPane.setResizeWeight(0.9);
contentPane.add(mainSplitPane, "w 100%, h 100%, wrap");
JPanel propertyContentPanel = new JPanel(new MigLayout("insets 0 0 0 0"));
mainSplitPane.setLeftComponent(propertyContentPanel);
sortColumnComponent = new SortColumnComponent();
propertyContentPanel.add(sortColumnComponent, "h 25!, w 100%, wrap");
treeMainTableSplitPane = new JSplitPane();
treeMainTableSplitPane.setDividerLocation(220);
propertyContentPanel.add(treeMainTableSplitPane, "h 100%, w 100%");
createMainTable();
mainTableScrollPane = new JRScrollPane();
treeMainTableSplitPane.setRightComponent(mainTableScrollPane);
mainTableLayer = new JXLayer<JRTable>(mainTable, new AbstractLayerUI<JRTable>() {
@Override
protected void processMouseEvent(final MouseEvent e, final JXLayer<? extends JRTable> l) {
if(preferenceStore.getEntryAsBoolean(PreferenceStoreFactory.PREFERENCE_KEYS.MAIN_TABLE_AUTO_SAVE_METADATA_ENABLED)) {
transferFocusOnClick(e, l);
//save meta data and dispatch the mouse event to the jtable so it changes the selection
if(saveMetadataButton.isEnabled()) {
if(e.getID() == MouseEvent.MOUSE_PRESSED && e.getSource() == mainTable ) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.SAVE_METADATA_ACTION, null)
.invokeAction(null, new Runnable() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
MouseEvent click = new MouseEvent((Component) e.getSource(), MouseEvent.MOUSE_CLICKED, e.getWhen(),
e.getModifiers(), e.getX(), e.getY(), e.getXOnScreen(), e.getYOnScreen(),
e.getClickCount(), e.isPopupTrigger(), e.getButton());
for(MouseListener ml: l.getView().getMouseListeners()){
ml.mousePressed(click);
ml.mouseReleased(click);
ml.mouseClicked(click);
}
}
});
}
});
}
});
}
e.consume();
}
}
}
private void transferFocusOnClick(final MouseEvent e, final JXLayer<? extends JRTable> l) {
if(e.getID() != MouseEvent.MOUSE_DRAGGED && e.getID() != MouseEvent.MOUSE_MOVED
&& e.getID() != MouseEvent.MOUSE_ENTERED && e.getID() != MouseEvent.MOUSE_EXITED) {
//transfer the focus cause that the edit mode in the meta data sheet
l.getView().requestFocus();
}
}
public long getLayerEventMask() {
//fix for mouse wheel scrolling @see https://www.java.net//node/696371
return AWTEvent.MOUSE_EVENT_MASK;
}
});
mainTableScrollPane.setViewportView(mainTableLayer);
treeTabbedPane = new JTabbedPane();
treeTabbedPane.setDropTarget(new DropTarget(treeTabbedPane, new DropTargetAdapter() {
@Override
public void dragOver(DropTargetDragEvent dtde) {
Point location = dtde.getLocation();
int indexAtLocation = treeTabbedPane.indexAtLocation(location.x, location.y);
if(indexAtLocation >= 0) {
treeTabbedPane.setSelectedIndex(indexAtLocation);
}
}
@Override
public void drop(DropTargetDropEvent dtde) {
}
}));
JComponent fileSystemTreeComp = createFileSystemTree();
treeTabbedPane.addTab(Bundle.getString("EborkerMainView.tabbedPane.fileSystem"), fileSystemTreeComp);
JComponent basePathTreeComp = createBasePathTree();
treeTabbedPane.addTab(Bundle.getString("EborkerMainView.tabbedPane.basePath"), basePathTreeComp);
treeMainTableSplitPane.setLeftComponent(treeTabbedPane);
treeMainTableSplitPane.setOneTouchExpandable(true);
JPanel sheetPanel = new JPanel(new MigLayout("insets 0 0 0 0"));
propertySheet = new PropertySheetPanel(new EbookSheetPropertyModel());
propertySheet.setMode(PropertySheet.VIEW_AS_FLAT_LIST);
propertySheet.setDescriptionVisible(true);
propertySheet.setShowCategoryButton(false);
addMetadataButton = new JMenuButton();
addMetadataButton.setIcon(new ImageIcon(Bundle.getResource("add_metadata_16.png")));
addMetadataButton.setText(EMPTY);
addMetadataButton.setWidth(50);
EmptyListModel<Action> emptyListModel = EmptyListModel.getSharedInstance();
addMetadataButton.setListModel(emptyListModel);
propertySheet.addToolbarComponent(addMetadataButton);
removeMetadataButton = new JButton(ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.REMOVE_METADATA_ENTRY_ACTION, null));
propertySheet.addToolbarComponent(removeMetadataButton);
saveMetadataButton = new JButton(ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.SAVE_METADATA_ACTION, null));
saveMetadataButton.setText(EMPTY);
new EnablePropertyChangeHighlighterSupport(saveMetadataButton, Color.RED, 3);
propertySheet.addToolbarComponent(saveMetadataButton);
((PropertyRendererRegistry)propertySheet.getRendererFactory()).registerRenderer((Class<?>) null, DefaultPropertyRenderer.class);
((PropertyEditorRegistry)propertySheet.getEditorFactory()).registerEditor((Class<?>) null, DefaultPropertyCellEditor.class);
((PropertyRendererRegistry)propertySheet.getRendererFactory()).registerRenderer(String.class, DefaultPropertyRenderer.class);
((PropertyEditorRegistry)propertySheet.getEditorFactory()).registerEditor(String.class, DefaultPropertyCellEditor.class);
DatePropertyCellRenderer calendarDatePropertyRenderer = new DatePropertyCellRenderer(((SimpleDateFormat) SimpleDateFormat.getDateInstance()).toPattern());
((PropertyEditorRegistry)propertySheet.getEditorFactory()).registerEditor(Date.class, new DatePropertyCellEditor());
((PropertyRendererRegistry)propertySheet.getRendererFactory()).registerRenderer(Date.class, calendarDatePropertyRenderer);
((PropertyEditorRegistry)propertySheet.getEditorFactory()).registerEditor("rating", StarRatingPropertyEditor.class);
((PropertyRendererRegistry)propertySheet.getRendererFactory()).registerRenderer("rating", StarRatingPropertyRenderer.class);
((PropertyEditorRegistry)propertySheet.getEditorFactory()).registerEditor("calibre:rating", StarRatingPropertyEditor.class);
((PropertyRendererRegistry)propertySheet.getRendererFactory()).registerRenderer("calibre:rating", StarRatingPropertyRenderer.class);
((PropertyEditorRegistry)propertySheet.getEditorFactory()).registerEditor(java.util.List.class, MultiListPropertyEditor.class);
((PropertyRendererRegistry)propertySheet.getRendererFactory()).registerRenderer(java.util.List.class, MultiListPropertyRenderer.class);
sheetPanel.add(propertySheet, "w 100%, h 100%");
propertySheetImageSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
propertySheetImageSplitPane.setAlignmentX(Component.RIGHT_ALIGNMENT);
propertySheetImageSplitPane.setOneTouchExpandable(true);
mainSplitPane.setRightComponent(propertySheetImageSplitPane);
JPanel imageViewerPanel = new JPanel(new MigLayout("insets 0 0 0 0"));
imageViewerPanel.setBorder(new EmptyBorder(3,3,3,3));
imageViewer = new SimpleImageViewer();
imageViewerPanel.add(imageViewer, "w 100%, h 100%");
propertySheetImageSplitPane.setRightComponent(imageViewerPanel);
propertySheetImageSplitPane.setLeftComponent(sheetPanel);
propertySheetImageSplitPane.setDividerLocation(getSize().height / 2);
mainSplitPane.setDividerLocation(getSize().width - 220);
filterFieldComponent = new FilterPanelComponent();
contentPane.add(filterFieldComponent, "w 100%, wrap");
JPanel statusPanel = new JPanel(new MigLayout("insets 0 5 0 0"));
contentPane.add(statusPanel, "w 100%, wrap");
JLabel statusLabel = new JLabel(Bundle.getString("EborkerMainView.status"));
statusPanel.add(statusLabel, "w 55!");
progressBar = new JProgressBar();
statusPanel.add(progressBar, "w 100%");
this.setContentPane(contentPane);
this.setJMenuBar(MainMenuBarController.getController().getView());
initializeGlobalKeystrokes();
treeComponentHandler = new MainViewTreeComponentHandler(basePathTree, fileSystemTree, this);
propertySheetHandler = new MainViewPropertySheetHandler(propertySheet, this);
ebookTableHandler = new MainViewEbookTableComponentHandler(mainTable, mainTableScrollPane);
}
/**
* Attach all needed listeners to the view
*/
void initListeners() {
mainTable.getSelectionModel().addListSelectionListener(new PropertySheetListSelectionListener());
mainTable.addMouseListener(getMainTablePopupMouseListener());
imageViewer.addMouseListener(new CoverPopupMouseListener());
basePathTree.addMouseListener(new BasePathTreePopupMouseListener());
fileSystemTree.addMouseListener(new FileSystemTreePopupMouseListener());
propertySheet.addPropertySheetChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent e) {
if("value".equals(e.getPropertyName())) {
//sheet has been edited
EventManager.fireEvent(EventManager.EVENT_TYPES.METADATA_SHEET_CONTENT_CHANGE, new ApplicationEvent(getEbookTableHandler().getSelectedEbookPropertyItems(), getSelectedMetadataProperty(), e.getSource()));
}
}
});
getPropertySheetHandler().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if(!e.getValueIsAdjusting()) {
EventManager.fireEvent(EventManager.EVENT_TYPES.METADATA_SHEET_SELECTION_CHANGE, new ApplicationEvent(getEbookTableHandler().getSelectedEbookPropertyItems(), getSelectedMetadataProperty(), e.getSource()));
}
}
});
mainTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if(!e.getValueIsAdjusting()) {
EventManager.fireEvent(EventManager.EVENT_TYPES.EBOOK_ITEM_SELECTION_CHANGE, new ApplicationEvent(getEbookTableHandler().getSelectedEbookPropertyItems(), getSelectedMetadataProperty(), e.getSource()));
}
}
});
treeTabbedPane.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
EventManager.fireEvent(EventManager.EVENT_TYPES.MAIN_TREE_VISIBILITY_CHANGED, new ApplicationEvent(getEbookTableHandler().getSelectedEbookPropertyItems(), getSelectedMetadataProperty(), e.getSource()));
}
});
filterFieldComponent.initListeners();
preferenceStore.addPreferenceChangeListener(new MainViewPreferenceListener());
}
private MouseListener getMainTablePopupMouseListener() {
if(mainTablePopupMouseListener == null) {
mainTablePopupMouseListener = new MainTablePopupMouseListener();
}
return mainTablePopupMouseListener;
}
private void createMainTable() {
mainTable = new JRTable();
mainTable.setName("MainTable");
mainTable.setRowHeight(74);
mainTable.setModel(new EbookPropertyDBTableModel(true));
mainTable.setDefaultRenderer(Object.class, new EbookTableCellRenderer(getMainTablePopupMouseListener()));
mainTable.setDefaultEditor(Object.class, new EbookTableCellEditor(new EbookTableCellEditor.EditListener() {
@Override
public void editingStoped() {
}
@Override
public void editingStarted() {
fileSystemTree.stopEditing();
fileSystemTree.clearSelection();
basePathTree.stopEditing();
basePathTree.clearSelection();
}
@Override
public void editingCanceled() {
}
}, getMainTablePopupMouseListener()));
mainTable.setTableHeader(null);
DefaultListSelectionModel defaultListSelectionModel = new DefaultListSelectionModel();
defaultListSelectionModel.setSelectionMode(DefaultListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
mainTable.setSelectionModel(defaultListSelectionModel);
mainTable.setDragEnabled(true);
mainTable.setStopEditOnSelectionChange(true);
MainViewMenuUtils.registerCopyToClipboardKeyAction(mainTable);
MainViewMenuUtils.registerPasteFromClipboardKeyAction(mainTable);
MainViewMenuUtils.registerDeleteKeyAction(mainTable);
MainViewMenuUtils.registerRefreshEntryKeyAction(mainTable);
MainViewMenuUtils.registerRenameFileKeyAction(mainTable);
MainViewMenuUtils.registerApplyFilterKeyAction(mainTable);
mainTable.putClientProperty(StringConvertor.class, new StringConvertor() {
@Override
public String toString(Object obj) {
if(obj instanceof EbookPropertyItem) {
EbookPropertyItem item = (EbookPropertyItem) obj;
return new StringBuilder().append(item.getResourceHandler().getName())
.append(" ").append(item.getAuthor())
.append(" ").append(item.getTitle())
.append(" ").append(item.getSeriesName())
.toString();
}
return StringUtil.toString(obj);
}
});
mainTable.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport info) {
//only import Strings
if (!(info.isDataFlavorSupported(DataFlavor.stringFlavor) || info.isDataFlavorSupported(DataFlavor.javaFileListFlavor))) {
return false;
}
JTable.DropLocation dl = (JTable.DropLocation) info.getDropLocation();
if (dl.getRow() == -1) {
return false;
}
return true;
}
public boolean importData(TransferHandler.TransferSupport info) {
if (!info.isDrop()) {
return false;
}
// Check for String flavor
if (!(info.isDataFlavorSupported(DataFlavor.stringFlavor) || info.isDataFlavorSupported(DataFlavor.javaFileListFlavor))) {
LoggerFactory.getLogger().log(Level.INFO, "List doesn't accept a drop of this type.");
return false;
}
JTable.DropLocation dl = (JTable.DropLocation) info.getDropLocation();
int dropRow = dl.getRow();
return PasteFromClipboardAction.importEbookFromClipboard(info.getTransferable(), dropRow);
}
public int getSourceActions(JComponent c) {
return COPY;
}
/**
* Create a new Transferable that is used to drag files from jeboorker to a native application.
*/
protected Transferable createTransferable(JComponent c) {
final JTable list = (JTable) c;
final int[] selectedRows = list.getSelectedRows();
final List<URI> uriList = new ArrayList<>();
final List<String> files = new ArrayList<>();
for (int i = 0; i < selectedRows.length; i++) {
EbookPropertyItem val = (EbookPropertyItem) mainTable.getModel().getValueAt(selectedRows[i], 0);
try {
uriList.add(new File(val.getFile()).toURI());
files.add(new File(val.getFile()).getPath());
} catch (Exception e) {
LoggerFactory.getLogger().log(Level.WARNING, "Failed to encode " + val.getResourceHandler().toString(), e);
}
}
return new FileTransferable(files);
}
});
}
private JComponent createFileSystemTree() {
final String fileSystemTreeName = "FileSystemTree";
JPanel fileSystemTreePanel = new JPanel(new MigLayout("insets 3 0 0 0")); // T, L, B, R.
fileSystemTreePanel.setBackground(SwingUtils.getBackgroundColor());
fileSystemTreePanel.setOpaque(true);
buttonPanel = new JPanel();
buttonPanel.setOpaque(false);
fileSystemTreePanel.add(buttonPanel, "w 100%, wrap");
buttonPanel.setLayout(new EqualsLayout(EqualsLayout.RIGHT, 3, true));
Dimension buttonDimension = new Dimension(28, 28);
JButton syncButton = new JButton(ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.SYNC_FOLDER_ACTION, null));
syncButton.setPreferredSize(buttonDimension);
buttonPanel.add(syncButton);
JButton collapseButton = new JButton(ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.FILE_SYSTEM_COLLAPSE_ALL_ACTION, fileSystemTreeName));
collapseButton.setPreferredSize(buttonDimension);
buttonPanel.add(collapseButton);
fileSystemTree = new JRTree();
setupTree(fileSystemTree);
fileSystemTree.setName(fileSystemTreeName);
fileSystemTree.setSelectionModel(new DefaultTreeSelectionModel());
FileSystemTreeModel fileSystemTreeModel = new FileSystemTreeModel();
fileSystemTree.setModel(fileSystemTreeModel);
fileSystemTree.setAutoMoveHorizontalSliders(preferenceStore.isTreeAutoScrollingEnabled());
fileSystemTree.setEditable(true);
FileSystemTreeCellRenderer fileSystemTreeCellRenderer = new FileSystemTreeCellRenderer();
fileSystemTree.setCellRenderer(fileSystemTreeCellRenderer);
fileSystemTree.setCellEditor(new FileSystemTreeCellEditor(fileSystemTree, fileSystemTreeCellRenderer));
fileSystemTree.addTreeExpansionListener(new TreeExpansionListener() {
@Override
public void treeExpanded(TreeExpansionEvent event) {
// reset the file node cache before open to take changed folders under account
TreePath path = event.getPath();
Object collapsedNode = path.getLastPathComponent();
if(collapsedNode instanceof FileSystemNode) {
((FileSystemNode) collapsedNode).reset();
}
}
@Override
public void treeCollapsed(TreeExpansionEvent event) {}
});
if(((DefaultMutableTreeNode) fileSystemTreeModel.getRoot()).getChildCount() == 1) {
fileSystemTree.addTreeExpansionListener(new TreeExpansionListener() {
@Override
public void treeExpanded(TreeExpansionEvent event) {
}
@Override
public void treeCollapsed(TreeExpansionEvent event) {
TreePath path = event.getPath();
if(path.getPathCount() == 2) {
fileSystemTree.expandPath(event.getPath());
}
}
});
//row 0 should always be expanded.
fileSystemTree.expandRow(0);
}
fileSystemTree.registerKeyboardAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TreePath[] selectionPaths = fileSystemTree.getSelectionPaths();
if(selectionPaths.length == 0) {
return;
} else if(selectionPaths.length == 1) {
Object lastPathComponent = selectionPaths[0].getLastPathComponent();
if(lastPathComponent instanceof FileSystemNode && ((FileSystemNode)lastPathComponent).getResource().isFileResource()) {
fileSystemTree.startEditingAtPath(selectionPaths[0]);
}
} else {
for(TreePath selectionPath : selectionPaths) {
Object lastPathComponent = selectionPath.getLastPathComponent();
if(lastPathComponent instanceof FileSystemNode && ((FileSystemNode)lastPathComponent).getResource().isDirectoryResource()) {
return;
}
}
ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.RENAME_FILE_ACTION, null).actionPerformed(e);
}
}
}, "RenameFile", MainViewMenuUtils.RENAME_KEY, JComponent.WHEN_FOCUSED);
JRScrollPane treeScroller = new JRScrollPane(fileSystemTree);
treeScroller.setOpaque(false);
treeScroller.getViewport().setOpaque(false);
fileSystemTreePanel.add(treeScroller, "w 100%, h 100%");
fileSystemTree.setRootVisible(false);
fileSystemTree.setRowHeight(25);
MainViewMenuUtils.registerCopyToClipboardKeyAction(fileSystemTree);
MainViewMenuUtils.registerPasteFromClipboardKeyAction(fileSystemTree);
MainViewMenuUtils.registerDeleteKeyAction(fileSystemTree);
MainViewMenuUtils.registerFileSystemRefreshKeyAction(fileSystemTree);
MainViewMenuUtils.registerApplyFilterKeyAction(fileSystemTree);
fileSystemTree.setDragEnabled(true);
fileSystemTree.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport info) {
return DragAndDropUtils.isFileImportRequest(info);
}
public boolean importData(TransferHandler.TransferSupport info) {
if (!info.isDrop()) {
return false;
}
if (!DragAndDropUtils.isFileImportRequest(info)) {
LoggerFactory.getLogger().log(Level.INFO, "List doesn't accept a drop of this type.");
return false;
}
JTree.DropLocation dl = (JTree.DropLocation) info.getDropLocation();
TreePath dropRow = dl.getPath();
Object lastPath = dropRow.getLastPathComponent();
try {
IResourceHandler targetPathResource = ((FileSystemNode) lastPath).getResource();
if (targetPathResource.isFileResource()) {
targetPathResource = targetPathResource.getParentResource();
}
Transferable transferable = info.getTransferable();
boolean isLocal = (boolean) ReflectionUtils.getFieldValue(transferable, "isLocal", false);
List<IResourceHandler> sourceResourceHandlers = ResourceHandlerFactory.getResourceHandler(transferable);
for (IResourceHandler sourceResourceHandler : sourceResourceHandlers) {
String basePathFor = preferenceStore.getBasePathFor(targetPathResource);
if (basePathFor != null) {
// drop to a folder that is managed by jeboorker.
PasteFromClipboardAction.importEbookFromClipboard(transferable, basePathFor, targetPathResource);
} else {
// do a simple copy or move
IResourceHandler targetPathResourceFile = targetPathResource.addPathStatement(sourceResourceHandler.getName());
if(notEqual(sourceResourceHandler, targetPathResourceFile)) {
IResourceHandler uniqueTargetPathResourceFile = ResourceHandlerFactory.getUniqueResourceHandler(targetPathResourceFile,
targetPathResourceFile.getFileExtension());
if(isLocal || (MOVE & info.getSourceDropActions()) == MOVE) {
sourceResourceHandler.moveTo(uniqueTargetPathResourceFile, false);
treeComponentHandler.refreshFileSystemTreeEntry(sourceResourceHandler);
} else {
sourceResourceHandler.copyTo(uniqueTargetPathResourceFile, false);
}
}
}
treeComponentHandler.refreshFileSystemTreeEntry(targetPathResource);
}
} catch (Exception e) {
LoggerFactory.getLogger(this).log(Level.WARNING, e.getMessage(), e);
return false;
}
return true;
}
public int getSourceActions(JComponent c) {
return COPY;
}
/**
* Create a new Transferable that is used to drag files from jeboorker to a native application.
*/
protected Transferable createTransferable(JComponent c) {
List<IResourceHandler> selectedTreeItems = MainController.getController().getMainTreeHandler().getSelectedTreeItems();
final List<URI> uriList = new ArrayList<>(selectedTreeItems.size());
final List<String> files = new ArrayList<>(selectedTreeItems.size());
for (int i = 0; i < selectedTreeItems.size(); i++) {
IResourceHandler selectedTreeItem = selectedTreeItems.get(i);
try {
uriList.add(selectedTreeItem.toFile().toURI());
files.add(selectedTreeItem.toFile().getPath());
} catch (Exception e) {
LoggerFactory.getLogger().log(Level.WARNING, "Failed to encode " + selectedTreeItem.toString(), e);
}
}
return new FileTransferable(files);
}
});
fileSystemTree.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
mainTable.stopEdit();
mainTable.getSelectionModel().clearSelection();
}
});
fileSystemTree.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
TreePath[] selectionPaths = fileSystemTree.getSelectionPaths();
List<IResourceHandler> resources = new FilterList<>(toIResourceHandler(selectionPaths), new Filter<IResourceHandler>() {
@Override
public boolean isFiltered(IResourceHandler resource) {
return resource == null || !ActionUtils.isSupportedEbookFormat(resource, false);
}
});
if(!resources.isEmpty() || controller.isEbookPropertyFileTableModel()) {
controller.changeToFileModel(resources);
}
}
private List<IResourceHandler> toIResourceHandler(TreePath[] path) {
if(path != null) {
List<IResourceHandler> result = new ArrayList<>(path != null ? path.length : 0);
for (TreePath value : path) {
Object node = value.getLastPathComponent();
if(node instanceof FileSystemNode) {
result.add(((FileSystemNode) node).getResource());
}
}
return result;
}
return Collections.emptyList();
}
});
return fileSystemTreePanel;
}
private JComponent createBasePathTree() {
final String basePathTreeName = "BasePathTree";
JPanel basePathTreePanel = new JPanel(new MigLayout("insets 3 0 0 0")); // T, L, B, R.
basePathTreePanel.setBackground(SwingUtils.getBackgroundColor());
basePathTreePanel.setOpaque(true);
buttonPanel = new JPanel();
buttonPanel.setOpaque(false);
basePathTreePanel.add(buttonPanel, "w 100%, wrap");
buttonPanel.setLayout(new EqualsLayout(EqualsLayout.RIGHT, 3, true));
Dimension buttonDimension = new Dimension(28, 28);
JButton syncButton = new JButton(ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.SYNC_FOLDER_ACTION, null));
syncButton.setPreferredSize(buttonDimension);
buttonPanel.add(syncButton);
JButton addButton = new JButton(ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.ADD_BASE_PATH_ACTION, null));
addButton.setPreferredSize(buttonDimension);
addButton.setText(EMPTY);
buttonPanel.add(addButton);
JButton collapseButton = new JButton(ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.FILE_SYSTEM_COLLAPSE_ALL_ACTION, basePathTreeName));
collapseButton.setPreferredSize(buttonDimension);
buttonPanel.add(collapseButton);
basePathTree = new JRTree();
setupTree(basePathTree);
basePathTree.setName(basePathTreeName);
basePathTree.setModel(new BasePathTreeModel());
basePathTree.setEditable(true);
BasePathTreeCellRenderer basePathTreeCellRenderer = new BasePathTreeCellRenderer(basePathTree);
basePathTree.setCellRenderer(basePathTreeCellRenderer);
basePathTree.setCellEditor(new BasePathTreeCellEditor(basePathTree));
basePathTree.setToggleExpandOnDoubleClick(true);
basePathTree.setAutoMoveHorizontalSliders(preferenceStore.isTreeAutoScrollingEnabled());
basePathTree.setRepaintAllOnChange(true);
basePathTree.setEditable(true);
JRScrollPane basePathTreeScroller = new JRScrollPane(basePathTree);
basePathTreeScroller.setOpaque(false);
basePathTreeScroller.getViewport().setOpaque(false);
basePathTreePanel.add(basePathTreeScroller, "w 100%, h 100%");
basePathTree.setRootVisible(false);
basePathTree.setRowHeight(25);
MainViewMenuUtils.registerDeleteKeyAction(basePathTree);
basePathTree.addMouseListener(new MouseAdapter() {
private static final String QUERY_IDENTIFER = "BASE_PATH_MOUSE_LISTENER";
private Object previousEditorValue;
@Override
public void mousePressed(MouseEvent e) {
final int row = basePathTree.getRowForLocation(e.getPoint().x, e.getPoint().y);
final TreePath filterTreePath = basePathTree.getPathForRow(row);
if(filterTreePath != null) {
Object cellEditorValue = filterTreePath.getLastPathComponent();
if(cellEditorValue == null || !cellEditorValue.equals(previousEditorValue)) {
if(cellEditorValue instanceof FileSystemNode) {
setPathFilter(((FileSystemNode)cellEditorValue).getName());
((BasePathTreeModel)basePathTree.getModel()).setFilterTreePath(filterTreePath);
MainController.getController().getEbookTableHandler().refreshTable();
} else {
boolean remove = MainController.getController().changeToDatabaseModel().removeWhereCondition(QUERY_IDENTIFER);
((BasePathTreeModel)basePathTree.getModel()).setFilterTreePath(null);
if(remove) {
MainController.getController().getEbookTableHandler().refreshTable();
}
}
}
previousEditorValue = cellEditorValue;
}
}
private void setPathFilter(final String fullResourceFilterPath) {
MainController.getController().changeToDatabaseModel().addWhereCondition(new EbookPropertyDBTableModel.EbookPropertyDBTableModelQuery() {
@Override
public String getIdentifier() {
return QUERY_IDENTIFER;
}
@Override
public void appendQuery(Where<EbookPropertyItem, EbookPropertyItem> where) throws SQLException {
String fullResourceFilterPathStatement = StringUtil.replace(fullResourceFilterPath, "\\", "\\\\");
where.like("file", fullResourceFilterPathStatement + "%");
}
});
}
});
basePathTree.setTransferHandler(new TransferHandler() {
public boolean canImport(TransferHandler.TransferSupport info) {
return DragAndDropUtils.isFileImportRequest(info);
}
public boolean importData(TransferHandler.TransferSupport info) {
if (!info.isDrop()) {
return false;
}
// Check for String flavor
if (!DragAndDropUtils.isFileImportRequest(info)) {
LoggerFactory.getLogger().log(Level.INFO, "List doesn't accept a drop of this type.");
return false;
}
JTree.DropLocation dl = (JTree.DropLocation) info.getDropLocation();
TreePath dropRow = dl.getPath();
Object lastPath = dropRow.getLastPathComponent();
Object firstPath = dropRow.getPath()[1]; //is the base path
IResourceHandler firstPathResource = ((FileSystemNode) firstPath).getResource();
IResourceHandler lastPathPathResource = ((FileSystemNode) lastPath).getResource();
try {
PasteFromClipboardAction.importEbookFromClipboard(info.getTransferable(), firstPathResource.toString(), lastPathPathResource);
basePathTree.startEditingAtPath(dropRow);
} catch (Exception e) {
try {
LoggerFactory.getLogger().log(Level.WARNING, "Failed to import " + ResourceHandlerFactory.getResourceHandler(info.getTransferable()) + " to " + lastPathPathResource, e);
} catch (Exception e1) {}
return false;
}
return true;
}
public int getSourceActions(JComponent c) {
return COPY;
}
/**
* Create a new Transferable that is used to drag files from jeboorker to a native application.
*/
protected Transferable createTransferable(JComponent c) {
return null;
}
});
basePathTree.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
mainTable.stopEdit();
mainTable.getSelectionModel().clearSelection();
fileSystemTree.stopEditing();
fileSystemTree.clearSelection();
}
});
return basePathTreePanel;
}
private void setupTree(JRTree tree) {
tree.setLargeModel(true);
tree.setRowHeight(0);
tree.setShowsRootHandles(true);
}
/**
* Shows the cover popup menu for the selected entries.
* @param location The location where the popup should appears.
* @param invoker The invoker for the popup menu.
*/
void showCoverPopupMenu(Point location, Component invoker) {
List<EbookPropertyItem> selectedItems = MainController.getController().getSelectedEbookPropertyItems();
JPopupMenu menu = createCoverPopupMenu(selectedItems);
//setup and show popup
if(menu.getComponentCount() > 0) {
menu.setLocation(location);
menu.show(invoker, location.x, location.y);
}
}
/**
* Shows the base path tree popup menu for the selected entries.
* @param location The location where the popup should appears.
* @param invoker The invoker for the popup menu.
*/
void showBasePathTreePopupMenu(Point location, Component invoker) {
JPopupMenu menu = new JPopupMenu();
TreePath selPath = basePathTree.getPathForLocation((int)location.getX(), (int)location.getY());
if(selPath.getLastPathComponent() instanceof FileSystemNode) {
final FileSystemNode pathNode = (FileSystemNode) selPath.getLastPathComponent();
List<IResourceHandler> items = controller.getMainTreeHandler().getSelectedTreeItems();
Action action = ActionFactory.getAction(ActionFactory.COMMON_ACTION_TYPES.PASTE_FROM_CLIPBOARD_ACTION, pathNode.getResource().toString());
menu.add(new JMenuItem(action));
menu.add(MainViewMenuUtils.createOpenFolderMenuItem(items));
menu.add(MainViewMenuUtils.createNewFolderMenuItem(basePathTree, fileSystemTree, pathNode));
JMenuItem deleteMenuItem = MainViewMenuUtils.createDeleteMenuItem(items);
if(PreferenceStoreFactory.getPreferenceStore(PreferenceStoreFactory.DB_STORE).getBasePath().isOneEntryABasePathMember(items)) {
deleteMenuItem.setEnabled(false);
}
menu.add(deleteMenuItem);
//setup and show popup
if(menu.getComponentCount() > 0) {
menu.setLocation(location);
menu.show(invoker, location.x, location.y);
}
}
}
/**
* Shows the popup menu for the selected entries.
* @param location The locaten where the popup should appears.
* @param invoker The invoker for the popup menu.
*/
void showFileSystemTreePopupMenu(Point location, Component invoker) {
TreePath selPath = fileSystemTree.getPathForLocation((int)location.getX(), (int)location.getY());
JPopupMenu menu = createFileSystemTreePopupMenu(selPath);
//setup and show popup
if(menu.getComponentCount() > 0) {
menu.setLocation(location);
menu.show(invoker, location.x, location.y);
}
}
private JPopupMenu createFileSystemTreePopupMenu(final TreePath selPath) {
final MainController controller = MainController.getController();
final List<IResourceHandler> items = controller.getMainTreeHandler().getSelectedTreeItems();
final FileSystemNode pathNode = (FileSystemNode) selPath.getLastPathComponent();
final JPopupMenu menu = new JPopupMenu();
if(items.size() == 1) {
// only visible to single selections
if(items.get(0).isDirectoryResource()) {
menu.add(MainViewMenuUtils.createFileSystemRefreshMenuItem(items));
}
menu.add(MainViewMenuUtils.createOpenFileMenuItem(items));
menu.add(MainViewMenuUtils.createOpenFolderMenuItem(items));
menu.add(MainViewMenuUtils.createNewFolderMenuItem(basePathTree, fileSystemTree, pathNode));
}
if(items.size() >= 1) {
menu.add(MainViewMenuUtils.createImportToMenu(items, Bundle.getString("MainMenuBarController.import"), ActionFactory.COMMON_ACTION_TYPES.FILE_SYSTEM_IMPORT_ACTION));
}
menu.add(MainViewMenuUtils.createSendToMenu());
menu.add(MainViewMenuUtils.createDeleteMenuItem(items));
return menu;
}
/**
* Shows the popup menu for the selected entries.
* @param location The locaten where the popup should appears.
* @param invoker The invoker for the popup menu.
*/
void showMainTablePopupMenu(Point location, Component invoker) {
JPopupMenu menu = createMainTablePopupMenu();
//setup and show popup
if(menu.getComponentCount() > 0) {
menu.setLocation(location);
menu.show(invoker, location.x, location.y);
}
}
/**
* Creates the popup menu for the main table having only these entries inside
* that can be processed with the given {@link EbookPropertyItem} list.
* @param items The items to be tested if they're matching against the menu entries.
* @return The desired {@link JPopupMenu}. Never returns <code>null</code>.
*/
private static JPopupMenu createMainTablePopupMenu() {
final MainController controller = MainController.getController();
final List<EbookPropertyItem> items = MainController.getController().getSelectedEbookPropertyItems();
final List<IResourceHandler> selectedResources = EbookPropertyItemUtils.createIResourceHandlerList(items);
final int[] selectedEbookPropertyItemRows = controller.getSelectedEbookPropertyItemRows();
final JPopupMenu menu = new JPopupMenu();
Action action = ActionFactory.getActionForItems(ActionFactory.DYNAMIC_ACTION_TYPES.EDIT_PLAIN_METADATA_ACTION, items, selectedEbookPropertyItemRows);
if(action.isEnabled()) {
menu.add(action);
}
action = ActionFactory.getActionForItems(ActionFactory.DYNAMIC_ACTION_TYPES.REFRESH_ENTRY_ACTION, items, selectedEbookPropertyItemRows);
JMenuItem item = new JMenuItem(action);
item.setAccelerator(MainViewMenuUtils.REFRESH_KEY);
if(action.isEnabled()) {
menu.add(item);
}
menu.add(MainViewMenuUtils.createRenameFileMenuItem());
if(items.size() == 1) {
//only visible to single selections
menu.add(MainViewMenuUtils.createOpenFileMenuItem(selectedResources));
menu.add(MainViewMenuUtils.createOpenFolderMenuItem(selectedResources));
}
menu.add(MainViewMenuUtils.createImportToMenu(selectedResources, Bundle.getString("MainMenuBarController.move"), ActionFactory.COMMON_ACTION_TYPES.MOVE_BETWEEN_BASE_FOLDER_ACTION));
menu.add(MainViewMenuUtils.createSendToMenu());
menu.add(MainViewMenuUtils.createDeleteMenuItem(selectedResources));
return menu;
}
/**
* Create the popup menu containing the cover actions.
* @param items The items to be tested if they're matching against the menu entries.
* @return The desired {@link JPopupMenu}. Never returns <code>null</code>.
*/
private static JPopupMenu createCoverPopupMenu(List<EbookPropertyItem> items) {
//create and fill popup menu
final MainController controller = MainController.getController();
int[] selectedEbookPropertyItemRows = controller.getSelectedEbookPropertyItemRows();
final JPopupMenu menu = new JPopupMenu();
addCoverMenuItems(menu, items, selectedEbookPropertyItemRows);
return menu;
}
static void addCoverMenuItems(JComponent menu, List<EbookPropertyItem> items, int[] rowsToRefreshAfter) {
if(!items.isEmpty()) {
Action action;
action = ActionFactory.getActionForItems(ActionFactory.DYNAMIC_ACTION_TYPES.SAVE_COVER_TO_CLIPBOARD_ACTION, items, rowsToRefreshAfter);
menu.add(new JMenuItem(action));
action = ActionFactory.getActionForItems(ActionFactory.DYNAMIC_ACTION_TYPES.SET_COVER_FROM_CLIPBOARD_ACTION, items, rowsToRefreshAfter);
menu.add(new JMenuItem(action));
menu.add(new JSeparator());
action = ActionFactory.getActionForItems(ActionFactory.DYNAMIC_ACTION_TYPES.SET_COVER_FROM_FILE_ACTION, items, rowsToRefreshAfter);
menu.add(new JMenuItem(action));
action = ActionFactory.getActionForItems(ActionFactory.DYNAMIC_ACTION_TYPES.SET_COVER_FROM_DOWNLOAD_ACTION, items, rowsToRefreshAfter);
menu.add(new JMenuItem(action));
action = ActionFactory.getActionForItems(ActionFactory.DYNAMIC_ACTION_TYPES.SET_COVER_FROM_EBOOK_ACTION, items, rowsToRefreshAfter);
menu.add(new JMenuItem(action));
action = ActionFactory.getActionForItems(ActionFactory.DYNAMIC_ACTION_TYPES.SAVE_COVER_TO_FILE_ACTION, items, rowsToRefreshAfter);
menu.add(new JMenuItem(action));
}
}
/**
* Shows a dialog to the user.
* @param message The message of the dialog
* @param title The dialog title.
* @param option The dialog option: JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.YES_NO_OPTION, JOptionPane.OK_CANCEL_OPTION
* @return 0: yes/ok, 1: no, 2:cancel, -1 none
*/
int showMessageBox(String message, String title, int option, String showAgainKey, int defaultValue, boolean isConfirmDialog) {
Number showAgain = preferenceStore.getGenericEntryAsNumber(showAgainKey);
if(showAgain == null) {
int n = defaultValue;
boolean dontShowAgain;
if(showAgainKey != null) {
JCheckBox checkbox = new JCheckBox(Bundle.getString("EborkerMainView.messagebox.showAgainMessage"));
Object[] params = {message, checkbox};
if(isConfirmDialog) {
n = JOptionPane.showConfirmDialog(this, params, title, option);
} else {
JOptionPane.showMessageDialog(this, params, title, option);
}
dontShowAgain = checkbox.isSelected();
} else {
if(isConfirmDialog) {
n = JOptionPane.showConfirmDialog(this, message, title, option);
} else {
JOptionPane.showMessageDialog(this, message, title, option);
}
dontShowAgain = false;
}
if(dontShowAgain) {
if(defaultValue >= 0) {
preferenceStore.addGenericEntryAsNumber(showAgainKey, defaultValue);
} else {
preferenceStore.addGenericEntryAsNumber(showAgainKey, n);
}
}
return n;
} else {
return showAgain.intValue();
}
}
JTree getSelectedTreePathComponent() {
Component[] allComponents = SwingUtils.getAllComponents(JTree.class, (Container) treeTabbedPane.getSelectedComponent());
if(allComponents.length >= 1) {
return (JTree) allComponents[0];
}
return null;
}
JTree getFileSystemTree() {
return fileSystemTree;
}
/**
* Tells the text filter field to display it self in and active filter color.
*/
public void setFilterColorEnabled(boolean enable) {
filterFieldComponent.enableFilterColor(enable);
}
public void refreshUI() {
// don't know why but otherwise the renderer won't work after changing the look and feel
if(!(mainTable.getDefaultRenderer(Object.class) instanceof EbookTableCellRenderer)) {
mainTable.setDefaultRenderer(Object.class, new EbookTableCellRenderer(getMainTablePopupMouseListener()));
}
}
/**
* Get the currently selected metadata property from the metadata sheet.
* @return The desired {@link Property} instance or <code>null</code> if no selection is made.
*/
public Property getSelectedMetadataProperty() {
final int selectedRow = propertySheet.getTable().getSelectedRow();
if(selectedRow >= 0) {
final EbookSheetPropertyModel model = (EbookSheetPropertyModel) propertySheet.getModel();
final PropertySheetTableModel.Item item = (Item) model.getObject(selectedRow);
final Property property = item.getProperty();
return property;
}
return null;
}
/**
* Set the given property as selected one in the metadata sheet.
* @param property The property to be set as selected.
*/
public void setSelectedMetadataProperty(final Property property) {
if(property != null) {
final EbookSheetPropertyModel model = getPropertySheetHandler().getModel();
final int rowCount = model.getRowCount();
for (int i = 0; i < rowCount; i++) {
final PropertySheetTableModel.Item item = (Item) model.getObject(i);
if(item != null && item.getName() != null && item.getName().equals(model.getDisplayName(property))) {
propertySheet.getTable().getSelectionModel().setSelectionInterval(i, i);
break;
} else {
if(property != null && item != null && item.getProperty() != null && item.getProperty().getName() != null && item.getProperty().getName().equals(property.getName())) {
propertySheet.getTable().getSelectionModel().setSelectionInterval(i, i);
break;
}
}
}
}
}
/**
* Rereads the metadata properties and set them to the sheet.
*/
public void refreshSheetProperties() {
try {
if(MainViewSelectionUtils.isMainTableSelection()) {
List<EbookPropertyItem> items = getEbookTableHandler().getSelectedEbookPropertyItems();
if(items.size() > 1) {
//multiple selection
EbookSheetPropertyMultiSelectionModel model = new EbookSheetPropertyMultiSelectionModel();
getPropertySheetHandler().setModel(model);
model.loadProperties(items);
clearImage();
EmptyListModel<Action> emptyListModel = EmptyListModel.getSharedInstance();
addMetadataButton.setListModel(emptyListModel);
} else if (items.size() == 1) {
//single selection
EbookSheetPropertyModel model = new EbookSheetPropertyModel();
getPropertySheetHandler().setModel(model);
if(items.get(0) != null) {
EbookPropertyItem ebookPropertyItem = items.get(0);
model.loadProperties(ebookPropertyItem);
byte[] cover = model.getCover();
if(cover != null && cover.length > 0) {
setImage(cover, ebookPropertyItem);
} else {
clearImage();
}
IMetadataReader reader = model.getMetadataReader();
if(reader != null) {
List<MetadataProperty> allMetadata = model.getAllMetadata();
MetadataAddListModel metadataAddListModel = new MetadataAddListModel(reader.getSupportedMetadata(), allMetadata, ebookPropertyItem);
addMetadataButton.setListModel(metadataAddListModel);
}
}
}
} else {
//no selection
getPropertySheetHandler().setModel(new EbookSheetPropertyMultiSelectionModel());
clearImage();
EmptyListModel<Action> emptyListModel = EmptyListModel.getSharedInstance();
addMetadataButton.setListModel(emptyListModel);
}
} catch (Exception e) {
LoggerFactory.getLogger().log(Level.WARNING, "Refresh property sheet has failed.", e);
}
}
/**
* Clears the image in the image viewer.
*/
private void clearImage() {
setImage(null, null);
}
/**
* Shows the image given with the <code>cover</code> parameter in the simple image viewer.
* The image viewer is set to black if the given <code>cover</code> is <code>null</code>.
*/
private void setImage(final byte[] cover, final EbookPropertyItem ebookPropertyItem) {
if (cover != null && ebookPropertyItem != null) {
//remove file extension by removing the separation dot because an image file name is expected.
final String coverFileName = StringUtil.replace(ebookPropertyItem.getResourceHandler().getResourceString(), new String[] {".", "/", "\\"}, "_");
imageViewer.setImageViewerResource(ResourceHandlerFactory.getVirtualResourceHandler(coverFileName, new VirtualStaticResourceDataLoader() {
ByteArrayInputStream byteArrayInputStream = null;
@Override
public InputStream getContentInputStream() {
if(byteArrayInputStream == null) {
byteArrayInputStream = new ByteArrayInputStream(cover);
}
byteArrayInputStream.reset();
return byteArrayInputStream;
}
@Override
public long length() {
return cover.length;
}
}));
} else {
imageViewer.setImageViewerResource(null);
}
}
/**
* Writes the application properties to the preference file
*/
void storeApplicationProperties() {
APreferenceStore preferenceStore = PreferenceStoreFactory.getPreferenceStore(PreferenceStoreFactory.DB_STORE);
preferenceStore.addGenericEntryAsNumber("mainWindowSizeWidth", getSize().width);
preferenceStore.addGenericEntryAsNumber("mainWindowSizeHeight", getSize().height);
preferenceStore.addGenericEntryAsNumber("mainWindowLocationX", getLocation().x);
preferenceStore.addGenericEntryAsNumber("mainWindowLocationY", getLocation().y);
preferenceStore.addGenericEntryAsNumber("mainWindowDividerLocation", CommonUtils.toNumber(mainSplitPane.getDividerLocation()));
preferenceStore.addGenericEntryAsNumber("lastRowCount", Integer.valueOf(mainTable.getRowCount()));
preferenceStore.addGenericEntryAsNumber("descriptionDividerLocation", Integer.valueOf(propertySheet.getDescriptionDividerLocation()));
preferenceStore.addGenericEntryAsNumber("treeMainTableDividerLocation", Integer.valueOf(treeMainTableSplitPane.getDividerLocation()));
preferenceStore.addGenericEntryAsNumber("propertySheetImageSplitPaneDividerLocation", Integer.valueOf(propertySheetImageSplitPane.getDividerLocation()));
preferenceStore.addGenericEntryAsString("basePathTreeSelection", TreeUtil.getExpansionStates(basePathTree));
preferenceStore.addGenericEntryAsString("fileSystemTreeSelection", TreeUtil.getExpansionStates(fileSystemTree));
sortColumnComponent.storeApplicationProperties();
filterFieldComponent.storeApplicationHistory();
}
/**
* Restores the application properties
*/
void restoreComponentProperties() {
APreferenceStore preferenceStore = PreferenceStoreFactory.getPreferenceStore(PreferenceStoreFactory.DB_STORE);
//restore the window size from the preferences.
Number mainWindowSizeWidth = preferenceStore.getGenericEntryAsNumber("mainWindowSizeWidth");
Number mainWindowSizeHeight = preferenceStore.getGenericEntryAsNumber("mainWindowSizeHeight");
if(mainWindowSizeWidth!=null && mainWindowSizeHeight!=null) {
setSize(mainWindowSizeWidth.intValue(), mainWindowSizeHeight.intValue());
}
//restore window location
Point entryAsScreenLocation = preferenceStore.getGenericEntryAsScreenLocation("mainWindowLocationX", "mainWindowLocationY");
if(entryAsScreenLocation != null) {
setLocation(entryAsScreenLocation);
}
//restore the divider location at the main window
final Number mainWindowDividerLocation = preferenceStore.getGenericEntryAsNumber("mainWindowDividerLocation");
if(mainWindowDividerLocation != null) {
int add = 0;
if(ReflectionUtils.getOS() == ReflectionUtils.OS_LINUX) {
//however, the splitpane has a difference of 9 between setting and getting the location.
add = -9;
}
mainSplitPane.setDividerLocation(mainWindowDividerLocation.intValue() + add);
}
//restore the divider location at the main window
final Number treeMainTableDividerLocation = preferenceStore.getGenericEntryAsNumber("treeMainTableDividerLocation");
if(treeMainTableDividerLocation != null) {
treeMainTableSplitPane.setDividerLocation(treeMainTableDividerLocation.intValue());
}
//restore the divider location in the property sheet
final Number descriptionDividerLocation = preferenceStore.getGenericEntryAsNumber("descriptionDividerLocation");
if(descriptionDividerLocation != null) {
propertySheet.setDescriptionDividerLocation(descriptionDividerLocation.intValue());
}
final Number propertySheetImageSplitPaneDividerLocation = preferenceStore.getGenericEntryAsNumber("propertySheetImageSplitPaneDividerLocation");
if (propertySheetImageSplitPaneDividerLocation != null) {
propertySheetImageSplitPane.setDividerLocation(propertySheetImageSplitPaneDividerLocation.intValue());
}
final String basePathTreeSelection = preferenceStore.getGenericEntryAsString("basePathTreeSelection");
if(basePathTreeSelection != null) {
TreeUtil.restoreExpanstionState(basePathTree, basePathTreeSelection);
}
final String fileSystemTreeSelection = preferenceStore.getGenericEntryAsString("fileSystemTreeSelection");
if(fileSystemTreeSelection != null) {
TreeUtil.restoreExpanstionState(fileSystemTree, fileSystemTreeSelection);
}
filterFieldComponent.restoreComponentProperties();
sortColumnComponent.restoreComponentProperties();
}
public List<Field> getSelectedFilterFields() {
return filterFieldComponent.getSelectedFilterFields();
}
public String getFilterText() {
return filterFieldComponent.getFilterText();
}
public void addFilterFieldSearch(String filterText) {
filterFieldComponent.addFilterFieldSearch(filterText);
}
public List<Field> getSortColumnSelectedFields() {
return sortColumnComponent.getSelectedFields();
}
public MainViewTreeComponentHandler getTreeComponentHandler() {
return treeComponentHandler;
}
public MainViewPropertySheetHandler getPropertySheetHandler() {
return propertySheetHandler;
}
/**
* Sets the image which is provided by the given {@link IResourceHandler} to the
* image viewer in the main view.
* @param imageResource The {@link IResourceHandler} instance providing the image
* data to be displayed. <code>null</code>if no image should be displayed.
*/
public void setImageViewerResource(IResourceHandler imageResource) {
imageViewer.setImageViewerResource(imageResource);
}
/**
* Gets the {@link IResourceHandler} for the image which is displayed in the image viewer.
* @return The desired {@link IResourceHandler} or <code>null</code>.
*/
public IResourceHandler getImageViewerResource() {
return imageViewer.getImageResource();
}
/**
* Gets the {@link BufferedImage} for the image which is displayed in the image viewer.
* @return The desired {@link BufferedImage} or <code>null</code>.
*/
public BufferedImage getImageViewerImage() {
return imageViewer.getImage();
}
/**
* Gets the progress indicator.
* @return The desired monitor instance of <code>null</code> if the monitor is not ready to use.
*/
public MainMonitor getProgressMonitor() {
if(progressBar != null) {
return MainMonitor.getInstance(progressBar);
}
return null;
}
public MainViewEbookTableComponentHandler getEbookTableHandler() {
return ebookTableHandler;
}
}