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.clickable.target.card;
21  
22  import java.awt.Color;
23  import java.awt.Component;
24  import java.awt.Image;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.net.URL;
28  import java.util.Collection;
29  import java.util.HashMap;
30  import java.util.Map;
31  import java.util.SortedMap;
32  import java.util.TreeMap;
33  
34  import javax.swing.Icon;
35  import javax.swing.ImageIcon;
36  import javax.swing.JMenuItem;
37  import javax.swing.JPopupMenu;
38  
39  import net.sf.firemox.clickable.target.player.Player;
40  import net.sf.firemox.database.DatabaseFactory;
41  import net.sf.firemox.deckbuilder.MdbLoader;
42  import net.sf.firemox.stack.StackManager;
43  import net.sf.firemox.token.IdConst;
44  import net.sf.firemox.tools.Configuration;
45  import net.sf.firemox.tools.Log;
46  import net.sf.firemox.tools.MToolKit;
47  import net.sf.firemox.tools.Picture;
48  import net.sf.firemox.tools.StatePicture;
49  import net.sf.firemox.ui.MagicUIComponents;
50  import net.sf.firemox.ui.TooltipFilter;
51  import net.sf.firemox.ui.UIHelper;
52  import net.sf.firemox.ui.i18n.LanguageManager;
53  import net.sf.firemox.ui.i18n.LanguageManagerMDB;
54  import net.sf.firemox.zone.MZone;
55  
56  import org.apache.commons.lang.ArrayUtils;
57  import org.apache.commons.lang.StringUtils;
58  
59  /***
60   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
61   * @since 0.80
62   */
63  public final class CardFactory {
64  
65  	/***
66  	 * The key identifying the "gathered" zone text/action.
67  	 */
68  	public static final String STR_GATHER = "gather";
69  
70  	/***
71  	 * The key identifying the "expand" zone text/action.
72  	 */
73  	public static final String STR_EXPAND = "expand";
74  
75  	private static final float CONFIG_SCALE = 0.25f;
76  
77  	/***
78  	 * Rotate angle * PI
79  	 */
80  	public static final double ROTATE_SCALE = 0.015625d * 2 * Math.PI;
81  
82  	private static final String CONFIG_KEY_SCALE = "scale";
83  
84  	/***
85  	 * The color identifying the playable activated abilities.
86  	 */
87  	public static final Color ACTIVATED_COLOR = Color.yellow;
88  
89  	/***
90  	 * Custom colors of Power/Toughness
91  	 */
92  	public static Color powerToughnessColor;
93  
94  	/***
95  	 * Creates a new instance of the CardFactory.
96  	 */
97  	private CardFactory() {
98  		super();
99  	}
100 
101 	/***
102 	 * Initialize the preview card picture
103 	 * 
104 	 * @return the preview card picture
105 	 */
106 	public static Picture initPreview() {
107 		try {
108 			DatabaseFactory.backImage = Picture.loadImage(
109 					MToolKit.getTbsPicture(MdbLoader.backPicture, false),
110 					new URL(MdbLoader.getArtURL() + "/" + MdbLoader.backPicture))
111 					.getContent();
112 		} catch (Throwable e) {
113 			// ignore this error
114 			Log.debug(e);
115 		}
116 		try {
117 			if (DatabaseFactory.backImage == null) {
118 				DatabaseFactory.backImage = Picture.loadImage(
119 						MToolKit.getTbsPicture("default.jpg"), null).getContent();
120 			}
121 			try {
122 				DatabaseFactory.damageImage = Picture.loadImage(
123 						MToolKit.getTbsPicture(MdbLoader.damagePicture, false),
124 						new URL(MdbLoader.getArtURL() + "/" + MdbLoader.damagePicture))
125 						.getContent();
126 			} catch (Throwable e) {
127 				// ignore this error
128 				Log.debug(e);
129 			}
130 			if (DatabaseFactory.damageImage == null) {
131 				DatabaseFactory.damageImage = Picture.loadImage(
132 						MToolKit.getTbsPicture("default.jpg"), null).getContent();
133 			}
134 			DatabaseFactory.scaledBackImage = Picture
135 					.getScaledImage(DatabaseFactory.backImage);
136 			DatabaseFactory.damageScaledImage = Picture
137 					.getScaledImage(DatabaseFactory.damageImage);
138 		} catch (Throwable e) {
139 			// ignore this error
140 			Log.debug(e);
141 		}
142 		previewCard = new Picture(IdConst.STD_WIDTH, IdConst.STD_HEIGHT);
143 		return previewCard;
144 	}
145 
146 	/***
147 	 * Return an instance of CardModel. There is only one instance of CardModel by
148 	 * card with the same name.
149 	 * 
150 	 * @param cardName
151 	 *          the card name
152 	 * @return a newly created instance of CardModel if this card has not yet been
153 	 *         loaded, or a shared instance.
154 	 * @param inputStream
155 	 *          the input stream containing the data of this card.
156 	 */
157 	public static CardModel getCardModel(String cardName, InputStream inputStream) {
158 		return getCardModel(cardName, inputStream, LoadMode.init);
159 	}
160 
161 	/***
162 	 * Return an instance of CardModel. There is only one instance of CardModel by
163 	 * card with the same name.
164 	 * 
165 	 * @param cardName
166 	 *          the card name
167 	 * @return a newly created instance of CardModel if this card has not yet been
168 	 *         loaded, or a shared instance.
169 	 * @param inputStream
170 	 *          the input stream containing the data of this card.
171 	 * @param loadMode
172 	 *          loading mode.
173 	 */
174 	public static CardModel getCardModel(String cardName,
175 			InputStream inputStream, LoadMode loadMode) {
176 		if (cardName.startsWith("_")) {
177 			String realCardName = cardName.substring(1);
178 			CardModel res = loadedCards.get(realCardName);
179 			if (res == null) {
180 				if (inputStream == null) {
181 					// MDB is not available
182 					res = new CardModelImpl(realCardName);
183 				} else if (loadMode == LoadMode.lazy) {
184 					res = new CardModelLazy(realCardName, inputStream);
185 				} else {
186 					res = new CardModelImpl(realCardName, inputStream);
187 				}
188 				loadedCards.put(realCardName, res);
189 			} else if (inputStream != null) {
190 				if (res instanceof CardModelLazy && loadMode != LoadMode.lazy) {
191 					res = new CardModelImpl(realCardName, inputStream);
192 					loadedCards.put(realCardName, res);
193 				} else {
194 					// consume the stream
195 					new CardModelImpl("", inputStream);
196 				}
197 			} else {
198 				res = new CardModelImpl(cardName);
199 			}
200 			return res;
201 		}
202 
203 		CardModel res = loadedCards.get(cardName);
204 		if (res == null) {
205 			if (loadMode == LoadMode.lazy) {
206 				res = new CardModelLazy(cardName, inputStream);
207 			} else {
208 				if (inputStream == null) {
209 					res = new CardModelImpl(cardName);
210 				} else {
211 					res = new CardModelImpl(cardName, inputStream);
212 				}
213 			}
214 			loadedCards.put(cardName, res);
215 		} else if (res instanceof CardModelLazy && loadMode != LoadMode.lazy) {
216 			res = new CardModelImpl(cardName, inputStream);
217 			loadedCards.put(cardName, res);
218 		}
219 		return res;
220 	}
221 
222 	/***
223 	 * All settings defined in the properties file and relating cards are managed
224 	 * here. Also, initialize the tooltip headers and topics to display fastest
225 	 * the tooltip of card.
226 	 */
227 	public static void initSettings() {
228 		ttPower = "<br><b>" + LanguageManager.getString("power") + ": </b>";
229 		ttToughness = "<br><b>" + LanguageManager.getString("toughness") + ": </b>";
230 		ttState = "<br><b>" + LanguageManager.getString("states") + ": </b>";
231 		ttDamage = "<br><b>" + LanguageManager.getString("damages") + ": </b>";
232 		ttProperties = "<br><b>" + LanguageManager.getString("properties")
233 				+ ": </b>";
234 		ttColors = "<br><b>" + LanguageManager.getString("colors") + ": </b>";
235 		ttTypes = "<br><b>" + LanguageManager.getString("types") + ": </b>";
236 		ttHeader = "<html><b>" + LanguageManager.getString("card.name") + ": </b>";
237 		ttHeaderAbility = "<html><b>"
238 				+ LanguageManager.getString("activatedability")
239 				+ ": </b><br>&nbsp;&nbsp;";
240 
241 		ttAbility = "<br><br><b>" + LanguageManager.getString("activatedability")
242 				+ ": </b><font color='#336600'>";
243 		ttAbiltityEnd = "</font>";
244 
245 		ttManacost = "<br><b>" + LanguageManager.getString("manacost") + " :</b>";
246 		ttManapaid = ")<br><b>" + LanguageManager.getString("manapaid") + " :</b>";
247 
248 		ttAdvancedAability = "<br><br><img src='file:///"
249 				+ MToolKit.getIconPath("warn.gif") + "'><font color='#660000'><b>"
250 				+ LanguageManager.getString("advanceactivatedability") + ": </b>";
251 		ttAdvancedAabilityEnd = "</font>";
252 
253 		// credits
254 		ttRulesAuthor = "<br><br><b>" + LanguageManager.getString("rulesauthor")
255 				+ ": </b>";
256 
257 		ttSource = "<br><b>" + LanguageManager.getString("source") + ": </b>";
258 
259 		contextMenu = new JPopupMenu(LanguageManager.getString("options"));
260 		contextMenu.setFont(MToolKit.defaultFont);
261 		countItem = new JMenuItem("", UIHelper.getIcon("count.gif"));
262 		countItem.setFont(MToolKit.defaultFont);
263 		expandItem = new JMenuItem(LanguageManager.getString(STR_EXPAND), UIHelper
264 				.getIcon(STR_EXPAND + IdConst.TYPE_PIC));
265 		expandItem.setToolTipText("<html>" + MagicUIComponents.HTML_ICON_TIP
266 				+ LanguageManager.getString("expandTTtip2"));
267 		expandItem.setActionCommand(STR_EXPAND);
268 		expandItem.addActionListener(SystemCard.instance);
269 		expandItem.setFont(MToolKit.defaultFont);
270 		gatherItem = new JMenuItem(LanguageManager.getString(STR_GATHER), UIHelper
271 				.getIcon(STR_GATHER + IdConst.TYPE_PIC));
272 		gatherItem.setToolTipText("<html>" + MagicUIComponents.HTML_ICON_TIP
273 				+ LanguageManager.getString("expandTTtip2"));
274 		gatherItem.setActionCommand(STR_GATHER);
275 		gatherItem.addActionListener(SystemCard.instance);
276 		gatherItem.setFont(MToolKit.defaultFont);
277 		javaDebugItem = new JMenuItem(LanguageManager.getString("javadebug"),
278 				UIHelper.getIcon("javadebug.gif"));
279 		javaDebugItem.addActionListener(SystemCard.instance);
280 		databaseCardInfoItem = new JMenuItem(LanguageManager
281 				.getString("databasecard"), UIHelper.getIcon("databasecard.gif"));
282 		databaseCardInfoItem.addActionListener(SystemCard.instance);
283 		reloadPictureItem = new JMenuItem(LanguageManager
284 				.getString("card.reload.picture"), UIHelper.getIcon("reload.gif"));
285 		reloadPictureItem.addActionListener(SystemCard.instance);
286 		updateColor(Configuration.getString("border-color", "auto"));
287 		updateScale();
288 	}
289 
290 	/***
291 	 * Update the scale, sizes and random angle of all cards of current game.
292 	 */
293 	public static void updateAllCardsUI() {
294 		updateScale();
295 		for (Player player : StackManager.PLAYERS) {
296 			for (MZone zone : player.zoneManager.getValidTargetZones()) {
297 				for (Component card : zone.getComponents()) {
298 					((MCard) card).getMUI().updateMUI();
299 					((MCard) card).getDatabase().updateMUI();
300 					((MCard) card).getMUI().updateSizes();
301 				}
302 			}
303 		}
304 	}
305 
306 	/***
307 	 * Update the card border's color and other UI colors requiring only a global
308 	 * repaint to update the UI.
309 	 * 
310 	 * @param colorStr
311 	 *          is the new card border's color
312 	 */
313 	public static void updateColor(String colorStr) {
314 		if (colorStr != null) {
315 			if ("white".equals(colorStr)) {
316 				borderColor = Color.WHITE;
317 			} else if ("gold".equals(colorStr)) {
318 				borderColor = Color.YELLOW.darker().darker();
319 			} else if ("black".equals(colorStr)) {
320 				borderColor = Color.BLACK;
321 			} else {
322 				// Auto
323 				borderColor = null;
324 			}
325 		}
326 		powerToughnessColor = new Color(Configuration.getInt("powerToughnessColor",
327 				Color.BLUE.getRGB()));
328 	}
329 
330 	/***
331 	 * Save writable string settings of cards
332 	 */
333 	public static void saveSettings() {
334 		if (Color.WHITE.equals(borderColor)) {
335 			borderColor = Color.WHITE;
336 			Configuration.setProperty("border-color", "white");
337 		} else if (Color.YELLOW.darker().darker().equals(borderColor)) {
338 			Configuration.setProperty("border-color", "gold");
339 		} else if (Color.BLACK.equals(borderColor)) {
340 			Configuration.setProperty("border-color", "black");
341 		} else {
342 			// Auto
343 			Configuration.setProperty("border-color", "auto");
344 		}
345 	}
346 
347 	/***
348 	 * Read from the specified stream the state picture options. The current
349 	 * offset of the stream must pointing on the number of state pictures.
350 	 * <ul>
351 	 * Structure of InputStream : Data[size]
352 	 * <li>number of states [1]</li>
353 	 * <li>state picture name i + \0 [...]</li>
354 	 * <li>state value i + \0 [...]</li>
355 	 * <li>state picture x i [2]</li>
356 	 * <li>state picture y i [2]</li>
357 	 * <li>state picture width i [2]</li>
358 	 * <li>state picture height i [2]</li>
359 	 * </ul>
360 	 * <br>
361 	 * Read from the specified stream the tooltip filters. The current offset of
362 	 * the stream must pointing on the number of tooltip filters.
363 	 * <ul>
364 	 * Structure of stream : Data[size]
365 	 * <li>display powerANDtoughness yes=1,no=0 [1]</li>
366 	 * <li>display states yes=1,no=0 [1]</li>
367 	 * <li>display types yes=1,no=0 [1]</li>
368 	 * <li>display colors yes=1,no=0 [1]</li>
369 	 * <li>display properties yes=1,no=0 [1]</li>
370 	 * <li>display damage yes=1,no=0 [1]</li>
371 	 * <li>filter [...]</li>
372 	 * </ul>
373 	 * 
374 	 * @param input
375 	 *          the stream containing settings.
376 	 * @throws IOException
377 	 *           If some other I/O error occurs
378 	 */
379 	public static void init(InputStream input) throws IOException {
380 		loadedCards.clear();
381 		// load state pictures of card
382 		statePictures = new StatePicture[input.read()];
383 		for (int i = 0; i < statePictures.length; i++) {
384 			statePictures[i] = new StatePicture(input);
385 		}
386 
387 		// load tooltip filters
388 		tooltipFilters = new TooltipFilter[input.read()];
389 		for (int i = 0; i < tooltipFilters.length; i++) {
390 			tooltipFilters[i] = new TooltipFilter(input);
391 		}
392 
393 		// read types name export (this list must be sorted)
394 		int count = input.read();
395 		exportedIdCardNames = new String[count];
396 		exportedIdCardValues = new int[count];
397 		for (int i = 0; i < count; i++) {
398 			exportedIdCardNames[i] = StringUtils.capitalize(LanguageManagerMDB
399 					.getString(MToolKit.readString(input)));
400 			exportedIdCardValues[i] = MToolKit.readInt16(input);
401 		}
402 
403 		// read properties name export (this list must be sorted)
404 		exportedProperties = new TreeMap<Integer, String>();
405 		for (int i = MToolKit.readInt16(input); i-- > 0;) {
406 			final Integer key = Integer.valueOf(MToolKit.readInt16(input));
407 			exportedProperties.put(key, StringUtils.capitalize(LanguageManagerMDB
408 					.getString(MToolKit.readString(input))));
409 		}
410 
411 		// property pictures
412 		if (propertyPicturesHTML != null) {
413 			propertyPicturesHTML.clear();
414 			propertyPictures.clear();
415 		} else {
416 			propertyPictures = new HashMap<Integer, Image>();
417 			propertyPicturesHTML = new HashMap<Integer, String>();
418 		}
419 		for (int i = MToolKit.readInt16(input); i-- > 0;) {
420 			final int property = MToolKit.readInt16(input);
421 			final String pictureStr = MToolKit.readString(input);
422 			if (pictureStr.length() > 0) {
423 				final String pictureName = "properties/" + pictureStr;
424 				propertyPicturesHTML.put(property, "<img src='file:///"
425 						+ MToolKit.getTbsHtmlPicture(pictureName) + "'>&nbsp;");
426 				final String pictureFile = MToolKit.getTbsPicture("properties/"
427 						+ pictureStr);
428 				if (pictureFile != null) {
429 					propertyPictures.put(property, Picture.loadImage(pictureFile));
430 				} else if (MagicUIComponents.isUILoaded()) {
431 					Log.error("Unable to load property picture '"
432 							+ MToolKit.getTbsPicture(pictureName, false) + "'");
433 				}
434 			}
435 		}
436 
437 		// Add system card
438 		loadedCards.put("system", new CardModelImpl("system"));
439 	}
440 
441 	/***
442 	 * Update the scaling transformation for all cards
443 	 */
444 	public static void updateScale() {
445 		float scale = getScale();
446 		cardWidth = (int) (IdConst.STD_WIDTH * scale);
447 		cardHeight = (int) (IdConst.STD_HEIGHT * scale);
448 
449 		// TODO perspective view for card --> not yet implemented
450 		// atImageSpace.concatenate(new AffineTransform(0.8f,0,-0.1f,1,10,0));
451 	}
452 
453 	/***
454 	 * Return the IdCard value from it's key name.
455 	 * 
456 	 * @param idCardName
457 	 *          the IdCard non-translated name
458 	 * @return the IdCard value from it's key name. <code>-1</code> if the given
459 	 *         name does not exist.
460 	 */
461 	public static int getIdCard(String idCardName) {
462 		final int index = ArrayUtils.indexOf(exportedIdCardNames, idCardName);
463 		if (index != -1) {
464 			return exportedIdCardValues[index];
465 		}
466 		return -1;
467 	}
468 
469 	/***
470 	 * Return the property value from it's name.
471 	 * 
472 	 * @param property
473 	 *          the property non-translated name
474 	 * @return the property value from it's name. <code>-1</code> if the given
475 	 *         name does not exist.
476 	 */
477 	public static int getProperty(String property) {
478 		for (Map.Entry<Integer, String> entry : exportedProperties.entrySet()) {
479 			if (entry.getValue().equals(property)) {
480 				return entry.getKey();
481 			}
482 		}
483 		return -1;
484 	}
485 
486 	/***
487 	 * Return the properties names between the given values.
488 	 * 
489 	 * @param minId
490 	 *          the minimal property id.
491 	 * @param maxId
492 	 *          the maximal property id.
493 	 * @return the properties names between the given values.
494 	 */
495 	public static Collection<String> getPropertiesName(int minId, int maxId) {
496 		return exportedProperties.headMap(maxId + 1).tailMap(minId).values();
497 	}
498 
499 	/***
500 	 * Returns the scale of images of cards.
501 	 * 
502 	 * @return the scale of images of cards.
503 	 */
504 	public static float getScale() {
505 		return Configuration.getFloat(CONFIG_KEY_SCALE, CONFIG_SCALE);
506 	}
507 
508 	/***
509 	 * The loaded cards. Card name is the key.
510 	 */
511 	private static Map<String, CardModel> loadedCards = new HashMap<String, CardModel>(
512 			100);
513 
514 	/***
515 	 * the state pictures check during each paint of cards
516 	 */
517 	static StatePicture[] statePictures;
518 
519 	/***
520 	 * the tooltip filters of cards
521 	 */
522 	static TooltipFilter[] tooltipFilters;
523 
524 	/***
525 	 * The associated menu to context menu of the clicked card.
526 	 */
527 	static JPopupMenu contextMenu;
528 
529 	/***
530 	 * Scaled height of card to display
531 	 */
532 	public static int cardHeight;
533 
534 	/***
535 	 * Scaled width of card to display
536 	 */
537 	public static int cardWidth;
538 
539 	/***
540 	 * The border color of all card
541 	 */
542 	public static Color borderColor;
543 
544 	/***
545 	 * The "power" topic string part of tooltip
546 	 */
547 	static String ttPower;
548 
549 	/***
550 	 * The "toughness" topic string part of tooltip
551 	 */
552 	static String ttToughness;
553 
554 	/***
555 	 * The "state" topic string part of tooltip
556 	 */
557 	static String ttState;
558 
559 	/***
560 	 * The "damage" topic string part of tooltip
561 	 */
562 	static String ttDamage;
563 
564 	/***
565 	 * The "properties" topic string part of tooltip.
566 	 */
567 	static String ttProperties;
568 
569 	/***
570 	 * The "colors" topic string part of tooltip.
571 	 */
572 	static String ttColors;
573 
574 	/***
575 	 * The "rules author" topics string part of tooltip.
576 	 */
577 	static String ttRulesAuthor;
578 
579 	/***
580 	 * The "activated ability" topic string part of tooltip.
581 	 */
582 	static String ttAbility;
583 
584 	static String ttAbiltityEnd;
585 
586 	static String ttAdvancedAability;
587 
588 	static String ttAdvancedAabilityEnd;
589 
590 	/***
591 	 * The "types" topic string part of tooltip.
592 	 */
593 	static String ttTypes;
594 
595 	/***
596 	 * The "header" and "card name" topics string part of tooltip.
597 	 */
598 	public static String ttHeader;
599 
600 	/***
601 	 * The "header" and "ability name" topics string part of tooltip
602 	 */
603 	static String ttHeaderAbility;
604 
605 	/***
606 	 * The "count card" item of context menu
607 	 */
608 	public static JMenuItem countItem;
609 
610 	/***
611 	 * The "expand panel" item of context menu
612 	 */
613 	public static JMenuItem expandItem;
614 
615 	/***
616 	 * The "gathered panel" item of context menu
617 	 */
618 	public static JMenuItem gatherItem;
619 
620 	/***
621 	 * The available Id card names.
622 	 */
623 	public static String[] exportedIdCardNames;
624 
625 	/***
626 	 * The available Id card values.
627 	 */
628 	public static int[] exportedIdCardValues;
629 
630 	/***
631 	 * The available properties.
632 	 */
633 	public static SortedMap<Integer, String> exportedProperties;
634 
635 	/***
636 	 * The available properties pictures as Html.
637 	 */
638 	public static Map<Integer, String> propertyPicturesHTML;
639 
640 	/***
641 	 * The available properties pictures as Image.
642 	 */
643 	public static Map<Integer, Image> propertyPictures;
644 
645 	/***
646 	 * The warning Icon.
647 	 */
648 	public static final Icon WARNING_PICTURE = new ImageIcon("images/warn.gif");
649 
650 	/***
651 	 * Mana cost header
652 	 */
653 	static String ttManacost;
654 
655 	/***
656 	 * Mana paid header
657 	 */
658 	static String ttManapaid;
659 
660 	/***
661 	 * the back image of all Magic card
662 	 */
663 	public static Picture previewCard = null;
664 
665 	/***
666 	 * The java debug display. Show java attributes of a card.
667 	 */
668 	static JMenuItem javaDebugItem;
669 
670 	/***
671 	 * Activate the the "database" tab of a card.
672 	 */
673 	static JMenuItem databaseCardInfoItem;
674 
675 	/***
676 	 * Force the picture to be reloaded.
677 	 */
678 	static JMenuItem reloadPictureItem;
679 
680 	/***
681 	 * The "source" topic string part of tooltip
682 	 */
683 	static String ttSource;
684 
685 	/***
686 	 * The last known card name.
687 	 */
688 	static String lastCardName;
689 
690 }