View Javadoc

1   /*
2    *   Firemox is a turn based strategy simulator
3    *   Copyright (C) 2003-2007 Fabrice Daugan
4    *
5    *   This program is free software; you can redistribute it and/or modify it 
6    * under the terms of the GNU General Public License as published by the Free 
7    * Software Foundation; either version 2 of the License, or (at your option) any
8    * later version.
9    *
10   *   This program is distributed in the hope that it will be useful, but WITHOUT 
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
13   * details.
14   *
15   *   You should have received a copy of the GNU General Public License along  
16   * with this program; if not, write to the Free Software Foundation, Inc., 
17   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   * 
19   */
20  package net.sf.firemox;
21  
22  import java.awt.Color;
23  import java.awt.Font;
24  import java.awt.Frame;
25  import java.awt.Toolkit;
26  import java.awt.event.ActionEvent;
27  import java.awt.event.MouseEvent;
28  import java.awt.event.WindowEvent;
29  import java.io.BufferedReader;
30  import java.io.File;
31  import java.io.FileFilter;
32  import java.io.FileInputStream;
33  import java.io.InputStreamReader;
34  import java.util.ArrayList;
35  import java.util.Arrays;
36  import java.util.Collections;
37  import java.util.LinkedList;
38  import java.util.List;
39  
40  import javax.swing.AbstractButton;
41  import javax.swing.ButtonGroup;
42  import javax.swing.JColorChooser;
43  import javax.swing.JDialog;
44  import javax.swing.JFrame;
45  import javax.swing.JOptionPane;
46  import javax.swing.JRadioButtonMenuItem;
47  import javax.swing.LookAndFeel;
48  import javax.swing.SwingUtilities;
49  import javax.swing.ToolTipManager;
50  import javax.swing.UIManager;
51  import javax.swing.UIManager.LookAndFeelInfo;
52  
53  import net.sf.firemox.action.PayMana;
54  import net.sf.firemox.clickable.target.card.CardFactory;
55  import net.sf.firemox.clickable.target.player.Player;
56  import net.sf.firemox.database.DatabaseFactory;
57  import net.sf.firemox.deckbuilder.Deck;
58  import net.sf.firemox.deckbuilder.DeckReader;
59  import net.sf.firemox.deckbuilder.MdbLoader;
60  import net.sf.firemox.network.Client;
61  import net.sf.firemox.network.ConnectionManager;
62  import net.sf.firemox.network.MChat;
63  import net.sf.firemox.network.Server;
64  import net.sf.firemox.network.message.CoreMessageType;
65  import net.sf.firemox.stack.EventManager;
66  import net.sf.firemox.stack.StackManager;
67  import net.sf.firemox.token.IdConst;
68  import net.sf.firemox.token.MCommonVars;
69  import net.sf.firemox.tools.Configuration;
70  import net.sf.firemox.tools.JavaVersion;
71  import net.sf.firemox.tools.Log;
72  import net.sf.firemox.tools.MToolKit;
73  import net.sf.firemox.tools.Pair;
74  import net.sf.firemox.tools.VersionChecker;
75  import net.sf.firemox.tools.WebBrowser;
76  import net.sf.firemox.ui.MUIManager;
77  import net.sf.firemox.ui.MagicUIComponents;
78  import net.sf.firemox.ui.SkinLF;
79  import net.sf.firemox.ui.UIHelper;
80  import net.sf.firemox.ui.component.LoaderConsole;
81  import net.sf.firemox.ui.component.ProxyConfiguration;
82  import net.sf.firemox.ui.component.SplashScreen;
83  import net.sf.firemox.ui.i18n.LanguageManager;
84  import net.sf.firemox.ui.wizard.About;
85  import net.sf.firemox.ui.wizard.AboutMdb;
86  import net.sf.firemox.ui.wizard.Bug;
87  import net.sf.firemox.ui.wizard.Feature;
88  import net.sf.firemox.ui.wizard.InputNumber;
89  import net.sf.firemox.ui.wizard.Settings;
90  import net.sf.firemox.ui.wizard.Wizard;
91  import net.sf.firemox.xml.XmlConfiguration;
92  import net.sf.firemox.xml.XmlParser;
93  import net.sf.firemox.xml.XmlParser.Node;
94  import net.sf.firemox.xml.magic.Oracle2Xml;
95  import net.sf.firemox.zone.Play;
96  import net.sf.firemox.zone.ZoneManager;
97  
98  import org.apache.commons.io.IOUtils;
99  import org.apache.commons.lang.ArrayUtils;
100 import org.jvnet.substance.SubstanceLookAndFeel;
101 
102 import com.l2fprod.util.ZipResourceLoader;
103 
104 /***
105  * @author Fabrice Daugan
106  * @version 0.54
107  * @since 0.54 All listeners are no more implemented as inner class
108  */
109 public final class Magic extends MagicUIComponents {
110 
111 	/***
112 	 * Creates new form Magic
113 	 */
114 	private Magic() {
115 		super();
116 		initComponents();
117 
118 		// list all installed Look&Feel
119 		UIListener uiListener = new UIListener();
120 		UIManager.LookAndFeelInfo[] uimTMP = UIManager.getInstalledLookAndFeels();
121 		final List<Pair<String, String>> lfList = new ArrayList<Pair<String, String>>();
122 		for (LookAndFeelInfo lookAndFeel : uimTMP) {
123 			Pair<String, String> info = new Pair<String, String>(lookAndFeel
124 					.getName(), lookAndFeel.getClassName());
125 			if (!lfList.contains(info)) {
126 				lfList.add(info);
127 			}
128 		}
129 
130 		// list all SkinLF themes
131 		final File[] themes = MToolKit.getFile("lib").listFiles(new FileFilter() {
132 			public boolean accept(File f) {
133 				return f != null && f.getName().endsWith(".zip");
134 			}
135 		});
136 
137 		int maxIndex = Configuration.getConfiguration().getMaxIndex(
138 				"themes.skinlf.caches.cache");
139 		List<Pair<String, String>> knownThemes = new ArrayList<Pair<String, String>>();
140 		for (int i = 0; i < maxIndex + 1; i++) {
141 			String file = Configuration.getConfiguration().getString(
142 					"themes.skinlf.caches.cache(" + i + ").[@file]");
143 			int index = ArrayUtils.indexOf(themes, MToolKit.getFile(file));
144 			if (index >= 0) {
145 				themes[index] = null;
146 				Pair<String, String> skin = new Pair<String, String>(Configuration
147 						.getConfiguration().getString(
148 								"themes.skinlf.caches.cache(" + i + ").[@name]"), file);
149 				knownThemes.add(skin);
150 				lfList.add(skin);
151 			}
152 		}
153 
154 		for (File theme : themes) {
155 			if (theme != null) {
156 				// a new theme --> will be cached
157 				try {
158 					final List<Node> properties = new XmlParser().parse(
159 							new ZipResourceLoader(theme.toURI().toURL())
160 									.getResourceAsStream("skinlf-themepack.xml")).getNodes(
161 							"property");
162 					PROPERTIES: for (int j = 0; j < properties.size(); j++) {
163 						if ("skin.name".equals(properties.get(j).getAttribute("name"))) {
164 							// skin name found
165 							String relativePath = MToolKit.getRelativePath(theme
166 									.getCanonicalPath());
167 							Pair<String, String> skin = new Pair<String, String>(properties
168 									.get(j).getAttribute("value"), "zip:" + relativePath);
169 							lfList.add(skin);
170 							knownThemes.add(new Pair<String, String>(properties.get(j)
171 									.getAttribute("value"), relativePath));
172 							break PROPERTIES;
173 						}
174 					}
175 				} catch (Exception e) {
176 					Log.error("Error in " + theme, e);
177 				}
178 			}
179 		}
180 
181 		Configuration.getConfiguration().clearProperty("themes.skinlf.caches");
182 		for (int index = 0; index < knownThemes.size(); index++) {
183 			Pair<String, String> skin = knownThemes.get(index);
184 			Configuration.getConfiguration().setProperty(
185 					"themes.skinlf.caches.cache(" + index + ").[@name]", skin.key);
186 			Configuration.getConfiguration().setProperty(
187 					"themes.skinlf.caches.cache(" + index + ").[@file]", skin.value);
188 		}
189 
190 		// create look and feel menu items
191 		Collections.sort(lfList);
192 		lookAndFeels = new JRadioButtonMenuItem[lfList.size() + 1];
193 		ButtonGroup group5 = new ButtonGroup();
194 		for (int i = 0; i < lfList.size(); i++) {
195 			final String lfName = lfList.get(i).key;
196 			final String lfClassName = lfList.get(i).value;
197 			lookAndFeels[i] = new JRadioButtonMenuItem(lfName);
198 			if (lookAndFeelName.equalsIgnoreCase(lfClassName)) {
199 				// this the current l&f
200 				lookAndFeels[i].setSelected(true);
201 			}
202 			if (!SkinLF.isSkinLF(lfClassName)) {
203 				lookAndFeels[i]
204 						.setEnabled(MToolKit.isAvailableLookAndFeel(lfClassName));
205 			}
206 			group5.add(lookAndFeels[i]);
207 			lookAndFeels[i].setActionCommand(lfClassName);
208 			themeMenu.add(lookAndFeels[i], i);
209 			lookAndFeels[i].addActionListener(uiListener);
210 		}
211 		lfList.clear();
212 
213 		initialdelayMenu.addActionListener(this);
214 		dismissdelayMenu.addActionListener(this);
215 
216 		ConnectionManager.enableConnectingTools(false);
217 
218 		// read auto mana option
219 		MCommonVars.autoMana = Configuration.getBoolean("automana", true);
220 		autoManaMenu.setSelected(MCommonVars.autoMana);
221 
222 		// Force to initialize the TBS settings
223 		MToolKit.tbsName = null;
224 		setMdb(Configuration.getString("lastTBS", IdConst.TBS_DEFAULT));
225 
226 		// set the autoStack mode
227 		MCommonVars.autoStack = Configuration.getBoolean("autostack", false);
228 		autoPlayMenu.setSelected(MCommonVars.autoStack);
229 
230 		// read maximum displayed colored mana in context
231 		PayMana.thresholdColored = Configuration.getInt("threshold-colored", 6);
232 
233 		ZoneManager.updateLookAndFeel();
234 
235 		// pack this frame
236 		pack();
237 
238 		// Maximize this frame
239 		setExtendedState(Frame.MAXIMIZED_BOTH);
240 
241 		if (batchMode != -1) {
242 
243 			final String deckFile = Configuration.getString(Configuration
244 					.getString("decks.deck(0)"));
245 			try {
246 				Deck batchDeck = DeckReader.getDeck(this, deckFile);
247 				switch (batchMode) {
248 				case BATCH_SERVER:
249 					ConnectionManager.server = new Server(batchDeck, null);
250 					ConnectionManager.server.start();
251 					break;
252 				case BATCH_CLIENT:
253 					ConnectionManager.client = new Client(batchDeck, null);
254 					ConnectionManager.client.start();
255 					break;
256 				default:
257 				}
258 			} catch (Throwable e) {
259 				throw new RuntimeException("Error in batch mode : ", e);
260 			}
261 		}
262 	}
263 
264 	/***
265 	 * invoked when player declines to response to an event.
266 	 * 
267 	 * @see net.sf.firemox.stack.ActionManager#manualSkip()
268 	 */
269 	public void manualSkip() {
270 		// do the right action : cancel or skip?
271 		if (StackManager.idHandedPlayer == 0) {
272 			Player.unsetHandedPlayer();
273 			sendManualSkip();
274 			// abort this spell/ability
275 			StackManager.actionManager.manualSkip();
276 		}
277 	}
278 
279 	/***
280 	 * Send the "manual skipped" action to opponent
281 	 */
282 	public static void sendManualSkip() {
283 		// we inform opponent that we abort this cast or skip phase/event
284 		net.sf.firemox.tools.Log.debug("      ...-> manual skip");
285 		ConnectionManager.send(CoreMessageType.SKIP);
286 	}
287 
288 	/***
289 	 * Exit the Application
290 	 * 
291 	 * @param evt
292 	 *          is ignored
293 	 */
294 	private void exitForm(WindowEvent evt) {
295 		try {
296 			ConnectionManager.closeConnexions();
297 		} catch (Throwable t) {
298 			// ignore error
299 		}
300 		saveSettings();
301 		System.exit(0);
302 	}
303 
304 	/***
305 	 * Save the settings
306 	 */
307 	public static void saveSettings() {
308 		// save part of LF_SETTINGS_FILE
309 		try {
310 			// save your preferred look and feel
311 			if (lookAndFeelName.toUpperCase().startsWith(
312 					"ZIP:" + MToolKit.getRelativePath().toUpperCase())) {
313 				Configuration.setProperty("preferred", "zip:"
314 						+ MToolKit.getFile(
315 								lookAndFeelName.substring("zip:".length()
316 										+ MToolKit.getRelativePath().length() + 1)).toString()
317 								.replace('//', '/'));
318 			} else {
319 				Configuration.setProperty("preferred", lookAndFeelName);
320 			}
321 
322 			// save back colors and wallpapers
323 			ZoneManager.saveSettings();
324 
325 			Configuration.setProperty("language", LanguageManager.getLanguage()
326 					.getKey());
327 			Configuration.setProperty("automana", MCommonVars.autoMana);
328 			Configuration.setProperty("autostack", MCommonVars.autoStack);
329 			Configuration.setProperty("lastTBS", MToolKit.tbsName);
330 
331 			// write proxy configuration
332 			Configuration.setProperty("logdisptime", logListing.isDispTime());
333 			Configuration.setProperty("loglocked", logListing.isLocked());
334 			Configuration.setProperty("chatdisptime", chatHistoryText.isDispTime());
335 			Configuration.setProperty("chatlocked", chatHistoryText.isLocked());
336 			Configuration.setProperty("threshold-colored", PayMana.thresholdColored);
337 			Configuration.setProperty("border-color",
338 					(CardFactory.borderColor == Color.BLACK ? "black"
339 							: CardFactory.borderColor == Color.WHITE ? "white" : "gold"));
340 
341 			targetTimer.saveSettings();
342 			CardFactory.saveSettings();
343 			DatabaseFactory.saveCache();
344 			Configuration.getConfiguration().save();
345 		} catch (Exception e) {
346 			JOptionPane.showMessageDialog(magicForm, LanguageManager
347 					.getString("savelfpb")
348 					+ " : " + e.getMessage(), LanguageManager.getString("error"),
349 					JOptionPane.WARNING_MESSAGE);
350 		}
351 
352 		// save the tbs settings
353 		MdbLoader.saveTBSSettings();
354 	}
355 
356 	/***
357 	 * Is the batch mode identifier.
358 	 */
359 	public static int batchMode = -1;
360 
361 	/***
362 	 * The SERVER batch mode.
363 	 */
364 	public static final int BATCH_SERVER = 0;
365 
366 	/***
367 	 * The CLIENT batch mode.
368 	 */
369 	public static final int BATCH_CLIENT = 1;
370 
371 	/***
372 	 * @param args
373 	 *          the command line arguments
374 	 * @throws Exception
375 	 */
376 	public static void main(String[] args) throws Exception {
377 		Log.debug("MP v" + IdConst.VERSION + ", jre:"
378 				+ System.getProperty("java.runtime.version") + ", jvm:"
379 				+ System.getProperty("java.vm.version") + ",os:"
380 				+ System.getProperty("os.name") + ", res:"
381 				+ Toolkit.getDefaultToolkit().getScreenSize().width + "x"
382 				+ Toolkit.getDefaultToolkit().getScreenSize().height + ", root:"
383 				+ MToolKit.getRootDir());
384 		System.setProperty("swing.aatext", "true");
385 		System.setProperty(SubstanceLookAndFeel.WATERMARK_IMAGE_PROPERTY, MToolKit
386 				.getIconPath(Play.ZONE_NAME + "/hardwoodfloor.png"));
387 
388 		System.getProperties().load(
389 				new FileInputStream(MToolKit.getFile("substancelaf.properties")));
390 		MToolKit.defaultFont = new Font("Arial", 0, 11);
391 		try {
392 			Log.init();
393 			if (args.length > 0) {
394 				final String[] args2 = new String[args.length - 1];
395 				System.arraycopy(args, 1, args2, 0, args.length - 1);
396 				if ("-rebuild".equals(args[0])) {
397 					XmlConfiguration.main(args2);
398 				} else if ("-oracle2xml".equals(args[0])) {
399 					Oracle2Xml.main(args2);
400 				} else if ("-batch".equals(args[0])) {
401 					if ("-server".equals(args[1])) {
402 						batchMode = BATCH_SERVER;
403 					} else if ("-client".equals(args[1])) {
404 						batchMode = BATCH_CLIENT;
405 					}
406 				} else {
407 					Log
408 							.error("Unknown options '"
409 									+ Arrays.toString(args)
410 									+ "'\nUsage : java -jar starter.jar <options>, where options are :\n"
411 									+ "\t-rebuild -game <tbs name> [-x] [-d] [-v] [-h] [-f] [-n]\n"
412 									+ "\t-oracle2xml -f <oracle file> -d <output directory> [-v] [-h]");
413 				}
414 				System.exit(0);
415 				return;
416 			}
417 			if (batchMode == -1 && !"Mac OS X".equals(System.getProperty("os.name"))) {
418 				splash = new SplashScreen(MToolKit.getIconPath("splash.jpg"), null,
419 						2000);
420 			}
421 
422 			// language settings
423 			LanguageManager.initLanguageManager(Configuration.getString("language",
424 					"auto"));
425 		} catch (Throwable t) {
426 			Log.error("START-ERROR : \n\t" + t.getMessage());
427 			System.exit(1);
428 			return;
429 		}
430 		Log.debug("MP Language : " + LanguageManager.getLanguage().getName());
431 		speparateAvatar = Toolkit.getDefaultToolkit().getScreenSize().height > 768;
432 
433 		// verify the java version, minimal is 1.5
434 		if (new JavaVersion().compareTo(new JavaVersion(IdConst.MINIMAL_JRE)) == -1) {
435 			Log.error(LanguageManager.getString("wrongjava") + IdConst.MINIMAL_JRE);
436 		}
437 
438 		// load look and feel settings
439 		lookAndFeelName = Configuration.getString("preferred",
440 				MUIManager.LF_SUBSTANCE_CLASSNAME);
441 		// try {
442 		// FileInputStream in= new FileInputStream("MAGIC.TTF");
443 		// MToolKit.defaultFont= Font.createFont(Font.TRUETYPE_FONT, in);
444 		// in.close();
445 		// MToolKit.defaultFont= MToolKit.defaultFont.deriveFont(Font.BOLD, 11);
446 		// }
447 		// catch (FileNotFoundException e) {
448 		// System.out.println("editorfont.ttf not found, using default.");
449 		// }
450 		// catch (Exception ex) {
451 		// ex.printStackTrace();
452 		// }
453 
454 		// Read available L&F
455 		final LinkedList<Pair<String, String>> lfList = new LinkedList<Pair<String, String>>();
456 		try {
457 			BufferedReader buffReader = new BufferedReader(new InputStreamReader(
458 					MToolKit.getResourceAsStream(IdConst.FILE_THEME_SETTINGS)));
459 			String line;
460 			while ((line = buffReader.readLine()) != null) {
461 				line = line.trim();
462 				if (!line.startsWith("#")) {
463 					final int index = line.indexOf(';');
464 					if (index != -1) {
465 						lfList.add(new Pair<String, String>(line.substring(0, index), line
466 								.substring(index + 1)));
467 					}
468 				}
469 			}
470 			IOUtils.closeQuietly(buffReader);
471 		} catch (Throwable e) {
472 			// no place for resolve this problem
473 			Log.debug("Error reading L&F properties : " + e.getMessage());
474 		}
475 		for (Pair<String, String> pair : lfList) {
476 			UIManager.installLookAndFeel(pair.key, pair.value);
477 		}
478 
479 		// install L&F
480 		if (SkinLF.isSkinLF(lookAndFeelName)) {
481 			// is a SkinLF Look & Feel
482 			/*
483 			 * Make sure we have a nice window decoration.
484 			 */
485 			SkinLF.installSkinLF(lookAndFeelName);
486 		} else {
487 			// is Metal Look & Feel
488 			if (!MToolKit.isAvailableLookAndFeel(lookAndFeelName)) {
489 				// preferred look&feel is not available
490 				JOptionPane.showMessageDialog(magicForm, LanguageManager.getString(
491 						"preferredlfpb", lookAndFeelName), LanguageManager
492 						.getString("error"), JOptionPane.INFORMATION_MESSAGE);
493 				setDefaultUI();
494 			}
495 
496 			// Install the preferred
497 			LookAndFeel newLAF = MToolKit.geLookAndFeel(lookAndFeelName);
498 			frameDecorated = newLAF.getSupportsWindowDecorations();
499 
500 			/*
501 			 * Make sure we have a nice window decoration.
502 			 */
503 			JFrame.setDefaultLookAndFeelDecorated(frameDecorated);
504 			JDialog.setDefaultLookAndFeelDecorated(frameDecorated);
505 			UIManager.setLookAndFeel(MToolKit.geLookAndFeel(lookAndFeelName));
506 		}
507 
508 		// Start main thread
509 		try {
510 			new Magic();
511 			SwingUtilities.invokeLater(SkinLF.REFRESH_RUNNER);
512 		} catch (Throwable e) {
513 			Log.fatal("In main thread, occurred exception : ", e);
514 			ConnectionManager.closeConnexions();
515 			return;
516 		}
517 	}
518 
519 	/***
520 	 * Initialize panel, life, poison, stack, menu
521 	 */
522 	public void initGame() {
523 		StackManager.reset();
524 		MdbLoader.loadTBSSettings();
525 		ZoneManager.updateReversed();
526 		Player.init();
527 		LoaderConsole.endTask();
528 		setVisible(true);
529 		backgroundBtn.stopButton();
530 		StackManager.noReplayToken.take();
531 		try {
532 			EventManager.start();
533 		} catch (Throwable t) {
534 			t.printStackTrace();
535 		} finally {
536 			StackManager.noReplayToken.release();
537 		}
538 	}
539 
540 	public void actionPerformed(ActionEvent e) {
541 		final String command = e.getActionCommand();
542 		final Object obj = e.getSource();
543 		if (obj == sendButton) {
544 			if (sendTxt.getText().length() != 0) {
545 				MChat.getInstance().sendMessage(sendTxt.getText() + "\n");
546 				sendTxt.setText("");
547 			}
548 		} else if (command != null && command.startsWith("border-")) {
549 			for (int i = cardBorderMenu.getComponentCount(); i-- > 0;) {
550 				((JRadioButtonMenuItem) cardBorderMenu.getComponent(i))
551 						.setSelected(false);
552 			}
553 			((JRadioButtonMenuItem) obj).setSelected(true);
554 			CardFactory.updateColor(command.substring("border-".length()));
555 			CardFactory.updateAllCardsUI();
556 			magicForm.repaint();
557 		} else if ("menu_help_mailing".equals(command)) {
558 			try {
559 				WebBrowser.launchBrowser("http://lists.sourceforge.net/lists/listinfo/"
560 						+ IdConst.PROJECT_NAME + "-user");
561 			} catch (Exception e1) {
562 				JOptionPane.showOptionDialog(this, LanguageManager.getString("error")
563 						+ " : " + e1.getMessage(), LanguageManager.getString("web-pb"),
564 						JOptionPane.OK_OPTION, JOptionPane.INFORMATION_MESSAGE, UIHelper
565 								.getIcon("wiz_update_error.gif"), null, null);
566 			}
567 		} else if ("menu_options_settings".equals(command)) {
568 			// Setting panel
569 			final Wizard settingsPanel = new Settings();
570 			settingsPanel.setVisible(true);
571 		} else if ("menu_help_check-update".equals(command)) {
572 			VersionChecker.checkVersion(this);
573 		} else if ("menu_game_new_client".equals(command)) {
574 			new net.sf.firemox.ui.wizard.Client().setVisible(true);
575 		} else if ("menu_game_new_server".equals(command)) {
576 			new net.sf.firemox.ui.wizard.Server().setVisible(true);
577 		} else if ("menu_tools_log".equals(command)) {
578 			new net.sf.firemox.ui.wizard.Log().setVisible(true);
579 		} else if ("menu_tools_featurerequest".equals(command)) {
580 			new Feature().setVisible(true);
581 		} else if ("menu_tools_bugreport".equals(command)) {
582 			new Bug().setVisible(true);
583 		} else if ("menu_game_skip".equals(command)) {
584 			if (ConnectionManager.isConnected() && skipButton.isEnabled()
585 					&& StackManager.idHandedPlayer == 0) {
586 				StackManager.noReplayToken.take();
587 				try {
588 					manualSkip();
589 				} catch (Throwable t) {
590 					t.printStackTrace();
591 				} finally {
592 					StackManager.noReplayToken.release();
593 				}
594 			}
595 		} else if ("menu_game_disconnect".equals(command)) {
596 			ConnectionManager.closeConnexions();
597 		} else if ("menu_tools_jdb".equals(command)) {
598 			DeckBuilder.loadFromMagic();
599 		} else if ("menu_game_exit".equals(command)) {
600 			exitForm(null);
601 		} else if (obj == autoManaMenu) {
602 			/*
603 			 * invoked you click directly on the "auto-mana option" of the menu
604 			 * "options". The opponent has to know that we are in "auto colorless mana
605 			 * use", since player will no longer click on the mana icon to define
606 			 * which colored mana active player has used as colorless mana, then the
607 			 * opponent have not to wait for active player choice, but apply the same
608 			 * Algorithm calculating which colored manas are used as colorless manas.
609 			 * This information is not sent immediately, but will be sent with the
610 			 * next action of active player.
611 			 */
612 			MCommonVars.autoMana = autoManaMenu.isSelected();
613 		} else if (obj == autoPlayMenu) {
614 			/*
615 			 * invoked you click directly on the "auto-play option" of the menu
616 			 * "options".
617 			 */
618 			MCommonVars.autoStack = autoPlayMenu.isSelected();
619 		} else if ("menu_tools_jcb".equals(command)) {
620 			// TODO cardBuilderMenu -> not yet implemented
621 			Log.info("cardBuilderMenu -> not yet implemented");
622 		} else if ("menu_game_proxy".equals(command)) {
623 			new ProxyConfiguration().setVisible(true);
624 		} else if ("menu_help_help".equals(command)) {
625 			/*
626 			 * Invoked you click directly on youLabel. Opponent will receive this
627 			 * information.
628 			 */
629 			try {
630 				WebBrowser.launchBrowser("http://prdownloads.sourceforge.net/"
631 						+ IdConst.PROJECT_NAME + "/7e_rulebook_EN.pdf?download");
632 			} catch (Exception e1) {
633 				JOptionPane.showOptionDialog(this, LanguageManager.getString("error")
634 						+ " : " + e1.getMessage(), LanguageManager.getString("web-pb"),
635 						JOptionPane.OK_OPTION, JOptionPane.INFORMATION_MESSAGE, UIHelper
636 								.getIcon("wiz_update_error.gif"), null, null);
637 			}
638 		} else if ("menu_help_about".equals(command)) {
639 			new About(this).setVisible(true);
640 		} else if ("menu_help_about.tbs".equals(command)) {
641 			new AboutMdb(this).setVisible(true);
642 		} else if (obj == reverseArtCheck || obj == reverseSideCheck) {
643 			Configuration.setProperty("reverseArt", reverseArtCheck.isSelected());
644 			Configuration.setProperty("reverseSide", reverseSideCheck.isSelected());
645 			ZoneManager.updateReversed();
646 			StackManager.PLAYERS[1].updateReversed();
647 			repaint();
648 			SwingUtilities.invokeLater(SkinLF.REFRESH_RUNNER);
649 		} else if (obj == soundMenu) {
650 			Configuration.setProperty("sound", soundMenu.isSelected());
651 			soundMenu.setIcon(soundMenu.isSelected() ? UIHelper.getIcon("sound.gif")
652 					: UIHelper.getIcon("soundoff.gif"));
653 		} else if ("menu_lf_randomAngle".equals(command)) {
654 			Configuration.setProperty("randomAngle", ((AbstractButton) e.getSource())
655 					.isSelected());
656 			CardFactory.updateAllCardsUI();
657 		} else if ("menu_lf_powerToughnessColor".equals(command)) {
658 			final Color powerToughnessColor = JColorChooser.showDialog(this,
659 					LanguageManager.getString("menu_lf_powerToughnessColor"),
660 					CardFactory.powerToughnessColor);
661 			if (powerToughnessColor != null) {
662 				Configuration.setProperty("powerToughnessColor", powerToughnessColor
663 						.getRGB());
664 				CardFactory.updateColor(null);
665 				repaint();
666 			}
667 		} else if (obj == initialdelayMenu) {
668 			// TODO factor this code with the one of Magic.class
669 			final ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
670 			new InputNumber(LanguageManager.getString("initialdelay"),
671 					LanguageManager.getString("initialdelay.tooltip"), 0,
672 					Integer.MAX_VALUE, toolTipManager.getInitialDelay()).setVisible(true);
673 			if (Wizard.optionAnswer == JOptionPane.YES_OPTION) {
674 				toolTipManager.setEnabled(Wizard.indexAnswer != 0);
675 				toolTipManager.setInitialDelay(Wizard.indexAnswer);
676 				initialdelayMenu.setText(LanguageManager.getString("initialdelay")
677 						+ (toolTipManager.isEnabled() ? " : " + Wizard.indexAnswer + " ms"
678 								: "(disabled)"));
679 				Configuration.setProperty("initialdelay", Wizard.indexAnswer);
680 			}
681 		} else if (obj == dismissdelayMenu) {
682 			// TODO factor this code with the one of Magic.class
683 			final ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
684 			new InputNumber(LanguageManager.getString("dismissdelay"),
685 					LanguageManager.getString("dismissdelay.tooltip"), 0,
686 					Integer.MAX_VALUE, toolTipManager.getDismissDelay()).setVisible(true);
687 			if (Wizard.optionAnswer == JOptionPane.YES_OPTION) {
688 				toolTipManager.setDismissDelay(Wizard.indexAnswer);
689 				Configuration.setProperty("dismissdelay", Wizard.indexAnswer);
690 				dismissdelayMenu.setText(LanguageManager.getString("dismissdelay")
691 						+ Wizard.indexAnswer + " ms");
692 			}
693 		}
694 
695 	}
696 
697 	public void mouseClicked(MouseEvent e) {
698 		Object obj = e.getSource();
699 		if (obj == skipButton) {
700 			/***
701 			 * invoked by a click directly on the "skip/cancel" of the label".
702 			 * 
703 			 * @param evt
704 			 *          mouse event
705 			 * @see MEventManager#raiseEvent(int,boolean)
706 			 * @see MEventManager#getNextStop()
707 			 * @see MPhase#breakpoint
708 			 * @see MPhase#skipAll
709 			 * @see Magic#manuaSkip()
710 			 */
711 			// only if enabled and left mouse button pressed
712 			StackManager.noReplayToken.take();
713 			try {
714 				if (ConnectionManager.isConnected() && skipButton.isEnabled()
715 						&& e.getButton() == MouseEvent.BUTTON1) {
716 					manualSkip();
717 				}
718 			} catch (Throwable t) {
719 				t.printStackTrace();
720 			} finally {
721 				StackManager.noReplayToken.release();
722 			}
723 		}
724 	}
725 
726 	@Override
727 	public void windowClosing(WindowEvent e) {
728 		Object obj = e.getSource();
729 		if (obj == this) {
730 			exitForm(e);
731 		}
732 	}
733 
734 }