/* * Copyright (c) 2014 tabletoptool.com team. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html * * Contributors: * rptools.com team - initial implementation * tabletoptool.com team - further development */ package com.t3.client.ui.macrobuttons.buttons; import java.awt.Cursor; import java.awt.Insets; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JButton; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import com.t3.client.T3Util; import com.t3.client.TabletopTool; import com.t3.client.ui.MacroButtonHotKeyManager; import com.t3.client.ui.macrobuttons.buttongroups.AbstractButtonGroup; import com.t3.client.ui.macrobuttons.buttongroups.ButtonGroup; import com.t3.client.ui.macrobuttons.panels.AbstractMacroPanel; import com.t3.model.MacroButtonProperties; import com.t3.model.Token; import com.t3.swing.SwingUtil; import com.t3.util.guidreference.NullHelper; import com.t3.util.guidreference.TokenReference; /** * Base class of {@link CampaignMacroButton} and {@link GlobalMacroButton}. {@link TokenMacroButton} doesn't extend this * class because it is very simple. <code>MacroButton</code>s that extend this class use {@link MacroButtonProperties}. * <p> * These buttons are used in Macro Button Panel in the UI. */ public class MacroButton extends JButton implements MouseListener { private final MacroButtonProperties properties; private final MacroButtonHotKeyManager hotKeyManager; private final ButtonGroup buttonGroup; private final AbstractMacroPanel panel; private final String panelClass; private final TokenReference token; private static final Insets buttonInsets = new Insets(2, 2, 2, 2); private DragSource dragSource; private DragGestureListener dgListener; private DragSourceListener dsListener; private static final Pattern MACRO_LABEL = Pattern.compile("^(/\\w+\\s+)(.*)$"); public MacroButton(MacroButtonProperties properties, ButtonGroup buttonGroup) { this(properties, buttonGroup, null); } public MacroButton(MacroButtonProperties properties, ButtonGroup buttonGroup, Token token) { this.properties = properties; this.buttonGroup = buttonGroup; this.panel = buttonGroup.getPanel(); this.panelClass = buttonGroup.getPanel().getPanelClass(); this.token=NullHelper.referenceToken(token); this.properties.setToken(token); this.properties.setSaveLocation(this.panelClass); this.properties.setButton(this); // we have to call setColor() and setText() here since properties only hold "dumb" data. setColor(properties.getColorKey()); setText(getButtonText()); hotKeyManager = new MacroButtonHotKeyManager(this); hotKeyManager.assignKeyStroke(properties.getHotKey()); setMargin(buttonInsets); makeDraggable(DragSource.DefaultCopyDrop); addMouseListener(this); ToolTipManager.sharedInstance().registerComponent(this); } public MacroButtonProperties getProperties() { return properties; } public MacroButtonHotKeyManager getHotKeyManager() { return hotKeyManager; } public Token getToken() { return NullHelper.value(token); } public AbstractButtonGroup getButtonGroup() { return buttonGroup; } public String getPanelClass() { return panelClass; } public void setColor(String colorKey) { //If the key doesn't correspond to one of our colors, then use the default // FJE Why?? if ("default".equals(colorKey)) { setBackground(null); } else { setBackground(T3Util.getColor(colorKey)); } } /* * Get the text for the macro button by filtering out label macro (if any), and add hotkey hint (if any) */ public String getButtonText() { String buttonLabel; String label = properties.getLabel(); Matcher m = MACRO_LABEL.matcher(label); if (m.matches()) buttonLabel = m.group(2); else buttonLabel = label; String div = "<div style='font-size: " + properties.getFontSize() + "; text-align: center'>"; String formatButtonLabel = "<p style='color: " + properties.getFontColorAsHtml() + "; " + getMinWidth() + getMaxWidth() + "'>" + buttonLabel; // if there is no hotkey (HOTKEY[0]) then no need to add hint String hotKey = properties.getHotKey(); String result = null; if (hotKey.equals(MacroButtonHotKeyManager.HOTKEYS[0])) result = "<html>" + div + formatButtonLabel; else result = "<html>" + div + formatButtonLabel + "<font style='font-size:0.8em'> (" + hotKey + ")"; return result; } public String getMinWidth() { // the min-width style doesn't appear to work in the current java, so I'm // using width instead. String newMinWidth = properties.getMinWidth(); if (newMinWidth != null && !newMinWidth.equals("")) { return " width:" + newMinWidth + ";"; // return " min-width:"+newMinWidth+";"; } return ""; } public String getMaxWidth() { // doesn't appear to work in current java, leaving it in just in case // it is supported in the future String newMaxWidth = properties.getMaxWidth(); if (newMaxWidth != null && !newMaxWidth.equals("")) { return " max-width:" + newMaxWidth + ";"; } return ""; } // Override these mouse events in subclasses to specify component specific behavior. @Override public void mouseClicked(MouseEvent event) { } @Override public void mousePressed(MouseEvent event) { } @Override public void mouseReleased(MouseEvent event) { if (SwingUtilities.isLeftMouseButton(event)) { // If any of the following 3 conditions are correct we want to run it against all selected tokens, // Shift is held down while clicking the button, the button has apply to selected tokens set, or its a common macro button if (SwingUtil.isShiftDown(event) || properties.getCommonMacro()) { if (TabletopTool.getFrame().getCurrentZoneRenderer().getSelectedTokensList().size() > 0) { properties.executeMacro(TabletopTool.getFrame().getCurrentZoneRenderer().getSelectedTokensList()); } } else { properties.executeMacro(); } } else if (SwingUtilities.isRightMouseButton(event)) { if (getPanelClass().equals("GlobalPanel")) { new MacroButtonPopupMenu(this, panelClass, false).show(this, event.getX(), event.getY()); } else if (getPanelClass().equals("CampaignPanel")) { if (TabletopTool.getPlayer().isGM()) { new MacroButtonPopupMenu(this, panelClass, false).show(this, event.getX(), event.getY()); } else { if (properties.getAllowPlayerEdits()) { new MacroButtonPopupMenu(this, panelClass, false).show(this, event.getX(), event.getY()); } } } else if (getPanelClass().equals("SelectionPanel") || getPanelClass().equals("ImpersonatePanel")) { if (TabletopTool.getFrame().getSelectionPanel().getCommonMacros().contains(properties)) { new MacroButtonPopupMenu(this, panelClass, true).show(this, event.getX(), event.getY()); } else { new MacroButtonPopupMenu(this, panelClass, false).show(this, event.getX(), event.getY()); } } } } @Override public void mouseEntered(MouseEvent event) { if (TabletopTool.getFrame().getCurrentZoneRenderer() == null) { return; } List<Token> selectedTokens = TabletopTool.getFrame().getCurrentZoneRenderer().getSelectedTokensList(); if (SwingUtil.isShiftDown(event)) { TabletopTool.getFrame().getCurrentZoneRenderer().setHighlightCommonMacros(selectedTokens); } else { if (getPanelClass() == "SelectionPanel") { List<Token> affectedTokens = new ArrayList<Token>(); if (getProperties().getCommonMacro()) { for (Token nextSelected : selectedTokens) { Boolean isCommonToToken = false; for (MacroButtonProperties nextMacro : nextSelected.getMacroList(true)) { if (nextMacro.hashCodeForComparison() == getProperties().hashCodeForComparison()) { isCommonToToken = true; } } if (isCommonToToken) { affectedTokens.add(nextSelected); } } } else if (getProperties().getToken() != null) { affectedTokens.add(getProperties().getToken()); } TabletopTool.getFrame().getCurrentZoneRenderer().setHighlightCommonMacros(affectedTokens); } } } @Override public void mouseExited(MouseEvent event) { List<Token> affectedTokens = new ArrayList<Token>(); if (TabletopTool.getFrame().getCurrentZoneRenderer() != null) { TabletopTool.getFrame().getCurrentZoneRenderer().setHighlightCommonMacros(affectedTokens); } } private void makeDraggable(Cursor cursor) { dragSource = DragSource.getDefaultDragSource(); dgListener = new DGListener(cursor); dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, dgListener); dsListener = new DSListener(); } private class DGListener implements DragGestureListener { final Cursor cursor; public DGListener(Cursor cursor) { this.cursor = cursor; } @Override public void dragGestureRecognized(DragGestureEvent dge) { Transferable t = new TransferableMacroButton(MacroButton.this); dge.startDrag(cursor, t, dsListener); } } private class DSListener implements DragSourceListener { @Override public void dragEnter(DragSourceDragEvent event) { //System.out.println("TMB: drag enter"); //DragSourceContext context = event.getDragSourceContext(); //context.getComponent() } @Override public void dragOver(DragSourceDragEvent event) { //System.out.println("TMB: drag over"); } @Override public void dropActionChanged(DragSourceDragEvent event) { //System.out.println("TMB: drop action changed"); } @Override public void dragExit(DragSourceEvent event) { //System.out.println("TMB: drag exit"); } @Override public void dragDropEnd(DragSourceDropEvent event) { //System.out.println("TMB: drag drop end"); // js commented out for testing - TabletopTool.getFrame().updateSelectionPanel(); List<Token> affectedTokens = new ArrayList<Token>(); TabletopTool.getFrame().getCurrentZoneRenderer().setHighlightCommonMacros(affectedTokens); } } public void clearHotkey() { getHotKeyManager().assignKeyStroke(MacroButtonHotKeyManager.HOTKEYS[0]); } @Override public String getToolTipText(MouseEvent e) { String tt = properties.getEvaluatedToolTip(); return tt.length() == 0 ? null : tt; } }