Skip to content
3 changes: 3 additions & 0 deletions src/main/java/net/rptools/maptool/client/AppPreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,9 @@ public static PreferenceStore getAppPreferenceStore() {
"Preferences.label.loadMRU.tooltip",
false);

public static final Preference<Boolean> initiativePanelShowsInfoInTitle =
store.defineBoolean("initShowTitleInfo", true);

public static final Preference<Boolean> initiativePanelShowsTokenImage =
store.defineBoolean("initShowTokens", true);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,26 @@
*/
package net.rptools.maptool.client.ui.tokenpanel;

import static net.rptools.maptool.client.ui.MapToolFrame.MTFrame.INITIATIVE;

import com.google.common.eventbus.Subscribe;
import com.jidesoft.docking.DockableFrame;
import com.jidesoft.docking.event.DockableFrameAdapter;
import com.jidesoft.docking.event.DockableFrameEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.*;
import java.util.List;
import java.util.Set;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.rptools.maptool.client.AppPreferences;
import net.rptools.maptool.client.AppUtil;
import net.rptools.maptool.client.MapTool;
import net.rptools.maptool.client.swing.SwingUtil;
import net.rptools.maptool.client.ui.MapToolFrame;
import net.rptools.maptool.client.ui.theme.Icons;
import net.rptools.maptool.client.ui.theme.RessourceManager;
import net.rptools.maptool.client.ui.zone.renderer.ZoneRenderer;
Expand Down Expand Up @@ -62,7 +64,7 @@ public class InitiativePanel extends JPanel
* Instance Variables
*-------------------------------------------------------------------------------------------*/

/** Model containing all of the tokens in this initiative. */
/** Model containing all the tokens in this initiative. */
private InitiativeList list;

/** The model used to display a list in the panel; */
Expand Down Expand Up @@ -98,7 +100,7 @@ public class InitiativePanel extends JPanel
/** The component that contains the initiative menu. */
private final JPopupMenu popupMenu;

/** The menu item that tells the GM if NPC's are visible. */
/** The menu item that tells the GM if NPCs are visible. */
private JCheckBoxMenuItem hideNPCMenuItem;

/**
Expand Down Expand Up @@ -135,10 +137,29 @@ public class InitiativePanel extends JPanel
*/
private boolean initPanelButtonsDisabled;

/** Flag indicating that additional information should be shown in the title bar. */
private boolean showTitleInfo = AppPreferences.initiativePanelShowsInfoInTitle.get();

/** Flag indicating that title bar change needs action. */
private boolean showTitleInfoPending = true;

/** Frame used in docking manager */
private DockableFrame dockableFrame = null;

/** Custom title component for {@link #dockableFrame} */
private final JLabel dockableFrameTitleComponent = new JLabel();

/** Display text used in {@link #dockableFrameTitleComponent} & {@link #dockableFrame} titles */
private static final String TITLE_LABEL_TEXT = "%s (%d, %d)";

/** Tooltip text used in {@link #dockableFrameTitleComponent} */
private static final String TITLE_LABEL_TOOLTIP_TEXT =
"<html><b>%s: </b>%d<br><b>%s: </b>%d</html>";

