/* * Copyright 2009-2020 Contributors (see credits.txt) * * This file is part of jEveAssets. * * jEveAssets is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * jEveAssets is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with jEveAssets; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package net.nikr.eve.jeveasset.gui.tabs.loadout; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.FilterList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.SeparatorList; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import ca.odell.glazedlists.swing.DefaultEventTableModel; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import net.nikr.eve.jeveasset.Program; import net.nikr.eve.jeveasset.data.api.my.MyAsset; import net.nikr.eve.jeveasset.data.sde.Item; import net.nikr.eve.jeveasset.gui.images.Images; import net.nikr.eve.jeveasset.gui.shared.CaseInsensitiveComparator; import net.nikr.eve.jeveasset.gui.shared.JOptionInput; import net.nikr.eve.jeveasset.gui.shared.components.JCustomFileChooser; import net.nikr.eve.jeveasset.gui.shared.components.JDropDownButton; import net.nikr.eve.jeveasset.gui.shared.components.JFixedToolBar; import net.nikr.eve.jeveasset.gui.shared.components.JMainTabSecondary; import net.nikr.eve.jeveasset.gui.shared.components.JTextDialog; import net.nikr.eve.jeveasset.gui.shared.components.ListComboBoxModel; import net.nikr.eve.jeveasset.gui.shared.filter.ExportDialog; import net.nikr.eve.jeveasset.gui.shared.filter.ExportFilterControl; import net.nikr.eve.jeveasset.gui.shared.menu.*; import net.nikr.eve.jeveasset.gui.shared.menu.MenuManager.TableMenu; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableColumn; import net.nikr.eve.jeveasset.gui.shared.table.EnumTableFormatAdaptor; import net.nikr.eve.jeveasset.gui.shared.table.EventListManager; import net.nikr.eve.jeveasset.gui.shared.table.EventModels; import net.nikr.eve.jeveasset.gui.shared.table.JSeparatorTable; import net.nikr.eve.jeveasset.gui.shared.table.PaddingTableCellRenderer; import net.nikr.eve.jeveasset.gui.tabs.loadout.Loadout.FlagType; import net.nikr.eve.jeveasset.i18n.General; import net.nikr.eve.jeveasset.i18n.GuiShared; import net.nikr.eve.jeveasset.i18n.TabsLoadout; import net.nikr.eve.jeveasset.io.local.EveFittingWriter; import net.nikr.eve.jeveasset.io.shared.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LoadoutsTab extends JMainTabSecondary { private static final Logger LOG = LoggerFactory.getLogger(LoadoutsTab.class); private enum LoadoutsAction { FILTER, OWNERS, EXPORT, EXPORT_EVE_SELECTED, EXPORT_EVE_ALL, EXPORT_EFT, COLLAPSE, EXPAND } private static final String SHIP_CATEGORY = "Ship"; //GUI private final JComboBox<String> jOwners; private final JComboBox<String> jShips; private final JButton jExpand; private final JButton jCollapse; private final JSeparatorTable jTable; private final JDropDownButton jExport; private final LoadoutsExportDialog loadoutsExportDialog; private final JCustomFileChooser jXmlFileChooser; private final JTextDialog jEftDialog; //Table private final EventList<Loadout> eventList; private final FilterList<Loadout> filterList; private final SeparatorList<Loadout> separatorList; private final DefaultEventSelectionModel<Loadout> selectionModel; private final DefaultEventTableModel<Loadout> tableModel; private final EnumTableFormatAdaptor<LoadoutTableFormat, Loadout> tableFormat; //Dialog ExportDialog<Loadout> exportDialog; public static final String NAME = "loadouts"; //Not to be changed! public LoadoutsTab(final Program program) { super(program, TabsLoadout.get().ship(), Images.TOOL_SHIP_LOADOUTS.getIcon(), true); loadoutsExportDialog = new LoadoutsExportDialog(program, this); ListenerClass listener = new ListenerClass(); jXmlFileChooser = JCustomFileChooser.createFileChooser(program.getMainWindow().getFrame(), "xml"); jEftDialog = new JTextDialog(program.getMainWindow().getFrame()); JFixedToolBar jToolBarTop = new JFixedToolBar(); JLabel jOwnersLabel = new JLabel(TabsLoadout.get().owner()); jToolBarTop.add(jOwnersLabel); jOwners = new JComboBox<>(); jOwners.setActionCommand(LoadoutsAction.OWNERS.name()); jOwners.addActionListener(listener); jToolBarTop.addComboBox(jOwners, 200); JLabel jShipsLabel = new JLabel(TabsLoadout.get().ship1()); jToolBarTop.add(jShipsLabel); jShips = new JComboBox<>(); jShips.setActionCommand(LoadoutsAction.FILTER.name()); jShips.addActionListener(listener); jToolBarTop.addComboBox(jShips, 0); JFixedToolBar jToolBarLeft = new JFixedToolBar(); jExport = new JDropDownButton(GuiShared.get().export(), Images.DIALOG_CSV_EXPORT.getIcon()); jToolBarLeft.addButton(jExport); JMenuItem jExportSqlCsvHtml = new JMenuItem(TabsLoadout.get().exportTableData(), Images.DIALOG_CSV_EXPORT.getIcon()); jExportSqlCsvHtml.setActionCommand(LoadoutsAction.EXPORT.name()); jExportSqlCsvHtml.addActionListener(listener); jExport.add(jExportSqlCsvHtml); JMenu jMenu = new JMenu(TabsLoadout.get().exportEveXml()); jMenu.setIcon(Images.MISC_EVE.getIcon()); jExport.add(jMenu); JMenuItem jExportEveXml = new JMenuItem(TabsLoadout.get().exportEveXmlSelected()); jExportEveXml.setActionCommand(LoadoutsAction.EXPORT_EVE_SELECTED.name()); jExportEveXml.addActionListener(listener); jMenu.add(jExportEveXml); JMenuItem jExportEveXmlAll = new JMenuItem(TabsLoadout.get().exportEveXmlAll()); jExportEveXmlAll.setActionCommand(LoadoutsAction.EXPORT_EVE_ALL.name()); jExportEveXmlAll.addActionListener(listener); jMenu.add(jExportEveXmlAll); JMenuItem jExportEft = new JMenuItem(TabsLoadout.get().exportEft()); jExportEft.setActionCommand(LoadoutsAction.EXPORT_EFT.name()); jExportEft.addActionListener(listener); jExportEft.setIcon(Images.TOOL_SHIP_LOADOUTS.getIcon()); jExport.add(jExportEft); JFixedToolBar jToolBarRight = new JFixedToolBar(); jCollapse = new JButton(TabsLoadout.get().collapse(), Images.MISC_COLLAPSED.getIcon()); jCollapse.setActionCommand(LoadoutsAction.COLLAPSE.name()); jCollapse.addActionListener(listener); jToolBarRight.addButton(jCollapse); jExpand = new JButton(TabsLoadout.get().expand(), Images.MISC_EXPANDED.getIcon()); jExpand.setActionCommand(LoadoutsAction.EXPAND.name()); jExpand.addActionListener(listener); jToolBarRight.addButton(jExpand); //Table Format tableFormat = new EnumTableFormatAdaptor<>(LoadoutTableFormat.class); //Backend eventList = EventListManager.create(); //Filter eventList.getReadWriteLock().readLock().lock(); filterList = new FilterList<>(eventList); eventList.getReadWriteLock().readLock().unlock(); //Separator separatorList = new SeparatorList<>(filterList, new LoadoutSeparatorComparator(), 1, Integer.MAX_VALUE); //Table Model tableModel = EventModels.createTableModel(separatorList, tableFormat); //Table jTable = new JSeparatorTable(program, tableModel, separatorList); jTable.setSeparatorRenderer(new LoadoutSeparatorTableCell(jTable, separatorList)); jTable.setSeparatorEditor(new LoadoutSeparatorTableCell(jTable, separatorList)); PaddingTableCellRenderer.install(jTable, 3); //Selection Model selectionModel = EventModels.createSelectionModel(separatorList); selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); jTable.setSelectionModel(selectionModel); //Listeners installTable(jTable, NAME); //Scroll JScrollPane jTableScroll = new JScrollPane(jTable); //Menu installMenu(program, new LoadoutTableMenu(), jTable, Loadout.class); List<EnumTableColumn<Loadout>> enumColumns = new ArrayList<>(); enumColumns.addAll(Arrays.asList(LoadoutExtendedTableFormat.values())); enumColumns.addAll(Arrays.asList(LoadoutTableFormat.values())); List<EventList<Loadout>> eventLists = new ArrayList<>(); eventLists.add(filterList); exportDialog = new ExportDialog<>(program.getMainWindow().getFrame(), NAME, null, new LoadoutsFilterControl(), eventLists, enumColumns); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(jToolBarTop, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(jToolBarLeft, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, Integer.MAX_VALUE) .addGap(0) .addComponent(jToolBarRight) ) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createSequentialGroup() .addComponent(jToolBarTop, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(jToolBarLeft, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(jToolBarRight, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ) .addComponent(jTableScroll, 0, 0, Short.MAX_VALUE) ); } @Override public void updateData() { if (!program.getOwnerNames(false).isEmpty()) { jOwners.setEnabled(true); String selectedItem = (String) jOwners.getSelectedItem(); jOwners.setModel(new ListComboBoxModel<>(program.getOwnerNames(true))); if (selectedItem != null && program.getOwnerNames(true).contains(selectedItem)) { jOwners.setSelectedItem(selectedItem); } else { jOwners.setSelectedIndex(0); } } else { jOwners.setEnabled(false); jOwners.setModel(new ListComboBoxModel<>()); jOwners.getModel().setSelectedItem(TabsLoadout.get().no()); jShips.setModel(new ListComboBoxModel<>()); jShips.getModel().setSelectedItem(TabsLoadout.get().no()); } updateTable(); } @Override public void clearData() { try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); } finally { eventList.getReadWriteLock().writeLock().unlock(); } } @Override public void updateCache() { } private String browse() { File windows = new File(javax.swing.filechooser.FileSystemView.getFileSystemView().getDefaultDirectory() + File.separator + "EVE" + File.separator + "fittings" ); File mac = new File(System.getProperty("user.home", ".") + File.separator + "Library" + File.separator + "Preferences" + File.separator + "EVE Online Preferences" + File.separator + "p_drive" + File.separator + "My Documents" + File.separator + "EVE" + File.separator + "fittings" ); LOG.info("Mac Browsing: {}", mac.getAbsolutePath()); if (windows.exists()) { //Windows jXmlFileChooser.setCurrentDirectory(windows); } else if (mac.exists()) { //Mac //PENDING TEST if fittings path is set correct on mac // should open: ~library/preferences/eve online preferences/p_drive/my documents/eve/overview jXmlFileChooser.setCurrentDirectory(mac); } else { //Others: use program directory is there is only Win & Mac clients jXmlFileChooser.setCurrentDirectory(new File(FileUtil.getUserDirectory())); } int bFound = jXmlFileChooser.showSaveDialog(program.getMainWindow().getFrame()); if (bFound == JFileChooser.APPROVE_OPTION) { File file = jXmlFileChooser.getSelectedFile(); return file.getAbsolutePath(); } else { return null; } } public void exportXml() { String fitName = loadoutsExportDialog.getFittingName(); String fitDescription = loadoutsExportDialog.getFittingDescription(); if (!fitName.isEmpty()) { String selectedShip = (String) jShips.getSelectedItem(); MyAsset exportAsset = null; for (MyAsset asset : program.getAssetList()) { String key = asset.getName() + " #" + asset.getItemID(); if (selectedShip.equals(key)) { exportAsset = asset; break; } } loadoutsExportDialog.setVisible(false); if (exportAsset == null) { return; } String filename = browse(); if (filename != null) { EveFittingWriter.save(Collections.singletonList(exportAsset), filename, fitName, fitDescription); } } else { JOptionPane.showMessageDialog(loadoutsExportDialog.getDialog(), TabsLoadout.get().name1(), TabsLoadout.get().empty(), JOptionPane.PLAIN_MESSAGE); } } private void exportEFT() { String selectedShip = (String) jShips.getSelectedItem(); MyAsset exportAsset = null; for (MyAsset asset : program.getAssetList()) { String key = asset.getName() + " #" + asset.getItemID(); if (selectedShip.equals(key)) { exportAsset = asset; break; } } if (exportAsset == null) { return; } String buildName = getBuildName(); if (buildName == null) { return; //Cancel } Map<String, Long> droneBay = new HashMap<>(); Map<String, Long> cargo = new HashMap<>(); Map<String, Map<Integer, String>> modulesByFlag = new HashMap<>(); for (MyAsset asset : exportAsset.getAssets()) { if (asset.getFlag().equals("DroneBay")) { Long count = droneBay.get(asset.getTypeName()); if (count == null) { count = 0L; } droneBay.put(asset.getTypeName(), count + asset.getCount()); } else if (asset.getFlag().equals("Cargo")) { Long count = cargo.get(asset.getTypeName()); if (count == null) { count = 0L; } cargo.put(asset.getTypeName(), count + asset.getCount()); } else { String flag = asset.getFlag().replaceAll("\\d", ""); int index; try { index = Integer.valueOf(asset.getFlag().replaceAll("\\D", "")); } catch (NumberFormatException ex) { continue; } Map<Integer, String> modules = modulesByFlag.get(flag); if (modules == null) { modules = new HashMap<>(); modulesByFlag.put(flag, modules); } if (asset.getCount() > 1) { modules.put(index, asset.getTypeName() + " x" + asset.getCount() + "\r\n"); } else { modules.put(index, asset.getTypeName() + "\r\n"); } } } StringBuilder builder = new StringBuilder(); //Type and Name builder.append("["); builder.append(exportAsset.getTypeName()); builder.append(", "); builder.append(buildName); builder.append("]\r\n"); writeModuls(builder, modulesByFlag.get("LoSlot")); writeModuls(builder, modulesByFlag.get("MedSlot")); writeModuls(builder, modulesByFlag.get("HiSlot")); writeModuls(builder, modulesByFlag.get("RigSlot")); writeModuls(builder, modulesByFlag.get("SubSystem")); writeCount(builder, droneBay); writeCount(builder, cargo); jEftDialog.exportText(builder.toString()); } private void writeModuls(StringBuilder builder, Map<Integer, String> modules) { if (modules == null || modules.isEmpty()) { return; } builder.append("\r\n"); for (String module : modules.values()) { builder.append(module); } } private void writeCount(StringBuilder builder, Map<String, Long> modules) { if (modules == null || modules.isEmpty()) { return; } builder.append("\r\n"); for (Map.Entry<String, Long> entry : modules.entrySet()) { if (entry.getValue() > 1) { builder.append(entry.getKey()); builder.append(" x"); builder.append(entry.getValue()); builder.append("\r\n"); } else { builder.append(entry.getKey()); } } } private String getBuildName() { String buildName = JOptionInput.showInputDialog(program.getMainWindow().getFrame(), "Enter Build Name", "Export EFT", JOptionPane.PLAIN_MESSAGE); if (buildName == null) { return null; //Cancel } else if (buildName.isEmpty()) { JOptionPane.showMessageDialog(program.getMainWindow().getFrame(), TabsLoadout.get().name1(), TabsLoadout.get().empty(), JOptionPane.PLAIN_MESSAGE); return getBuildName(); } else { return buildName; } } private void updateTable() { List<Loadout> ship = new ArrayList<>(); for (MyAsset asset : program.getAssetList()) { String key = asset.getName() + " #" + asset.getItemID(); if (!asset.getItem().getCategory().equals(SHIP_CATEGORY) || !asset.isSingleton()) { continue; } Loadout moduleShip = new Loadout(asset.getItem(), asset.getLocation(), asset.getOwner(), TabsLoadout.get().totalShip(), key, TabsLoadout.get().flagTotalValue(), null, asset.getDynamicPrice(), 1, true); Loadout moduleModules = new Loadout(new Item(0), asset.getLocation(), asset.getOwner(), TabsLoadout.get().totalModules(), key, TabsLoadout.get().flagTotalValue(), null, 0, 0, false); Loadout moduleTotal = new Loadout(new Item(0), asset.getLocation(), asset.getOwner(), TabsLoadout.get().totalAll(), key, TabsLoadout.get().flagTotalValue(), null, asset.getDynamicPrice(), 1, false); ship.add(moduleShip); ship.add(moduleModules); ship.add(moduleTotal); Map<Integer, Loadout> modules = new HashMap<>(); for (MyAsset assetModule : asset.getAssets()) { Loadout module = modules.get(assetModule.getTypeID()); if (module == null //New || assetModule.getFlag().contains(FlagType.HIGH_SLOT.getFlag()) || assetModule.getFlag().contains(FlagType.MEDIUM_SLOT.getFlag()) || assetModule.getFlag().contains(FlagType.LOW_SLOT.getFlag()) || assetModule.getFlag().contains(FlagType.RIG_SLOTS.getFlag()) || assetModule.getFlag().contains(FlagType.SUB_SYSTEMS.getFlag()) ) { module = new Loadout(assetModule.getItem(), assetModule.getLocation(), assetModule.getOwner(), assetModule.getName(), key, assetModule.getFlag(), assetModule.getDynamicPrice(), (assetModule.getDynamicPrice() * assetModule.getCount()), assetModule.getCount(), false); modules.put(assetModule.getTypeID(), module); ship.add(module); } else { //Add count module.addCount(assetModule.getCount()); module.addValue(assetModule.getDynamicPrice() * assetModule.getCount()); } moduleModules.addValue(assetModule.getDynamicPrice() * assetModule.getCount()); moduleModules.addCount(assetModule.getCount()); moduleTotal.addValue(assetModule.getDynamicPrice() * assetModule.getCount()); moduleTotal.addCount(assetModule.getCount()); } } //Save separator expanded/collapsed state jTable.saveExpandedState(); //Update list try { eventList.getReadWriteLock().writeLock().lock(); eventList.clear(); eventList.addAll(ship); } finally { eventList.getReadWriteLock().writeLock().unlock(); } //Restore separator expanded/collapsed state jTable.loadExpandedState(); } private class LoadoutTableMenu implements TableMenu<Loadout> { @Override public MenuData<Loadout> getMenuData() { return new MenuData<>(selectionModel.getSelected()); } @Override public JMenu getFilterMenu() { return null; } @Override public JMenu getColumnMenu() { return tableFormat.getMenu(program, tableModel, jTable, NAME); } @Override public void addInfoMenu(JComponent jComponent) { JMenuInfo.module(jComponent, selectionModel.getSelected()); } @Override public void addToolMenu(JComponent jComponent) { } } private class ListenerClass implements ActionListener { @Override public void actionPerformed(final ActionEvent e) { if (LoadoutsAction.OWNERS.name().equals(e.getActionCommand())) { String owner = (String) jOwners.getSelectedItem(); List<String> charShips = new ArrayList<>(); for (MyAsset asset : program.getAssetList()) { String key = asset.getName() + " #" + asset.getItemID(); if (!asset.getItem().getCategory().equals(SHIP_CATEGORY) || !asset.isSingleton()) { continue; } if (!owner.equals(asset.getOwnerName()) && !owner.equals(General.get().all())) { continue; } charShips.add(key); } if (!charShips.isEmpty()) { Collections.sort(charShips, new CaseInsensitiveComparator()); jExpand.setEnabled(true); jCollapse.setEnabled(true); jExport.setEnabled(true); jOwners.setEnabled(true); jShips.setEnabled(true); String selectedItem = (String) jShips.getSelectedItem(); jShips.setModel(new ListComboBoxModel<>(charShips)); if (selectedItem != null && charShips.contains(selectedItem)) { jShips.setSelectedItem(selectedItem); } else { jShips.setSelectedIndex(0); } } else { jExpand.setEnabled(false); jCollapse.setEnabled(false); jExport.setEnabled(false); jShips.setEnabled(false); jShips.setModel(new ListComboBoxModel<>()); jShips.getModel().setSelectedItem(TabsLoadout.get().no1()); } } else if (LoadoutsAction.FILTER.name().equals(e.getActionCommand())) { String selectedShip = (String) jShips.getSelectedItem(); filterList.setMatcher(new Loadout.LoadoutMatcher(selectedShip)); } else if (LoadoutsAction.COLLAPSE.name().equals(e.getActionCommand())) { jTable.expandSeparators(false); } else if (LoadoutsAction.EXPAND.name().equals(e.getActionCommand())) { jTable.expandSeparators(true); } else if (LoadoutsAction.EXPORT_EVE_SELECTED.name().equals(e.getActionCommand())) { loadoutsExportDialog.setVisible(true); } else if (LoadoutsAction.EXPORT_EVE_ALL.name().equals(e.getActionCommand())) { String filename = browse(); List<MyAsset> ships = new ArrayList<>(); for (MyAsset asset : program.getAssetList()) { if (!asset.getItem().getCategory().equals(SHIP_CATEGORY) || !asset.isSingleton() || asset.getAssets().isEmpty()) { continue; } ships.add(asset); } if (filename != null) { EveFittingWriter.save(new ArrayList<>(ships), filename); } } else if (LoadoutsAction.EXPORT_EFT.name().equals(e.getActionCommand())) { exportEFT(); } else if (LoadoutsAction.EXPORT.name().equals(e.getActionCommand())) { exportDialog.setVisible(true); } } } private class LoadoutsFilterControl extends ExportFilterControl<Loadout> { @Override protected EnumTableColumn<?> valueOf(final String column) { try { return LoadoutTableFormat.valueOf(column); } catch (IllegalArgumentException exception) { } try { return LoadoutExtendedTableFormat.valueOf(column); } catch (IllegalArgumentException exception) { } throw new RuntimeException("Fail to parse filter column: " + column); } @Override protected List<EnumTableColumn<Loadout>> getShownColumns() { return new ArrayList<>(tableFormat.getShownColumns()); } @Override protected void saveSettings(final String msg) { program.saveSettings("Ship Loudouts Table: " + msg); //Save Ship Loudout Export Setttings (Filters not used) } } }