First commit of tasks-tracker-plugin-master
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
package net.reldo.taskstracker.panel;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
public class Colors {
|
||||
public static Color QUALIFIED_TEXT_COLOR = new Color(34, 177, 77);
|
||||
public static Color UNQUALIFIED_BACKGROUND_COLOR = new Color(70, 30, 0);
|
||||
public static Color UNQUALIFIED_TEXT_COLOR = new Color(251, 93, 93);
|
||||
public static Color COMPLETED_BACKGROUND_COLOR = new Color(0, 50, 0);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.reldo.taskstracker.panel;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import net.reldo.taskstracker.TasksTrackerPlugin;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
|
||||
public class Icons
|
||||
{
|
||||
private static final String completeBtnPath = "panel/components/complete_button/";
|
||||
public static final Icon INCOMPLETE_ONLY_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, completeBtnPath + "incomplete_only_icon.png"));
|
||||
public static final Icon COMPLETE_ONLY_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, completeBtnPath + "complete_only_icon.png"));
|
||||
public static final Icon COMPLETE_INCOMPLETE_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, completeBtnPath + "complete_and_incomplete_icon.png"));
|
||||
|
||||
private static final String ignoredBtnPath = "panel/components/ignored_button/";
|
||||
public static final BufferedImage semivisibleimg = ImageUtil.loadImageResource(TasksTrackerPlugin.class, ignoredBtnPath + "semivisible_icon.png");
|
||||
public static final Icon SEMIVISIBLE_ICON = new ImageIcon(ImageUtil.alphaOffset(semivisibleimg, -180));
|
||||
public static final Icon INVISIBLE_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, ignoredBtnPath + "invisible_icon.png"));
|
||||
public static final Icon VISIBLE_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, ignoredBtnPath + "visible_icon.png"));
|
||||
|
||||
private static final String trackedBtnPath = "panel/components/tracked_button/";
|
||||
public static final Icon UNTRACKED_ONLY_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, trackedBtnPath + "untracked_icon.png"));
|
||||
public static final Icon TRACKED_ONLY_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, trackedBtnPath + "tracked_icon.png"));
|
||||
public static final Icon TRACKED_UNTRACKED_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, trackedBtnPath + "tracked_and_untracked_icon.png"));
|
||||
|
||||
private static final String sortBtnPath = "panel/components/sort_button/";
|
||||
public static final Icon ASCENDING_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, sortBtnPath + "ascending_icon.png"));
|
||||
public static final Icon DESCENDING_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, sortBtnPath + "descending_icon.png"));
|
||||
|
||||
private static final String expandBtnPath = "panel/components/";
|
||||
public static final Icon MENU_EXPANDED_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, expandBtnPath + "filter_menu_expanded.png"));
|
||||
public static final BufferedImage collapseImg = ImageUtil.loadImageResource(TasksTrackerPlugin.class, expandBtnPath + "filter_menu_collapsed.png");
|
||||
public static final Icon MENU_ICON_HOVER = new ImageIcon(collapseImg);
|
||||
|
||||
public static final Icon MENU_COLLAPSED_ICON = new ImageIcon(ImageUtil.alphaOffset(collapseImg, -180));
|
||||
public static final ImageIcon PLUS_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, "plus.png"));
|
||||
public static final ImageIcon MINUS_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, "minus.png"));
|
||||
public static final ImageIcon EYE_ICON = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, "eye.png"));
|
||||
public static final ImageIcon EYE_CROSS_GREY = new ImageIcon(ImageUtil.loadImageResource(TasksTrackerPlugin.class, "eye-cross-grey.png"));
|
||||
}
|
||||
@@ -0,0 +1,543 @@
|
||||
package net.reldo.taskstracker.panel;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.MatteBorder;
|
||||
import javax.swing.plaf.basic.BasicButtonUI;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.reldo.taskstracker.TasksTrackerConfig;
|
||||
import net.reldo.taskstracker.TasksTrackerPlugin;
|
||||
import net.reldo.taskstracker.config.ConfigValues;
|
||||
import net.reldo.taskstracker.data.jsondatastore.types.FilterConfig;
|
||||
import net.reldo.taskstracker.data.jsondatastore.types.FilterType;
|
||||
import net.reldo.taskstracker.data.task.TaskService;
|
||||
import net.reldo.taskstracker.data.task.TaskType;
|
||||
import net.reldo.taskstracker.panel.components.SearchBox;
|
||||
import net.reldo.taskstracker.panel.components.TriToggleButton;
|
||||
import net.reldo.taskstracker.panel.filters.ComboItem;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
|
||||
@Slf4j
|
||||
public class LoggedInPanel extends JPanel
|
||||
{
|
||||
public TaskListPanel taskListPanel;
|
||||
private JComboBox<ComboItem<TaskType>> taskTypeDropdown;
|
||||
|
||||
private final TaskService taskService;
|
||||
private final TasksTrackerPlugin plugin;
|
||||
private final TasksTrackerConfig config;
|
||||
|
||||
// Filter buttons
|
||||
private final TriToggleButton completedFilterBtn = new TriToggleButton();
|
||||
private final TriToggleButton trackedFilterBtn = new TriToggleButton();
|
||||
private final TriToggleButton ignoredFilterBtn = new TriToggleButton();
|
||||
private final JPanel titlePanel = new JPanel();
|
||||
|
||||
// Task list tabs
|
||||
private final JPanel tabPane = new JPanel();
|
||||
|
||||
// sub-filter panel
|
||||
private SubFilterPanel subFilterPanel;
|
||||
private SortPanel sortPanel;
|
||||
private final JToggleButton collapseBtn = new JToggleButton();
|
||||
|
||||
public LoggedInPanel(TasksTrackerPlugin plugin, TasksTrackerConfig config, TaskService taskService)
|
||||
{
|
||||
super(false);
|
||||
this.plugin = plugin;
|
||||
this.taskService = taskService;
|
||||
this.config = config;
|
||||
|
||||
createPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
return getParent().getSize();
|
||||
}
|
||||
|
||||
public void redraw()
|
||||
{
|
||||
// taskTypeDropdown may become de-synced after profile change
|
||||
String selectedTaskTypeJsonName = taskTypeDropdown.getItemAt(taskTypeDropdown.getSelectedIndex()).getValue().getTaskJsonName();
|
||||
if(!selectedTaskTypeJsonName.equals(config.taskTypeJsonName()))
|
||||
{
|
||||
log.debug("Task type dropdown de-synced, attempting to find current task type");
|
||||
for(int i = 0; i < taskTypeDropdown.getItemCount(); i++)
|
||||
{
|
||||
ComboItem<TaskType> item = taskTypeDropdown.getItemAt(i);
|
||||
if(item.getValue().getTaskJsonName().equals(config.taskTypeJsonName()))
|
||||
{
|
||||
log.debug("Current task type found, setting selected task type");
|
||||
taskTypeDropdown.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
subFilterPanel.redraw();
|
||||
sortPanel.redraw();
|
||||
updateCollapseButtonText();
|
||||
|
||||
taskListPanel.redraw();
|
||||
}
|
||||
|
||||
public void refreshAllTasks()
|
||||
{
|
||||
updateCollapseButtonText();
|
||||
taskListPanel.refreshAllTasks();
|
||||
}
|
||||
|
||||
private void createPanel()
|
||||
{
|
||||
setLayout(new BorderLayout());
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
taskListPanel = new TaskListPanel(plugin, taskService);
|
||||
|
||||
add(getNorthPanel(), BorderLayout.NORTH);
|
||||
add(getCenterPanel(), BorderLayout.CENTER);
|
||||
add(getSouthPanel(), BorderLayout.SOUTH);
|
||||
|
||||
loadAndApplyFilters(config.taskListTab());
|
||||
if(config.taskListTab().equals(ConfigValues.TaskListTabs.TRACKED))
|
||||
{
|
||||
trackedFilterBtn.setState(1);
|
||||
trackedFilterBtn.setEnabled(false);
|
||||
plugin.getConfigManager().setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, "trackedFilter", ConfigValues.TrackedFilterValues.TRACKED);
|
||||
}
|
||||
}
|
||||
|
||||
private JPanel getCenterPanel() {
|
||||
// wrapper for the task list and tab buttons
|
||||
final JPanel taskListPanel = new JPanel(new BorderLayout());
|
||||
taskListPanel.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
taskListPanel.setBorder(new MatteBorder(0, 0, 1, 0, ColorScheme.MEDIUM_GRAY_COLOR));
|
||||
taskListPanel.setAlignmentX(JPanel.CENTER_ALIGNMENT);
|
||||
|
||||
tabPane.setLayout(new BoxLayout(tabPane, BoxLayout.X_AXIS));
|
||||
tabPane.setBorder(new EmptyBorder(0,0,0,0));
|
||||
tabPane.setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH,24));
|
||||
|
||||
JToggleButton trackedTab = tabButton("Tracked Tasks", ConfigValues.TaskListTabs.TRACKED);
|
||||
JToggleButton allTab = tabButton("All Tasks", ConfigValues.TaskListTabs.ALL);
|
||||
JToggleButton customTab = tabButton("Custom", ConfigValues.TaskListTabs.CUSTOM);
|
||||
|
||||
ButtonGroup tabGroup = new ButtonGroup();
|
||||
|
||||
tabGroup.add(trackedTab);
|
||||
tabGroup.add(allTab);
|
||||
tabGroup.add(customTab);
|
||||
|
||||
tabPane.add(Box.createHorizontalGlue());
|
||||
tabPane.add(trackedTab);
|
||||
tabPane.add(Box.createHorizontalGlue());
|
||||
tabPane.add(allTab);
|
||||
tabPane.add(Box.createHorizontalGlue());
|
||||
tabPane.add(customTab);
|
||||
tabPane.add(Box.createHorizontalGlue());
|
||||
|
||||
taskListPanel.add(tabPane, BorderLayout.NORTH);
|
||||
taskListPanel.add(this.taskListPanel, BorderLayout.CENTER);
|
||||
|
||||
// set initial filter states to "complete and incomplete", "tracked and untracked", "not ignored"
|
||||
Map<String, Integer> filterStates = new HashMap<>();
|
||||
filterStates.put("completed",0);
|
||||
filterStates.put("tracked",0);
|
||||
filterStates.put("ignored",0);
|
||||
for(ConfigValues.TaskListTabs tab : ConfigValues.TaskListTabs.values())
|
||||
{
|
||||
filterStore.put(tab, filterStates);
|
||||
}
|
||||
|
||||
switch (config.taskListTab())
|
||||
{
|
||||
case TRACKED:
|
||||
trackedTab.setSelected(true);
|
||||
break;
|
||||
case ALL:
|
||||
allTab.setSelected(true);
|
||||
break;
|
||||
case CUSTOM:
|
||||
customTab.setSelected(true);
|
||||
break;
|
||||
}
|
||||
tabChanged(config.taskListTab());
|
||||
|
||||
return taskListPanel;
|
||||
}
|
||||
|
||||
public void tabChanged(ConfigValues.TaskListTabs newTab)
|
||||
{
|
||||
if(newTab != null) {
|
||||
changeTab(newTab);
|
||||
|
||||
switch (newTab) {
|
||||
case TRACKED:
|
||||
trackedFilterBtn.setState(1);
|
||||
trackedFilterBtn.setEnabled(false);
|
||||
plugin.getConfigManager().setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, "taskListTab", newTab);
|
||||
filterButtonAction("tracked");
|
||||
break;
|
||||
case ALL:
|
||||
trackedFilterBtn.setState(0);
|
||||
trackedFilterBtn.setEnabled(false);
|
||||
completedFilterBtn.setState(0);
|
||||
completedFilterBtn.setEnabled(false);
|
||||
ignoredFilterBtn.setState(1);
|
||||
ignoredFilterBtn.setEnabled(false);
|
||||
plugin.getConfigManager().setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, "taskListTab", newTab);
|
||||
actionAllFilterButtons();
|
||||
break;
|
||||
case CUSTOM:
|
||||
plugin.getConfigManager().setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, "taskListTab", newTab);
|
||||
plugin.refreshAllTasks();
|
||||
break;
|
||||
default:
|
||||
plugin.refreshAllTasks();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JToggleButton tabButton(String label, ConfigValues.TaskListTabs tab)
|
||||
{
|
||||
JToggleButton button = new JToggleButton(label);
|
||||
|
||||
button.setBorder(new EmptyBorder(2,5,2,5));
|
||||
button.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
button.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
|
||||
button.addActionListener(e -> tabChanged(tab));
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
private void changeTab(ConfigValues.TaskListTabs newTab)
|
||||
{
|
||||
saveFilters();
|
||||
resetFilters();
|
||||
loadAndApplyFilters(newTab);
|
||||
}
|
||||
|
||||
private final Map<ConfigValues.TaskListTabs, Map<String, Integer>> filterStore = new HashMap<>();
|
||||
|
||||
private void saveFilters()
|
||||
{
|
||||
ConfigValues.TaskListTabs tab = config.taskListTab();
|
||||
|
||||
Map<String, Integer> filterStates = new HashMap<>();
|
||||
filterStates.put("completed", config.completedFilter().ordinal());
|
||||
filterStates.put("tracked", config.trackedFilter().ordinal());
|
||||
filterStates.put("ignored", config.ignoredFilter().ordinal());
|
||||
|
||||
filterStore.put(tab, filterStates);
|
||||
}
|
||||
|
||||
private void resetFilters()
|
||||
{
|
||||
completedFilterBtn.setEnabled(true);
|
||||
trackedFilterBtn.setEnabled(true);
|
||||
ignoredFilterBtn.setEnabled(true);
|
||||
}
|
||||
|
||||
private void loadAndApplyFilters(ConfigValues.TaskListTabs tab)
|
||||
{
|
||||
Map<String,Integer> filterStates = filterStore.get(tab);
|
||||
|
||||
if(filterStates == null) return;
|
||||
|
||||
Enum configValue;
|
||||
|
||||
completedFilterBtn.setState(filterStates.get("completed"));
|
||||
trackedFilterBtn.setState(filterStates.get("tracked"));
|
||||
ignoredFilterBtn.setState(filterStates.get("ignored"));
|
||||
|
||||
configValue = ConfigValues.CompletedFilterValues.values()[completedFilterBtn.getState()];
|
||||
plugin.getConfigManager().setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, "completedFilter", configValue);
|
||||
|
||||
configValue = ConfigValues.TrackedFilterValues.values()[trackedFilterBtn.getState()];
|
||||
plugin.getConfigManager().setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, "trackedFilter", configValue);
|
||||
|
||||
configValue = ConfigValues.IgnoredFilterValues.values()[ignoredFilterBtn.getState()];
|
||||
plugin.getConfigManager().setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, "ignoredFilter", configValue);
|
||||
}
|
||||
|
||||
private JPanel getSouthPanel()
|
||||
{
|
||||
JPanel southPanel = new JPanel(new BorderLayout());
|
||||
southPanel.setBorder(new EmptyBorder(5,0,2,0));
|
||||
|
||||
JButton importButton = new JButton("Import");
|
||||
importButton.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
importButton.setLayout(new BorderLayout(0, PluginPanel.BORDER_OFFSET));
|
||||
importButton.addActionListener(e -> plugin.openImportJsonDialog());
|
||||
southPanel.add(importButton, BorderLayout.WEST);
|
||||
|
||||
JButton totalsButton = new JButton("Totals");
|
||||
totalsButton.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
totalsButton.setLayout(new BorderLayout(0, PluginPanel.BORDER_OFFSET));
|
||||
totalsButton.addActionListener(e -> plugin.sendTotalsToChat());
|
||||
southPanel.add(totalsButton, BorderLayout.CENTER);
|
||||
|
||||
JButton exportButton = new JButton("Export");
|
||||
exportButton.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
exportButton.setLayout(new BorderLayout(0, PluginPanel.BORDER_OFFSET));
|
||||
exportButton.addActionListener(e -> plugin.copyJsonToClipboard());
|
||||
southPanel.add(exportButton, BorderLayout.EAST);
|
||||
|
||||
return southPanel;
|
||||
}
|
||||
|
||||
private JPanel getNorthPanel()
|
||||
{
|
||||
JPanel northPanel = new JPanel();
|
||||
BoxLayout layout = new BoxLayout(northPanel, BoxLayout.Y_AXIS);
|
||||
northPanel.setLayout(layout);
|
||||
northPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
|
||||
taskTypeDropdown = new JComboBox<>();
|
||||
taskTypeDropdown.setAlignmentX(LEFT_ALIGNMENT);
|
||||
taskTypeDropdown.setFocusable(false);
|
||||
initTaskTypeDropdownAsync();
|
||||
|
||||
// Wrapper for collapsible sub-filter menu
|
||||
JPanel subFilterWrapper = new JPanel();
|
||||
subFilterWrapper.setLayout(new BorderLayout());
|
||||
subFilterWrapper.setBorder(new MatteBorder(1, 0, 1, 0, ColorScheme.MEDIUM_GRAY_COLOR));
|
||||
subFilterWrapper.setAlignmentX(LEFT_ALIGNMENT);
|
||||
subFilterWrapper.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
// collapse button
|
||||
SwingUtil.removeButtonDecorations(collapseBtn);
|
||||
collapseBtn.setIcon(Icons.MENU_COLLAPSED_ICON);
|
||||
collapseBtn.setSelectedIcon(Icons.MENU_EXPANDED_ICON);
|
||||
collapseBtn.setRolloverIcon(Icons.MENU_ICON_HOVER);
|
||||
SwingUtil.addModalTooltip(collapseBtn, "Collapse filters", "Expand filters");
|
||||
collapseBtn.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
collapseBtn.setAlignmentX(LEFT_ALIGNMENT);
|
||||
collapseBtn.setUI(new BasicButtonUI()); // substance breaks the layout
|
||||
collapseBtn.addActionListener(ev -> subFilterPanel.setVisible(!subFilterPanel.isVisible()));
|
||||
collapseBtn.setHorizontalTextPosition(JButton.CENTER);
|
||||
collapseBtn.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
|
||||
collapseBtn.setFont(FontManager.getRunescapeSmallFont());
|
||||
collapseBtn.setBorder(new EmptyBorder(2, 0, 2, 0));
|
||||
collapseBtn.setFocusable(false);
|
||||
|
||||
// panel to hold sub-filters
|
||||
subFilterPanel = new SubFilterPanel(plugin, taskService);
|
||||
|
||||
subFilterWrapper.add(collapseBtn, BorderLayout.NORTH);
|
||||
subFilterWrapper.add(subFilterPanel, BorderLayout.CENTER);
|
||||
|
||||
sortPanel = new SortPanel(plugin, taskService, taskListPanel);
|
||||
|
||||
northPanel.add(getTitleAndButtonPanel());
|
||||
northPanel.add(Box.createVerticalStrut(10));
|
||||
northPanel.add(taskTypeDropdown);
|
||||
northPanel.add(Box.createVerticalStrut(2));
|
||||
northPanel.add(getSearchPanel());
|
||||
northPanel.add(Box.createVerticalStrut(2));
|
||||
northPanel.add(sortPanel);
|
||||
northPanel.add(Box.createVerticalStrut(2));
|
||||
northPanel.add(subFilterWrapper);
|
||||
|
||||
return northPanel;
|
||||
}
|
||||
|
||||
private JPanel getTitleAndButtonPanel()
|
||||
{
|
||||
titlePanel.setLayout(new BorderLayout());
|
||||
titlePanel.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
titlePanel.setPreferredSize(new Dimension(0, 30));
|
||||
titlePanel.setBorder(new EmptyBorder(5, 5, 5, 10));
|
||||
|
||||
JLabel title = new JLabel("Tasks Tracker");
|
||||
title.setHorizontalAlignment(SwingConstants.LEFT);
|
||||
title.setForeground(Color.WHITE);
|
||||
|
||||
JPopupMenu reloadPluginPopup = new JPopupMenu();
|
||||
reloadPluginPopup.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
JMenuItem reloadPluginMenuItem = new JMenuItem("Reload plugin");
|
||||
reloadPluginMenuItem.addActionListener(e -> plugin.reloadTaskType());
|
||||
reloadPluginPopup.add(reloadPluginMenuItem);
|
||||
title.setComponentPopupMenu(reloadPluginPopup);
|
||||
|
||||
// Filter button bar
|
||||
final JPanel viewControls = new JPanel();
|
||||
viewControls.setLayout(new BoxLayout(viewControls, BoxLayout.X_AXIS));
|
||||
viewControls.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
// Completed tasks filter button
|
||||
SwingUtil.removeButtonDecorations(completedFilterBtn);
|
||||
completedFilterBtn.setIcons(Icons.COMPLETE_INCOMPLETE_ICON, Icons.COMPLETE_ONLY_ICON, Icons.INCOMPLETE_ONLY_ICON);
|
||||
completedFilterBtn.setToolTips("All tasks", "Completed tasks only", "Incomplete tasks only");
|
||||
completedFilterBtn.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
completedFilterBtn.setStateChangedAction(e -> filterButtonAction("completed"));
|
||||
completedFilterBtn.popupMenuEnabled(true);
|
||||
completedFilterBtn.setState(config.completedFilter().ordinal());
|
||||
|
||||
viewControls.add(completedFilterBtn);
|
||||
|
||||
// Tracked tasks filter button
|
||||
SwingUtil.removeButtonDecorations(trackedFilterBtn);
|
||||
trackedFilterBtn.setIcons(Icons.TRACKED_UNTRACKED_ICON, Icons.TRACKED_ONLY_ICON, Icons.UNTRACKED_ONLY_ICON);
|
||||
trackedFilterBtn.setToolTips("All tasks", "Tracked tasks only", "Untracked tasks only");
|
||||
trackedFilterBtn.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
trackedFilterBtn.setStateChangedAction(e -> filterButtonAction("tracked"));
|
||||
trackedFilterBtn.popupMenuEnabled(true);
|
||||
trackedFilterBtn.setState(config.trackedFilter().ordinal());
|
||||
|
||||
viewControls.add(trackedFilterBtn);
|
||||
|
||||
// Ignored tasks filter button
|
||||
SwingUtil.removeButtonDecorations(ignoredFilterBtn);
|
||||
ignoredFilterBtn.setIcons(Icons.SEMIVISIBLE_ICON, Icons.VISIBLE_ICON, Icons.INVISIBLE_ICON);
|
||||
ignoredFilterBtn.setToolTips("Hide ignored tasks", "All tasks", "Ignored tasks only");
|
||||
ignoredFilterBtn.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
ignoredFilterBtn.setStateChangedAction(e -> filterButtonAction("ignored"));
|
||||
ignoredFilterBtn.popupMenuEnabled(true);
|
||||
ignoredFilterBtn.setState(config.ignoredFilter().ordinal());
|
||||
|
||||
viewControls.add(ignoredFilterBtn);
|
||||
|
||||
titlePanel.add(viewControls, BorderLayout.EAST);
|
||||
titlePanel.add(title, BorderLayout.WEST);
|
||||
titlePanel.setAlignmentX(LEFT_ALIGNMENT);
|
||||
|
||||
return titlePanel;
|
||||
}
|
||||
|
||||
private void filterButtonActionNoRefresh(String filter)
|
||||
{
|
||||
int state;
|
||||
Enum configValue;
|
||||
|
||||
switch (filter)
|
||||
{
|
||||
case "completed":
|
||||
state = completedFilterBtn.getState();
|
||||
configValue = ConfigValues.CompletedFilterValues.values()[state];
|
||||
break;
|
||||
case "tracked":
|
||||
state = trackedFilterBtn.getState();
|
||||
configValue = ConfigValues.TrackedFilterValues.values()[state];
|
||||
break;
|
||||
case "ignored":
|
||||
state = ignoredFilterBtn.getState();
|
||||
configValue = ConfigValues.IgnoredFilterValues.values()[state];
|
||||
break;
|
||||
default:
|
||||
log.debug("Filter button action failed due to unrecognised filter.");
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.getConfigManager().setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, filter + "Filter", configValue);
|
||||
}
|
||||
|
||||
private void filterButtonAction(String filter)
|
||||
{
|
||||
filterButtonActionNoRefresh(filter);
|
||||
plugin.refreshAllTasks();
|
||||
}
|
||||
|
||||
private void actionAllFilterButtons()
|
||||
{
|
||||
filterButtonActionNoRefresh("tracked");
|
||||
filterButtonActionNoRefresh("ignored");
|
||||
filterButtonActionNoRefresh("completed");
|
||||
plugin.refreshAllTasks();
|
||||
}
|
||||
|
||||
private JPanel getSearchPanel()
|
||||
{
|
||||
JPanel filtersPanel = new JPanel();
|
||||
filtersPanel.setAlignmentX(LEFT_ALIGNMENT);
|
||||
filtersPanel.setLayout(new BoxLayout(filtersPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
SearchBox textSearch = new SearchBox();
|
||||
textSearch.addTextChangedListener(() -> {
|
||||
plugin.taskTextFilter = textSearch.getText().toLowerCase();
|
||||
plugin.refreshAllTasks();
|
||||
});
|
||||
|
||||
filtersPanel.add(textSearch);
|
||||
|
||||
return filtersPanel;
|
||||
}
|
||||
|
||||
private void updateCollapseButtonText()
|
||||
{
|
||||
if (taskService.getCurrentTaskType() == null) return;
|
||||
|
||||
ArrayList<FilterConfig> filters = taskService.getCurrentTaskType().getFilters();
|
||||
|
||||
int countInclusive = 0;
|
||||
int countExclusive = 0;
|
||||
|
||||
for (FilterConfig filterConfig : filters)
|
||||
{
|
||||
String filterText = Optional.ofNullable(plugin.getConfigManager()
|
||||
.getConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME,
|
||||
taskService.getCurrentTaskType().getFilterConfigPrefix() + filterConfig.getConfigKey()))
|
||||
.orElse("");
|
||||
|
||||
int count = (filterText.isEmpty() || filterText.equals("-1")) ? 0 : filterText.split(",").length;
|
||||
|
||||
if (filterConfig.getFilterType().equals(FilterType.BUTTON_FILTER)) countInclusive += count;
|
||||
if (filterConfig.getFilterType().equals(FilterType.DROPDOWN_FILTER)) countExclusive += count;
|
||||
}
|
||||
|
||||
collapseBtn.setText(countInclusive + " inclusive, " + countExclusive + " exclusive filters");
|
||||
}
|
||||
|
||||
private void initTaskTypeDropdownAsync() {
|
||||
TaskType currentTaskType = taskService.getCurrentTaskType();
|
||||
taskService.getTaskTypesByJsonName().thenAccept(taskTypes -> {
|
||||
ArrayList<ComboItem<TaskType>> taskTypeItems = new ArrayList<>();
|
||||
taskTypes.forEach((taskTypeJsonName, taskType) -> {
|
||||
ComboItem<TaskType> item = new ComboItem<>(taskType, taskType.getName());
|
||||
taskTypeItems.add(item);
|
||||
taskTypeDropdown.addItem(item);
|
||||
});
|
||||
|
||||
ComboItem<TaskType> currentTaskTypeComboItem = taskTypeItems.stream()
|
||||
.filter(item -> item.getValue().equals(currentTaskType))
|
||||
.findFirst().orElseGet(() -> taskTypeItems.get(0));
|
||||
taskTypeDropdown.setSelectedItem(currentTaskTypeComboItem);
|
||||
taskTypeDropdown.addActionListener(e -> {
|
||||
TaskType taskType = taskTypeDropdown.getItemAt(taskTypeDropdown.getSelectedIndex()).getValue();
|
||||
taskService.setTaskType(taskType).thenAccept(wasTaskTypeChanged ->{
|
||||
if (wasTaskTypeChanged) {
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
redraw();
|
||||
plugin.refreshAllTasks();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package net.reldo.taskstracker.panel;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class LoggedOutPanel extends JPanel
|
||||
{
|
||||
public LoggedOutPanel()
|
||||
{
|
||||
this.add(new JLabel("Log into an account to track tasks."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package net.reldo.taskstracker.panel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.SwingUtilities;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.reldo.taskstracker.TasksTrackerPlugin;
|
||||
import net.reldo.taskstracker.config.ConfigValues;
|
||||
import net.reldo.taskstracker.data.task.TaskService;
|
||||
import net.reldo.taskstracker.panel.components.FixedWidthPanel;
|
||||
import net.reldo.taskstracker.panel.components.MultiToggleButton;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
|
||||
@Slf4j
|
||||
public class SortPanel extends FixedWidthPanel
|
||||
{
|
||||
|
||||
private final TasksTrackerPlugin plugin;
|
||||
private final TaskService taskService;
|
||||
private final TaskListPanel taskListPanel;
|
||||
private final ConfigManager configManager;
|
||||
private JComboBox<String> sortDropdown;
|
||||
private MultiToggleButton directionButton;
|
||||
|
||||
public SortPanel(TasksTrackerPlugin plugin, TaskService taskService, TaskListPanel taskListPanel)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
this.configManager = plugin.getConfigManager();
|
||||
this.taskService = taskService;
|
||||
this.taskListPanel = taskListPanel;
|
||||
|
||||
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
|
||||
setAlignmentX(LEFT_ALIGNMENT);
|
||||
}
|
||||
|
||||
public void redraw()
|
||||
{
|
||||
removeAll();
|
||||
|
||||
List<String> criteriaList = taskService.getSortedIndexes().keySet().stream()
|
||||
.sorted()
|
||||
.map((str) -> str.substring(0, 1).toUpperCase() + str.substring(1))
|
||||
.collect(Collectors.toList());
|
||||
criteriaList.add(0,"Default");
|
||||
|
||||
String[] criteriaArray = criteriaList.toArray(new String[0]);
|
||||
sortDropdown = new JComboBox<>(criteriaArray);
|
||||
sortDropdown.setAlignmentX(LEFT_ALIGNMENT);
|
||||
sortDropdown.setSelectedIndex(0);
|
||||
sortDropdown.addActionListener(e -> {
|
||||
updateConfig();
|
||||
SwingUtilities.invokeLater(taskListPanel::redraw);
|
||||
});
|
||||
sortDropdown.setFocusable(false);
|
||||
|
||||
directionButton = new MultiToggleButton(2);
|
||||
SwingUtil.removeButtonDecorations(directionButton);
|
||||
directionButton.setIcons(new Icon[]{Icons.ASCENDING_ICON, Icons.DESCENDING_ICON});
|
||||
directionButton.setToolTips(new String[]{"Ascending", "Descending"});
|
||||
directionButton.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
directionButton.setStateChangedAction(e -> {
|
||||
updateConfig();
|
||||
SwingUtilities.invokeLater(taskListPanel::redraw);
|
||||
});
|
||||
|
||||
add(sortDropdown);
|
||||
add(directionButton);
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
protected void updateConfig()
|
||||
{
|
||||
log.debug("updateConfig {}, {}, {}", TasksTrackerPlugin.CONFIG_GROUP_NAME, "sortCriteria", sortDropdown.getItemAt(sortDropdown.getSelectedIndex()).toLowerCase());
|
||||
configManager.setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, "sortCriteria", sortDropdown.getItemAt(sortDropdown.getSelectedIndex()).toLowerCase());
|
||||
|
||||
ConfigValues.SortDirections configValue = ConfigValues.SortDirections.values()[directionButton.getState()];
|
||||
log.debug("updateConfig {}, {}, {}", TasksTrackerPlugin.CONFIG_GROUP_NAME, "sortDirection", configValue);
|
||||
configManager.setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, "sortDirection", configValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package net.reldo.taskstracker.panel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.reldo.taskstracker.TasksTrackerPlugin;
|
||||
import net.reldo.taskstracker.data.jsondatastore.types.FilterConfig;
|
||||
import net.reldo.taskstracker.data.jsondatastore.types.FilterValueType;
|
||||
import net.reldo.taskstracker.data.task.TaskService;
|
||||
import net.reldo.taskstracker.panel.components.FixedWidthPanel;
|
||||
import net.reldo.taskstracker.panel.filters.ComboItem;
|
||||
import net.reldo.taskstracker.panel.filters.DynamicButtonFilterPanel;
|
||||
import net.reldo.taskstracker.panel.filters.DynamicDropdownFilterPanel;
|
||||
import net.reldo.taskstracker.panel.filters.FilterPanel;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
@Slf4j
|
||||
public class SubFilterPanel extends FixedWidthPanel
|
||||
{
|
||||
private final List<FilterPanel> filterPanels = new ArrayList<>();
|
||||
private TasksTrackerPlugin plugin;
|
||||
private TaskService taskService;
|
||||
|
||||
public SubFilterPanel(TasksTrackerPlugin plugin, TaskService taskService)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
this.taskService = taskService;
|
||||
log.debug("SubFilterPanel.constructor");
|
||||
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
setBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
public void redraw()
|
||||
{
|
||||
log.debug("SubFilterPanel.redraw"); // TODO: figure out why this calls multiple times upon switching task type
|
||||
|
||||
removeAll();
|
||||
|
||||
filterPanels.clear();
|
||||
filterPanels.addAll(getFilterPanels(taskService.getCurrentTaskType().getFilters()));
|
||||
filterPanels.forEach((filterPanel) -> {
|
||||
add(filterPanel);
|
||||
filterPanel.redraw();
|
||||
});
|
||||
}
|
||||
|
||||
private List<FilterPanel> getFilterPanels(ArrayList<FilterConfig> filterConfigs)
|
||||
{
|
||||
List<FilterPanel> filterPanels = new ArrayList<>();
|
||||
for (FilterConfig filterConfig : filterConfigs)
|
||||
{
|
||||
try
|
||||
{
|
||||
FilterPanel filterPanel = createDynamicFilterPanel(filterConfig);
|
||||
if (filterPanel == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
filterPanels.add(filterPanel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.error("error creating filter panel {} {}", filterConfig.getConfigKey(), ex);
|
||||
}
|
||||
}
|
||||
return filterPanels;
|
||||
}
|
||||
|
||||
private FilterPanel createDynamicFilterPanel(FilterConfig filterConfig) throws Exception
|
||||
{
|
||||
switch (filterConfig.getFilterType())
|
||||
{
|
||||
case BUTTON_FILTER:
|
||||
return new DynamicButtonFilterPanel(plugin, filterConfig, taskService.getCurrentTaskType());
|
||||
case DROPDOWN_FILTER:
|
||||
ComboItem[] dropdownItems = getDropdownItems(filterConfig);
|
||||
return new DynamicDropdownFilterPanel(plugin, filterConfig, taskService.getCurrentTaskType(), dropdownItems);
|
||||
default:
|
||||
log.error("invalid filter type " + filterConfig.getFilterType());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ComboItem[] getDropdownItems(FilterConfig filterConfig) throws ExecutionException, InterruptedException
|
||||
{
|
||||
if (filterConfig.getValueType() == null)
|
||||
{
|
||||
throw new Error("invalid filterConfig for dropdown items");
|
||||
}
|
||||
if (filterConfig.getValueType().equals(FilterValueType.PARAM_INTEGER))
|
||||
{
|
||||
String enumName = filterConfig.getOptionLabelEnum();
|
||||
if (!enumName.isEmpty())
|
||||
{
|
||||
HashMap<Integer, String> enumEntries = taskService.getStringEnumValuesAsync(enumName).get(); // TODO: blocking call
|
||||
ArrayList<ComboItem<Integer>> options = new ArrayList<>();
|
||||
options.add(new ComboItem<>(-1, ""));
|
||||
for (Map.Entry<Integer, String> entry : enumEntries.entrySet())
|
||||
{
|
||||
if (filterConfig.getValueName().equals("tier"))
|
||||
{
|
||||
if (entry.getValue().equals("All") || entry.getValue().equals("Tier"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
options.add(new ComboItem<>(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return options.toArray(new ComboItem[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return new ComboItem[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package net.reldo.taskstracker.panel;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.reldo.taskstracker.TasksTrackerPlugin;
|
||||
import net.reldo.taskstracker.config.ConfigValues;
|
||||
import net.reldo.taskstracker.data.jsondatastore.types.TaskDefinitionSkill;
|
||||
import net.reldo.taskstracker.data.task.TaskFromStruct;
|
||||
import net.reldo.taskstracker.data.task.TaskService;
|
||||
import net.reldo.taskstracker.panel.components.FixedWidthPanel;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
|
||||
@Slf4j
|
||||
public class TaskListPanel extends JScrollPane
|
||||
{
|
||||
public TasksTrackerPlugin plugin;
|
||||
private final HashMap<Integer, TaskPanel> taskPanelsByStructId = new HashMap<>();
|
||||
private final TaskListListPanel taskList;
|
||||
private final TaskService taskService;
|
||||
private final JLabel emptyTasks = new JLabel();
|
||||
|
||||
public TaskListPanel(TasksTrackerPlugin plugin, TaskService taskService)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
|
||||
taskList = new TaskListListPanel(plugin);
|
||||
this.taskService = taskService;
|
||||
|
||||
setViewportView(taskList);
|
||||
setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
}
|
||||
|
||||
public String getEmptyTaskListMessage()
|
||||
{
|
||||
return "No tasks match the current filters.";
|
||||
}
|
||||
|
||||
public void redraw()
|
||||
{
|
||||
taskList.redraw();
|
||||
}
|
||||
|
||||
public void refreshAllTasks()
|
||||
{
|
||||
log.debug("TaskListPanel.refreshAllTasks");
|
||||
if (!SwingUtilities.isEventDispatchThread())
|
||||
{
|
||||
log.error("Task list panel refresh failed - not event dispatch thread.");
|
||||
return;
|
||||
}
|
||||
for (TaskPanel taskPanel : taskPanelsByStructId.values())
|
||||
{
|
||||
taskPanel.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshMultipleTasks(Collection<TaskFromStruct> tasks)
|
||||
{
|
||||
log.debug("TaskListPanel.refreshMultipleTasks {}", tasks.size());
|
||||
if (!SwingUtilities.isEventDispatchThread())
|
||||
{
|
||||
log.error("Task list panel refresh failed - not event dispatch thread.");
|
||||
return;
|
||||
}
|
||||
for (TaskFromStruct task : tasks)
|
||||
{
|
||||
refresh(task);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshTask(TaskFromStruct task)
|
||||
{
|
||||
log.debug("TaskListPanel.refreshMultipleTasks {}", task.getName());
|
||||
refresh(task);
|
||||
}
|
||||
|
||||
private void refresh(TaskFromStruct task)
|
||||
{
|
||||
if (!SwingUtilities.isEventDispatchThread())
|
||||
{
|
||||
log.error("Task list panel refresh failed - not event dispatch thread.");
|
||||
return;
|
||||
}
|
||||
if (task == null)
|
||||
{
|
||||
log.debug("Attempted to refresh null task");
|
||||
return;
|
||||
}
|
||||
|
||||
emptyTasks.setVisible(false);
|
||||
|
||||
TaskPanel panel = taskPanelsByStructId.get(task.getStructId());
|
||||
if (panel != null)
|
||||
{
|
||||
panel.refresh();
|
||||
}
|
||||
|
||||
boolean isAnyTaskPanelVisible = taskPanelsByStructId.values().stream()
|
||||
.anyMatch(TaskPanel::isVisible);
|
||||
|
||||
if (!isAnyTaskPanelVisible)
|
||||
{
|
||||
emptyTasks.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshTaskPanelsWithSkill(Skill skill)
|
||||
{
|
||||
// Refresh all task panels for tasks with 'skill' or
|
||||
// 'SKILLS' (any skill) or 'TOTAL LEVEL' as a requirement.
|
||||
taskPanelsByStructId.values().stream()
|
||||
.filter(tp ->
|
||||
{
|
||||
List<TaskDefinitionSkill> skillsList = tp.task.getTaskDefinition().getSkills();
|
||||
if (skillsList == null || skillsList.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return skillsList.stream()
|
||||
.map(TaskDefinitionSkill::getSkill)
|
||||
.anyMatch(s -> s.equalsIgnoreCase(skill.getName()) ||
|
||||
s.equalsIgnoreCase("SKILLS") ||
|
||||
s.equalsIgnoreCase("TOTAL LEVEL")
|
||||
);
|
||||
})
|
||||
.forEach(TaskPanel::refresh);
|
||||
}
|
||||
|
||||
private class TaskListListPanel extends FixedWidthPanel
|
||||
{
|
||||
private final TasksTrackerPlugin plugin;
|
||||
|
||||
public TaskListListPanel(TasksTrackerPlugin plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
|
||||
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
setBorder(new EmptyBorder(0, 10, 10, 10));
|
||||
setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
|
||||
emptyTasks.setBorder(new EmptyBorder(10,0,10,0));
|
||||
emptyTasks.setText("<html><center>" + getEmptyTaskListMessage() + "</center></html>");
|
||||
emptyTasks.setFont(FontManager.getRunescapeSmallFont());
|
||||
emptyTasks.setHorizontalAlignment(JLabel.CENTER);
|
||||
emptyTasks.setVerticalAlignment(JLabel.CENTER);
|
||||
add(emptyTasks);
|
||||
emptyTasks.setVisible(false);
|
||||
}
|
||||
|
||||
public void redraw()
|
||||
{
|
||||
log.debug("TaskListPanel.redraw");
|
||||
if(SwingUtilities.isEventDispatchThread())
|
||||
{
|
||||
removeAll();
|
||||
taskPanelsByStructId.clear();
|
||||
add(emptyTasks);
|
||||
emptyTasks.setVisible(false);
|
||||
|
||||
log.debug("TaskListPanel creating panels");
|
||||
List<TaskFromStruct> tasks = taskService.getTasks();
|
||||
if (tasks == null || tasks.isEmpty())
|
||||
{
|
||||
emptyTasks.setVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int indexPosition = 0; indexPosition < tasks.size(); indexPosition++)
|
||||
{
|
||||
int adjustedIndexPosition = indexPosition;
|
||||
if (plugin.getConfig().sortDirection().equals(ConfigValues.SortDirections.DESCENDING))
|
||||
{
|
||||
adjustedIndexPosition = tasks.size() - (adjustedIndexPosition + 1);
|
||||
}
|
||||
TaskFromStruct task = tasks.get(taskService.getSortedTaskIndex(plugin.getConfig().sortCriteria(), adjustedIndexPosition));
|
||||
TaskPanel taskPanel = new TaskPanel(plugin, task);
|
||||
add(taskPanel);
|
||||
taskPanelsByStructId.put(task.getStructId(), taskPanel);
|
||||
}
|
||||
|
||||
log.debug("TaskListPanel validate and repaint");
|
||||
validate();
|
||||
repaint();
|
||||
}
|
||||
else
|
||||
{
|
||||
log.error("Task list panel redraw failed - not event dispatch thread.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
package net.reldo.taskstracker.panel;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JToolTip;
|
||||
import javax.swing.ToolTipManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.reldo.taskstracker.HtmlUtil;
|
||||
import net.reldo.taskstracker.TasksTrackerConfig;
|
||||
import net.reldo.taskstracker.TasksTrackerPlugin;
|
||||
import net.reldo.taskstracker.config.ConfigValues.CompletedFilterValues;
|
||||
import net.reldo.taskstracker.config.ConfigValues.IgnoredFilterValues;
|
||||
import net.reldo.taskstracker.config.ConfigValues.TrackedFilterValues;
|
||||
import net.reldo.taskstracker.data.jsondatastore.types.FilterType;
|
||||
import net.reldo.taskstracker.data.jsondatastore.types.TaskDefinitionSkill;
|
||||
import net.reldo.taskstracker.data.task.TaskFromStruct;
|
||||
import net.reldo.taskstracker.data.task.filters.Filter;
|
||||
import net.reldo.taskstracker.data.task.filters.ParamButtonFilter;
|
||||
import net.reldo.taskstracker.data.task.filters.ParamDropdownFilter;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.client.game.SkillIconManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
|
||||
@Slf4j
|
||||
public class TaskPanel extends JPanel
|
||||
{
|
||||
public final TaskFromStruct task;
|
||||
|
||||
private final JLabel tierIcon = new JLabel();
|
||||
private final JPanel container = new JPanel(new BorderLayout());
|
||||
private final JPanel body = new JPanel(new BorderLayout());
|
||||
private final JLabel name = new JLabel("task");
|
||||
private final JLabel description = new JLabel("description");
|
||||
private final JPanel buttons = new JPanel();
|
||||
private final JToggleButton toggleTrack = new JToggleButton();
|
||||
private final JToggleButton toggleIgnore = new JToggleButton();
|
||||
|
||||
protected final ArrayList<Filter> filters = new ArrayList<>();
|
||||
|
||||
protected TasksTrackerPlugin plugin;
|
||||
|
||||
public TaskPanel(TasksTrackerPlugin plugin, TaskFromStruct task)
|
||||
{
|
||||
super(new BorderLayout());
|
||||
this.plugin = plugin;
|
||||
this.task = task;
|
||||
createPanel();
|
||||
setComponentPopupMenu(getPopupMenu());
|
||||
ToolTipManager.sharedInstance().registerComponent(this);
|
||||
|
||||
task.getTaskType().getFilters().forEach((filterConfig) -> {
|
||||
String paramName = filterConfig.getValueName();
|
||||
if (filterConfig.getFilterType().equals(FilterType.BUTTON_FILTER))
|
||||
{
|
||||
Filter filter = new ParamButtonFilter(plugin.getConfigManager(), paramName, task.getTaskType().getTaskJsonName() + "." + filterConfig.getConfigKey());
|
||||
filters.add(filter);
|
||||
}
|
||||
else if (filterConfig.getFilterType().equals(FilterType.DROPDOWN_FILTER))
|
||||
{
|
||||
Filter filter = new ParamDropdownFilter(plugin.getConfigManager(), paramName, task.getTaskType().getTaskJsonName() + "." + filterConfig.getConfigKey());
|
||||
filters.add(filter);
|
||||
}
|
||||
});
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
public JPopupMenu getPopupMenu()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getTaskTooltip()
|
||||
{
|
||||
StringBuilder tooltipText = new StringBuilder();
|
||||
tooltipText.append(HtmlUtil.wrapWithBold(task.getName())).append(HtmlUtil.HTML_LINE_BREAK);
|
||||
tooltipText.append(task.getDescription()).append(HtmlUtil.HTML_LINE_BREAK);
|
||||
|
||||
String skillSection = getSkillSectionHtml();
|
||||
if (skillSection != null)
|
||||
{
|
||||
tooltipText.append(skillSection).append(HtmlUtil.HTML_LINE_BREAK);
|
||||
}
|
||||
|
||||
String wikiNotes = task.getTaskDefinition().getWikiNotes();
|
||||
if (wikiNotes != null)
|
||||
{
|
||||
tooltipText.append(HtmlUtil.HTML_LINE_BREAK).append(wikiNotes).append(HtmlUtil.HTML_LINE_BREAK);
|
||||
}
|
||||
|
||||
if (task.isCompleted())
|
||||
{
|
||||
tooltipText.append(HtmlUtil.HTML_LINE_BREAK);
|
||||
String datePattern = "MM-dd-yyyy hh:mma";
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
|
||||
tooltipText.append("✔ ").append(simpleDateFormat.format(new Date(task.getCompletedOn())));
|
||||
}
|
||||
|
||||
Float completionPercent = task.getTaskDefinition().getCompletionPercent();
|
||||
if (completionPercent != null)
|
||||
{
|
||||
tooltipText.append(HtmlUtil.HTML_LINE_BREAK).append("Players Completed: ").append(completionPercent).append('%');
|
||||
}
|
||||
|
||||
return HtmlUtil.wrapWithHtml(
|
||||
HtmlUtil.wrapWithWrappingParagraph(tooltipText.toString(), 200)
|
||||
);
|
||||
}
|
||||
|
||||
public Color getTaskBackgroundColor()
|
||||
{
|
||||
if (plugin.playerSkills == null)
|
||||
{
|
||||
return ColorScheme.DARKER_GRAY_COLOR;
|
||||
}
|
||||
|
||||
if (task.isCompleted())
|
||||
{
|
||||
return Colors.COMPLETED_BACKGROUND_COLOR;
|
||||
}
|
||||
|
||||
if (task.getTaskDefinition().getSkills() == null || task.getTaskDefinition().getSkills().size() == 0)
|
||||
{
|
||||
return ColorScheme.DARKER_GRAY_COLOR;
|
||||
}
|
||||
|
||||
for (TaskDefinitionSkill requiredSkill : task.getTaskDefinition().getSkills())
|
||||
{
|
||||
Skill skill;
|
||||
String requiredSkillName = requiredSkill.getSkill().toUpperCase();
|
||||
try
|
||||
{
|
||||
skill = Skill.valueOf(requiredSkillName);
|
||||
}
|
||||
catch (IllegalArgumentException ex)
|
||||
{
|
||||
log.error("invalid skill name " + requiredSkillName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (plugin.playerSkills[skill.ordinal()] < requiredSkill.getLevel())
|
||||
{
|
||||
return Colors.UNQUALIFIED_BACKGROUND_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
return ColorScheme.DARKER_GRAY_COLOR;
|
||||
}
|
||||
|
||||
public void createPanel()
|
||||
{
|
||||
setLayout(new BorderLayout());
|
||||
setBorder(new EmptyBorder(0, 0, 7, 0));
|
||||
|
||||
container.setBorder(new EmptyBorder(7, 7, 6, 0));
|
||||
|
||||
// Body
|
||||
|
||||
name.setFont(FontManager.getRunescapeSmallFont());
|
||||
name.setForeground(Color.WHITE);
|
||||
body.add(name, BorderLayout.NORTH);
|
||||
|
||||
description.setFont(FontManager.getRunescapeSmallFont());
|
||||
description.setForeground(Color.GRAY);
|
||||
body.add(description, BorderLayout.CENTER);
|
||||
|
||||
// Buttons
|
||||
buttons.setLayout(new BoxLayout(buttons, BoxLayout.Y_AXIS));
|
||||
buttons.setBorder(new EmptyBorder(0, 0, 0, 7));
|
||||
|
||||
toggleTrack.setPreferredSize(new Dimension(8, 8));
|
||||
toggleTrack.setIcon(Icons.PLUS_ICON);
|
||||
toggleTrack.setSelectedIcon(Icons.MINUS_ICON);
|
||||
toggleTrack.setBorder(new EmptyBorder(5, 0, 5, 0));
|
||||
toggleTrack.addActionListener(e -> {
|
||||
task.setTracked(toggleTrack.isSelected());
|
||||
plugin.pluginPanel.taskListPanel.refreshTask(task);
|
||||
plugin.saveCurrentTaskTypeData();
|
||||
});
|
||||
SwingUtil.removeButtonDecorations(toggleTrack);
|
||||
|
||||
toggleIgnore.setPreferredSize(new Dimension(8, 8));
|
||||
toggleIgnore.setIcon(Icons.EYE_CROSS_GREY);
|
||||
toggleIgnore.setSelectedIcon(Icons.EYE_ICON);
|
||||
SwingUtil.addModalTooltip(toggleIgnore, "Unignore", "Ignore");
|
||||
toggleIgnore.setBorder(new EmptyBorder(5, 0, 5, 0));
|
||||
toggleIgnore.addActionListener(e -> {
|
||||
task.setIgnored(!task.isIgnored());
|
||||
plugin.pluginPanel.taskListPanel.refreshTask(task);
|
||||
plugin.saveCurrentTaskTypeData();
|
||||
});
|
||||
SwingUtil.removeButtonDecorations(toggleIgnore);
|
||||
|
||||
buttons.add(toggleTrack);
|
||||
buttons.add(toggleIgnore);
|
||||
|
||||
// Full
|
||||
container.add(tierIcon, BorderLayout.WEST);
|
||||
container.add(body, BorderLayout.CENTER);
|
||||
container.add(buttons, BorderLayout.EAST);
|
||||
|
||||
BufferedImage tierSprite = task.getTaskType().getTierSprites().get(task.getTier());
|
||||
if (tierSprite != null)
|
||||
{
|
||||
tierIcon.setMinimumSize(new Dimension(Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT));
|
||||
tierIcon.setIcon(new ImageIcon(tierSprite));
|
||||
tierIcon.setBorder(new EmptyBorder(0, 0, 0, 5));
|
||||
}
|
||||
else
|
||||
{
|
||||
tierIcon.setBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
add(container, BorderLayout.NORTH);
|
||||
|
||||
addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e)
|
||||
{
|
||||
if (e.isPopupTrigger())
|
||||
{
|
||||
JPopupMenu menu = createWikiPopupMenu();
|
||||
menu.show(e.getComponent(), e.getX(), e.getY());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public JPopupMenu createWikiPopupMenu()
|
||||
{
|
||||
JPopupMenu popupMenu = new JPopupMenu();
|
||||
JMenuItem openWikiItem = new JMenuItem("Wiki");
|
||||
openWikiItem.addActionListener(e -> openRuneScapeWiki());
|
||||
popupMenu.add(openWikiItem);
|
||||
return popupMenu;
|
||||
}
|
||||
|
||||
private void openRuneScapeWiki()
|
||||
{
|
||||
String wikiUrl = String.format("https://oldschool.runescape.wiki/%s", URLEncoder.encode(task.getName().replace(' ', '_'), StandardCharsets.UTF_8));
|
||||
if (Desktop.isDesktopSupported())
|
||||
{
|
||||
try
|
||||
{
|
||||
Desktop.getDesktop().browse(new URI(wikiUrl));
|
||||
}
|
||||
catch (IOException | URISyntaxException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log.warn("Desktop browsing is not supported on this system.");
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh()
|
||||
{
|
||||
setBackgroundColor(getTaskBackgroundColor());
|
||||
name.setText(HtmlUtil.wrapWithHtml(task.getName()));
|
||||
description.setText(HtmlUtil.wrapWithHtml(task.getDescription()));
|
||||
toggleTrack.setSelected(task.isTracked());
|
||||
toggleIgnore.setSelected(task.isIgnored());
|
||||
|
||||
setVisible(meetsFilterCriteria());
|
||||
|
||||
revalidate();
|
||||
}
|
||||
|
||||
protected boolean meetsFilterCriteria()
|
||||
{
|
||||
String nameLowercase = task.getName().toLowerCase();
|
||||
String descriptionLowercase = task.getDescription().toLowerCase();
|
||||
if (plugin.taskTextFilter != null &&
|
||||
!nameLowercase.contains(plugin.taskTextFilter) &&
|
||||
!descriptionLowercase.contains(plugin.taskTextFilter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TasksTrackerConfig config = plugin.getConfig();
|
||||
|
||||
for (Filter filter : filters)
|
||||
{
|
||||
if (!filter.meetsCriteria(task))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.completedFilter().equals(CompletedFilterValues.INCOMPLETE) && task.isCompleted())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (config.completedFilter().equals(CompletedFilterValues.COMPLETE) && !task.isCompleted())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.ignoredFilter().equals(IgnoredFilterValues.NOT_IGNORED) && task.isIgnored())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (config.ignoredFilter().equals(IgnoredFilterValues.IGNORED) && !task.isIgnored())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.trackedFilter().equals(TrackedFilterValues.UNTRACKED) && task.isTracked())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !config.trackedFilter().equals(TrackedFilterValues.TRACKED) || task.isTracked();
|
||||
}
|
||||
|
||||
private void setBackgroundColor(Color color)
|
||||
{
|
||||
container.setBackground(color);
|
||||
body.setBackground(color);
|
||||
buttons.setBackground(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMaximumSize()
|
||||
{
|
||||
return new Dimension(PluginPanel.PANEL_WIDTH, getPreferredSize().height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JToolTip createToolTip()
|
||||
{
|
||||
JToolTip customTooltip = new JToolTip();
|
||||
customTooltip.setFont(FontManager.getRunescapeSmallFont());
|
||||
return customTooltip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTipText(MouseEvent mouseEvent)
|
||||
{
|
||||
return getTaskTooltip();
|
||||
}
|
||||
|
||||
private String getSkillSectionHtml()
|
||||
{
|
||||
List<TaskDefinitionSkill> requiredSkills = task.getTaskDefinition().getSkills();
|
||||
if (requiredSkills == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
StringBuilder skillSection = new StringBuilder();
|
||||
skillSection.append(HtmlUtil.HTML_LINE_BREAK);
|
||||
for (TaskDefinitionSkill requiredSkill : requiredSkills)
|
||||
{
|
||||
Skill skill;
|
||||
try
|
||||
{
|
||||
skill = Skill.valueOf(requiredSkill.getSkill().toUpperCase());
|
||||
}
|
||||
catch (IllegalArgumentException ex)
|
||||
{
|
||||
log.warn("unknown skill: {}", requiredSkill.getSkill().toUpperCase(), ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Integer requiredLevel = requiredSkill.getLevel();
|
||||
int playerLevel = -1;
|
||||
if (requiredLevel == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (plugin.playerSkills != null)
|
||||
{
|
||||
playerLevel = plugin.playerSkills[skill.ordinal()];
|
||||
}
|
||||
String skillMessage = getSkillRequirementHtml(requiredSkill.getSkill().toLowerCase(), playerLevel, requiredLevel);
|
||||
skillSection.append(skillMessage).append(" ");
|
||||
}
|
||||
|
||||
return skillSection.toString();
|
||||
}
|
||||
|
||||
private String getSkillRequirementHtml(String skillName, Integer playerLevel, int requiredLevel)
|
||||
{
|
||||
String skillIconPath = "/skill_icons_small/" + skillName + ".png";
|
||||
URL url = SkillIconManager.class.getResource(skillIconPath);
|
||||
Color color = playerLevel >= requiredLevel ? Colors.QUALIFIED_TEXT_COLOR : Colors.UNQUALIFIED_TEXT_COLOR;
|
||||
return HtmlUtil.imageTag(url) + " " + HtmlUtil.colorTag(color, playerLevel + "/" + requiredLevel);
|
||||
}
|
||||
|
||||
private String getPointsTooltipText()
|
||||
{
|
||||
int points = this.task.getPoints();
|
||||
if (points == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return " - " + points + " points";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.reldo.taskstracker.panel;
|
||||
|
||||
import net.reldo.taskstracker.data.task.TaskFromStruct;
|
||||
|
||||
public interface TaskPanelFactory
|
||||
{
|
||||
TaskPanel create(TaskFromStruct task);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package net.reldo.taskstracker.panel;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.reldo.taskstracker.TasksTrackerConfig;
|
||||
import net.reldo.taskstracker.TasksTrackerPlugin;
|
||||
import net.reldo.taskstracker.data.task.TaskService;
|
||||
import net.runelite.client.game.SpriteManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
|
||||
@Slf4j
|
||||
public class TasksTrackerPluginPanel extends PluginPanel
|
||||
{
|
||||
private final LoggedInPanel loggedInPanel;
|
||||
private final LoggedOutPanel loggedOutPanel = new LoggedOutPanel();
|
||||
|
||||
public TaskListPanel taskListPanel;
|
||||
|
||||
private boolean loggedInPanelVisible = false;
|
||||
|
||||
public TasksTrackerPluginPanel(TasksTrackerPlugin plugin, TasksTrackerConfig config, SpriteManager spriteManager, TaskService taskService)
|
||||
{
|
||||
super(false);
|
||||
|
||||
setBorder(new EmptyBorder(6, 6, 6, 6));
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
loggedInPanel = new LoggedInPanel(plugin, config, taskService);
|
||||
taskListPanel = loggedInPanel.taskListPanel;
|
||||
add(loggedInPanel, BorderLayout.NORTH);
|
||||
loggedInPanel.setVisible(false);
|
||||
|
||||
// Add error pane
|
||||
add(loggedOutPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(PANEL_WIDTH + SCROLLBAR_WIDTH, super.getPreferredSize().height);
|
||||
}
|
||||
|
||||
public void redraw()
|
||||
{
|
||||
if (loggedInPanelVisible)
|
||||
{
|
||||
loggedInPanel.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshAllTasks()
|
||||
{
|
||||
if (loggedInPanelVisible)
|
||||
{
|
||||
loggedInPanel.refreshAllTasks();
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoggedIn(boolean loggedIn)
|
||||
{
|
||||
if(SwingUtilities.isEventDispatchThread())
|
||||
{
|
||||
updateVisiblePanel(loggedIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.error("Failed to update loggedIn state - not event dispatch thread.");
|
||||
}
|
||||
}
|
||||
|
||||
public void hideLoggedInPanel()
|
||||
{
|
||||
if(SwingUtilities.isEventDispatchThread())
|
||||
{
|
||||
updateVisiblePanel(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.error("Failed to update logged in panel visibility - not event dispatch thread.");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateVisiblePanel(boolean loggedInPanelVisible)
|
||||
{
|
||||
if (loggedInPanelVisible != this.loggedInPanelVisible)
|
||||
{
|
||||
if (loggedInPanelVisible)
|
||||
{
|
||||
loggedOutPanel.setVisible(false);
|
||||
loggedInPanel.setVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
loggedInPanel.setVisible(false);
|
||||
loggedOutPanel.setVisible(true);
|
||||
}
|
||||
|
||||
validate();
|
||||
repaint();
|
||||
}
|
||||
this.loggedInPanelVisible = loggedInPanelVisible;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.reldo.taskstracker.panel.components;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionListener;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import static net.runelite.client.ui.PluginPanel.PANEL_WIDTH;
|
||||
|
||||
public class CheckBox extends JPanel
|
||||
{
|
||||
private final JCheckBox jCheckBox = new JCheckBox();
|
||||
|
||||
public CheckBox(String name)
|
||||
{
|
||||
setLayout(new BorderLayout());
|
||||
setMinimumSize(new Dimension(PANEL_WIDTH, 0));
|
||||
|
||||
JLabel label = new JLabel(name);
|
||||
add(label, BorderLayout.CENTER);
|
||||
|
||||
jCheckBox.setBackground(ColorScheme.LIGHT_GRAY_COLOR);
|
||||
add(jCheckBox, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
public boolean isSelected()
|
||||
{
|
||||
return jCheckBox.isSelected();
|
||||
}
|
||||
|
||||
public void setSelected(boolean selected)
|
||||
{
|
||||
jCheckBox.setSelected(selected);
|
||||
}
|
||||
|
||||
public void addActionListener(ActionListener l)
|
||||
{
|
||||
jCheckBox.addActionListener(l);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.reldo.taskstracker.panel.components;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.JPanel;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
|
||||
public class FixedWidthPanel extends JPanel
|
||||
{
|
||||
@Override
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(PluginPanel.PANEL_WIDTH, super.getPreferredSize().height);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package net.reldo.taskstracker.panel.components;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class MultiToggleButton extends JButton
|
||||
{
|
||||
|
||||
// Icons
|
||||
private final Icon[] icons;
|
||||
// Tooltips
|
||||
private final String[] tooltips;
|
||||
private final int stateCount;
|
||||
@Setter
|
||||
private ActionListener stateChangedAction = null;
|
||||
@Getter
|
||||
private int state = 0;
|
||||
final JPopupMenu popupMenu = new JPopupMenu();
|
||||
private boolean popupMenuEnabled = false;
|
||||
|
||||
public MultiToggleButton(int stateCount)
|
||||
{
|
||||
super();
|
||||
this.stateCount = stateCount;
|
||||
icons = new Icon[stateCount];
|
||||
tooltips = new String[stateCount];
|
||||
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
addActionListener(e -> changeStateThenAction());
|
||||
}
|
||||
|
||||
public void popupMenuEnabled(boolean enabled)
|
||||
{
|
||||
if(popupMenuEnabled != enabled)
|
||||
{
|
||||
popupMenuEnabled = enabled;
|
||||
if(popupMenuEnabled)
|
||||
{
|
||||
this.setComponentPopupMenu(popupMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.remove(popupMenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setIcon(Icon icon, int state)
|
||||
{
|
||||
if (state < 0 || state > stateCount || icon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
icons[state] = icon;
|
||||
|
||||
if (state == this.state) setIconState();
|
||||
}
|
||||
|
||||
public boolean setIcons(Icon[] icons)
|
||||
{
|
||||
if (icons == null || icons.length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < icons.length; i++)
|
||||
{
|
||||
setIcon(icons[i], i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setToolTip(String tooltip, int state)
|
||||
{
|
||||
if (state < 0 || state > 3 || tooltip == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tooltips[state] = tooltip;
|
||||
addPopupMenuItem(tooltip, state);
|
||||
|
||||
if (state == this.state) setTooltipState();
|
||||
}
|
||||
|
||||
public boolean setToolTips(String[] tooltips)
|
||||
{
|
||||
if (tooltips == null || tooltips.length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < tooltips.length; i++)
|
||||
{
|
||||
setToolTip(tooltips[i], i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void changeState()
|
||||
{
|
||||
setState((++state) % stateCount);
|
||||
}
|
||||
|
||||
public void changeStateThenAction()
|
||||
{
|
||||
setStateThenAction((++state) % stateCount);
|
||||
}
|
||||
|
||||
private void setIconState()
|
||||
{
|
||||
super.setIcon(icons[state]);
|
||||
}
|
||||
|
||||
private void setTooltipState()
|
||||
{
|
||||
super.setToolTipText(tooltips[state]);
|
||||
}
|
||||
|
||||
public void setState(int state)
|
||||
{
|
||||
this.state = state;
|
||||
setIconState();
|
||||
setTooltipState();
|
||||
}
|
||||
|
||||
public void setStateThenAction(int state)
|
||||
{
|
||||
setState(state);
|
||||
if(stateChangedAction != null) this.stateChangedAction.actionPerformed(new ActionEvent(this, 0, ""));
|
||||
}
|
||||
|
||||
private void addPopupMenuItem(String text, int state)
|
||||
{
|
||||
JMenuItem menuItem = new JMenuItem(text);
|
||||
menuItem.addActionListener(e -> {if(isEnabled())setState(state);});
|
||||
popupMenu.add(menuItem);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package net.reldo.taskstracker.panel.components;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.ui.components.IconTextField;
|
||||
|
||||
public class SearchBox extends IconTextField
|
||||
{
|
||||
private SearchBoxCallback fn;
|
||||
|
||||
public SearchBox()
|
||||
{
|
||||
this.setIcon(IconTextField.Icon.SEARCH);
|
||||
this.setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH - 20, 30));
|
||||
this.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
this.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR);
|
||||
this.getDocument().addDocumentListener(new DocumentListener()
|
||||
{
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent documentEvent)
|
||||
{
|
||||
fn.call();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent documentEvent)
|
||||
{
|
||||
fn.call();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent documentEvent)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
this.addActionListener(e -> fn.call()
|
||||
);
|
||||
}
|
||||
|
||||
public void addTextChangedListener(SearchBoxCallback fn)
|
||||
{
|
||||
this.fn = fn;
|
||||
}
|
||||
|
||||
public interface SearchBoxCallback
|
||||
{
|
||||
void call();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package net.reldo.taskstracker.panel.components;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
public class TriToggleButton extends MultiToggleButton
|
||||
{
|
||||
public TriToggleButton()
|
||||
{
|
||||
super(3);
|
||||
}
|
||||
|
||||
public boolean setIcons(Icon icon0, Icon icon1, Icon icon2)
|
||||
{
|
||||
if (icon0 == null || icon1 == null || icon2 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
setIcon(icon0, 0);
|
||||
setIcon(icon1, 1);
|
||||
setIcon(icon2, 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean setToolTips(String tooltip0, String tooltip1, String tooltip2)
|
||||
{
|
||||
if (tooltip0 == null || tooltip1 == null || tooltip2 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
setToolTip(tooltip0, 0);
|
||||
setToolTip(tooltip1, 1);
|
||||
setToolTip(tooltip2, 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package net.reldo.taskstracker.panel.filters;
|
||||
|
||||
public class ComboItem<T>
|
||||
{
|
||||
private T value;
|
||||
private String label;
|
||||
|
||||
public ComboItem(T value, String label)
|
||||
{
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public T getValue()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return this.label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package net.reldo.taskstracker.panel.filters;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import net.reldo.taskstracker.TasksTrackerPlugin;
|
||||
import net.reldo.taskstracker.data.jsondatastore.types.FilterConfig;
|
||||
import net.reldo.taskstracker.data.jsondatastore.types.FilterCustomItem;
|
||||
import net.reldo.taskstracker.data.task.TaskType;
|
||||
import net.runelite.client.hiscore.HiscoreSkill;
|
||||
import static net.runelite.client.hiscore.HiscoreSkill.*;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
|
||||
public class DynamicButtonFilterPanel extends FilterButtonPanel
|
||||
{
|
||||
private final FilterConfig filterConfig;
|
||||
private final TaskType taskType;
|
||||
|
||||
/**
|
||||
* Real skills, ordered in the way they should be displayed in the panel.
|
||||
*/
|
||||
private static final List<HiscoreSkill> SKILLS = ImmutableList.of(
|
||||
ATTACK, HITPOINTS, MINING,
|
||||
STRENGTH, AGILITY, SMITHING,
|
||||
DEFENCE, HERBLORE, FISHING,
|
||||
RANGED, THIEVING, COOKING,
|
||||
PRAYER, CRAFTING, FIREMAKING,
|
||||
MAGIC, FLETCHING, WOODCUTTING,
|
||||
RUNECRAFT, SLAYER, FARMING,
|
||||
CONSTRUCTION, HUNTER
|
||||
);
|
||||
|
||||
public DynamicButtonFilterPanel(TasksTrackerPlugin plugin, FilterConfig filterConfig, TaskType taskType)
|
||||
{
|
||||
super(plugin, filterConfig.getLabel());
|
||||
this.filterConfig = filterConfig;
|
||||
this.taskType = taskType;
|
||||
this.configKey = taskType.getFilterConfigPrefix() + filterConfig.getConfigKey();
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JPanel makeButtonPanel()
|
||||
{
|
||||
// Panel that holds tier icons
|
||||
JPanel buttonPanel = new JPanel();
|
||||
buttonPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
LinkedHashMap<String, BufferedImage> buttonImages = getIconImages();
|
||||
LinkedHashMap<String, String> buttonTooltips = getTooltips();
|
||||
|
||||
buttonPanel.setLayout(new GridLayout(buttonImages.size() / 3, 3));
|
||||
|
||||
// For each filter value create a button and add it to the UI
|
||||
buttonImages.forEach((key, image) -> {
|
||||
String tooltip = buttonTooltips.get(key);
|
||||
JToggleButton button = makeButton(tooltip, image);
|
||||
button.setSelected(getConfigButtonState(key));
|
||||
buttons.put(key, button);
|
||||
buttonPanel.add(button);
|
||||
});
|
||||
|
||||
return buttonPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LinkedHashMap<String, BufferedImage> getIconImages()
|
||||
{
|
||||
LinkedHashMap<String, BufferedImage> images = new LinkedHashMap<>();
|
||||
|
||||
if (filterConfig.getConfigKey().equals("skill"))
|
||||
{
|
||||
String skillName;
|
||||
BufferedImage skillImage;
|
||||
int index = 0;
|
||||
|
||||
for (FilterCustomItem customItem : filterConfig.getCustomItems())
|
||||
{
|
||||
if (customItem.getValue() != 0)
|
||||
{
|
||||
skillName = SKILLS.get(index).name().toLowerCase();
|
||||
|
||||
String directory = "/skill_icons_small/";
|
||||
String skillIcon = directory + skillName + ".png";
|
||||
|
||||
skillImage = ImageUtil.loadImageResource(getClass(), skillIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
skillImage = ImageUtil.loadImageResource(TasksTrackerPlugin.class, "panel/components/no_skill.png");
|
||||
}
|
||||
|
||||
String key = customItem.getValue().toString();
|
||||
images.put(key, skillImage);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (FilterCustomItem customItem : filterConfig.getCustomItems())
|
||||
{
|
||||
String key = customItem.getValue().toString();
|
||||
images.put(key, taskType.getSpritesById().get(customItem.getSpriteId()));
|
||||
}
|
||||
}
|
||||
return images;
|
||||
}
|
||||
|
||||
private LinkedHashMap<String, String> getTooltips()
|
||||
{
|
||||
LinkedHashMap<String, String> tooltips = new LinkedHashMap<>();
|
||||
for (FilterCustomItem customItem : filterConfig.getCustomItems())
|
||||
{
|
||||
String key = customItem.getValue().toString();
|
||||
tooltips.put(key, customItem.getTooltip());
|
||||
}
|
||||
return tooltips;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package net.reldo.taskstracker.panel.filters;
|
||||
|
||||
import java.awt.GridLayout;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.reldo.taskstracker.TasksTrackerPlugin;
|
||||
import net.reldo.taskstracker.data.jsondatastore.types.FilterConfig;
|
||||
import net.reldo.taskstracker.data.task.TaskType;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
|
||||
@Slf4j
|
||||
public class DynamicDropdownFilterPanel extends FilterPanel
|
||||
{
|
||||
private final String configKey;
|
||||
private final FilterConfig filterConfig;
|
||||
private final ConfigManager configManager;
|
||||
private final TasksTrackerPlugin plugin;
|
||||
private final ComboItem[] items;
|
||||
private JComboBox<ComboItem> dropdown;
|
||||
|
||||
public DynamicDropdownFilterPanel(TasksTrackerPlugin plugin, FilterConfig filterConfig, TaskType taskType, ComboItem[] items)
|
||||
{
|
||||
this.configManager = plugin.getConfigManager();
|
||||
this.plugin = plugin;
|
||||
this.filterConfig = filterConfig;
|
||||
this.items = items;
|
||||
this.configKey = taskType.getFilterConfigPrefix() + filterConfig.getConfigKey();
|
||||
|
||||
setLayout(new GridLayout(1,2));
|
||||
setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
setBorder(new EmptyBorder(5, 10, 5, 10));
|
||||
}
|
||||
|
||||
private JComboBox<ComboItem> makeDropdownPanel()
|
||||
{
|
||||
JComboBox<ComboItem> dropdown = new JComboBox<>(items);
|
||||
dropdown.setFont(FontManager.getRunescapeSmallFont());
|
||||
dropdown.setAlignmentX(LEFT_ALIGNMENT);
|
||||
dropdown.setSelectedItem(items[0]);
|
||||
dropdown.setFocusable(false);
|
||||
dropdown.setBackground(ColorScheme.DARK_GRAY_COLOR.brighter());
|
||||
dropdown.addActionListener(e -> {
|
||||
ComboItem selection = dropdown.getItemAt(dropdown.getSelectedIndex());
|
||||
updateFilterConfig();
|
||||
plugin.refreshAllTasks();
|
||||
log.debug("selected: {} {}", selection.getLabel(), selection.getValue());
|
||||
});
|
||||
|
||||
return dropdown;
|
||||
}
|
||||
|
||||
private JLabel makeLabel()
|
||||
{
|
||||
JLabel label = new JLabel(filterConfig.getLabel() + ":");
|
||||
label.setFont(FontManager.getRunescapeSmallFont());
|
||||
label.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
|
||||
return label;
|
||||
}
|
||||
|
||||
protected void updateFilterConfig()
|
||||
{
|
||||
log.debug("updateFilterConfig {}, {}, {}", TasksTrackerPlugin.CONFIG_GROUP_NAME, configKey, dropdown.getItemAt(dropdown.getSelectedIndex()).getValue());
|
||||
configManager.setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, configKey, dropdown.getItemAt(dropdown.getSelectedIndex()).getValue());
|
||||
}
|
||||
|
||||
public void redraw()
|
||||
{
|
||||
if(SwingUtilities.isEventDispatchThread())
|
||||
{
|
||||
removeAll();
|
||||
|
||||
dropdown = makeDropdownPanel();
|
||||
|
||||
add(makeLabel());
|
||||
add(dropdown);
|
||||
|
||||
updateFilterConfig();
|
||||
|
||||
validate();
|
||||
repaint();
|
||||
}
|
||||
else
|
||||
{
|
||||
log.error("Dropdown filter panel redraw failed - not event dispatch thread.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package net.reldo.taskstracker.panel.filters;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.plaf.basic.BasicBorders;
|
||||
import javax.swing.plaf.basic.BasicButtonUI;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.reldo.taskstracker.TasksTrackerPlugin;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
|
||||
@Slf4j
|
||||
public abstract class FilterButtonPanel extends FilterPanel
|
||||
{
|
||||
protected final TasksTrackerPlugin plugin;
|
||||
private final String label;
|
||||
|
||||
protected final Map<String, JToggleButton> buttons = new HashMap<>();
|
||||
protected String configKey;
|
||||
protected JPanel buttonPanel;
|
||||
|
||||
protected JToggleButton collapseBtn;
|
||||
private final String expandBtnPath = "panel/components/";
|
||||
private final BufferedImage collapseImg = ImageUtil.loadImageResource(TasksTrackerPlugin.class, expandBtnPath + "filter_buttons_collapsed.png");
|
||||
private final Icon MENU_COLLAPSED_ICON = new ImageIcon(ImageUtil.alphaOffset(collapseImg, -180));
|
||||
private final Icon MENU_ICON_HOVER = new ImageIcon(collapseImg);
|
||||
private final BufferedImage expandedImg = ImageUtil.loadImageResource(TasksTrackerPlugin.class, expandBtnPath + "filter_buttons_expanded.png");
|
||||
private final Icon MENU_EXPANDED_ICON = new ImageIcon(ImageUtil.alphaOffset(expandedImg, -180));
|
||||
private final Icon MENU_ICON_HOVER_SELECTED = new ImageIcon(expandedImg);
|
||||
|
||||
|
||||
public FilterButtonPanel(TasksTrackerPlugin plugin, String label)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
protected abstract LinkedHashMap<String, BufferedImage> getIconImages();
|
||||
|
||||
protected abstract JPanel makeButtonPanel();
|
||||
|
||||
protected JToggleButton makeButton(String tooltip, BufferedImage image)
|
||||
{
|
||||
JToggleButton button = new JToggleButton();
|
||||
button.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
button.setBorder(new BasicBorders.ToggleButtonBorder(ColorScheme.DARKER_GRAY_COLOR,
|
||||
ColorScheme.DARKER_GRAY_COLOR.darker(),
|
||||
ColorScheme.MEDIUM_GRAY_COLOR.darker(),
|
||||
ColorScheme.MEDIUM_GRAY_COLOR));
|
||||
button.setFocusable(false);
|
||||
|
||||
if (image != null) {
|
||||
ImageIcon selectedIcon = new ImageIcon(image);
|
||||
ImageIcon deselectedIcon = new ImageIcon(ImageUtil.alphaOffset(image, -180));
|
||||
|
||||
button.setIcon(deselectedIcon);
|
||||
button.setSelectedIcon(selectedIcon);
|
||||
button.setPreferredSize(new Dimension(image.getWidth(), image.getHeight() + 10));
|
||||
} else {
|
||||
button.setPreferredSize(new Dimension(button.getPreferredSize().width, 50));
|
||||
}
|
||||
button.setToolTipText(tooltip.substring(0,1).toUpperCase() + tooltip.substring(1).toLowerCase());
|
||||
|
||||
button.addActionListener(e -> {
|
||||
updateFilterText();
|
||||
updateCollapseButtonText();
|
||||
plugin.refreshAllTasks();
|
||||
});
|
||||
|
||||
button.setSelected(true);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
protected JPanel allOrNoneButtons()
|
||||
{
|
||||
JPanel buttonWrapper = new JPanel();
|
||||
buttonWrapper.setLayout(new BoxLayout(buttonWrapper, BoxLayout.X_AXIS));
|
||||
buttonWrapper.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
buttonWrapper.setAlignmentX(JPanel.CENTER_ALIGNMENT);
|
||||
|
||||
JButton all = new JButton("all");
|
||||
SwingUtil.removeButtonDecorations(all);
|
||||
all.setFocusable(false);
|
||||
all.setForeground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||
all.setFont(FontManager.getRunescapeSmallFont());
|
||||
all.setPreferredSize(new Dimension(50, 0));
|
||||
all.addActionListener(e -> {
|
||||
setAllSelected(true);
|
||||
updateFilterText();
|
||||
updateCollapseButtonText();
|
||||
plugin.refreshAllTasks();
|
||||
});
|
||||
|
||||
JButton none = new JButton("none");
|
||||
SwingUtil.removeButtonDecorations(none);
|
||||
none.setFocusable(false);
|
||||
none.setForeground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||
none.setFont(FontManager.getRunescapeSmallFont());
|
||||
none.setPreferredSize(new Dimension(50, 0));
|
||||
none.addActionListener(e -> {
|
||||
setAllSelected(false);
|
||||
updateFilterText();
|
||||
updateCollapseButtonText();
|
||||
plugin.refreshAllTasks();
|
||||
});
|
||||
|
||||
JLabel separator = new JLabel("|");
|
||||
separator.setForeground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||
|
||||
buttonWrapper.add(Box.createHorizontalGlue());
|
||||
buttonWrapper.add(all);
|
||||
buttonWrapper.add(Box.createHorizontalGlue());
|
||||
buttonWrapper.add(separator);
|
||||
buttonWrapper.add(Box.createHorizontalGlue());
|
||||
buttonWrapper.add(none);
|
||||
buttonWrapper.add(Box.createHorizontalGlue());
|
||||
|
||||
return buttonWrapper;
|
||||
}
|
||||
|
||||
public JToggleButton makeCollapseButton()
|
||||
{
|
||||
JToggleButton collapseBtn = new JToggleButton();
|
||||
|
||||
// collapse button
|
||||
SwingUtil.removeButtonDecorations(collapseBtn);
|
||||
collapseBtn.setIcon(MENU_COLLAPSED_ICON);
|
||||
collapseBtn.setSelectedIcon(MENU_EXPANDED_ICON);
|
||||
collapseBtn.setRolloverIcon(MENU_ICON_HOVER);
|
||||
collapseBtn.setRolloverSelectedIcon(MENU_ICON_HOVER_SELECTED);
|
||||
SwingUtil.addModalTooltip(collapseBtn, "Collapse filters", "Expand filters");
|
||||
collapseBtn.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
collapseBtn.setAlignmentX(LEFT_ALIGNMENT);
|
||||
collapseBtn.setUI(new BasicButtonUI()); // substance breaks the layout
|
||||
collapseBtn.addActionListener(ev -> buttonPanel.setVisible(!buttonPanel.isVisible()));
|
||||
collapseBtn.setHorizontalTextPosition(JButton.CENTER);
|
||||
collapseBtn.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
|
||||
collapseBtn.setFont(FontManager.getRunescapeSmallFont());
|
||||
collapseBtn.setBorder(new EmptyBorder(2, 0, 2, 0));
|
||||
collapseBtn.setFocusable(false);
|
||||
collapseBtn.setSelected(true);
|
||||
|
||||
return collapseBtn;
|
||||
}
|
||||
|
||||
protected void updateFilterText()
|
||||
{
|
||||
String filterText = buttons.entrySet().stream()
|
||||
.filter(e -> e.getValue().isSelected())
|
||||
.map(e -> "f-" + e.getKey() + "-f") // prefix included to cover cases where one key name is contained in another (e.g. "Master" -> "Grandmaster")
|
||||
.collect(Collectors.joining(","));
|
||||
|
||||
plugin.getConfigManager().setConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, configKey, filterText);
|
||||
}
|
||||
|
||||
protected boolean getConfigButtonState(String buttonKey)
|
||||
{
|
||||
String configValue = plugin.getConfigManager().getConfiguration(TasksTrackerPlugin.CONFIG_GROUP_NAME, configKey);
|
||||
boolean isEmptyFilterSelection = configValue == null || configValue.isEmpty() || configValue.equals("-1");
|
||||
if (isEmptyFilterSelection)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return configValue.contains("f-" + buttonKey + "-f");
|
||||
}
|
||||
|
||||
protected void setAllSelected(boolean state)
|
||||
{
|
||||
buttons.values().forEach(button -> button.setSelected(state));
|
||||
}
|
||||
|
||||
protected void updateCollapseButtonText()
|
||||
{
|
||||
collapseBtn.setText(label + " - " + buttons.values().stream().filter(JToggleButton::isSelected).count() + " / " + buttons.size());
|
||||
}
|
||||
|
||||
public void redraw()
|
||||
{
|
||||
if(SwingUtilities.isEventDispatchThread())
|
||||
{
|
||||
buttons.clear();
|
||||
removeAll();
|
||||
|
||||
collapseBtn = makeCollapseButton();
|
||||
buttonPanel = makeButtonPanel();
|
||||
|
||||
add(collapseBtn, BorderLayout.NORTH);
|
||||
add(buttonPanel, BorderLayout.CENTER);
|
||||
add(allOrNoneButtons(), BorderLayout.SOUTH);
|
||||
updateFilterText();
|
||||
updateCollapseButtonText();
|
||||
|
||||
collapseBtn.setVisible(plugin.getConfig().filterPanelCollapsible());
|
||||
|
||||
validate();
|
||||
repaint();
|
||||
}
|
||||
else
|
||||
{
|
||||
log.error("Filter button panel redraw failed - not event dispatch thread.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.reldo.taskstracker.panel.filters;
|
||||
|
||||
import net.reldo.taskstracker.panel.components.FixedWidthPanel;
|
||||
|
||||
public abstract class FilterPanel extends FixedWidthPanel
|
||||
{
|
||||
public abstract void redraw();
|
||||
}
|
||||
Reference in New Issue
Block a user