/*---------------------------------------------------------------------------------------------
* Constructor
*-------------------------------------------------------------------------------------------*/
/** Setup the menu */
/** Set up the menu */
public InitiativePanel() {

// Build the form and add it's component
Expand Down Expand Up @@ -178,7 +199,7 @@ public InitiativePanel() {

// Set up the list with an empty model
displayList =
new JList<TokenInitiative>() {
new JList<>() {
@Override
public boolean getScrollableTracksViewportWidth() {
// Make sure the width of the list always tracks with the width of the panel. Without
Expand Down Expand Up @@ -243,9 +264,13 @@ public boolean getScrollableTracksViewportWidth() {
"initPanel.warnWhenResettingRoundCounter", TOGGLE_WARN_WHEN_RESETTING_COUNTER_ACTION);
I18N.setAction("initPanel.next", NEXT_ACTION);
I18N.setAction("initPanel.prev", PREV_ACTION);
I18N.setAction("initPanel.showTokenCountInTitle", SHOW_TOKEN_COUNT_IN_TITLE);

updateView();

new MapToolEventBus().getMainEventBus().register(this);

SwingUtilities.invokeLater(() -> dockableFrame = getDockableFrame());
}

private static class TextlessButton extends JButton {
Expand All @@ -266,6 +291,7 @@ private static class TextlessButton extends JButton {
* GM's and Player's properly
*/
public void updateView() {
updateFrameTitle();
displayList.setDragEnabled(hasGMPermission());

// Set up the buttons
Expand Down Expand Up @@ -329,10 +355,16 @@ public void updateView() {
popupMenu.addSeparator();
popupMenu.add(new JMenuItem(REMOVE_TOKEN_ACTION));
} // endif
if (MapTool.getPlayer().isGM()) {
popupMenu.addSeparator();
JCheckBoxMenuItem showTitleInfoCB = new JCheckBoxMenuItem(SHOW_TOKEN_COUNT_IN_TITLE);
showTitleInfoCB.setSelected(AppPreferences.initiativePanelShowsInfoInTitle.get());
popupMenu.add(showTitleInfoCB);
}
valueChanged(null);
}

/** Remove all of the tokens from the model and clear round and current */
/** Remove all the tokens from the model and clear round and current */
public void clearTokens() {
list.clearModel();
}
Expand Down Expand Up @@ -402,6 +434,13 @@ public boolean isShowInitState() {
return showInitState;
}

/**
* @return Getter for showTitleInfo
*/
public boolean isShowTitleInfo() {
return showTitleInfo;
}

/**
* @return Getter for model
*/
Expand All @@ -410,7 +449,7 @@ public InitiativeListModel getModel() {
}

/**
* Set the zone that we are currently working on.
* Set the zone we are working on.
*
* @param aZone The new zone
*/
Expand Down Expand Up @@ -442,15 +481,14 @@ public void setZone(Zone aZone) {
public boolean hasOwnerPermission(Token token) {
if (token == null) return false;
if (hasGMPermission()) return true;
if (ownerPermissions
return ownerPermissions
&& (!MapTool.getServerPolicy().useStrictTokenManagement()
|| token.isOwner(MapTool.getPlayer().getName()))) return true;
return false;
|| token.isOwner(MapTool.getPlayer().getName()));
}

/**
* See if the current player has permission to execute GM restricted actions. This is <b>not</b>
* related to so-called <i>trusted macros</i> in MTscript.
* related to so-called <i>trusted macros</i> in MT Script.
*
* @return The value <code>true</code> if this player has permission for all actions.
*/
Expand Down Expand Up @@ -503,7 +541,7 @@ public boolean isInitPanelButtonsDisabled() {
* Updates the "Disable Panel Buttons" setting, and tweaks the Next/Previous button tooltips
* appropriately. Updates the view.
*
* @param initPanelButtonsDisabled
* @param initPanelButtonsDisabled disable panel buttons
*/
public void setInitPanelButtonsDisabled(boolean initPanelButtonsDisabled) {
this.initPanelButtonsDisabled = initPanelButtonsDisabled;
Expand All @@ -526,8 +564,7 @@ public void setInitPanelButtonsDisabled(boolean initPanelButtonsDisabled) {
public boolean isMovementLocked(Token token) {
if (!movementLock || list == null || list.getSize() == 0) return false;
if (model.getCurrentTokenInitiative() == null) return true;
if (model.getCurrentTokenInitiative().getToken() == token) return false;
return true;
return model.getCurrentTokenInitiative().getToken() != token;
}

/**
Expand All @@ -553,7 +590,87 @@ private void onInitiativeListChanged(InitiativeListChanged event) {

int oldSize = model.getSize();
setList(list);
if (oldSize != model.getSize()) displayList.getSelectionModel().clearSelection();
if (oldSize != model.getSize()) {
displayList.getSelectionModel().clearSelection();
}
}

public DockableFrame getDockableFrame() {
if (dockableFrame == null) {
MapToolFrame mapToolFrame = MapTool.getFrame();
if (mapToolFrame == null) { // this happens on startup before everything gets loaded
return null;
}
dockableFrame = mapToolFrame.getFrame(INITIATIVE);
if (dockableFrame != null) {
dockableFrame.setTitleLabelComponent(dockableFrameTitleComponent);

dockableFrame.addDockableFrameListener(
new DockableFrameAdapter() {
@Override
public void dockableFrameAdded(DockableFrameEvent dockableFrameEvent) {
super.dockableFrameAdded(dockableFrameEvent);
updateFrameTitle();
}

@Override
public void dockableFrameShown(DockableFrameEvent dockableFrameEvent) {
super.dockableFrameShown(dockableFrameEvent);
updateFrameTitle();
}

@Override
public void dockableFrameTabShown(DockableFrameEvent dockableFrameEvent) {
super.dockableFrameTabShown(dockableFrameEvent);
updateFrameTitle();
}
});
}
}
return dockableFrame;
}

private void updateFrameTitle() {
if (!MapTool.getPlayer().isGM() || getDockableFrame() == null && !showTitleInfoPending) {
return;
}
SwingUtilities.invokeLater(
() -> {
String tooltip, text;
if (isShowTitleInfo()) {
int pc = 0, npc = 0;
if (list != null && list.getSize() > 0 && MapTool.getPlayer().isGM()) {
for (TokenInitiative ti : list.getTokens()) {
if (ti.getToken().getType().equals(Type.PC)) {
pc++;
} else {
npc++;
}
}
}

text = String.format(TITLE_LABEL_TEXT, I18N.getText("panel.Initiative"), pc, npc);
tooltip =
String.format(
TITLE_LABEL_TOOLTIP_TEXT,
I18N.getText("Token.Type.PC"),
pc,
I18N.getText("Token.Type.NPC"),
npc);
dockableFrameTitleComponent.setText(text);
dockableFrameTitleComponent.setToolTipText(tooltip);
dockableFrame.setSideTitle(text);
dockableFrame.setTabTitle(text);
} else {
text = I18N.getText("panel.Initiative");
tooltip = I18N.getText("panel.Initiative.description");
dockableFrameTitleComponent.setText(text);
dockableFrameTitleComponent.setToolTipText(tooltip);
dockableFrame.setSideTitle(text);
dockableFrame.setTabTitle(text);
showTitleInfoPending = false;
}
});
}

@Subscribe
Expand Down Expand Up @@ -612,28 +729,29 @@ public void valueChanged(ListSelectionEvent e) {
*/
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(InitiativeList.ROUND_PROP)) {
updateRound();
} else if (evt.getPropertyName().equals(InitiativeList.CURRENT_PROP)) {
Token t = list.getCurrentToken();
if (t == null) return;
String s = I18N.getText("initPanel.displayMessage", t.getName());
if (InitiativeListModel.isTokenVisible(t, list.isHideNPC())
&& t.getType() != Type.NPC
&& AppPreferences.showInitiativeGainedMessage.get())
MapTool.addMessage(TextMessage.say(null, s));
displayList.ensureIndexIsVisible(model.getDisplayIndex(list.getCurrent()));
NEXT_ACTION.setEnabled(
!isInitPanelButtonsDisabled() && hasOwnerPermission(list.getCurrentToken()));
} else if (evt.getPropertyName().equals(InitiativeList.TOKENS_PROP)) {
if ((evt.getOldValue() == null && evt.getNewValue() instanceof TokenInitiative)
|| (evt.getNewValue() == null & evt.getOldValue() instanceof TokenInitiative))
displayList.getSelectionModel().clearSelection();
} else if (evt.getPropertyName().equals(InitiativeList.HIDE_NPCS_PROP)) {
displayList.getSelectionModel().clearSelection();
} else if (evt.getPropertyName().equals(InitiativeList.OWNER_PERMISSIONS_PROP)) {
updateView();
} // endif
updateFrameTitle();
switch (evt.getPropertyName()) {
case InitiativeList.ROUND_PROP -> updateRound();
case InitiativeList.CURRENT_PROP -> {
Token t = list.getCurrentToken();
if (t == null) return;
String s = I18N.getText("initPanel.displayMessage", t.getName());
if (InitiativeListModel.isTokenVisible(t, list.isHideNPC())
&& t.getType() != Type.NPC
&& AppPreferences.showInitiativeGainedMessage.get())
MapTool.addMessage(TextMessage.say(null, s));
displayList.ensureIndexIsVisible(model.getDisplayIndex(list.getCurrent()));
NEXT_ACTION.setEnabled(
!isInitPanelButtonsDisabled() && hasOwnerPermission(list.getCurrentToken()));
}
case InitiativeList.TOKENS_PROP -> {
if ((evt.getOldValue() == null && evt.getNewValue() instanceof TokenInitiative)
|| (evt.getNewValue() == null & evt.getOldValue() instanceof TokenInitiative))
displayList.getSelectionModel().clearSelection();
}
case InitiativeList.HIDE_NPCS_PROP -> displayList.getSelectionModel().clearSelection();
case InitiativeList.OWNER_PERMISSIONS_PROP -> updateView();
}
}

/*---------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -705,6 +823,18 @@ public void actionPerformed(ActionEvent e) {
}
};

/** This action toggles the display of token counts in the title bar. */
public final Action SHOW_TOKEN_COUNT_IN_TITLE =
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
showTitleInfo = ((JCheckBoxMenuItem) e.getSource()).isSelected();
showTitleInfoPending = true;
AppPreferences.initiativePanelShowsInfoInTitle.set(showTitleInfo);
updateFrameTitle();
}
};

/** This action toggles the display of token images. */
public final Action SHOW_TOKEN_STATES_ACTION =
new AbstractAction() {
Expand Down Expand Up @@ -776,7 +906,7 @@ public void actionPerformed(ActionEvent e) {
}
};

/** This action will set the initiative state of the currently selected token. */
/** This action will set the initiative state of the current selected token. */
public final Action SET_INIT_STATE_VALUE =
new AbstractAction() {
@Override
Expand All @@ -788,7 +918,7 @@ public void actionPerformed(ActionEvent e) {
if (hasGMPermission()
&& token != null
&& token.getGMName() != null
&& token.getGMName().trim().length() != 0)
&& !token.getGMName().trim().isEmpty())
sName += " (" + token.getGMName().trim() + ")";
String s = I18N.getText("initPanel.enterState", sName);
String input = JOptionPane.showInputDialog(s, ti.getState());
Expand All @@ -797,7 +927,7 @@ public void actionPerformed(ActionEvent e) {
}
};

/** This action will clear the initiative state of the currently selected token. */
/** This action will clear the initiative state of the current selected token. */
public final Action CLEAR_INIT_STATE_VALUE =
new AbstractAction() {
@Override
Expand Down Expand Up @@ -831,7 +961,7 @@ public void actionPerformed(ActionEvent e) {
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
List<Token> tokens = new ArrayList<Token>();
List<Token> tokens = new ArrayList<>();
for (Token token : list.getZone().getTokensForLayers(Zone.Layer::isTokenLayer)) {
if (token.getType() == Type.PC) tokens.add(token);
} // endfor
Expand Down
Loading
Loading