From fb540e97289a54da419e4d5db79a89c0ab2e9750 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Thu, 19 Aug 2021 21:33:14 +0400 Subject: [PATCH] * GUI: fixed multiple bugs and performance issues with Deck Editor and sets filter/search; --- .../mage/client/deckeditor/CardSelector.java | 216 +++++++++++------- .../client/dialog/PickCheckBoxDialog.java | 12 +- .../client/util/sets/ConstructedFormats.java | 3 +- 3 files changed, 144 insertions(+), 87 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java index 5e706e36a6..9e84078d6d 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java @@ -42,11 +42,14 @@ import java.util.*; import static mage.client.dialog.PreferencesDialog.*; /** - * @author BetaSteward_at_googlemail.com, nantuko + * GUI: deck editor's panel with filters and search + * + * @author BetaSteward_at_googlemail.com, nantuko, JayDi85 */ public class CardSelector extends javax.swing.JPanel implements ComponentListener, DragCardTarget { private static final Logger logger = Logger.getLogger(CardSelector.class); + private final String MULTI_SETS_SELECTION_TEXT = "Multiple sets selected"; private final java.util.List cards = new ArrayList<>(); private BigCard bigCard; @@ -54,8 +57,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene private final SortSetting sortSetting; private static final Map pdAllowed = new HashMap<>(); private static Listener setsDbListener = null; - - private final String TEST_MULTI_SET = "Multiple Sets selected"; + private boolean isSetsFilterLoading = false; // use it on sets combobox modify private final ActionListener searchAction = evt -> jButtonSearchActionPerformed(evt); @@ -71,17 +73,15 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene setGUISize(); currentView = mainModel; // by default we use List View + // prepare search dialog with checkboxes listCodeSelected = new CheckBoxList(); - - String[] setCodes = ConstructedFormats.getTypes(); - java.util.List result = new ArrayList<>(); - - for (String item : setCodes) { + List checkboxes = new ArrayList<>(); + for (String item : ConstructedFormats.getTypes()) { if (!item.equals(ConstructedFormats.ALL_SETS)) { - result.add(item); + checkboxes.add(item); } } - listCodeSelected.setListData(result.toArray()); + listCodeSelected.setListData(checkboxes.toArray()); } private void makeTransparent() { @@ -216,9 +216,15 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene this.btnClear.setVisible(true); this.cbExpansionSet.setVisible(true); this.btnExpansionSearch.setVisible(true); -// cbExpansionSet.setModel(new DefaultComboBoxModel<>(ConstructedFormats.getTypes())); - // Action event on Expansion set triggers loadCards method - cbExpansionSet.setSelectedIndex(0); + + // select "all" by default + try { + isSetsFilterLoading = true; + cbExpansionSet.setSelectedIndex(0); + } finally { + isSetsFilterLoading = false; + } + filterCards(); } private FilterCard buildFilter() { @@ -274,21 +280,62 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene } filter.add(Predicates.or(predicates)); - if (this.cbExpansionSet.isVisible()) { - String expansionSelection = this.cbExpansionSet.getSelectedItem().toString(); - if (!expansionSelection.equals("- All Sets")) { - List> expansionPredicates = new ArrayList<>(); - for (String setCode : ConstructedFormats.getSetsByFormat(expansionSelection)) { - expansionPredicates.add(new ExpansionSetPredicate(setCode)); - } - filter.add(Predicates.or(expansionPredicates)); + List filteredSets = getFilteredSets(); + if (!filteredSets.isEmpty()) { + List> expansionPredicates = new ArrayList<>(); + for (String setCode : filteredSets) { + expansionPredicates.add(new ExpansionSetPredicate(setCode)); } + filter.add(Predicates.or(expansionPredicates)); } } return filter; } + private void setSetsSelection(String newSelection) { + // combo and checkbox can contain different elements (e.g. without "all" or "multi" options), + // so must search by string value + for (int index = 0; index < cbExpansionSet.getItemCount(); index++) { + if (cbExpansionSet.getItemAt(index).equals(newSelection)) { + if (cbExpansionSet.getSelectedIndex() != index) { + cbExpansionSet.setSelectedIndex(index); + } + } + } + } + + private List getFilteredSets() { + // empty list - show all sets + + List res = new ArrayList<>(); + if (!this.cbExpansionSet.isVisible()) { + return res; + } + + if (listCodeSelected.getCheckedIndices().length <= 1) { + // single set selected + String expansionSelection = this.cbExpansionSet.getSelectedItem().toString(); + if (!expansionSelection.equals(ConstructedFormats.ALL_SETS) + && !expansionSelection.startsWith(MULTI_SETS_SELECTION_TEXT)) { + res.addAll(ConstructedFormats.getSetsByFormat(expansionSelection)); + } + } else { + // multiple sets selected + int[] choiseValue = listCodeSelected.getCheckedIndices(); + ListModel x = listCodeSelected.getModel(); + + for (int itemIndex : choiseValue) { + java.util.List listReceived = ConstructedFormats.getSetsByFormat(x.getElementAt(itemIndex).toString()); + listReceived.stream() + .filter(item -> !res.contains(item)) + .forEachOrdered(res::add); + } + } + + return res; + } + private CardCriteria buildCriteria() { CardCriteria criteria = new CardCriteria(); criteria.black(this.tbBlack.isSelected()); @@ -338,27 +385,10 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene criteria.rarities(Rarity.SPECIAL); criteria.rarities(Rarity.BONUS); } - if (this.cbExpansionSet.isVisible()) { - if (listCodeSelected.getCheckedIndices().length <= 1) { - String expansionSelection = this.cbExpansionSet.getSelectedItem().toString(); - if (!expansionSelection.equals("- All Sets")) { - java.util.List setCodes = ConstructedFormats.getSetsByFormat(expansionSelection); - criteria.setCodes(setCodes.toArray(new String[0])); - } - } else { - java.util.List setCodes = new ArrayList<>(); - //java.util.List listReceived=new ArrayList<>() ; - int[] choiseValue = listCodeSelected.getCheckedIndices(); - ListModel x = listCodeSelected.getModel(); - - for (int itemIndex : choiseValue) { - - java.util.List listReceived = ConstructedFormats.getSetsByFormat(x.getElementAt(itemIndex).toString()); - listReceived.stream().filter(item -> !setCodes.contains(item)).forEachOrdered(setCodes::add); - } - criteria.setCodes(setCodes.toArray(new String[0])); - } + List filteredSets = getFilteredSets(); + if (!filteredSets.isEmpty()) { + criteria.setCodes(filteredSets.toArray(new String[0])); } return criteria; @@ -681,7 +711,9 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene cbExpansionSetActionPerformed(evt); } }); + // auto-update sets list on changes + // doesn't use any more due to db recreation on update setsDbListener = new Listener() { @Override public void event(RepositoryEvent event) { @@ -1218,19 +1250,37 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene }// //GEN-END:initComponents private void cbExpansionSetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbExpansionSetActionPerformed - if (!cbExpansionSet.getSelectedItem().toString().contains(TEST_MULTI_SET)) { - int index = cbExpansionSet.getSelectedIndex(); - if (cbExpansionSet.getItemAt(0).contains(TEST_MULTI_SET)) { - cbExpansionSet.removeItemAt(0); - index--; + // one item selected by user + + // ignore combobox modifing + if (isSetsFilterLoading) { + return; + } + + // auto-remove unused multi-select item and sync checkboxes + if (!cbExpansionSet.getSelectedItem().toString().startsWith(MULTI_SETS_SELECTION_TEXT)) { + int currentSelection = cbExpansionSet.getSelectedIndex(); + isSetsFilterLoading = true; + try { + // remove multi item and fix selection + if (cbExpansionSet.getItemAt(0).startsWith(MULTI_SETS_SELECTION_TEXT)) { + cbExpansionSet.removeItemAt(0); + currentSelection = Math.max(0, currentSelection - 1); + } + } finally { + isSetsFilterLoading = false; } + + // sync checkboxes listCodeSelected.uncheckAll(); - if (index > 0) { - //ofset because all sets is removed from the list - listCodeSelected.setChecked(index - 1, true); + if (currentSelection > 0) { + // if not "all" option selected + // checkbox haven't "all", so use another indexes + listCodeSelected.setChecked(currentSelection - 1, true); } } + // update data filterCards(); }//GEN-LAST:event_cbExpansionSetActionPerformed @@ -1241,7 +1291,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene }//GEN-LAST:event_btnClearActionPerformed private void btnBoosterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnBoosterActionPerformed - java.util.List sets = ConstructedFormats.getSetsByFormat(this.cbExpansionSet.getSelectedItem().toString()); + List sets = getFilteredSets(); if (sets.size() == 1) { if (!this.limited) { this.limited = true; @@ -1415,43 +1465,45 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene }//GEN-LAST:event_chkRulesActionPerformed private void btnExpansionSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExpansionSearchActionPerformed + // search and check multiple items + + int[] oldChecks = listCodeSelected.getCheckedIndices(); + + // call dialog FastSearchUtil.showFastSearchForStringComboBox(listCodeSelected, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE); -// - int[] choiseValue = listCodeSelected.getCheckedIndices(); - ListModel x = listCodeSelected.getModel(); - if (choiseValue.length == 0)//none - { - cbExpansionSet.setSelectedIndex(0); - } else if (choiseValue.length == 1)//one - { - String itemSelected = listCodeSelected.getModel().getElementAt(choiseValue[0]).toString(); - for (int index = 0; index < cbExpansionSet.getItemCount(); index++) { - if (cbExpansionSet.getItemAt(index).equals(itemSelected)) { - cbExpansionSet.setSelectedIndex(index); - } - } - - } else//many - { - String message = String.format("%s:%d", TEST_MULTI_SET, choiseValue.length); - - cbExpansionSet.insertItemAt(message, 0); - cbExpansionSet.setSelectedIndex(0); - - if (cbExpansionSet.getItemAt(1).contains(TEST_MULTI_SET)) { - cbExpansionSet.removeItemAt(1); - } - - //listCodeSelected.setChecked(index-1, true); - //cbExpansionSet. + int[] newChecks = listCodeSelected.getCheckedIndices(); + if (Arrays.equals(oldChecks, newChecks)) { + // no changes or cancel + return; } - /*for(int itemIndex: choiseValue){ - // LogLog.warn(String.format("%d:%s",itemIndex,x.getElementAt(itemIndex).toString())); + isSetsFilterLoading = true; + try { + // delete old item + if (cbExpansionSet.getItemAt(0).startsWith(MULTI_SETS_SELECTION_TEXT)) { + cbExpansionSet.removeItemAt(0); + } + + // set new selection + if (newChecks.length == 0) { + // all + cbExpansionSet.setSelectedIndex(0); + } else if (newChecks.length == 1) { + // one + setSetsSelection(listCodeSelected.getModel().getElementAt(newChecks[0]).toString()); + } else { + // multiple + // insert custom text + String message = String.format("%s: %d", MULTI_SETS_SELECTION_TEXT, newChecks.length); + cbExpansionSet.insertItemAt(message, 0); + cbExpansionSet.setSelectedIndex(0); + } + } finally { + isSetsFilterLoading = false; } - */ -// + + // update data filterCards(); }//GEN-LAST:event_btnExpansionSearchActionPerformed diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java index 5768bfe42b..3345dbf0f8 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java @@ -11,6 +11,7 @@ import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; +import java.util.stream.Collectors; /** * App GUI: fast search in the combobox, uses in deck editor (sets choosing) @@ -26,6 +27,7 @@ public class PickCheckBoxDialog extends MageDialog { CheckBoxList.CheckBoxListModel m_dataModel; CheckBoxList tList; + int[] startingCheckboxes; // restore to it on cancel final private static String HTML_TEMPLATE = "
%s
"; @@ -276,6 +278,12 @@ public class PickCheckBoxDialog extends MageDialog { } private void doCancel() { + // restore starting checkboxes + Set checks = Arrays.stream(startingCheckboxes).boxed().collect(Collectors.toSet()); + for (int i = 0; i < tList.getModel().getSize(); i++) { + tList.setChecked(i, checks.contains(i)); + } + this.listChoices.clearSelection(); this.choice.clearChoice(); hideDialog(); @@ -289,6 +297,7 @@ public class PickCheckBoxDialog extends MageDialog { public PickCheckBoxDialog(CheckBoxList list) { initComponents(); tList = list; + startingCheckboxes = list.getCheckedIndices(); this.listChoices.setModel(dataModel); this.setModal(true); @@ -302,7 +311,6 @@ public class PickCheckBoxDialog extends MageDialog { if (this.tList instanceof javax.swing.JList) { setFocus(tList); } - } } @@ -553,9 +561,7 @@ public class PickCheckBoxDialog extends MageDialog { }//GEN-LAST:event_closeDialog private void btClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btClearActionPerformed - // TODO add your handling code here: this.tList.uncheckAll(); - //this.tList.repaint(); scrollList.repaint(); }//GEN-LAST:event_btClearActionPerformed diff --git a/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java b/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java index 5e15d23168..eb5bb4c3f9 100644 --- a/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java +++ b/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java @@ -10,7 +10,7 @@ import mage.game.events.Listener; import java.util.*; /** - * Utility class for constructed formats (expansions and other editions). + * Utility class for constructed formats (expansions and other editions). Uses in GUI for set's combobox. * * @author nantuko */ @@ -73,7 +73,6 @@ public final class ConstructedFormats { return underlyingSetCodesPerFormat.get(format); } return all; - } public static void ensureLists() {