From 8eee6cf9158444c7bafeef6bd7fb47e8e141a531 Mon Sep 17 00:00:00 2001 From: "Walied K. Yassen" Date: Thu, 1 Aug 2024 22:34:42 +0300 Subject: [PATCH] Add filters panel and update --- .run/Proxy.run.xml | 15 -- .../src/main/kotlin/net/rsprox/gui/App.kt | 10 +- .../main/kotlin/net/rsprox/gui/AppIcons.kt | 9 + .../kotlin/net/rsprox/gui/FiltersSidePanel.kt | 247 ++++++++++++++++++ .../kotlin/net/rsprox/gui/dialogs/Dialogs.kt | 28 ++ .../src/main/kotlin/net/rsprox/gui/main.kt | 4 + .../net/rsprox/gui/sessions/SessionPanel.kt | 49 ++-- .../kotlin/net/rsprox/gui/sidebar/SideBar.kt | 6 +- .../src/main/resources/icons/collapse.svg | 4 + .../main/resources/icons/collapse_dark.svg | 4 + .../src/main/resources/icons/copy.svg | 8 + .../src/main/resources/icons/copy_dark.svg | 8 + .../src/main/resources/icons/delete.svg | 4 + .../src/main/resources/icons/delete_dark.svg | 4 + .../src/main/resources/icons/expand.svg | 4 + .../src/main/resources/icons/expand_dark.svg | 4 + .../kotlin/net/rsprox/proxy/ProxyService.kt | 3 +- .../filters/DefaultPropertyFilterSetStore.kt | 11 +- .../shared/filters/PropertyFilterSetStore.kt | 9 +- 19 files changed, 376 insertions(+), 55 deletions(-) delete mode 100644 .run/Proxy.run.xml create mode 100644 gui/proxy-tool/src/main/kotlin/net/rsprox/gui/FiltersSidePanel.kt create mode 100644 gui/proxy-tool/src/main/kotlin/net/rsprox/gui/dialogs/Dialogs.kt create mode 100644 gui/proxy-tool/src/main/resources/icons/collapse.svg create mode 100644 gui/proxy-tool/src/main/resources/icons/collapse_dark.svg create mode 100644 gui/proxy-tool/src/main/resources/icons/copy.svg create mode 100644 gui/proxy-tool/src/main/resources/icons/copy_dark.svg create mode 100644 gui/proxy-tool/src/main/resources/icons/delete.svg create mode 100644 gui/proxy-tool/src/main/resources/icons/delete_dark.svg create mode 100644 gui/proxy-tool/src/main/resources/icons/expand.svg create mode 100644 gui/proxy-tool/src/main/resources/icons/expand_dark.svg diff --git a/.run/Proxy.run.xml b/.run/Proxy.run.xml deleted file mode 100644 index 864f6954..00000000 --- a/.run/Proxy.run.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - \ No newline at end of file diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/App.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/App.kt index 4c444d4f..7874ac84 100644 --- a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/App.kt +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/App.kt @@ -17,9 +17,14 @@ public class App { private val frame = JFrame() private val sessionsPanel = SessionsPanel(this) public val statusBar: StatusBar = StatusBar() - public val service: ProxyService = ProxyService(UnpooledByteBufAllocator.DEFAULT) + public lateinit var service: ProxyService public fun init() { + // We have to start before populating right now. + service = ProxyService(UnpooledByteBufAllocator.DEFAULT) + service.start() + + val defaultSize = UIScale.scale(Dimension(800, 600)) // Configure the app frame. @@ -45,7 +50,6 @@ public class App { public fun start() { frame.isVisible = true frame.setLocationRelativeTo(null) - service.start() } private fun setupMenuBar() { @@ -66,7 +70,7 @@ public class App { private fun createSideBar() = SideBar().apply { addButton(AppIcons.Settings, "Sessions", JPanel()) - addButton(AppIcons.Filter, "Filters", JPanel()) + addButton(AppIcons.Filter, "Filters", FiltersSidePanel(service)) selectedIndex = -1 } diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/AppIcons.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/AppIcons.kt index b7ad4b63..898dcd6e 100644 --- a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/AppIcons.kt +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/AppIcons.kt @@ -1,12 +1,17 @@ package net.rsprox.gui import com.formdev.flatlaf.extras.FlatSVGIcon +import com.formdev.flatlaf.extras.FlatSVGUtils import javax.imageio.ImageIO import javax.swing.ImageIcon public object AppIcons { public val Add: FlatSVGIcon = loadSvgIcon("add") + public val Collapse: FlatSVGIcon = loadSvgIcon("collapse") + public val Copy: FlatSVGIcon = loadSvgIcon("copy") + public val Delete: FlatSVGIcon = loadSvgIcon("delete") + public val Expand: FlatSVGIcon = loadSvgIcon("expand") public val Filter: FlatSVGIcon = loadSvgIcon("filter") public val Java: ImageIcon = loadIcon("java") public val Native: ImageIcon = loadIcon("native") @@ -17,6 +22,10 @@ public object AppIcons { public val User: FlatSVGIcon = loadSvgIcon("user") public val Web: FlatSVGIcon = loadSvgIcon("web") + // favicons + public val Favicon16: ImageIcon = ImageIcon(FlatSVGUtils.svg2image("/favicon.svg", 16, 16)) + + private fun loadIcon(name: String): ImageIcon { val image = ImageIO.read(javaClass.getResource("/icons/$name.png")) return ImageIcon(image) diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/FiltersSidePanel.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/FiltersSidePanel.kt new file mode 100644 index 00000000..c0960143 --- /dev/null +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/FiltersSidePanel.kt @@ -0,0 +1,247 @@ +package net.rsprox.gui + +import com.formdev.flatlaf.extras.components.FlatButton +import com.formdev.flatlaf.extras.components.FlatButton.ButtonType +import com.formdev.flatlaf.extras.components.FlatLabel +import com.formdev.flatlaf.extras.components.FlatSeparator +import com.formdev.flatlaf.extras.components.FlatTabbedPane +import com.formdev.flatlaf.icons.FlatCheckBoxIcon +import net.miginfocom.swing.MigLayout +import net.rsprox.gui.dialogs.Dialogs +import net.rsprox.proxy.ProxyService +import net.rsprox.shared.StreamDirection +import net.rsprox.shared.filters.PropertyFilter +import net.rsprox.shared.filters.ProtCategory +import java.awt.BorderLayout +import java.awt.Dimension +import java.awt.event.ActionListener +import java.awt.event.ItemEvent +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent +import javax.swing.* + +public class FiltersSidePanel( + private val proxyService: ProxyService +) : JPanel() { + + private val presetsBoxModel = DefaultComboBoxModel() + private val presetsBox = JComboBox(presetsBoxModel) + private val copyButton = createControlButton(AppIcons.Copy, "Copy selected preset into new preset") + private val createButton = createControlButton(AppIcons.Add, "Create new preset from default filters") + private val deleteButton = createControlButton(AppIcons.Delete, "Delete selected preset") + private val checkboxes = hashMapOf() + + init { + layout = MigLayout("fill, ins panel, wrap 1, hidemode 3", "[grow]", "[][][][grow, fill]") + minimumSize = Dimension(210, 0) + + presetsBox.addItemListener { e -> + if (e.stateChange != ItemEvent.SELECTED) return@addItemListener + proxyService.filterSetStore.setActive(presetsBox.selectedIndex) + updateButtonState() + updateFilterState() + } + + createButton.addActionListener { + val name = Dialogs.showInputString(parent = this, "Create new preset", "Enter preset name") + ?: return@addActionListener + if (presetsBoxModel.getIndexOf(name) != -1) { + Dialogs.showError(parent = this, message = "Preset with name '$name' already exists.") + return@addActionListener + } + proxyService.filterSetStore.create(name) + populatePresets() + presetsBoxModel.selectedItem = name + } + + deleteButton.addActionListener { + val selectedIndex = presetsBox.selectedIndex + if (selectedIndex == -1) return@addActionListener + val presetName = presetsBox.selectedItem as String + val result = JOptionPane.showConfirmDialog( + this, + "Are you sure you want to delete the selected preset?", + "Delete '${presetName}' preset", + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE + ) + if (result != JOptionPane.YES_OPTION) return@addActionListener + proxyService.filterSetStore.delete(selectedIndex) + populatePresets() + } + + copyButton.addActionListener { + val selectedIndex = presetsBox.selectedIndex + if (selectedIndex == -1) return@addActionListener + val name = Dialogs.showInputString(parent = this, "Copy preset", "Enter new preset name") + ?: return@addActionListener + if (presetsBoxModel.getIndexOf(name) != -1) { + Dialogs.showError(parent = this, message = "Preset with name '$name' already exists.") + return@addActionListener + } + val filterSet = proxyService.filterSetStore.get(selectedIndex) ?: return@addActionListener + val newFilterSet = proxyService.filterSetStore.create(name) + for (property in PropertyFilter.entries) { + newFilterSet[property] = filterSet[property] + } + populatePresets() + presetsBoxModel.selectedItem = name + } + + add(FlatLabel().apply { text = "Presets:" }) + + add(presetsBox, "growx") + + val controlPanel = JPanel().apply { + layout = MigLayout("insets 0", "[grow][grow][grow]", "[32px]") + add(copyButton, "grow, hmin 32px") + add(createButton, "grow, hmin 32px") + add(deleteButton, "grow, hmin 32px") + } + + add(controlPanel, "growx") + + val tabbedGroup = FlatTabbedPane() + tabbedGroup.addTab("Server to Client", createFilterPanel(StreamDirection.SERVER_TO_CLIENT)) + tabbedGroup.addTab("Client to Server", createFilterPanel(StreamDirection.CLIENT_TO_SERVER)) + + add(tabbedGroup, "grow, pushy") + + populatePresets() + updateButtonState() + updateFilterState() + } + + private fun updateFilterState() { + val active = proxyService.filterSetStore.getActive() + for ((property, checkbox) in checkboxes) { + checkbox.isSelected = active[property] + } + } + + private fun updateButtonState() { + val selectedIndex = presetsBox.selectedIndex + if (selectedIndex == -1) return + deleteButton.isEnabled = selectedIndex != 0 + checkboxes.values.forEach { it.isEnabled = selectedIndex != 0 } + } + + private fun createFilterPanel(serverToClient: StreamDirection): JScrollPane { + val scrollPane = JScrollPane(FiltersPanel(serverToClient)).apply { + horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER + verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED + border = null + } + return scrollPane + } + + private fun populatePresets() { + val oldSelectedItem = presetsBox.selectedItem + presetsBoxModel.removeAllElements() + for (i in 0 until proxyService.filterSetStore.size) { + val filterSet = proxyService.filterSetStore.get(i) ?: continue + presetsBoxModel.addElement(filterSet.getName()) + } + if (oldSelectedItem != null) { + val selectedIndex = presetsBoxModel.getIndexOf(oldSelectedItem) + if (selectedIndex == -1) { + presetsBox.selectedIndex = presetsBoxModel.size - 1 + } else { + presetsBox.selectedIndex = selectedIndex + } + } else { + presetsBox.selectedIndex = presetsBoxModel.size - 1 + } + } + + private fun createControlButton(icon: Icon, tooltip: String) = FlatButton().apply { + this.buttonType = ButtonType.square + this.icon = icon + this.toolTipText = tooltip + isFocusPainted = false + } + + private inner class FiltersPanel(private val direction: StreamDirection) : JPanel() { + init { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + + val filteredProperties = PropertyFilter.entries + .filter { it.direction == direction } + .groupBy { it.category } + + for ((category, properties) in filteredProperties) { + add(createCategoryPanel(category, properties)) + } + } + } + + private fun createCategoryPanel(category: ProtCategory, properties: List) = JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + + val content = JPanel() + content.border = null + content.layout = BoxLayout(content, BoxLayout.Y_AXIS) + for (property in properties) { + content.add(createPropertyFilterPanel(property)) + } + + add(createCategoryHeaderPanel(content, category)) + add(FlatSeparator()) + + add(content) + + } + + private fun createCategoryHeaderPanel(content: JPanel, category: ProtCategory) = JPanel(BorderLayout()).apply { + val toggle = FlatButton() + toggle.toolTipText = "Collapse" + toggle.icon = AppIcons.Collapse + toggle.buttonType = ButtonType.toolBarButton + + val collapseAction = ActionListener { + content.isVisible = !content.isVisible + toggle.icon = if (content.isVisible) AppIcons.Collapse else AppIcons.Expand + toggle.toolTipText = if (content.isVisible) "Collapse" else "Expand" + } + + toggle.addActionListener(collapseAction) + add(toggle, BorderLayout.WEST) + + val label = FlatLabel() + label.text = category.label + label.labelType = FlatLabel.LabelType.large + label.toolTipText = category.label + add(label, BorderLayout.CENTER) + + label.addMouseListener(object : MouseAdapter() { + override fun mouseReleased(e: MouseEvent) { + if (SwingUtilities.isLeftMouseButton(e) + && e.x >= 0 && e.x <= label.width && e.y >= 0 && e.y <= label.height + ) { + collapseAction.actionPerformed(null) + } + } + }) + } + + private fun createPropertyFilterPanel(property: PropertyFilter) = JPanel().apply { + layout = BorderLayout() + border = BorderFactory.createEmptyBorder(5, 5, 5, 5) + + val checkbox = JCheckBox() + checkbox.addActionListener { + val active = proxyService.filterSetStore.getActive() + active[property] = checkbox.isSelected + } + add(checkbox, BorderLayout.EAST) + + val label = FlatLabel() + label.labelType = FlatLabel.LabelType.large + label.text = property.label + label.toolTipText = property.tooltip + add(label, BorderLayout.CENTER) + + checkboxes[property] = checkbox + } +} + diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/dialogs/Dialogs.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/dialogs/Dialogs.kt new file mode 100644 index 00000000..b567b3e3 --- /dev/null +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/dialogs/Dialogs.kt @@ -0,0 +1,28 @@ +package net.rsprox.gui.dialogs + +import java.awt.Component +import javax.swing.JOptionPane + +public object Dialogs { + + public fun showInputString( + parent: Component? = null, + title: String, + message: String, + initialValue: String = "" + ): String? { + return JOptionPane.showInputDialog( + parent, + message, + title, + JOptionPane.QUESTION_MESSAGE, + null, + null, + initialValue + ) as String? + } + + public fun showError(parent: Component? = null, title: String = "Error", message: String) { + JOptionPane.showMessageDialog(parent, message, title, JOptionPane.ERROR_MESSAGE) + } +} diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/main.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/main.kt index 9b7e98c9..5f4d1b12 100644 --- a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/main.kt +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/main.kt @@ -2,11 +2,15 @@ import com.formdev.flatlaf.extras.FlatInspector import com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMaterialDeepOceanIJTheme import net.rsprox.gui.App import javax.swing.SwingUtilities +import javax.swing.UIManager public fun main() { FlatInspector.install("ctrl shift alt X") SwingUtilities.invokeLater { + UIManager.put("Component.focusWidth", 0) + FlatMaterialDeepOceanIJTheme.setup() + val app = App() app.init() app.start() diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionPanel.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionPanel.kt index 1a755696..84c0baa5 100644 --- a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionPanel.kt +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sessions/SessionPanel.kt @@ -8,6 +8,7 @@ import net.rsprox.gui.App import net.rsprox.proxy.binary.BinaryHeader import net.rsprox.proxy.progressbar.ProgressBarNotifier import net.rsprox.shared.SessionMonitor +import net.rsprox.shared.property.RootProperty import org.jdesktop.swingx.JXTreeTable import org.jdesktop.swingx.decorator.ColorHighlighter import org.jdesktop.swingx.decorator.HighlightPredicate @@ -160,33 +161,39 @@ public class SessionPanel( streamNode = null } + override fun onIncomingBytesPerSecondUpdate(bytesPerLastSecond: Long) { + } + + override fun onOutgoingBytesPerSecondUpdate(bytesPerLastSecond: Long) { + } + override fun onNameUpdate(name: String) { metrics.username = name sessionsPanel.updateTabTitle(this@SessionPanel,name) notifyMetricsChanged() } - override fun onTranscribe(cycle: Int, message: String) { - val streamNode = streamNode - ?: error("Stream node is null") - SwingUtilities.invokeLater { - val tickNode: DefaultMutableTreeTableNode - if (cycle != lastCycle) { - tickNode = createTickNode(cycle) - tableModel.insertNodeInto(tickNode, streamNode, streamNode.childCount) - this.tickNode = tickNode - lastCycle = cycle - } else { - tickNode = this.tickNode - ?: error("Tick node is null") - } - tableModel.insertNodeInto(createNode(id++, cycle, message), tickNode, tickNode.childCount) - val row = treeTable.rowCount - 1 - treeTable.expandRow(row) - if (scrolledToLatest) { - scrollPane.verticalScrollBar.value = scrollPane.verticalScrollBar.maximum - } - } + override fun onTranscribe(cycle: Int, property: RootProperty<*>) { +// val streamNode = streamNode +// ?: error("Stream node is null") +// SwingUtilities.invokeLater { +// val tickNode: DefaultMutableTreeTableNode +// if (cycle != lastCycle) { +// tickNode = createTickNode(cycle) +// tableModel.insertNodeInto(tickNode, streamNode, streamNode.childCount) +// this.tickNode = tickNode +// lastCycle = cycle +// } else { +// tickNode = this.tickNode +// ?: error("Tick node is null") +// } +// tableModel.insertNodeInto(createNode(id++, cycle, message), tickNode, tickNode.childCount) +// val row = treeTable.rowCount - 1 +// treeTable.expandRow(row) +// if (scrolledToLatest) { +// scrollPane.verticalScrollBar.value = scrollPane.verticalScrollBar.maximum +// } +// } } } diff --git a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sidebar/SideBar.kt b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sidebar/SideBar.kt index 9226be03..d70dd83b 100644 --- a/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sidebar/SideBar.kt +++ b/gui/proxy-tool/src/main/kotlin/net/rsprox/gui/sidebar/SideBar.kt @@ -13,11 +13,7 @@ public class SideBar : FlatTabbedPane() { } public fun addButton(icon: Icon, tooltip: String, content: JPanel) { - addTab("", icon, JPanel().apply { - val label = FlatLabel() - label.text = tooltip - add(label) - }, tooltip) + addTab("", icon, content, tooltip) } override fun updateUI() { diff --git a/gui/proxy-tool/src/main/resources/icons/collapse.svg b/gui/proxy-tool/src/main/resources/icons/collapse.svg new file mode 100644 index 00000000..d47d0121 --- /dev/null +++ b/gui/proxy-tool/src/main/resources/icons/collapse.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/proxy-tool/src/main/resources/icons/collapse_dark.svg b/gui/proxy-tool/src/main/resources/icons/collapse_dark.svg new file mode 100644 index 00000000..28c680a2 --- /dev/null +++ b/gui/proxy-tool/src/main/resources/icons/collapse_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/proxy-tool/src/main/resources/icons/copy.svg b/gui/proxy-tool/src/main/resources/icons/copy.svg new file mode 100644 index 00000000..df3e7429 --- /dev/null +++ b/gui/proxy-tool/src/main/resources/icons/copy.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/gui/proxy-tool/src/main/resources/icons/copy_dark.svg b/gui/proxy-tool/src/main/resources/icons/copy_dark.svg new file mode 100644 index 00000000..a7072426 --- /dev/null +++ b/gui/proxy-tool/src/main/resources/icons/copy_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/gui/proxy-tool/src/main/resources/icons/delete.svg b/gui/proxy-tool/src/main/resources/icons/delete.svg new file mode 100644 index 00000000..a858096a --- /dev/null +++ b/gui/proxy-tool/src/main/resources/icons/delete.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/proxy-tool/src/main/resources/icons/delete_dark.svg b/gui/proxy-tool/src/main/resources/icons/delete_dark.svg new file mode 100644 index 00000000..03ff9f24 --- /dev/null +++ b/gui/proxy-tool/src/main/resources/icons/delete_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/proxy-tool/src/main/resources/icons/expand.svg b/gui/proxy-tool/src/main/resources/icons/expand.svg new file mode 100644 index 00000000..5b5e3f3d --- /dev/null +++ b/gui/proxy-tool/src/main/resources/icons/expand.svg @@ -0,0 +1,4 @@ + + + + diff --git a/gui/proxy-tool/src/main/resources/icons/expand_dark.svg b/gui/proxy-tool/src/main/resources/icons/expand_dark.svg new file mode 100644 index 00000000..3302422d --- /dev/null +++ b/gui/proxy-tool/src/main/resources/icons/expand_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/ProxyService.kt b/proxy/src/main/kotlin/net/rsprox/proxy/ProxyService.kt index 912346e0..a3fb720d 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/ProxyService.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/ProxyService.kt @@ -68,7 +68,8 @@ public class ProxyService( private lateinit var worldListProvider: WorldListProvider private lateinit var operatingSystem: OperatingSystem private lateinit var rsa: RSAPrivateCrtKeyParameters - private lateinit var filterSetStore: PropertyFilterSetStore + public lateinit var filterSetStore: PropertyFilterSetStore + private set private var properties: ProxyProperties by Delegates.notNull() private var availablePort: Int = -1 private val processes: MutableMap = mutableMapOf() diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/filters/DefaultPropertyFilterSetStore.kt b/proxy/src/main/kotlin/net/rsprox/proxy/filters/DefaultPropertyFilterSetStore.kt index bf2c6d33..29934d2b 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/filters/DefaultPropertyFilterSetStore.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/filters/DefaultPropertyFilterSetStore.kt @@ -8,16 +8,17 @@ public class DefaultPropertyFilterSetStore( private val rootPath: Path, private val filterSets: MutableList = mutableListOf(), ) : PropertyFilterSetStore { - override fun create(index: Int): PropertyFilterSet { - if (index == 0) { - throw IllegalArgumentException("Element cannot be created at index 0.") - } + + override val size: Int + get() = filterSets.size + + override fun create(name: String): PropertyFilterSet { for (filter in filterSets) { if (filter is DefaultPropertyFilterSet) { filter.setActive(false) } } - val filter = DefaultPropertyFilterSet.create(rootPath, "Unnamed") + val filter = DefaultPropertyFilterSet.create(rootPath, name) filterSets += filter return filter } diff --git a/shared/src/main/kotlin/net/rsprox/shared/filters/PropertyFilterSetStore.kt b/shared/src/main/kotlin/net/rsprox/shared/filters/PropertyFilterSetStore.kt index d07c073d..07f5a491 100644 --- a/shared/src/main/kotlin/net/rsprox/shared/filters/PropertyFilterSetStore.kt +++ b/shared/src/main/kotlin/net/rsprox/shared/filters/PropertyFilterSetStore.kt @@ -1,16 +1,15 @@ package net.rsprox.shared.filters public interface PropertyFilterSetStore { - public fun create(index: Int): PropertyFilterSet + + public val size: Int + + public fun create(name: String): PropertyFilterSet public fun delete(index: Int): PropertyFilterSet? public fun get(index: Int): PropertyFilterSet? - public fun getOrCreate(index: Int): PropertyFilterSet { - return get(index) ?: create(index) - } - public fun getActive(): PropertyFilterSet public fun setActive(index: Int)