/******************************************************************************* * Copyright (c) 2014 Open Door Logistics (www.opendoorlogistics.com) * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v3 * which accompanies this distribution, and is available at http://www.gnu.org/licenses/lgpl.txt ******************************************************************************/ package com.opendoorlogistics.utils.ui; import java.awt.BorderLayout; import java.awt.datatransfer.*; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.swing.*; import javax.swing.text.DefaultEditorKit; import org.w3c.dom.Document; import com.opendoorlogistics.core.scripts.io.XMLConversionHandler; import com.opendoorlogistics.core.tables.utils.HasShortDescription; import com.opendoorlogistics.core.utils.XMLUtils; import com.opendoorlogistics.core.utils.ui.PopupMenuMouseAdapter; public abstract class ItemsPanel<T> extends JPanel { protected final List<T> items; protected final JScrollPane listScrollPane; protected final List<MyAction> actions; protected final String itemName; protected boolean printNumbered; protected JComponent itemsComponent; private XMLConversionHandler conversionHandler; protected class ItemContainer { final T item; final int indx; ItemContainer(T item, int indx) { this.item = item; this.indx = indx; } @Override public String toString() { return (printNumbered ? Integer.toString(indx+1) + ". " : "") + (HasShortDescription.class.isInstance(item)? ((HasShortDescription)item).getShortDescription() : item.toString()); } } public abstract class MyAction extends SimpleAction { public MyAction(SimpleActionConfig config) { super(config); } @Override public void updateEnabledState() { setEnabled(requiresSelection == false || getSelected() != null); } } public void addTitleLabel(String title) { add(new JLabel(title),BorderLayout.NORTH); } protected abstract JComponent createItemsComponent(); public ItemsPanel(List<T> items, String itemName) { this.items = items; this.itemName = itemName; this.itemsComponent = createItemsComponent(); setLayout(new BorderLayout()); listScrollPane = new JScrollPane(); listScrollPane.setViewportView(itemsComponent); setLayout(new BorderLayout()); add(listScrollPane, BorderLayout.CENTER); JToolBar toolBar = new JToolBar(); toolBar.setFloatable(false); add(toolBar, BorderLayout.SOUTH); // create right-click popup menu on the list final JPopupMenu popup = new JPopupMenu(); itemsComponent.addMouseListener(new PopupMenuMouseAdapter() { @Override protected void launchMenu(MouseEvent me) { popup.show(me.getComponent(), me.getX(), me.getY()); } }); // // create double click event on list // itemsComponent.addMouseListener(new MouseAdapter() { // public void mouseClicked(MouseEvent evt) { // if (evt.getClickCount() >= 2) { // // launchSelectedTable(); // } // } // }); // create all actions and add as buttons and menu items actions = createActions(); for (Action action : actions) { toolBar.add(action); popup.add(action); } // create double click event on the list itemsComponent.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { if (evt.getClickCount() >= 2) { editSelected(); } } }); updateList(); updateAppearance(); } private void onAction(String actionStr){ // See http://stackoverflow.com/questions/17589304/how-to-invoke-jtable-action-from-outside-jbutton Action action = itemsComponent.getActionMap().get(actionStr); if(action!=null){ ActionEvent newAE = new ActionEvent(itemsComponent, ActionEvent.ACTION_PERFORMED, actionStr); action.actionPerformed(newAE); } } protected List<MyAction> createActions() { ArrayList<MyAction> ret = new ArrayList<>(); ret.add(new MyAction(SimpleActionConfig.addItem.setItemName(itemName)) { @Override public void actionPerformed(ActionEvent e) { T item = createNewItem(); if (item != null) { addNewItem(item); } } }); ret.add(new MyAction(SimpleActionConfig.editItem.setItemName(itemName)) { @Override public void actionPerformed(ActionEvent e) { editSelected(); } }); ret.add(new MyAction(SimpleActionConfig.copyItem.setItemName(itemName)) { @Override public void actionPerformed(ActionEvent e) { onAction("copy"); } @Override public void updateEnabledState() { setEnabled(conversionHandler!=null && getSelected()!=null); } }); ret.add(new MyAction(SimpleActionConfig.pasteItem.setItemName(itemName)) { @Override public void actionPerformed(ActionEvent e) { onAction("paste"); } @Override public void updateEnabledState() { setEnabled(conversionHandler!=null ); } }); ret.add(new MyAction(SimpleActionConfig.moveItemUp.setItemName(itemName)) { @Override public void actionPerformed(ActionEvent e) { int indx = getSelectedIndx(); if (indx > 0) { T item = items.remove(indx); indx--; items.add(indx, item); updateList(); setSelectedIndex(indx); } } }); ret.add(new MyAction(SimpleActionConfig.moveItemDown.setItemName(itemName)) { @Override public void actionPerformed(ActionEvent e) { int indx = getSelectedIndx(); if (indx < items.size() - 1) { T item = items.remove(indx); indx++; items.add(indx, item); updateList(); setSelectedIndex(indx); } } }); ret.add(new MyAction(SimpleActionConfig.deleteItem.setItemName(itemName)) { @Override public void actionPerformed(ActionEvent e) { items.remove(getSelectedIndx()); updateList(); } }); return ret; } protected abstract void updateList(); protected void updateAppearance() { for (MyAction action : actions) { action.updateEnabledState(); } } protected abstract int getSelectedIndx(); protected abstract void setSelectedIndex(int index); protected abstract T createNewItem(); protected abstract T editItem(T item); protected T getSelected(){ int indx = getSelectedIndx(); if(indx!=-1){ return items.get(indx); } return null; } public void editSelected() { int indx = getSelectedIndx(); T selected = getSelected(); if(selected==null){ return; } T edited = editItem(selected); if (edited != null) { items.set(indx, edited); updateList(); setSelectedIndex(indx); } } public void update(){ updateList(); updateAppearance(); } public void select(T object){ for(int i =0 ; i<items.size() ; i++){ if(items.get(i)==object){ setSelectedIndex(i); break; } } } public boolean isPrintNumbered() { return printNumbered; } public void setPrintNumbered(boolean printNumbered) { this.printNumbered = printNumbered; } public XMLConversionHandler getConversionHandler() { return conversionHandler; } public void setConversionHandler(XMLConversionHandler conversionHandler) { this.conversionHandler = conversionHandler; if(conversionHandler!=null){ itemsComponent.setTransferHandler(new XMLTransferHandler()); }else{ itemsComponent.setTransferHandler(null); } updateAppearance(); } private void addNewItem(T item) { items.add(item); updateList(); setSelectedIndex(items.size() - 1); } private class XMLTransferHandler extends TransferHandler{ @Override public void exportToClipboard(JComponent comp, Clipboard clip, int action) { Transferable c = createTransferable(comp); clip.setContents(c, null); exportDone(comp, c, action); } @Override public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } @Override public boolean canImport(TransferHandler.TransferSupport support) { return conversionHandler!=null; } @SuppressWarnings("unchecked") @Override public boolean importData(JComponent c, Transferable t) { if(conversionHandler!=null){ if (canImport(new TransferHandler.TransferSupport(c, t))) { DataFlavor flavor = DataFlavor.stringFlavor; if (t.isDataFlavorSupported(flavor)) { try { Object data = t.getTransferData(flavor); if (data instanceof String) { Document doc = XMLUtils.parse((String)data); if(doc!=null){ List<Object> list = conversionHandler.fromXML(doc); if(list!=null){ for(Object obj:list){ addNewItem((T)obj); } } } } } catch (Throwable e) { } } } } return false; } @Override protected Transferable createTransferable(JComponent c) { if(conversionHandler!=null && getSelected()!=null){ Document doc = conversionHandler.toXML(getSelected()); if(doc!=null){ String s= XMLUtils.toString(doc, XMLUtils.getPrettyPrintFormat()); return new StringSelection(s); } } return null; } } }