1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.firemox;
20
21 import java.awt.BorderLayout;
22 import java.awt.Color;
23 import java.awt.Component;
24 import java.awt.Dimension;
25 import java.awt.Paint;
26 import java.awt.event.ActionEvent;
27 import java.awt.event.InputEvent;
28 import java.awt.event.KeyEvent;
29 import java.awt.event.MouseEvent;
30 import java.awt.event.WindowEvent;
31 import java.io.FileInputStream;
32 import java.io.IOException;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.TreeMap;
41
42 import javax.swing.BorderFactory;
43 import javax.swing.Box;
44 import javax.swing.BoxLayout;
45 import javax.swing.JButton;
46 import javax.swing.JComboBox;
47 import javax.swing.JComponent;
48 import javax.swing.JDialog;
49 import javax.swing.JFileChooser;
50 import javax.swing.JFrame;
51 import javax.swing.JLabel;
52 import javax.swing.JList;
53 import javax.swing.JMenu;
54 import javax.swing.JMenuBar;
55 import javax.swing.JMenuItem;
56 import javax.swing.JOptionPane;
57 import javax.swing.JPanel;
58 import javax.swing.JScrollPane;
59 import javax.swing.JSeparator;
60 import javax.swing.JTabbedPane;
61 import javax.swing.JTable;
62 import javax.swing.JTextField;
63 import javax.swing.JToggleButton;
64 import javax.swing.JToolBar;
65 import javax.swing.KeyStroke;
66 import javax.swing.ListSelectionModel;
67 import javax.swing.ScrollPaneConstants;
68 import javax.swing.SwingConstants;
69 import javax.swing.Timer;
70 import javax.swing.border.EtchedBorder;
71 import javax.swing.event.ListSelectionEvent;
72 import javax.swing.event.ListSelectionListener;
73 import javax.swing.event.TableModelEvent;
74 import javax.swing.event.TableModelListener;
75
76 import net.sf.firemox.chart.CardColor;
77 import net.sf.firemox.chart.CardManaCost;
78 import net.sf.firemox.chart.CardTypes;
79 import net.sf.firemox.chart.ChartFilter;
80 import net.sf.firemox.chart.ChartSets;
81 import net.sf.firemox.chart.IChartKey;
82 import net.sf.firemox.chart.IDataProvider;
83 import net.sf.firemox.chart.datasets.Dataset;
84 import net.sf.firemox.clickable.target.card.CardFactory;
85 import net.sf.firemox.clickable.target.card.CardModel;
86 import net.sf.firemox.clickable.target.card.MCard;
87 import net.sf.firemox.deckbuilder.CardLoader;
88 import net.sf.firemox.deckbuilder.CardView;
89 import net.sf.firemox.deckbuilder.ConstraintsChecker;
90 import net.sf.firemox.deckbuilder.Deck;
91 import net.sf.firemox.deckbuilder.DeckConstraints;
92 import net.sf.firemox.deckbuilder.DeckReader;
93 import net.sf.firemox.deckbuilder.DeckRules;
94 import net.sf.firemox.deckbuilder.MdbLoader;
95 import net.sf.firemox.token.IdCardColors;
96 import net.sf.firemox.token.IdCommonToken;
97 import net.sf.firemox.token.IdConst;
98 import net.sf.firemox.tools.Configuration;
99 import net.sf.firemox.tools.Converter;
100 import net.sf.firemox.tools.FileFilterPlus;
101 import net.sf.firemox.tools.MCardCompare;
102 import net.sf.firemox.tools.MSaveDeck;
103 import net.sf.firemox.tools.MToolKit;
104 import net.sf.firemox.tools.Picture;
105 import net.sf.firemox.ui.HireListener;
106 import net.sf.firemox.ui.MCardTableModel;
107 import net.sf.firemox.ui.MListModel;
108 import net.sf.firemox.ui.RefreshableAdd;
109 import net.sf.firemox.ui.TimerGlassPane;
110 import net.sf.firemox.ui.UIHelper;
111 import net.sf.firemox.ui.component.ThreadSafeJList;
112 import net.sf.firemox.ui.i18n.LanguageManager;
113 import net.sf.firemox.ui.wizard.About;
114
115 import org.apache.commons.io.FilenameUtils;
116 import org.apache.commons.lang.ArrayUtils;
117 import org.jfree.chart.ChartPanel;
118 import org.jfree.chart.JFreeChart;
119
120 /***
121 * This class is a deck builder compatible with Firemox deck format. Can
122 * also export/import other formats.
123 *
124 * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
125 * @author <a href="mailto:goldeneyemdk@users.sourceforge.net">Sebastien Genete
126 * </a>
127 * @author Jan Blaha for deck loader and statistics
128 * @since 0.2 2003/12/06, settings are loaded.
129 * @since 0.2 you can load a deck file.
130 * @since 0.2 you can load a specified MDB file (is MagicProject card list
131 * file).
132 * @since 0.3 2003/12/12, you can save a deck file.
133 * @since 0.3 new deck feature.
134 * @since 0.4 sort MDB file feature for optimized load.
135 * @since 0.4 deck are saved with alphabetically sort.
136 * @since 0.5 statistics feature added.
137 * @since 0.81 deck converter added.
138 * @since 0.83 cleaned code, deck constraints form added.
139 * @since 0.93 pie chart added, color filtering
140 * @since 0.94 use of JTable instead of JList
141 */
142 public final class DeckBuilder extends AbstractMainForm implements
143 ListSelectionListener, RefreshableAdd, IDataProvider, TableModelListener {
144
145 private static final int WINDOW_WIDTH = 700;
146
147 private static final int WINDOW_HEIGHT = 700;
148
149 /***
150 * Card loader bar
151 */
152 protected CardLoader cardLoader;
153
154 /***
155 * Load timer
156 */
157 protected Timer timer;
158
159 private final TimerGlassPane timerPanel;
160
161 private JComponent listScrollerLeft;
162
163 /***
164 * Creates new form DeckBuilder
165 */
166 private DeckBuilder() {
167 super("DeckBuilder");
168 form = this;
169 timerPanel = new TimerGlassPane();
170 cardLoader = new CardLoader(timerPanel);
171 timer = new Timer(200, cardLoader);
172 setGlassPane(timerPanel);
173 try {
174 setIconImage(Picture.loadImage(IdConst.IMAGES_DIR + "deckbuilder.gif"));
175 } catch (Exception e) {
176
177 }
178
179
180 loadSettings();
181
182
183 final JMenuItem newItem = UIHelper.buildMenu("menu_db_new", 'n', this);
184 newItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
185 InputEvent.CTRL_MASK));
186
187 final JMenuItem loadItem = UIHelper.buildMenu("menu_db_load", 'o', this);
188 loadItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
189 InputEvent.CTRL_MASK));
190
191 final JMenuItem saveAsItem = UIHelper
192 .buildMenu("menu_db_saveas", 'a', this);
193 saveAsItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F12, 0));
194
195 final JMenuItem saveItem = UIHelper.buildMenu("menu_db_save", 's', this);
196 saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
197 InputEvent.CTRL_MASK));
198
199 final JMenuItem quitItem = UIHelper.buildMenu("menu_db_exit", this);
200 quitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4,
201 InputEvent.ALT_MASK));
202
203 final JMenuItem deckConstraintsItem = UIHelper.buildMenu(
204 "menu_db_constraints", 'c', this);
205 deckConstraintsItem.setAccelerator(KeyStroke
206 .getKeyStroke(KeyEvent.VK_F3, 0));
207
208 final JMenuItem aboutItem = UIHelper
209 .buildMenu("menu_help_about", 'a', this);
210 aboutItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1,
211 InputEvent.SHIFT_MASK));
212
213 final JMenuItem convertDCK = UIHelper
214 .buildMenu("menu_convert_DCK_MP", this);
215
216 final JMenu mainMenu = UIHelper.buildMenu("menu_file");
217 mainMenu.add(newItem);
218 mainMenu.add(loadItem);
219 mainMenu.add(saveAsItem);
220 mainMenu.add(saveItem);
221 mainMenu.add(new JSeparator());
222 mainMenu.add(quitItem);
223
224 super.optionMenu = new JMenu("Options");
225
226 final JMenu convertMenu = UIHelper.buildMenu("menu_convert");
227 convertMenu.add(convertDCK);
228
229 final JMenuItem helpItem = UIHelper.buildMenu("menu_help_help", 'h', this);
230 helpItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0));
231
232 final JMenu helpMenu = new JMenu("?");
233 helpMenu.add(helpItem);
234 helpMenu.add(deckConstraintsItem);
235 helpMenu.add(aboutItem);
236
237 final JMenuBar menuBar = new JMenuBar();
238 menuBar.add(mainMenu);
239 initAbstractMenu();
240 menuBar.add(optionMenu);
241 menuBar.add(convertMenu);
242 menuBar.add(helpMenu);
243 setJMenuBar(menuBar);
244 addWindowListener(this);
245
246
247 final JLabel amountLeft = new JLabel("<html>0/?", SwingConstants.RIGHT);
248
249
250 allListModel = new MListModel<MCardCompare>(amountLeft, false);
251 leftList = new ThreadSafeJList(allListModel);
252 leftList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
253 leftList.setLayoutOrientation(JList.VERTICAL);
254 leftList.getSelectionModel().addListSelectionListener(this);
255 leftList.addMouseListener(this);
256 leftList.setVisibleRowCount(10);
257
258
259 addQtyTxt = new JTextField("1");
260
261
262 addButton = new JButton(LanguageManager.getString("db_add"));
263 addButton.setMnemonic('a');
264 addButton.setEnabled(false);
265
266
267 final Box addPanel = Box.createHorizontalBox();
268 addPanel.add(addButton);
269 addPanel.add(addQtyTxt);
270 addPanel.setMaximumSize(new Dimension(32010, 26));
271
272
273 cardNameTxt = new JTextField();
274 new HireListener(cardNameTxt, addButton, this, leftList);
275
276 final JLabel searchLabel = new JLabel(LanguageManager
277 .getString("db_search")
278 + " : ");
279 searchLabel.setLabelFor(cardNameTxt);
280
281
282 final Box searchPanel = Box.createHorizontalBox();
283 searchPanel.add(searchLabel);
284 searchPanel.add(cardNameTxt);
285 searchPanel.setMaximumSize(new Dimension(32010, 26));
286
287 listScrollerLeft = new JScrollPane(leftList);
288 MToolKit.addOverlay(listScrollerLeft);
289
290
291 final JPanel srcPanel = new JPanel(null);
292 srcPanel.add(searchPanel);
293 srcPanel.add(listScrollerLeft);
294 srcPanel.add(amountLeft);
295 srcPanel.add(addPanel);
296 srcPanel.setMinimumSize(new Dimension(220, 200));
297 srcPanel.setLayout(new BoxLayout(srcPanel, BoxLayout.Y_AXIS));
298
299
300 constraintsChecker = new ConstraintsChecker();
301 constraintsChecker.setBorder(new EtchedBorder());
302 final JScrollPane constraintsCheckerScroll = new JScrollPane(
303 constraintsChecker);
304 MToolKit.addOverlay(constraintsCheckerScroll);
305
306
307 oracleText = new JLabel();
308 oracleText.setPreferredSize(new Dimension(180, 200));
309 oracleText.setVerticalAlignment(SwingConstants.TOP);
310
311 final JScrollPane oracle = new JScrollPane(oracleText,
312 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
313 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
314 MToolKit.addOverlay(oracle);
315
316
317 initSets();
318 datasets = new ChartSets();
319 final JTabbedPane tabbedPane = new JTabbedPane();
320 for (ChartFilter filter : ChartFilter.values()) {
321 final Dataset dataSet = filter.createDataSet(this);
322 final JFreeChart chart = new JFreeChart(null, null, filter.createPlot(
323 dataSet, painterMapper.get(filter)), false);
324 datasets.addDataSet(filter, dataSet);
325 ChartPanel pieChartPanel = new ChartPanel(chart, true);
326 tabbedPane.add(pieChartPanel, filter.getTitle());
327 }
328
329 tabbedPane.add(constraintsCheckerScroll, LanguageManager
330 .getString("db_constraints"));
331 tabbedPane.add(oracle, LanguageManager.getString("db_text"));
332 tabbedPane.setSelectedComponent(oracle);
333
334
335 toolBar = new JToolBar();
336 toolBar.setFloatable(false);
337 final JButton clearButton = UIHelper.buildButton("clear");
338 clearButton.addActionListener(this);
339 toolBar.add(clearButton);
340 final JToggleButton toggleColorlessButton = new JToggleButton(UIHelper
341 .getTbsIcon("mana/colorless/small/" + MdbLoader.unknownSmlMana), true);
342 toggleColorlessButton.setActionCommand("0");
343 toggleColorlessButton.addActionListener(this);
344 toolBar.add(toggleColorlessButton);
345 for (int index = 1; index < IdCardColors.CARD_COLOR_NAMES.length; index++) {
346 final JToggleButton toggleButton = new JToggleButton(
347 UIHelper.getTbsIcon("mana/colored/small/"
348 + MdbLoader.coloredSmlManas[index]), true);
349 toggleButton.setActionCommand(String.valueOf(index));
350 toggleButton.addActionListener(this);
351 toolBar.add(toggleButton);
352 }
353
354
355 final List<String> idCards = new ArrayList<String>(Arrays
356 .asList(CardFactory.exportedIdCardNames));
357 Collections.sort(idCards);
358 final Object[] cardTypes = ArrayUtils.addAll(new String[] { LanguageManager
359 .getString("db_types.any") }, idCards.toArray());
360 idCardComboBox = new JComboBox(cardTypes);
361 idCardComboBox.setSelectedIndex(0);
362 idCardComboBox.addActionListener(this);
363 idCardComboBox.setActionCommand("cardTypeFilter");
364
365
366 final List<String> properties = new ArrayList<String>(CardFactory
367 .getPropertiesName(DeckConstraints.getMinProperty(), DeckConstraints
368 .getMaxProperty()));
369 Collections.sort(properties);
370 final Object[] cardProperties = ArrayUtils.addAll(
371 new String[] { LanguageManager.getString("db_properties.any") },
372 properties.toArray());
373 propertiesComboBox = new JComboBox(cardProperties);
374 propertiesComboBox.setSelectedIndex(0);
375 propertiesComboBox.addActionListener(this);
376 propertiesComboBox.setActionCommand("propertyFilter");
377
378 final JLabel colors = new JLabel(" " + LanguageManager.getString("colors")
379 + " : ");
380 final JLabel types = new JLabel(" " + LanguageManager.getString("types")
381 + " : ");
382 final JLabel property = new JLabel(" "
383 + LanguageManager.getString("properties") + " : ");
384
385
386 final Box filterPanel = Box.createHorizontalBox();
387 filterPanel.add(colors);
388 filterPanel.add(toolBar);
389 filterPanel.add(types);
390 filterPanel.add(idCardComboBox);
391 filterPanel.add(property);
392 filterPanel.add(propertiesComboBox);
393
394 getContentPane().add(filterPanel, BorderLayout.NORTH);
395
396
397
398
399 final JLabel rightAmount = new JLabel("0/?", SwingConstants.RIGHT);
400 rightAmount.setMaximumSize(new Dimension(220, 26));
401
402
403 rightListModel = new MCardTableModel(new MListModel<MCardCompare>(
404 rightAmount, true));
405 rightListModel.addTableModelListener(this);
406 rightList = new JTable(rightListModel);
407 rightList.setShowGrid(false);
408 rightList.setTableHeader(null);
409 rightList.getSelectionModel().addListSelectionListener(this);
410 rightList.getColumnModel().getColumn(0).setMaxWidth(25);
411 rightList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
412
413
414 deckNameTxt = new JTextField("loading...");
415 deckNameTxt.setEditable(false);
416 deckNameTxt.setBorder(null);
417 final JLabel deckLabel = new JLabel(LanguageManager.getString("db_deck")
418 + " : ");
419 deckLabel.setLabelFor(deckNameTxt);
420 final Box deckNamePanel = Box.createHorizontalBox();
421 deckNamePanel.add(deckLabel);
422 deckNamePanel.add(deckNameTxt);
423 deckNamePanel.setMaximumSize(new Dimension(220, 26));
424
425
426 removeQtyTxt = new JTextField("1");
427
428
429 removeButton = new JButton(LanguageManager.getString("db_remove"));
430 removeButton.setMnemonic('r');
431 removeButton.addMouseListener(this);
432 removeButton.setEnabled(false);
433
434
435 final Box removePanel = Box.createHorizontalBox();
436 removePanel.add(removeButton);
437 removePanel.add(removeQtyTxt);
438 removePanel.setMaximumSize(new Dimension(220, 26));
439
440
441 final JScrollPane deskListScroller = new JScrollPane(rightList);
442 MToolKit.addOverlay(deskListScroller);
443 deskListScroller.setBorder(BorderFactory.createLineBorder(Color.GRAY));
444 deskListScroller.setMinimumSize(new Dimension(220, 200));
445 deskListScroller.setMaximumSize(new Dimension(220, 32000));
446
447 final Box destPanel = Box.createVerticalBox();
448 destPanel.add(deckNamePanel);
449 destPanel.add(deskListScroller);
450 destPanel.add(rightAmount);
451 destPanel.add(removePanel);
452 destPanel.setMinimumSize(new Dimension(220, 200));
453 destPanel.setMaximumSize(new Dimension(220, 32000));
454
455
456 cardPictureNameTxt = new JLabel("<html><i>no selected card</i>");
457 final Box cardPictureNamePanel = Box.createHorizontalBox();
458 cardPictureNamePanel.add(cardPictureNameTxt);
459 cardPictureNamePanel.setMaximumSize(new Dimension(32010, 26));
460
461
462 final JPanel viewCard = new JPanel(null);
463 viewCard.add(cardPictureNamePanel);
464 viewCard.add(CardView.getInstance());
465 viewCard.add(tabbedPane);
466 viewCard.setLayout(new BoxLayout(viewCard, BoxLayout.Y_AXIS));
467
468 final Box mainPanel = Box.createHorizontalBox();
469 mainPanel.add(destPanel);
470 mainPanel.add(viewCard);
471
472
473 getContentPane().add(srcPanel, BorderLayout.WEST);
474 getContentPane().add(mainPanel, BorderLayout.CENTER);
475
476
477 getRootPane().setPreferredSize(new Dimension(WINDOW_WIDTH, WINDOW_HEIGHT));
478 getRootPane().setMinimumSize(getRootPane().getPreferredSize());
479 pack();
480 }
481
482 /***
483 * Load a given deck file into the given list.
484 *
485 * @param fileName
486 * deck file name.
487 * @param names
488 * loaded cards to complete.
489 */
490 protected void loadDeck(String fileName, MListModel<MCardCompare> names) {
491
492 if (fileName == null || fileName.length() == 0) {
493 return;
494 }
495
496
497 final String deckName = FilenameUtils.removeExtension(FilenameUtils
498 .getName(fileName));
499 setTitle("DeckBuilder : " + deckName);
500 deckNameTxt.setText(deckName);
501
502 names.clear();
503 datasets.removeAll();
504 try {
505 Deck currentDeck = DeckReader.getDeck(this, fileName);
506 if (currentDeck == null) {
507
508 return;
509 }
510
511
512 DeckReader.validateDeck(this, currentDeck, (String) null);
513
514
515 final FileInputStream dbStream = MdbLoader.resetMdb();
516 for (MCardCompare cardCompare : currentDeck.getCards()) {
517 names.add(cardCompare);
518 datasets.addCard(cardCompare.getModel(dbStream), cardCompare
519 .getAmount());
520 }
521 constraintsChecker.setDeck(currentDeck);
522 } catch (IOException e) {
523 e.printStackTrace();
524 } finally {
525 updateChecker();
526 setAsSaved();
527 }
528 }
529
530 private void setCard(MCardCompare card) {
531 CardView.getInstance().setCard(card);
532 cardPictureNameTxt.setText(card.getName());
533 FileInputStream dbStream = MdbLoader.resetMdb();
534 try {
535 oracleText.setText("<html>Oracle Rules:<br><br>"
536 + ((MCard) card.getCard(dbStream)).getDatabase().getProperty(
537 "card.text"));
538 } catch (IOException e) {
539
540 e.printStackTrace();
541 }
542 }
543
544 public void valueChanged(ListSelectionEvent e) {
545 if (!e.getValueIsAdjusting()) {
546 if (e.getSource() == leftList.getSelectionModel()) {
547 if (leftList.getSelectedIndex() == -1 || allListModel.isEmpty()) {
548
549 addButton.setEnabled(false);
550 } else {
551
552 addButton.setEnabled(true);
553
554
555 final MCardCompare selectedCard = (MCardCompare) leftList
556 .getSelectedValue();
557 cardNameTxt.setText(selectedCard.getName());
558 setCard(selectedCard);
559 }
560 } else if (e.getSource() == rightList.getSelectionModel()) {
561 if (rightList.getSelectedRow() == -1) {
562
563 removeButton.setEnabled(false);
564 } else {
565
566 removeButton.setEnabled(true);
567
568
569 setCard(rightListModel.getCards().getElementAt(
570 rightList.getSelectedRow()));
571 }
572 }
573 }
574 }
575
576 /***
577 * Exit the Application
578 */
579 private void exitForm() {
580 verifyModification();
581 if (consoleMode) {
582 System.exit(0);
583 } else {
584 setVisible(false);
585 }
586 }
587
588 /***
589 * Load the deck builder from the command line.
590 *
591 * @param args
592 * the command line arguments
593 */
594 public static void main(String[] args) {
595 consoleMode = true;
596 JFrame.setDefaultLookAndFeelDecorated(true);
597 JDialog.setDefaultLookAndFeelDecorated(true);
598 autoLoad();
599 }
600
601 /***
602 * Load the deck builder from Magic class.
603 */
604 public static void loadFromMagic() {
605 consoleMode = false;
606 autoLoad();
607 }
608
609 /***
610 * Load the deck builder
611 */
612 private static void autoLoad() {
613 if (form == null) {
614 form = new DeckBuilder();
615 form.setLocation(
616 (form.getToolkit().getScreenSize().width - WINDOW_WIDTH) / 2, (form
617 .getToolkit().getScreenSize().height - WINDOW_HEIGHT) / 2);
618 }
619 form.setVisible(true);
620 if (form.allListModel.isEmpty()) {
621 form.timerPanel.setVisible(true);
622 form.timer.start();
623 new Thread(
624 /***
625 * This class refresh the loading bar
626 */
627 new Runnable() {
628 public void run() {
629
630 form.readAvailableCards(form.allListModel);
631
632
633 if (Configuration.getString("decks.deck(0)", "").length() > 0) {
634 form.loadDeck(Configuration.getString("decks.deck(0)"),
635 form.rightListModel.getCards());
636 form.rightListModel.refresh();
637 } else {
638 form.setAsNew();
639 }
640
641 form.timer.stop();
642 form.cardLoader.resetCounter();
643 }
644 }).start();
645 }
646 }
647
648 /***
649 * Adding a card to the deck
650 *
651 * @param unitary
652 */
653 public void refreshAddComponent(boolean unitary) {
654
655 if (leftList.isSelectionEmpty())
656 return;
657
658 String name = leftList.getSelectedValue().toString();
659 int qty = 1;
660 if (!unitary) {
661 try {
662 qty = Integer.parseInt(addQtyTxt.getText());
663 } catch (Exception e1) {
664 JOptionPane.showMessageDialog(form, "Malformed integer for quantity",
665 "Internal Error", JOptionPane.ERROR_MESSAGE);
666 return;
667 }
668 }
669
670 if (name.length() == 0) {
671 cardNameTxt.requestFocusInWindow();
672 return;
673 }
674
675 int index = rightListModel.getCards().indexOf(name);
676 final MCardCompare card;
677 if (index == -1) {
678
679 int allIndex = allListModel.indexOf(name);
680 assert allIndex != -1;
681 card = allListModel.getElementAt(allIndex).clone();
682 card.add(qty);
683 rightListModel.getCards().insertElementAt(card, 0);
684 rightListModel.fireTableRowsInserted(0, 0);
685
686
687 cardNameTxt.requestFocusInWindow();
688 cardNameTxt.setText("");
689 } else {
690 rightListModel.getCards().getElementAt(index).add(qty);
691 rightListModel.fireTableCellUpdated(index, 0);
692 }
693
694
695 final FileInputStream dbStream = MdbLoader.resetMdb();
696 datasets.addCard(getCardModel(name, dbStream), qty);
697
698
699 modifiedSinceSave = true;
700 }
701
702 /***
703 * removes cards from current deck according to the remove panel
704 */
705 private void removeCardFromDeck() {
706
707 final MCardCompare card = rightListModel.getCards().getElementAt(
708 rightList.getSelectedRow());
709
710 int qty = 1;
711
712 try {
713 qty = Integer.parseInt(removeQtyTxt.getText());
714 } catch (Exception e1) {
715 JOptionPane.showMessageDialog(form, "Malformed integer for quantity",
716 "Internal Error", JOptionPane.ERROR_MESSAGE);
717 return;
718 }
719
720 card.remove(qty);
721
722 if (card.getAmount() <= 0) {
723 rightListModel.getCards().remove(rightList.getSelectedRow());
724 rightListModel.fireTableRowsDeleted(0, rightList.getRowCount());
725 } else
726 rightListModel.fireTableCellUpdated(rightListModel.getCards().indexOf(
727 card.getName()), 0);
728
729 final FileInputStream dbStream = MdbLoader.resetMdb();
730 datasets.removeCard(getCardModel(card.getName(), dbStream), qty);
731 modifiedSinceSave = true;
732
733 }
734
735 /***
736 * Update the checker and repaint the right list.
737 */
738 private void updateChecker() {
739 constraintsChecker.updateCheckers();
740 rightList.repaint();
741 }
742
743 /***
744 * Return the associated cardModel to the given real card name. The card is
745 * searched in the input starting from a given offset.
746 *
747 * @param realCardName
748 * the card name as written in the MDB stream.
749 * @param input
750 * the input stream of current MDB.
751 * @return the corresponding CardModel instance, or null if the card has not
752 * been matched.
753 */
754 private CardModel getCardModel(String realCardName, FileInputStream input) {
755 try {
756 final int index = allListModel.indexOf(realCardName);
757 final MCardCompare card = allListModel.getElementAt(index);
758 return card.getModel(input);
759 } catch (IOException e) {
760 return null;
761 }
762 }
763
764 /***
765 * check if the current deck has been modified since it has been saved. If the
766 * current deck has been modified, we ask to the user if he want to save it
767 * before loading another.
768 *
769 * @return true if the user has chosen to save the deck before continuing and
770 * if the save has success. False otherwise
771 */
772 private boolean verifyModification() {
773 if (!modifiedSinceSave) {
774
775 return true;
776 }
777
778
779 Object[] options = { "Ok", "No", "Cancel" };
780 switch (JOptionPane.showOptionDialog(form,
781 "Current deck has been modified, save it before loading another?",
782 "Save changes", JOptionPane.YES_NO_CANCEL_OPTION,
783 JOptionPane.WARNING_MESSAGE, null, options, null)) {
784 case 0:
785
786 return saveCurrentDeck();
787 case 1:
788
789 return true;
790 default:
791
792 return false;
793 }
794 }
795
796 /***
797 * Save the current deck. If the current deck has not been saved once, user
798 * have to specify the file's name of this new deck
799 *
800 * @return true if the current deck has been correctly saved. false otherwise.
801 */
802 private boolean saveCurrentDeck() {
803 if (isNew || Configuration.getString("decks.deck(0)", "").length() == 0
804 && MToolKit.getDeckFile(this, JFileChooser.SAVE_DIALOG) == null) {
805 return false;
806 }
807 return MSaveDeck.saveDeck(Configuration.getString("decks.deck(0)"),
808 rightListModel.getCards(), form);
809 }
810
811 /***
812 * load the settings of jDecBuilder First byte is the Version Then :
813 *
814 * @since 0.2 the MDB file
815 * @since 0.2 the last deck file used
816 * @since 0.7 the settings are read from .properties file
817 */
818 private void loadSettings() {
819
820 if (consoleMode || MToolKit.tbsName == null) {
821
822
823
824
825 LanguageManager.initLanguageManager(Configuration.getString("language",
826 "auto"));
827 optionMenu = new JMenu(LanguageManager.getString("options"));
828 optionMenu.setMnemonic('o');
829 initAbstractMenu();
830 final String tbsName = Configuration.getString("lastTBS");
831 if (tbsName != null && tbsName.length() != 0) {
832 setMdb(tbsName);
833 }
834 }
835
836 }
837
838 /***
839 * Invoked when an action occurs.
840 *
841 * @param e
842 * attached event
843 */
844 @SuppressWarnings("unchecked")
845 public void actionPerformed(ActionEvent e) {
846 String command = e.getActionCommand();
847 if ("menu_help_about".equals(command)) {
848 new About(form).setVisible(true);
849 } else if ("menu_db_exit".equals(command)) {
850 exitForm();
851 } else if ("menu_db_new".equals(command)) {
852 if (!verifyModification()) {
853 return;
854 }
855 setTitle("DeckBuilder");
856 deckNameTxt.setText("");
857 rightListModel.getCards().clear();
858 datasets.removeAll();
859 modifiedSinceSave = false;
860 updateChecker();
861 setAsNew();
862 } else if ("menu_convert_DCK_MP".equals(command)) {
863
864
865
866 try {
867 Converter.convertDCK(MToolKit.showDialogFile(
868 "Choose a directory of DCK to convert", 'o', null, FILTER_DECK,
869 this, JFileChooser.OPEN_DIALOG, JFileChooser.DIRECTORIES_ONLY)
870 .getCanonicalPath());
871 } catch (IOException e1) {
872 JOptionPane.showMessageDialog(this,
873 "Error occurred reading the specified directory", "File problem",
874 JOptionPane.ERROR_MESSAGE);
875 } catch (Exception e1) {
876
877 }
878 } else if ("menu_db_constraints".equals(command)) {
879
880 new DeckRules(this).setVisible(true);
881 } else if ("menu_help_help".equals(command)) {
882
883
884
885
886 JOptionPane.showMessageDialog(form,
887 "Sorry, no documentation available for deck builder",
888 "Negative yet implemented", JOptionPane.INFORMATION_MESSAGE);
889 } else if ("menu_db_load".equals(command)) {
890 if (verifyModification()) {
891 String deckFile = MToolKit.getDeckFile(this, JFileChooser.OPEN_DIALOG);
892 if (deckFile != null) {
893 loadDeck(deckFile, rightListModel.getCards());
894 }
895 }
896 } else if ("menu_db_saveas".equals(command)) {
897 String deckFile = MToolKit.getDeckFile(this, JFileChooser.SAVE_DIALOG);
898 if (deckFile != null) {
899 MSaveDeck.saveDeck(deckFile, rightListModel.getCards(), form);
900 setAsSaved();
901 }
902 } else if ("menu_db_save".equals(command)) {
903 saveCurrentDeck();
904 setAsSaved();
905 } else {
906
907 final MListModel<MCardCompare> model = (MListModel<MCardCompare>) leftList
908 .getModel();
909
910 final FileInputStream dbStream = MdbLoader.resetMdb();
911
912 final List<MCardCompare> toRemove = new ArrayList<MCardCompare>();
913
914 if ("clear".equals(command)) {
915
916 for (Component component : toolBar.getComponents()) {
917 if (component instanceof JToggleButton) {
918 ((JToggleButton) component).setSelected(true);
919 }
920 }
921 }
922 model.addAll(model.removedDelegate);
923
924 final int cardType = CardFactory.getIdCard((String) idCardComboBox
925 .getSelectedItem());
926 if (cardType != -1) {
927
928
929 for (MCardCompare cardCompare : model.delegate) {
930 try {
931 final CardModel cardModel = cardCompare.getModel(dbStream);
932 if (!MCard.hasIdCard(cardModel.getIdCard(), cardType)) {
933 toRemove.add(cardCompare);
934 }
935 } catch (IOException e1) {
936 e1.printStackTrace();
937 }
938 }
939 model.removeAll(toRemove);
940 toRemove.clear();
941 }
942
943
944
945
946 int property = CardFactory.getProperty((String) propertiesComboBox
947 .getSelectedItem());
948
949 if (property != -1) {
950
951
952 for (MCardCompare cardCompare : model.delegate) {
953 try {
954 final CardModel cardModel = cardCompare.getModel(dbStream);
955 if (!MCard.hasProperty(cardModel.getProperties(), property)) {
956 toRemove.add(cardCompare);
957 }
958 } catch (IOException e1) {
959 e1.printStackTrace();
960 }
961 }
962 model.removeAll(toRemove);
963 toRemove.clear();
964 }
965
966
967 for (int i = 1; i < IdCardColors.CARD_COLOR_VALUES.length + 1; i++) {
968 final JToggleButton colorButton = (JToggleButton) toolBar
969 .getComponent(i);
970 if (!colorButton.isSelected()) {
971 for (MCardCompare cardCompare : model.delegate) {
972 try {
973 final CardModel cardModel = cardCompare.getModel(dbStream);
974 if (i == 1) {
975 if (cardModel.getIdColor() == 0) {
976 toRemove.add(cardCompare);
977 }
978 } else if ((cardModel.getIdColor() & IdCardColors.CARD_COLOR_VALUES[i - 1]) == IdCardColors.CARD_COLOR_VALUES[i - 1]) {
979 toRemove.add(cardCompare);
980 }
981 } catch (IOException e1) {
982 e1.printStackTrace();
983 }
984 }
985 model.removeAll(toRemove);
986 toRemove.clear();
987 }
988 }
989 leftList.repaint();
990 if (!model.isEmpty())
991 leftList.setSelectedIndex(0);
992 }
993 }
994
995 /***
996 * Set the current TBS name.
997 *
998 * @param tbsName
999 * the TBS to define as current.
1000 */
1001 protected void setToolKitMdb(String tbsName) {
1002 MdbLoader.setToolKitMdb(tbsName);
1003 readAvailableCards(allListModel);
1004 }
1005
1006 public void mouseClicked(MouseEvent e) {
1007 if (e.getSource() == leftList && e.getClickCount() == 2) {
1008 refreshAddComponent(true);
1009 } else if (e.getSource() == removeButton
1010 && rightList.getSelectedRow() != -1) {
1011 removeCardFromDeck();
1012 } else if (e.getSource() == cardNameTxt) {
1013 cardNameTxt.selectAll();
1014 }
1015 }
1016
1017 @Override
1018 public void windowClosing(WindowEvent e) {
1019 exitForm();
1020 }
1021
1022 /***
1023 * Set the working deck as new.
1024 */
1025 protected void setAsNew() {
1026 isNew = true;
1027 }
1028
1029 /***
1030 * Set the working deck as saved.
1031 */
1032 protected void setAsSaved() {
1033 isNew = false;
1034 modifiedSinceSave = false;
1035 String filename = FilenameUtils.removeExtension(FilenameUtils
1036 .getName(Configuration.getString("decks.deck(0)")));
1037 setTitle("DeckBuilder : ".concat(filename));
1038 deckNameTxt.setText(filename);
1039 }
1040
1041 /***
1042 * Are we working with a new deck?
1043 */
1044 private boolean isNew = false;
1045
1046 private final ChartSets datasets;
1047
1048 private Map<ChartFilter, Map<Integer, IChartKey>> keyMapper;
1049
1050 private Map<ChartFilter, Map<Integer, Paint>> painterMapper;
1051
1052 private void initSets() {
1053 final Map<Integer, Paint> painterColorMapper = new TreeMap<Integer, Paint>();
1054 for (int index = IdCardColors.CARD_COLOR_VALUES.length; index-- > 0;) {
1055 painterColorMapper.put(IdCardColors.CARD_COLOR_VALUES[index],
1056 IdCardColors.CARD_COLOR[index]);
1057 }
1058 painterColorMapper.put(ChartFilter.DEFAULT_KEY, Color.YELLOW.darker()
1059 .darker());
1060 painterMapper = new HashMap<ChartFilter, Map<Integer, Paint>>();
1061 painterMapper.put(ChartFilter.color, painterColorMapper);
1062
1063 final Map<Integer, IChartKey> keyColorMapper = new TreeMap<Integer, IChartKey>();
1064 for (int index = 0; index < IdCardColors.CARD_COLOR_VALUES.length; index++) {
1065 keyColorMapper.put(IdCardColors.CARD_COLOR_VALUES[index], new CardColor(
1066 LanguageManager.getString(IdCardColors.CARD_COLOR_NAMES[index]),
1067 IdCardColors.CARD_COLOR_VALUES[index]));
1068 }
1069 keyColorMapper.put(ChartFilter.DEFAULT_KEY, CardColor.UNKNOW_COLOR);
1070
1071 final Map<Integer, IChartKey> keyTypeMapper = new TreeMap<Integer, IChartKey>();
1072 for (int index = 0; index < CardFactory.exportedIdCardNames.length; index++) {
1073 keyTypeMapper.put(CardFactory.exportedIdCardValues[index], new CardTypes(
1074 CardFactory.exportedIdCardNames[index],
1075 CardFactory.exportedIdCardValues[index]));
1076 }
1077 keyTypeMapper.put(ChartFilter.DEFAULT_KEY, CardTypes.UNKNOW_TYPE);
1078
1079 keyMapper = new HashMap<ChartFilter, Map<Integer, IChartKey>>();
1080 keyMapper.put(ChartFilter.color, keyColorMapper);
1081 keyMapper.put(ChartFilter.type, keyTypeMapper);
1082 keyMapper.put(ChartFilter.property, new TreeMap<Integer, IChartKey>());
1083 keyMapper.put(ChartFilter.manacost, new TreeMap<Integer, IChartKey>());
1084 }
1085
1086 private Map<Integer, IChartKey> getMapper(ChartFilter filter) {
1087 return keyMapper.get(filter);
1088 }
1089
1090 public List<IChartKey> getKeys(ChartFilter filter) {
1091 List<IChartKey> list = new ArrayList<IChartKey>(getMapper(filter).values());
1092 Collections.sort(list);
1093 return list;
1094 }
1095
1096 public Collection<IChartKey> getKeys(CardModel cardModel, ChartFilter filter) {
1097 Collection<IChartKey> result = new ArrayList<IChartKey>();
1098 switch (filter) {
1099 case color:
1100 int idColor = cardModel.getIdColor();
1101 if (idColor == 0)
1102 result.add(getMapper(filter).get(IdCardColors.CARD_COLOR_VALUES[0]));
1103 else {
1104 for (IChartKey value : getMapper(filter).values()) {
1105 if (value.getIntegerKey() != 0
1106 && MCard.hasIdColor(idColor, value.getIntegerKey())) {
1107 result.add(value);
1108 }
1109 }
1110 }
1111 break;
1112 case type:
1113 int idCard = cardModel.getIdCard();
1114 for (IChartKey value : getMapper(filter).values()) {
1115 if (MCard.hasIdCard(idCard, value.getIntegerKey()))
1116 result.add(value);
1117 }
1118 break;
1119 case manacost:
1120 int total = 0;
1121 for (int index = IdCommonToken.WHITE_MANA + 1; index-- > 0;) {
1122 total += cardModel.getStaticRegisters()[index];
1123 }
1124 result.add(new CardManaCost(total));
1125 break;
1126 default:
1127
1128 }
1129 if (result.isEmpty()) {
1130 IChartKey defaultKey = getMapper(filter).get(ChartFilter.DEFAULT_KEY);
1131 if (defaultKey != null)
1132 result.add(getMapper(filter).get(ChartFilter.DEFAULT_KEY));
1133 }
1134 return result;
1135 }
1136
1137 public void tableChanged(TableModelEvent e) {
1138 if (e.getType() == TableModelEvent.UPDATE)
1139 rightListModel.getCards().refresh();
1140 }
1141
1142 /***
1143 * Read available cards from file and add them to the specified
1144 * <code>cardNames</code>
1145 *
1146 * @param cardNames
1147 * to this list method add card names
1148 */
1149 protected void readAvailableCards(MListModel<MCardCompare> cardNames) {
1150 final FileInputStream dbStream = MdbLoader.resetMdb();
1151 listScrollerLeft.setVisible(false);
1152 try {
1153 cardNames.clear();
1154 while (dbStream.available() > 2) {
1155
1156 final String cardName = MToolKit.readString(dbStream);
1157
1158
1159 final long offset = MToolKit.readInt24(dbStream);
1160 final MCardCompare cardCompare = new MCardCompare(cardName, offset);
1161 cardNames.add(cardCompare);
1162 }
1163 } catch (IOException ex2) {
1164
1165 ex2.printStackTrace();
1166 } finally {
1167 listScrollerLeft.setVisible(true);
1168 cardNames.refresh();
1169 }
1170 }
1171
1172 private static final FileFilterPlus FILTER_DECK = new FileFilterPlus("dck",
1173 "DCK : Shandalar deck file");
1174
1175 /***
1176 * The left list model containing all cards.
1177 */
1178 protected final MListModel<MCardCompare> allListModel;
1179
1180 /***
1181 * The right table model containing the current deck cards.
1182 */
1183 protected final MCardTableModel rightListModel;
1184
1185 private static boolean modifiedSinceSave = false;
1186
1187 private final JButton addButton;
1188
1189 private final JButton removeButton;
1190
1191 /***
1192 * The right list : cards in the deck.
1193 */
1194 private final JTable rightList;
1195
1196 /***
1197 * The left list : available cards.
1198 */
1199 protected final JList leftList;
1200
1201 private final JTextField cardNameTxt;
1202
1203 /***
1204 * Add text
1205 */
1206 private final JTextField addQtyTxt;
1207
1208 /***
1209 * Remove text
1210 */
1211 private final JTextField removeQtyTxt;
1212
1213 /***
1214 * The label displayed above the card picture
1215 */
1216 private final JLabel cardPictureNameTxt;
1217
1218 /***
1219 * indicates if deck builder was launched from console
1220 */
1221 public static boolean consoleMode = false;
1222
1223 /***
1224 * The toolBar containing some filters and card type combobox.
1225 */
1226 private final JToolBar toolBar;
1227
1228 private final JComboBox idCardComboBox;
1229
1230 private final JComboBox propertiesComboBox;
1231
1232 private final JLabel oracleText;
1233
1234 private final ConstraintsChecker constraintsChecker;
1235
1236 /***
1237 * The deck title
1238 */
1239 private final JTextField deckNameTxt;
1240
1241 /***
1242 * The unique instance of this form.
1243 */
1244 public static DeckBuilder form;
1245 }