diff --git a/megamek/i18n/megamek/client/messages.properties b/megamek/i18n/megamek/client/messages.properties index 74e35376313..0c3d2477ca6 100644 --- a/megamek/i18n/megamek/client/messages.properties +++ b/megamek/i18n/megamek/client/messages.properties @@ -2162,6 +2162,7 @@ MekSelectorDialog.Search.ArmorType=Armor Type: MekSelectorDialog.Search.Any=Any MekSelectorDialog.Search.or=Or MekSelectorDialog.Search.and=And +MekSelectorDialog.Search.Combine=Note: TW and AS search filters can be used at the same time! MekSelectorDialog.Search.AtLeast=at least MekSelectorDialog.Search.EqualTo=equal to MekSelectorDialog.Search.NoMoreThan=no more than @@ -2174,7 +2175,7 @@ MekSelectorDialog.Search.Armor25=25% of maximum MekSelectorDialog.Search.Armor50=50% of maximum MekSelectorDialog.Search.Armor75=75% of maximum MekSelectorDialog.Search.Armor90=90% of maximum -MekSelectorDialog.Search.WeaponClass=Weapon Type +MekSelectorDialog.Search.WeaponClass=Equipment Group MekSelectorDialog.Search.Weapons=Weapons MekSelectorDialog.Search.Equipment=Equipment MekSelectorDialog.Search.Year=Design year: diff --git a/megamek/src/megamek/client/ui/advancedsearch/ASAdvancedSearchPanel.java b/megamek/src/megamek/client/ui/advancedsearch/ASAdvancedSearchPanel.java index bc2b37d913f..29dee41b274 100644 --- a/megamek/src/megamek/client/ui/advancedsearch/ASAdvancedSearchPanel.java +++ b/megamek/src/megamek/client/ui/advancedsearch/ASAdvancedSearchPanel.java @@ -571,6 +571,7 @@ private void updateEnabled() { pvTo.setEnabled(usePV.isSelected()); mvBetween.setEnabled(useMV.isSelected()); + mvMode.setEnabled(useMV.isSelected()); mvFrom.setEnabled(useMV.isSelected()); mvAnd.setEnabled(useMV.isSelected()); mvTo.setEnabled(useMV.isSelected()); diff --git a/megamek/src/megamek/client/ui/advancedsearch/AdvancedSearchDialog2.java b/megamek/src/megamek/client/ui/advancedsearch/AdvancedSearchDialog2.java index 6f46b8e51bc..2bd98d2cc28 100644 --- a/megamek/src/megamek/client/ui/advancedsearch/AdvancedSearchDialog2.java +++ b/megamek/src/megamek/client/ui/advancedsearch/AdvancedSearchDialog2.java @@ -18,6 +18,10 @@ */ package megamek.client.ui.advancedsearch; +import com.formdev.flatlaf.FlatClientProperties; +import com.formdev.flatlaf.FlatIconColors; +import com.formdev.flatlaf.extras.FlatSVGIcon; +import com.formdev.flatlaf.extras.components.FlatButton; import megamek.client.ui.Messages; import megamek.client.ui.baseComponents.AbstractButtonDialog; import megamek.client.ui.swing.ButtonEsc; @@ -45,7 +49,7 @@ public AdvancedSearchDialog2(JFrame parent, int allowedYear) { year = allowedYear; totalWarTab = new TWAdvancedSearchPanel(year); advancedSearchPane.addTab("Total Warfare", totalWarTab); - advancedSearchPane.addTab("Alpha Strike", alphaStrikeTab); + advancedSearchPane.addTab("Alpha Strike", new TWAdvancedSearchPanel.StandardScrollPane(alphaStrikeTab)); initialize(); } @@ -74,13 +78,24 @@ protected JPanel createButtonPanel() { okButton.addActionListener(this::okButtonActionPerformed); getRootPane().setDefaultButton(okButton); + JPanel notePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + notePanel.add(Box.createHorizontalStrut(20)); + var noteLabel = new JLabel(Messages.getString("MekSelectorDialog.Search.Combine")); + noteLabel.putClientProperty(FlatClientProperties.STYLE, "foreground: mix($Label.foreground, #afa, 60%)"); + notePanel.add(noteLabel); + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 20, 0)); - buttonPanel.setBorder(BorderFactory.createCompoundBorder( - new MatteBorder(1, 0, 0, 0, UIManager.getColor("Separator.foreground")), - new EmptyBorder(10, 0, 10, 0))); buttonPanel.add(okButton); buttonPanel.add(cancelButton); - return buttonPanel; + + JPanel outerPanel = new JPanel(new GridLayout(1,1)); + outerPanel.setBorder(BorderFactory.createCompoundBorder( + new MatteBorder(1, 0, 0, 0, UIManager.getColor("Separator.foreground")), + new EmptyBorder(10, 0, 10, 0))); + outerPanel.add(notePanel); + outerPanel.add(buttonPanel); + + return outerPanel; } @Override diff --git a/megamek/src/megamek/client/ui/advancedsearch/AdvancedSearchEquipmentClass.java b/megamek/src/megamek/client/ui/advancedsearch/AdvancedSearchEquipmentClass.java new file mode 100644 index 00000000000..568cebc7e35 --- /dev/null +++ b/megamek/src/megamek/client/ui/advancedsearch/AdvancedSearchEquipmentClass.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek 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 3 of the License, or + * (at your option) any later version. + * + * MegaMek 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 MegaMek. If not, see . + */ +package megamek.client.ui.advancedsearch; + +import java.util.Locale; + +enum AdvancedSearchEquipmentClass { + EMPTY, AUTOCANNON, RAC, ULTRA, LIGHT, MACHINE_GUN, GAUSS, BALLISTIC, PLASMA, ENERGY, LASER, PULSE, RE_ENGINEERED, PPC, TASER, FLAMER, MISSILE, + LRM, MRM, SRM, PHYSICAL, AMS, PRACTICAL_PHYSICAL, INFANTRY_SUIT, PROBE; + + public boolean matches(String name) { + if (this == EMPTY) { + return true; + } + name = name.toLowerCase(Locale.ROOT); + if (name.contains("ammo")) { + return false; + } + if (this == PHYSICAL) { + return name.contains("backhoe") || name.contains("saw") || name.contains("whip") || name.contains("claw") || + name.contains("combine") || name.contains("flail") || name.contains("hatchet") || name.contains("driver") || + name.contains("lance") || name.contains("mace") || name.contains("drill") || name.contains("ram") || + name.contains("blade") || name.contains("cutter") || name.contains("shield") || name.contains("welder") || + name.contains("sword") || name.contains("talons") || name.contains("wrecking"); + } else if (this == PRACTICAL_PHYSICAL) { + return name.contains("claw") || name.contains("flail") || name.contains("hatchet") || name.contains("lance") + || name.contains("mace") || name.contains("blade") || name.contains("shield") || name.contains("sword") + || name.contains("talons"); + } else if (this == MISSILE) { + return name.contains("lrm") || name.contains("mrm") || name.contains("srm"); + } else if (this == RE_ENGINEERED) { + return name.contains("engineered"); + } else if (this == ENERGY) { + return LASER.matches(name) || PPC.matches(name) || FLAMER.matches(name); + } else if (this == MACHINE_GUN) { + return (name.contains("mg") || name.contains("machine")) && !name.contains("ammo"); + } else if (this == BALLISTIC) { + return AUTOCANNON.matches(name) || GAUSS.matches(name) || MACHINE_GUN.matches(name); + } else if (this == RAC) { + return name.contains("rotary"); + } else if (this == ULTRA) { + return name.contains("ultraa"); + } else if (this == INFANTRY_SUIT) { + return (name.contains("suit") || name.contains(" kit") || name.contains(", standard") || name.contains(", concealed") + || name.contains("clothing") || name.contains("vest") || name.contains("chainmail") || name.contains("parka")) + && !name.contains("ecm") && !name.contains("generic") && !name.contains("suite"); + } else if (this == AMS) { + return name.contains("ams") || name.contains("antimiss"); + } else if (this == PROBE) { + return name.contains("probe"); + } else if (name.contains(name().toLowerCase(Locale.ROOT)) && !name.contains("ammo")) { + return true; + } + return false; + } + + @Override + public String toString() { + return switch (this) { + case EMPTY -> ""; + case AUTOCANNON -> "Autocannon"; + case ULTRA -> "Ultra A/C"; + case LIGHT -> "Light A/C"; + case MACHINE_GUN -> "Machine Gun"; + case GAUSS -> "Gauss"; + case BALLISTIC -> "Ballistic"; + case PLASMA -> "Plasma"; + case ENERGY -> "Energy"; + case LASER -> "Laser"; + case PULSE -> "Pulse Laser"; + case RE_ENGINEERED -> "Re-Engineered Laser"; + case PPC -> "PPC"; + case TASER -> "Taser"; + case FLAMER -> "Flamer"; + case MISSILE -> "Missile"; + case PHYSICAL -> "Physical (inc. industrial equipment)"; + case PRACTICAL_PHYSICAL -> "Physical (weapons only)"; + case INFANTRY_SUIT -> "Infantry Armor Suits"; + case PROBE -> "Active Probes"; + default -> super.toString(); + }; + } +} diff --git a/megamek/src/megamek/client/ui/advancedsearch/MekSearchFilter.java b/megamek/src/megamek/client/ui/advancedsearch/MekSearchFilter.java index 657fd8ef067..490fcd74c9c 100644 --- a/megamek/src/megamek/client/ui/advancedsearch/MekSearchFilter.java +++ b/megamek/src/megamek/client/ui/advancedsearch/MekSearchFilter.java @@ -331,7 +331,7 @@ private ExpNode createFTFromTokensRecursively(Iterator toks, ExpNod currNode = new ExpNode(); } - ExpNode newChild = new ExpNode(ft.weaponClass, ft.qty, ft.atleast); + ExpNode newChild = new ExpNode(ft.equipmentClass, ft.qty, ft.atleast); currNode.children.add(newChild); return createFTFromTokensRecursively(toks, currNode); } @@ -969,7 +969,7 @@ private boolean evaluate(List eq, List qty, ExpNode n) { // Base Case: See if any of the equipment matches the leaf node in // sufficient quantity if (n.children.isEmpty()) { - if (n.weaponClass != null) { + if (n.equipmentClass != null) { // Since weapon classes can match across different types of equipment, we have // to sum up // all equipment that matches the weaponClass value. @@ -981,7 +981,7 @@ private boolean evaluate(List eq, List qty, ExpNode n) { // Now, stream that map, filtering on a match with the WeaponClass, then extract // the quantities and sum them up. int total = nameQtyPairs.stream() - .filter(p -> n.weaponClass.matches(p.getKey())) + .filter(p -> n.equipmentClass.matches(p.getKey())) .map(Map.Entry::getValue) .reduce(0, Integer::sum); @@ -1088,7 +1088,7 @@ public static class ExpNode { public ExpNode parent; public BoolOp operation; public String name; - public WeaponClass weaponClass; + public AdvancedSearchEquipmentClass equipmentClass; public int qty; public List children; public boolean atleast; @@ -1111,7 +1111,7 @@ public ExpNode(ExpNode e) { // if (e.name != null) { name = e.name; // } - weaponClass = e.weaponClass; + equipmentClass = e.equipmentClass; Iterator nodeIter = e.children.iterator(); children = new LinkedList<>(); while (nodeIter.hasNext()) { @@ -1122,17 +1122,17 @@ public ExpNode(ExpNode e) { public ExpNode(String n, int q, boolean atleast) { parent = null; name = n; - weaponClass = null; + equipmentClass = null; qty = q; operation = BoolOp.NOP; children = new LinkedList<>(); this.atleast = atleast; } - public ExpNode(WeaponClass n, int q, boolean atleast) { + public ExpNode(AdvancedSearchEquipmentClass n, int q, boolean atleast) { parent = null; name = null; - weaponClass = n; + equipmentClass = n; qty = q; operation = BoolOp.NOP; children = new LinkedList<>(); @@ -1149,11 +1149,11 @@ public String toString() { } else { return qty + " " + name + "s"; } - } else if (weaponClass != null) { + } else if (equipmentClass != null) { if (qty == 1) { - return qty + " " + weaponClass.toString(); + return qty + " " + equipmentClass.toString(); } else { - return qty + " " + weaponClass.toString() + "s"; + return qty + " " + equipmentClass.toString() + "s"; } } } diff --git a/megamek/src/megamek/client/ui/advancedsearch/QuirksSearchTab.java b/megamek/src/megamek/client/ui/advancedsearch/QuirksSearchTab.java index 0982e7fd925..639324b7c61 100644 --- a/megamek/src/megamek/client/ui/advancedsearch/QuirksSearchTab.java +++ b/megamek/src/megamek/client/ui/advancedsearch/QuirksSearchTab.java @@ -48,7 +48,7 @@ class QuirksSearchTab extends JPanel { listWeaponQuirkType = new TriStateItemList(new WeaponQuirks(), 17); JPanel unitQuirksPanel = new JPanel(new BorderLayout()); - JPanel quirkIEPanel = new JPanel(new FlowLayout()); + JPanel quirkIEPanel = new JPanel(); quirkIEPanel.add(new JLabel(Messages.getString("MekSelectorDialog.Search.Quirk"))); quirkIEPanel.add(Box.createHorizontalStrut(15)); quirkIEPanel.add(new JLabel("\u2611")); @@ -57,9 +57,12 @@ class QuirksSearchTab extends JPanel { quirkIEPanel.add(cQuirkExclude); unitQuirksPanel.add(quirkIEPanel, BorderLayout.NORTH); unitQuirksPanel.add(new JScrollPane(listQuirkType.getComponent()), BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + buttonPanel.add(btnQuirksClear); + unitQuirksPanel.add(buttonPanel, BorderLayout.SOUTH); JPanel weaponQuirkPanel = new JPanel(new BorderLayout()); - JPanel weaponQuirkIEPanel = new JPanel(new FlowLayout()); + JPanel weaponQuirkIEPanel = new JPanel(); weaponQuirkIEPanel.add(new JLabel(Messages.getString("MekSelectorDialog.Search.WeaponQuirk"))); weaponQuirkIEPanel.add(Box.createHorizontalStrut(15)); weaponQuirkIEPanel.add(new JLabel("\u2611")); diff --git a/megamek/src/megamek/client/ui/advancedsearch/WeaponClass.java b/megamek/src/megamek/client/ui/advancedsearch/WeaponClass.java deleted file mode 100644 index 3ce1377c355..00000000000 --- a/megamek/src/megamek/client/ui/advancedsearch/WeaponClass.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. - * - * This file is part of MegaMek. - * - * MegaMek 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 3 of the License, or - * (at your option) any later version. - * - * MegaMek 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 MegaMek. If not, see . - */ -package megamek.client.ui.advancedsearch; - -enum WeaponClass { - AUTOCANNON { - public String toString() { - return "Autocannon"; - } - }, - RAC, - ULTRA { - public String toString() { - return "Ultra A/C"; - } - }, - LIGHT { - public String toString() { - return "Light A/C"; - } - }, - MACHINE_GUN { - public String toString() { - return "Machine Gun"; - } - }, - GAUSS { - public String toString() { - return "Gauss"; - } - }, - BALLISTIC { - public String toString() { - return "Ballistic"; - } - }, - PLASMA { - public String toString() { - return "Plasma"; - } - }, - ENERGY { - public String toString() { - return "Energy"; - } - }, - LASER { - public String toString() { - return "Laser"; - } - }, - PULSE { - public String toString() { - return "Pulse Laser"; - } - }, - RE_ENGINEERED { - public String toString() { - return "Re-Engineered Laser"; - } - }, - PPC { - public String toString() { - return "PPC"; - } - }, - TASER { - public String toString() { - return "Taser"; - } - }, - FLAMER { - public String toString() { - return "Flamer"; - } - }, - MISSILE { - public String toString() { - return "Missile"; - } - }, - LRM, - MRM, - SRM, - PHYSICAL { - public String toString() { - return "Physical (inc. industrial equipment)"; - } - }, - AMS, - PRACTICAL_PHYSICAL { - public String toString() { - return "Physical (weapons only)"; - } - }; - - public boolean matches(String name) { - if (name.toLowerCase().contains("ammo")) { - return false; - } - if (this == PHYSICAL) { - String lName = name.toLowerCase(); - - if (lName.contains("backhoe") || - lName.contains("saw") || - lName.contains("whip") || - lName.contains("claw") || - lName.contains("combine") || - lName.contains("flail") || - lName.contains("hatchet") || - lName.contains("driver") || - lName.contains("lance") || - lName.contains("mace") || - lName.contains("drill") || - lName.contains("ram") || - lName.contains("blade") || - lName.contains("cutter") || - lName.contains("shield") || - lName.contains("welder") || - lName.contains("sword") || - lName.contains("talons") || - lName.contains("wrecking")) { - return true; - } - } else if (this == PRACTICAL_PHYSICAL) { - String lName = name.toLowerCase(); - - if (lName.contains("claw") || - lName.contains("flail") || - lName.contains("hatchet") || - lName.contains("lance") || - lName.contains("mace") || - lName.contains("blade") || - lName.contains("shield") || - lName.contains("sword") || - lName.contains("talons")) { - return true; - } - } else if (this == MISSILE) { - if ((name.toLowerCase().contains("lrm") || - name.toLowerCase().contains("mrm") || - name.toLowerCase().contains("srm")) && - !name.toLowerCase().contains("ammo")) { - return true; - } - } else if (this == RE_ENGINEERED) { - if (name.toLowerCase().contains("engineered")) { - return true; - } - } else if (this == ENERGY) { - if (WeaponClass.LASER.matches(name) || WeaponClass.PPC.matches(name) || WeaponClass.FLAMER.matches(name)) { - return true; - } - } else if (this == MACHINE_GUN) { - if ((name.toLowerCase().contains("mg") || name.toLowerCase().contains("machine")) && !name.toLowerCase().contains("ammo")) { - return true; - } - } else if (this == BALLISTIC) { - return WeaponClass.AUTOCANNON.matches(name) || - WeaponClass.GAUSS.matches(name) || - WeaponClass.MACHINE_GUN.matches(name); - } else if (this == RAC) { - if (name.toLowerCase().contains("rotary")) { - return true; - } - } else if (this == ULTRA) { - if (name.toLowerCase().contains("ultraa")) { - return true; - } - } else if (name.toLowerCase().contains(name().toLowerCase()) && !name.toLowerCase().contains("ammo")) { - return true; - } - return false; - } -} diff --git a/megamek/src/megamek/client/ui/advancedsearch/WeaponClassFT.java b/megamek/src/megamek/client/ui/advancedsearch/WeaponClassFT.java index 14d0c988e1b..90a148bc44c 100644 --- a/megamek/src/megamek/client/ui/advancedsearch/WeaponClassFT.java +++ b/megamek/src/megamek/client/ui/advancedsearch/WeaponClassFT.java @@ -24,20 +24,20 @@ */ class WeaponClassFT extends EquipmentFilterToken { - WeaponClass weaponClass; + AdvancedSearchEquipmentClass equipmentClass; - WeaponClassFT(WeaponClass in_class, int in_qty) { + WeaponClassFT(AdvancedSearchEquipmentClass in_class, int in_qty) { this(in_class, in_qty, true); } - WeaponClassFT(WeaponClass in_class, int in_qty, boolean atleast) { - weaponClass = in_class; + WeaponClassFT(AdvancedSearchEquipmentClass in_class, int in_qty, boolean atleast) { + equipmentClass = in_class; qty = in_qty; this.atleast = atleast; } @Override public String toString() { - return (atleast ? "" : "less than ") + qty + " " + weaponClass.toString() + ((qty != 1) ? "s" : ""); + return (atleast ? "" : "less than ") + qty + " " + equipmentClass.toString() + ((qty != 1) ? "s" : ""); } } diff --git a/megamek/src/megamek/client/ui/advancedsearch/WeaponSearchTab.java b/megamek/src/megamek/client/ui/advancedsearch/WeaponSearchTab.java index f40a327fc28..497e4d7ea3a 100644 --- a/megamek/src/megamek/client/ui/advancedsearch/WeaponSearchTab.java +++ b/megamek/src/megamek/client/ui/advancedsearch/WeaponSearchTab.java @@ -41,24 +41,21 @@ class WeaponSearchTab extends JPanel implements KeyListener, DocumentListener, F final List filterTokens = new ArrayList<>(); - final JButton btnLeftParen = new JButton("("); - final JButton btnRightParen = new JButton(")"); - final JToggleButton btnLessThan = new JToggleButton("<"); - final JToggleButton btnAtLeast = new JToggleButton("\u2265"); - final JButton btnAdd = new JButton(Messages.getString("MekSelectorDialog.Search.add")); - final JButton btnAddMultiOr = new JButton("Add [OR]"); - final JButton btnAddMultiAnd = new JButton("Add [AND]"); - final JButton btnAnd = new JButton(Messages.getString("MekSelectorDialog.Search.and")); - final JButton btnOr = new JButton(Messages.getString("MekSelectorDialog.Search.or")); - final JButton btnClear = new JButton(Messages.getString("MekSelectorDialog.Reset")); - final JButton btnBack = new JButton("Back"); - final JLabel lblWEEqExpTxt = new JLabel(Messages.getString("MekSelectorDialog.Search.FilterExpression")); + private final JButton btnLeftParen = new JButton("("); + private final JButton btnRightParen = new JButton(")"); + private final JSpinner equipmentCount; + private final JToggleButton btnLessThan = new JToggleButton("<"); + private final JToggleButton btnAtLeast = new JToggleButton("\u2265"); + private final JButton btnAdd = new JButton(Messages.getString("MekSelectorDialog.Search.add")); + private final JButton btnAddMultiOr = new JButton("Add [OR]"); + private final JButton btnAddMultiAnd = new JButton("Add [AND]"); + private final JButton btnAnd = new JButton(Messages.getString("MekSelectorDialog.Search.and")); + private final JButton btnOr = new JButton(Messages.getString("MekSelectorDialog.Search.or")); + private final JButton btnClear = new JButton(Messages.getString("MekSelectorDialog.Reset")); + private final JButton btnBack = new JButton("Back"); + private final JLabel lblWEEqExpTxt = new JLabel(Messages.getString("MekSelectorDialog.Search.FilterExpression")); final JTextArea txtWEEqExp = new JTextArea("", 2, 40); - final JScrollPane expWEScroller = new JScrollPane(txtWEEqExp, - JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, - JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - final JLabel lblUnitType = new JLabel(Messages.getString("MekSelectorDialog.Search.UnitType")); private final JButton btnUnitTypeAll = new JButton("All"); private final JToggleButton btnUnitTypeMek = new JToggleButton("Mek"); private final JToggleButton btnUnitTypeVee = new JToggleButton("Veh"); @@ -69,12 +66,9 @@ class WeaponSearchTab extends JPanel implements KeyListener, DocumentListener, F private final List unitTypeButtons = List.of(btnUnitTypeMek, btnUnitTypePM, btnUnitTypeBA, btnUnitTypeCI, btnUnitTypeAero, btnUnitTypeVee); - final JLabel lblTechClass = new JLabel(Messages.getString("MekSelectorDialog.Search.TechClass")); private final JToggleButton btnTechClassIS = new JToggleButton("Inner Sphere"); private final JToggleButton btnTechClassClan = new JToggleButton("Clan"); - final JLabel lblTechLevelBase = new JLabel(Messages.getString("MekSelectorDialog.Search.TechLevel")); -// final JList techLevelSelector = new JList<>(); private final JButton btnTechLevelOfficial = new JButton("Official"); private final JToggleButton btnTechLevelIntro = new JToggleButton("Intro"); private final JToggleButton btnTechLevelStd = new JToggleButton("Standard"); @@ -84,25 +78,19 @@ class WeaponSearchTab extends JPanel implements KeyListener, DocumentListener, F private final List techLevelButtons = List.of(btnTechLevelIntro, btnTechLevelStd, btnTechLevelAdv, btnTechLevelExp, btnTechLevelUnoff); - final JLabel tableFilterTextLabel = new JLabel(Messages.getString("MekSelectorDialog.Search.TableFilter")); - final JTextField tableFilterText = new JTextField(10); + private final JTextField tableFilterText = new JTextField(10); private final JButton filterClearButton = new JButton("X"); + private final JComboBox weaponClassFilter = new JComboBox<>(AdvancedSearchEquipmentClass.values()); - final JLabel lblWeapons = new JLabel(Messages.getString("MekSelectorDialog.Search.Weapons")); - final JScrollPane scrTableWeapons = new JScrollPane(); - final SearchableTable tblWeapons; - final WeaponsTableModel weaponsModel; - final TableRowSorter weaponsSorter; + private final SearchableTable tblWeapons; + private final WeaponsTableModel weaponsModel; + private final TableRowSorter weaponsSorter; - final JLabel lblEquipment = new JLabel(Messages.getString("MekSelectorDialog.Search.Equipment")); - final JScrollPane scrTableEquipment = new JScrollPane(); - final SearchableTable tblEquipment; - final EquipmentTableModel equipmentModel; - final TableRowSorter equipmentSorter; + private final SearchableTable tblEquipment; + private final EquipmentTableModel equipmentModel; + private final TableRowSorter equipmentSorter; - final JLabel lblWeaponClass = new JLabel(Messages.getString("MekSelectorDialog.Search.WeaponClass")); - final JSpinner weaponClassCount; - final JComboBox weaponClassChooser; + private final JComboBox weaponClassChooser = new JComboBox<>(AdvancedSearchEquipmentClass.values()); private JComponent focusedSelector = null; private final TWAdvancedSearchPanel parentPanel; @@ -132,13 +120,6 @@ class WeaponSearchTab extends JPanel implements KeyListener, DocumentListener, F btnUnitTypeAll.addActionListener(e -> allUnitTypesClicked()); unitTypeButtons.forEach(button -> button.setSelected(true)); -// techLevelSelector.setLayoutOrientation(JList.HORIZONTAL_WRAP); -// techLevelSelector.setVisibleRowCount(1); -// techLevelSelector.setListData(TechConstants.T_SIMPLE_NAMES); -// techLevelSelector.setSelectedIndices(new int[]{0, 1, 2, 3}); // all except unofficial as the default selection -// techLevelSelector.addListSelectionListener(e -> filterTables()); -// techLevelSelector.setCellRenderer(new ChoiceRenderer()); - btnTechClassClan.setSelected(true); btnTechClassIS.setSelected(true); @@ -146,9 +127,7 @@ class WeaponSearchTab extends JPanel implements KeyListener, DocumentListener, F techLevelButtons.forEach(button -> button.setSelected(button != btnTechLevelUnoff)); addToggleActionListeners(); - // Set up Weapon Class chooser - weaponClassCount = new JSpinner(new SpinnerNumberModel(1, 1, 20, 1)); - weaponClassChooser = new JComboBox<>(WeaponClass.values()); + equipmentCount = new JSpinner(new SpinnerNumberModel(1, 1, 20, 1)); weaponClassChooser.addFocusListener(this); // Setup Weapons Table @@ -181,8 +160,6 @@ public Dimension getPreferredScrollableViewportSize() { tblWeapons.getColumnModel().getColumn(i).setPreferredWidth(weaponsModel.getPreferredWidth(i)); } - scrTableWeapons.setViewportView(tblWeapons); - // Setup Equipment Table equipmentModel = new EquipmentTableModel(parentPanel); tblEquipment = new SearchableTable(equipmentModel, EquipmentTableModel.COL_NAME) { @@ -207,8 +184,6 @@ public Dimension getPreferredScrollableViewportSize() { tblEquipment.getColumnModel().getColumn(1).setCellRenderer(costRenderer); tblEquipment.getColumnModel().getColumn(2).setCellRenderer(techBaseRenderer); - scrTableEquipment.setViewportView(tblEquipment); - // Populate Tables populateWeaponsAndEquipmentChoices(); @@ -234,6 +209,7 @@ public Dimension getPreferredScrollableViewportSize() { filterClearButton.addActionListener(e -> tableFilterText.setText("")); filterClearButton.setToolTipText("Clear the filter text"); filterClearButton.putClientProperty(FlatClientProperties.STYLE_CLASS, "small"); + weaponClassFilter.addActionListener(e -> filterTables()); JPanel upperPanel = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); @@ -241,10 +217,11 @@ public Dimension getPreferredScrollableViewportSize() { gbc.gridy = 0; gbc.anchor = GridBagConstraints.WEST; gbc.gridwidth = 1; - gbc.insets = new Insets(5, 0, 5, 0); - upperPanel.add(lblTechClass, gbc); + gbc.insets = new Insets(2, 0, 2, 0); + upperPanel.add(new JLabel(Messages.getString("MekSelectorDialog.Search.TechClass")), gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; JPanel techClassButtonPanel = new JPanel(new GridLayout(1, 2, 10, 0)); + techClassButtonPanel.setBorder(new EmptyBorder(0, 20, 0, 0)); gbc.weightx = 0; techClassButtonPanel.add(btnTechClassIS); techClassButtonPanel.add(btnTechClassClan); @@ -253,9 +230,10 @@ public Dimension getPreferredScrollableViewportSize() { gbc.gridy++; gbc.gridwidth = 1; gbc.weightx = 0; - upperPanel.add(lblUnitType, gbc); + upperPanel.add(new JLabel(Messages.getString("MekSelectorDialog.Search.UnitType")), gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; JPanel unitTypeButtonPanel = new JPanel(new GridLayout(1, 7, 10, 0)); + unitTypeButtonPanel.setBorder(new EmptyBorder(0, 20, 0, 0)); unitTypeButtonPanel.add(btnUnitTypeAll); unitTypeButtonPanel.add(btnUnitTypeMek); unitTypeButtonPanel.add(btnUnitTypeVee); @@ -268,9 +246,10 @@ public Dimension getPreferredScrollableViewportSize() { gbc.gridy++; gbc.gridwidth = 1; gbc.weightx = 0; - upperPanel.add(lblTechLevelBase, gbc); + upperPanel.add(new JLabel(Messages.getString("MekSelectorDialog.Search.TechLevel")), gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; JPanel techLevelButtonPanel = new JPanel(new GridLayout(1, 6, 10, 0)); + techLevelButtonPanel.setBorder(new EmptyBorder(0, 20, 0, 0)); techLevelButtonPanel.add(btnTechLevelOfficial); techLevelButtonPanel.add(btnTechLevelIntro); techLevelButtonPanel.add(btnTechLevelStd); @@ -281,9 +260,12 @@ public Dimension getPreferredScrollableViewportSize() { gbc.weightx = 0; JPanel filterPanel = new JPanel(); - filterPanel.add(tableFilterTextLabel); + filterPanel.add(new JLabel(Messages.getString("MekSelectorDialog.Search.TableFilter"))); filterPanel.add(tableFilterText); filterPanel.add(filterClearButton); + filterPanel.add(Box.createHorizontalStrut(10)); + filterPanel.add(new JLabel("Equipment Group:")); + filterPanel.add(weaponClassFilter); gbc.gridy++; gbc.gridwidth = GridBagConstraints.REMAINDER; upperPanel.add(filterPanel, gbc); @@ -292,65 +274,67 @@ public Dimension getPreferredScrollableViewportSize() { gbc.gridx = GridBagConstraints.RELATIVE; gbc.gridy++; gbc.anchor = GridBagConstraints.WEST; - upperPanel.add(lblWeapons, gbc); + upperPanel.add(new JLabel(Messages.getString("MekSelectorDialog.Search.Weapons")), gbc); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.CENTER; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridy++; - upperPanel.add(scrTableWeapons, gbc); + upperPanel.add(new JScrollPane(tblWeapons), gbc); gbc.gridy++; - upperPanel.add(Box.createVerticalStrut(20), gbc); + upperPanel.add(Box.createVerticalStrut(10), gbc); gbc.fill = GridBagConstraints.NONE; gbc.gridwidth = 1; gbc.gridy++; gbc.anchor = GridBagConstraints.WEST; - upperPanel.add(lblEquipment, gbc); + upperPanel.add(new JLabel(Messages.getString("MekSelectorDialog.Search.Equipment")), gbc); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.CENTER; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridy++; - upperPanel.add(scrTableEquipment, gbc); + upperPanel.add(new JScrollPane(tblEquipment), gbc); gbc.gridy++; - upperPanel.add(Box.createVerticalStrut(20), gbc); + upperPanel.add(Box.createVerticalStrut(10), gbc); - gbc.gridwidth = 1; gbc.gridy++; gbc.anchor = GridBagConstraints.WEST; gbc.insets = new Insets(0, 0, 0, 20); - upperPanel.add(lblWeaponClass, gbc); + upperPanel.add(new JLabel(Messages.getString("MekSelectorDialog.Search.WeaponClass")), gbc); gbc.gridy++; JPanel weaponClassPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); weaponClassPanel.add(weaponClassChooser); upperPanel.add(weaponClassPanel, gbc); - JPanel btnPanel = new JPanel(); - btnPanel.add(btnAtLeast); - btnPanel.add(btnLessThan); - btnPanel.add(weaponClassCount); - btnPanel.add(btnAdd); - btnPanel.add(btnAddMultiAnd); - btnPanel.add(btnAddMultiOr); - btnPanel.add(btnLeftParen); - btnPanel.add(btnRightParen); - btnPanel.add(btnAnd); - btnPanel.add(btnOr); - btnPanel.add(btnBack); - btnPanel.add(btnClear); + JPanel addBtnPanel = new JPanel(); + addBtnPanel.add(equipmentCount); + addBtnPanel.add(btnAtLeast); + addBtnPanel.add(btnLessThan); + addBtnPanel.add(btnAdd); + addBtnPanel.add(btnAddMultiAnd); + addBtnPanel.add(btnAddMultiOr); + + JPanel controlBtnPanel = new JPanel(); + controlBtnPanel.add(btnLeftParen); + controlBtnPanel.add(btnRightParen); + controlBtnPanel.add(btnAnd); + controlBtnPanel.add(btnOr); + controlBtnPanel.add(btnBack); + controlBtnPanel.add(btnClear); Box filterExpressionPanel = Box.createHorizontalBox(); filterExpressionPanel.setBorder(new EmptyBorder(0, 20, 0, 20)); filterExpressionPanel.add(lblWEEqExpTxt); filterExpressionPanel.add(Box.createHorizontalStrut(20)); - filterExpressionPanel.add(expWEScroller); + filterExpressionPanel.add(new JScrollPane(txtWEEqExp)); Box filterAssemblyPanel = Box.createVerticalBox(); filterAssemblyPanel.add(Box.createVerticalStrut(10)); - filterAssemblyPanel.add(btnPanel); + filterAssemblyPanel.add(addBtnPanel); + filterAssemblyPanel.add(controlBtnPanel); filterAssemblyPanel.add(filterExpressionPanel); filterAssemblyPanel.add(Box.createVerticalStrut(10)); @@ -374,7 +358,9 @@ public boolean include(Entry ent boolean unitTypeMatch = matchUnitTypeToWeapon(wp); boolean textFilterMatch = (tableFilterText.getText() == null) || (tableFilterText.getText().length() < 2) || matchWeaponTextFilter(entry); - return techLvlMatch && techClassMatch && unitTypeMatch && textFilterMatch; + boolean equipmentClassMatch = (weaponClassFilter.getSelectedItem() instanceof AdvancedSearchEquipmentClass equipmentclass) + && equipmentclass.matches(wp.getInternalName()); + return techLvlMatch && techClassMatch && unitTypeMatch && textFilterMatch && equipmentClassMatch; } }; } catch (PatternSyntaxException ignored) { @@ -395,7 +381,9 @@ public boolean include(Entry e boolean unitTypeMatch = matchUnitTypeToMisc(eq); boolean textFilterMatch = (tableFilterText.getText() == null) || (tableFilterText.getText().length() < 2) || matchEquipmentTextFilter(entry); - return techLvlMatch && techClassMatch && unitTypeMatch && textFilterMatch; + boolean equipmentClassMatch = (weaponClassFilter.getSelectedItem() instanceof AdvancedSearchEquipmentClass equipmentclass) + && equipmentclass.matches(eq.getInternalName()); + return techLvlMatch && techClassMatch && unitTypeMatch && textFilterMatch && equipmentClassMatch; } }; } catch (PatternSyntaxException ignored) { @@ -532,7 +520,7 @@ private void addWeaponFilter(int row, int qty, boolean atleast) { private void addFilter(boolean and) { boolean atleast = btnAtLeast.isSelected(); - int qty = (int) weaponClassCount.getValue(); + int qty = (int) equipmentCount.getValue(); if (focusedSelector == tblEquipment) { int[] rows = tblEquipment.getSelectedRows(); if (rows.length == 1) { @@ -563,7 +551,7 @@ private void addFilter(boolean and) { addFilterToken(new RightParensFilterToken()); } } else if ((focusedSelector == weaponClassChooser) && (weaponClassChooser.getSelectedItem() != null)) { - filterTokens.add(new WeaponClassFT((WeaponClass) weaponClassChooser.getSelectedItem(), qty, atleast)); + filterTokens.add(new WeaponClassFT((AdvancedSearchEquipmentClass) weaponClassChooser.getSelectedItem(), qty, atleast)); } else { // if something else is focused, do nothing @@ -659,7 +647,8 @@ private void focusWeaponClasschooser() { } private boolean hasFocusedSelector() { - return (focusedSelector == weaponClassChooser) || (focusedSelector == tblEquipment) || (focusedSelector == tblWeapons); + return (focusedSelector != null) + && ((focusedSelector == weaponClassChooser) || (focusedSelector == tblEquipment) || (focusedSelector == tblWeapons)); } void adaptTokenButtons() { @@ -709,6 +698,11 @@ private void backOperation() { removeToggleActionListeners(); techLevelButtons.forEach(button -> button.setSelected(e.getSource() == button)); addToggleActionListeners(); + } else if ((source == btnTechClassClan || source == btnTechClassIS) && ((e.getModifiers() & Event.SHIFT_MASK) == 0)) { + removeToggleActionListeners(); + btnTechClassClan.setSelected(source == btnTechClassClan); + btnTechClassIS.setSelected(source == btnTechClassIS); + addToggleActionListeners(); } filterTables(); }; diff --git a/megamek/src/megamek/client/ui/swing/util/FlatLafStyleBuilder.java b/megamek/src/megamek/client/ui/swing/util/FlatLafStyleBuilder.java index b7a4739cf62..557427c2be2 100644 --- a/megamek/src/megamek/client/ui/swing/util/FlatLafStyleBuilder.java +++ b/megamek/src/megamek/client/ui/swing/util/FlatLafStyleBuilder.java @@ -18,6 +18,7 @@ */ package megamek.client.ui.swing.util; +import com.formdev.flatlaf.FlatClientProperties; import megamek.common.annotations.Nullable; import javax.swing.*; @@ -106,6 +107,6 @@ public void apply(JComponent component) { if ((fontName != null) && !fontName.isBlank()) { styleText += " \"" + fontName + "\""; } - component.putClientProperty("FlatLaf.style", styleText); + component.putClientProperty(FlatClientProperties.STYLE, styleText); } }