Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a filter panel #196

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0b76808
Fix an incorrect initializaion of dividers positions
mi-sts May 4, 2023
92daab0
Add a filters panel view
mi-sts May 5, 2023
14b4e6a
Styling a controlsfx rangeslider for mfx design
mi-sts May 8, 2023
e657351
Create and customize validated integer text field
mi-sts May 9, 2023
99bc3b9
Codestyle
mi-sts May 9, 2023
9318fe2
Update filter settings dialog design and add a logic
mi-sts May 10, 2023
5613fb4
Codestyle
mi-sts May 10, 2023
d40b97b
Codestyle
mi-sts May 10, 2023
5b78f44
Fix validation bugs
mi-sts May 11, 2023
7a5d9fe
Add a filter applying logic
mi-sts May 11, 2023
6ea64ee
Fix a filter selection breaking bug
mi-sts May 11, 2023
fb590f6
Make filtered frames sorted in intial way
mi-sts May 11, 2023
5e0c745
Fix bugs with checboxes selections and some design
mi-sts May 12, 2023
126459d
Add a range slider uids visualization
mi-sts May 12, 2023
8ae7c50
Codestyle
mi-sts May 12, 2023
7bcda61
Trying to fix MFXListView bugs
mi-sts May 12, 2023
1a306fb
Small fix
mi-sts May 12, 2023
de30c33
Fix validation bugs
mi-sts May 12, 2023
d7f80bf
Remove redundant code
mi-sts May 12, 2023
f48d099
Codestyle
mi-sts May 12, 2023
c412bb0
Small fix
mi-sts May 12, 2023
9da6563
Naming
mi-sts May 14, 2023
52f5b6a
Refactor the filter setting class
mi-sts May 14, 2023
d0fe77c
Codestyle
mi-sts May 14, 2023
bdaf679
Codestyle
mi-sts May 14, 2023
9651b95
Codestyle
mi-sts May 16, 2023
28e909a
Fix bug with empty catalogue after a removing all filters
mi-sts May 16, 2023
5d5dffa
Keep text if textfield is empty
mi-sts May 16, 2023
e18552b
Apply filters when reimport a project
mi-sts May 16, 2023
7b08235
Fix bug with not working uids filter setting
mi-sts May 16, 2023
0cff312
Codestyle
mi-sts May 16, 2023
953a44f
Fix bug with two layer visibility buttons
mi-sts May 16, 2023
cd0342a
Small fix
mi-sts May 16, 2023
802c07f
Fix bug with not working dragged catalogue files image
mi-sts May 17, 2023
5ca3090
Fix an all filters are disabled bug
mi-sts Jun 18, 2023
0a0bf4d
Add logic for a saving unchecked settings
mi-sts Jun 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ dependencies {
implementation("junit:junit:$junitVersion")
implementation("org.junit.jupiter:junit-jupiter:$junitJupiterVersion")
implementation("org.controlsfx:controlsfx:$controlsfxVersion")
implementation("de.codecentric.centerdevice:javafxsvg:1.3.0")

testImplementation("org.junit.jupiter:junit-jupiter:$junitJupiterVersion")
testImplementation("org.junit.jupiter:junit-jupiter-params:$junitJupiterParamsVersion")
Expand Down
22 changes: 20 additions & 2 deletions src/main/kotlin/solve/SolveApp.kt
Original file line number Diff line number Diff line change
@@ -1,27 +1,45 @@
package solve

import de.codecentric.centerdevice.javafxsvg.SvgImageLoaderFactory
import javafx.stage.Stage
import solve.main.MainView
import solve.scene.view.landmarks.AnimationProvider
import solve.scene.view.landmarks.JavaFXAnimationProvider
import solve.styles.ApplicationStylesheet
import solve.utils.SVGImageLoaderDimensionProvider
import solve.utils.ServiceLocator
import tornadofx.App
import tornadofx.FX.Companion.stylesheets
import tornadofx.launch

class SolveApp : App(MainView::class) {
class SolveApp : App(MainView::class, ApplicationStylesheet::class) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have global application style class Style.kt, can we merge them?

override fun start(stage: Stage) {
initializeDependencies()
registerServices()

with(stage) {
width = 1000.0
height = 600.0
isMaximized = true
}
registerServices()
super.start(stage)
}

private fun registerServices() {
ServiceLocator.registerService<AnimationProvider>(JavaFXAnimationProvider())
}

private fun initializeDependencies() {
SvgImageLoaderFactory.install(SVGImageLoaderDimensionProvider())

initializeStyle()
}

private fun initializeStyle() {
stylesheets.add("https://fonts.googleapis.com/css2?family=Roboto+Condensed")
stylesheets.add("https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@700")
stylesheets.add("https://fonts.googleapis.com/css2?family=Roboto")
}
}

fun main(args: Array<String>) = launch<SolveApp>(args)
2 changes: 0 additions & 2 deletions src/main/kotlin/solve/catalogue/CatalogueUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import tornadofx.tooltip
val ProjectFrame.layers: List<ProjectLayer>
get() = landmarkFiles.map { it.projectLayer }.distinct()

fun Double.floor(): Int = kotlin.math.floor(this).toInt()

fun <T> synchronizeListViewsSelections(firstListView: ListView<T>, secondListView: ListView<T>) {
secondListView.selectionModel = firstListView.selectionModel
}
Expand Down
10 changes: 9 additions & 1 deletion src/main/kotlin/solve/catalogue/view/CatalogueView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import solve.catalogue.view.fields.CatalogueFieldsView
import solve.catalogue.view.fields.CatalogueFileNamesFieldsView
import solve.catalogue.view.fields.CataloguePreviewImagesFieldsView
import solve.constants.IconsCatalogueApplyPath
import solve.filters.view.FilterPanelView
import solve.project.model.ProjectFrame
import solve.utils.addSafely
import solve.utils.createInsetsWithValue
Expand All @@ -42,6 +43,7 @@ class CatalogueView : View() {
}

private val settingsView: CatalogueSettingsView by inject()
private val filterPanelView: FilterPanelView by inject()
private val controller: CatalogueController by inject()

private val fields = FXCollections.observableArrayList<CatalogueField>()
Expand Down Expand Up @@ -91,7 +93,13 @@ class CatalogueView : View() {
vgrow = Priority.ALWAYS
}

override val root = catalogueNode.also { initializeNodes() }
override val root = vbox {
add(catalogueNode)
initializeNodes()
add(filterPanelView)

vgrow = Priority.ALWAYS
}

init {
accelerators[KeyCodeCombination(KeyCode.ENTER)] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import javafx.scene.input.TransferMode
import javafx.scene.layout.Priority
import javafx.scene.paint.Color
import solve.catalogue.controller.CatalogueController
import solve.catalogue.floor
import solve.catalogue.model.CatalogueField
import solve.project.model.ProjectFrame
import solve.scene.view.SceneView
import solve.utils.deselectAllItems
import solve.utils.floorToInt
import solve.utils.onSelectionChanged
import solve.utils.selectAllItems
import solve.utils.selectedItems
Expand Down Expand Up @@ -115,16 +115,16 @@ abstract class CatalogueFieldsView : View() {

private fun createFileNameFieldsSnapshot(fields: List<CatalogueField>): Image {
val snapshotFields = fields.take(dragViewMaxFieldsNumber)
val prefSnapshotHeight = (snapshotFields.count() * listViewCellHeight).floor()
val prefSnapshotHeight = (snapshotFields.count() * listViewCellHeight).floorToInt()

val fieldsSnapshotNode = createFieldsSnapshotNode(snapshotFields)
fieldsListView.getChildList()?.remove(fieldsSnapshotNode)

val nodeSnapshot = fieldsSnapshotNode.snapshot(null, null)
return WritableImage(
nodeSnapshot.pixelReader,
nodeSnapshot.width.floor(),
min(nodeSnapshot.height.floor(), prefSnapshotHeight)
nodeSnapshot.width.floorToInt(),
min(nodeSnapshot.height.floorToInt(), prefSnapshotHeight)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package solve.catalogue.view.fields

import javafx.scene.control.Labeled
import javafx.scene.image.ImageView
import javafx.scene.text.Font
import solve.catalogue.model.CatalogueField
import solve.constants.IconsCatalogueImagePath
import solve.styles.Style
import solve.utils.loadResourcesImage
import tornadofx.*

Expand Down Expand Up @@ -44,7 +46,9 @@ class CatalogueFileNamesFieldsView : CatalogueFieldsView() {
if (iconImageView != null) {
add(iconImageView)
}
label(it.fileName)
text(it.fileName) {
font = Font.font(Style.Font, 14.0)
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/kotlin/solve/constants/ResourcesPaths.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@ const val IconsLayers = "/icons/sidepanel/Layers.png"
const val IconsLayersFilled = "/icons/sidepanel/LayersFilled.png"
const val IconsGrid = "/icons/sidepanel/Grid.png"
const val IconsGridSelected = "/icons/sidepanel/GridSelected.png"
Comment on lines 27 to 29
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create an issue to convert all icons to svg

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

const val IconsFiltersAddPath = "icons/filters/add.svg"
const val IconsFiltersOrCheckBoxPath = "icons/filters/or_checkbox.svg"

// Common icons.
const val IconsEditPath = "icons/common/edit.svg"
const val IconsDeletePath = "icons/common/delete.svg"
59 changes: 59 additions & 0 deletions src/main/kotlin/solve/filters/controller/FilterPanelController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package solve.filters.controller

import solve.catalogue.controller.CatalogueController
import solve.filters.model.Filter
import solve.filters.model.FilterPanelModel
import solve.project.controller.ProjectController
import solve.project.model.ProjectFrame
import tornadofx.*

class FilterPanelController : Controller() {
val model = FilterPanelModel()

private val projectController: ProjectController by inject()
private val catalogueController: CatalogueController by inject()

init {
addBindings()
}

fun addFilter(filter: Filter) {
model.addFilter(filter)
}

fun removeFilter(filter: Filter) {
model.removeFilter(filter)
}

fun editFilter(editingFilter: Filter, editedFilter: Filter) {
model.replaceFilter(editingFilter, editedFilter)
}

fun applyFilters() {
val filteredFrames = getFilteredProjectFrames()
catalogueController.setCatalogueFrames(filteredFrames)
}

private fun addBindings() {
projectController.model.projectProperty.onChange {
applyFilters()
Comment on lines +38 to +39
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any case when a lot of updates happen at once?

}
model.filters.onChange {
applyFilters()
}
}

private fun getFilteredProjectFrames(): List<ProjectFrame> {
val projectFrames = projectController.model.project.frames

if (model.filters.isEmpty() || model.filters.all { !it.enabled }) {
return projectFrames
}

val enabledFilters = model.filters.filter { it.enabled }
val notOrderedFilteredFrames = enabledFilters.map { it.apply(projectFrames) }.flatten().distinct()
val projectFrameToIndexMap = projectFrames.indices.associateBy { index -> projectFrames[index] }

return notOrderedFilteredFrames.sortedBy { frame -> projectFrameToIndexMap[frame] }
}
}
48 changes: 48 additions & 0 deletions src/main/kotlin/solve/filters/model/Filter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package solve.filters.model

import solve.filters.settings.model.FilterSetting
import solve.filters.settings.model.IndicesStepFilterSetting
import solve.filters.settings.model.TimePeriodFilterSetting
import solve.filters.settings.model.UIDFilterSetting
import solve.project.model.ProjectFrame

class Filter(val settings: List<FilterSetting<out Any>>) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be make it mutable to avoid problems with list view?

var enabled: Boolean = true
val preview: String by lazy { createPreviewText() }

fun apply(frames: List<ProjectFrame>): List<ProjectFrame> {
if (!enabled) {
return frames
}

var suitableFrames = frames
settings.forEach { suitableFrames = it.apply(suitableFrames) }

return suitableFrames
}

private fun createPreviewText(): String {
val indicesStepSetting = settings.firstOrNull { it is IndicesStepFilterSetting } as? IndicesStepFilterSetting
val timePeriodSetting = settings.firstOrNull { it is TimePeriodFilterSetting } as? TimePeriodFilterSetting
val uidSetting = settings.firstOrNull { it is UIDFilterSetting } as? UIDFilterSetting

val prefix = "Show "
val indicesStepPart = if (indicesStepSetting != null) {
"every ${indicesStepSetting.settingValue} image "
} else {
"images "
}
val timePeriodPart = if (timePeriodSetting != null) {
"from ${timePeriodSetting.settingValue.x} to ${timePeriodSetting.settingValue.y} "
} else {
""
}
val uidPart = if (uidSetting != null) {
"with landmark ${uidSetting.settingValue}"
} else {
""
}

return "$prefix$indicesStepPart$timePeriodPart$uidPart"
}
}
27 changes: 27 additions & 0 deletions src/main/kotlin/solve/filters/model/FilterPanelModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package solve.filters.model

import javafx.collections.FXCollections
import javafx.collections.ObservableList

class FilterPanelModel {
private val _filters = FXCollections.observableArrayList<Filter>()
val filters: ObservableList<Filter> = FXCollections.synchronizedObservableList(_filters)

fun addFilter(filter: Filter) {
_filters.add(filter)
}

fun removeFilter(filter: Filter) {
_filters.remove(filter)
}

fun replaceFilter(oldFilter: Filter, newFilter: Filter) {
if (!_filters.contains(oldFilter)) {
return
}

val oldFilterIndex = _filters.indexOf(oldFilter)
_filters.remove(oldFilter)
_filters.add(oldFilterIndex, newFilter)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package solve.filters.settings.controller

import solve.filters.controller.FilterPanelController
import solve.filters.model.Filter
import solve.filters.settings.model.FilterSetting
import tornadofx.*

class FilterSettingsController : Controller() {
private val panelController: FilterPanelController by inject()

fun createFilter(filterSettings: List<FilterSetting<out Any>>) {
val filter = Filter(filterSettings)
panelController.addFilter(filter)
}

fun editFilter(editingFilter: Filter, editedFilterSettings: List<FilterSetting<out Any>>) {
val newFilter = Filter(editedFilterSettings)
newFilter.enabled = editingFilter.enabled

panelController.editFilter(editingFilter, newFilter)
}
}
20 changes: 20 additions & 0 deletions src/main/kotlin/solve/filters/settings/model/FilterSetting.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package solve.filters.settings.model

import solve.project.model.ProjectFrame

abstract class FilterSetting<T>(settingValue: T) {
var enabled: Boolean = true

var settingValue: T = settingValue
protected set

fun apply(fields: List<ProjectFrame>) : List<ProjectFrame> {
if (!enabled)
return fields;

return applySetting(fields)
}
protected abstract fun applySetting(fields: List<ProjectFrame>): List<ProjectFrame>

abstract fun edit(newValue: T)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package solve.filters.settings.model

import solve.project.model.ProjectFrame

class IndicesStepFilterSetting(step: Int) : FilterSetting<Int>(step) {
override fun applySetting(fields: List<ProjectFrame>) = fields.slice(
(settingValue - 1)..fields.lastIndex step this.settingValue
)

override fun edit(newValue: Int) {
settingValue = newValue
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package solve.filters.settings.model

import solve.project.model.ProjectFrame
import solve.utils.structures.IntPoint

class TimePeriodFilterSetting(timePeriod: IntPoint) : FilterSetting<IntPoint>(timePeriod) {
override fun applySetting(fields: List<ProjectFrame>): List<ProjectFrame> =
fields.filter { it.timestamp in settingValue.x..settingValue.y }

override fun edit(newValue: IntPoint) {
settingValue = newValue
}
}
11 changes: 11 additions & 0 deletions src/main/kotlin/solve/filters/settings/model/UIDFilterSetting.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package solve.filters.settings.model

import solve.project.model.ProjectFrame

class UIDFilterSetting(uid: Long) : FilterSetting<Long>(uid) {
override fun applySetting(fields: List<ProjectFrame>) = fields.filter { it.uids.contains(settingValue) }

override fun edit(newValue: Long) {
settingValue = newValue
}
}
Loading