Skip to content

Commit

Permalink
#150: adds an experimental implementation to replace BlockViewPane
Browse files Browse the repository at this point in the history
ChunkListView exploits ListView features and enables LogoRRR to handle bigger log files as well
  • Loading branch information
rladstaetter committed Oct 27, 2023
1 parent 8a3dc79 commit 1911310
Show file tree
Hide file tree
Showing 11 changed files with 430 additions and 167 deletions.
98 changes: 20 additions & 78 deletions app/src/main/scala/app/logorrr/views/block/BlockImage.scala
Original file line number Diff line number Diff line change
@@ -1,102 +1,44 @@
package app.logorrr.views.block

import app.logorrr.model.LogEntry
import app.logorrr.util.{CanLog, ColorUtil, JfxUtils}
import app.logorrr.util.{CanLog, ColorUtil}
import app.logorrr.views.search.Filter
import javafx.beans.property.{SimpleIntegerProperty, SimpleListProperty, SimpleObjectProperty}
import javafx.beans.value.ChangeListener
import javafx.beans.{InvalidationListener, Observable}
import javafx.beans.property.{ReadOnlyDoubleProperty, SimpleIntegerProperty, SimpleListProperty, SimpleObjectProperty}
import javafx.scene.image.WritableImage
import javafx.scene.paint.Color

import scala.jdk.CollectionConverters.CollectionHasAsScala

object BlockImage {

/** width is constrained by the maximum texture width which is set to 4096 */
val MaxWidth = 4096

/** max height of a single SQView, constrained by maximum texture height (4096) */
val MaxHeight = 4096
val MaxHeight = 100
val Height = 100

}


class BlockImage(name: String
, widthProperty: SimpleIntegerProperty
, widthProperty: ReadOnlyDoubleProperty
, blockSizeProperty: SimpleIntegerProperty
, entriesProperty: java.util.List[LogEntry]
, entries: java.util.List[LogEntry]
, filtersProperty: SimpleListProperty[Filter]
, selectedElemProperty: SimpleObjectProperty[LogEntry]) extends CanLog {

private var lpb: LPixelBuffer = _
/**
* height property is calculated on the fly depending on the blockwidth/blockheight,
* width of BlockImage, number of elements and max size of possible of texture (4096).
* */
val heightProperty: SimpleIntegerProperty = new SimpleIntegerProperty()

val imageProperty = new SimpleObjectProperty[WritableImage]()

private val heightListener: ChangeListener[Number] = JfxUtils.onNew[Number](height => {
// logTrace("heightListener " + height)
setImage(getWidth, height.intValue)
})

private val blockSizeListener: InvalidationListener = (_: Observable) => {
repaint("blockSizeListener")
, selectedElemProperty: SimpleObjectProperty[LogEntry]
, heightProperty: SimpleIntegerProperty)
extends WritableImage(LPixelBuffer(name
, widthProperty.get().toInt
, heightProperty.get()
, blockSizeProperty
, entries
, filtersProperty
, selectedElemProperty
, Array.fill((widthProperty.get() * heightProperty.get()).toInt)(ColorUtil.toARGB(Color.WHITE)))) with CanLog {

def draw(i: Int, color: Color): Unit = {
logError("implement me")
}

val widthListener: ChangeListener[Number] = JfxUtils.onNew[Number](_ => {
repaint("widthListener")
})

init()

def init(): Unit = {
addListener()
}


def shutdown(): Unit = {
lpb = null
// just wipe out everything (?!)
imageProperty.set(null)
removeListener()
}


def addListener(): Unit = {
heightProperty.addListener(heightListener)
widthProperty.addListener(widthListener)
blockSizeProperty.addListener(blockSizeListener)
}

def removeListener(): Unit = {
heightProperty.removeListener(heightListener)
widthProperty.removeListener(widthListener)
blockSizeProperty.removeListener(blockSizeListener)
logError("implement me")
}


private def setImage(width: Int, height: Int): Unit = {
lpb = LPixelBuffer(width
, height
, blockSizeProperty
, entriesProperty
, filtersProperty
, selectedElemProperty
, Array.fill(width * height)(ColorUtil.toARGB(Color.WHITE)))
this.imageProperty.set(new WritableImage(lpb))
}

// todo check visibility
def repaint(ctx: String): Unit = Option(lpb).foreach(_.repaint(ctx, filtersProperty.asScala.toSeq, selectedElemProperty.get()))

def setHeight(height: Int): Unit = heightProperty.set(height)

def getWidth: Int = widthProperty.get()

def draw(i: Int, color: Color): Unit = lpb.draw(i, color)

}
65 changes: 32 additions & 33 deletions app/src/main/scala/app/logorrr/views/block/BlockView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import app.logorrr.util.{CanLog, JfxUtils}
import app.logorrr.views.search.Filter
import javafx.beans.property.{ReadOnlyDoubleProperty, SimpleIntegerProperty, SimpleListProperty, SimpleObjectProperty}
import javafx.beans.value.{ChangeListener, ObservableValue}
import javafx.collections.FXCollections
import javafx.event.EventHandler
import javafx.scene.image.ImageView
import javafx.scene.input.MouseEvent
Expand Down Expand Up @@ -61,11 +60,18 @@ class BlockView(name: String
, blockSizeProperty: SimpleIntegerProperty
, outerWidthProperty: ReadOnlyDoubleProperty
, selectedElemProperty: SimpleObjectProperty[LogEntry]
, entries: java.util.List[LogEntry]) extends ImageView with CanLog {

, entries: java.util.List[LogEntry]
, heightProperty: SimpleIntegerProperty) extends ImageView with CanLog {

setStyle(
"""
|-fx-padding: 0;
|-fx-margin: 0;
|-fx-background-insets: 0;
| """.stripMargin)
/*
private val widthProperty = new SimpleIntegerProperty(outerWidthProperty.get().intValue())

private val onClickListener: ChangeListener[LogEntry] = JfxUtils.onNew {
logEntry =>
selectedElemProperty.set(logEntry)
Expand All @@ -85,15 +91,17 @@ class BlockView(name: String
}
}
val selectedEntryProperty: SimpleObjectProperty[LogEntry] = new SimpleObjectProperty[LogEntry]()
val selectedEntryProperty: SimpleObjectProperty[LogEntry] = new SimpleObjectProperty[LogEntry]()
*/
private val blockImage = new BlockImage(name
, widthProperty
, outerWidthProperty
, blockSizeProperty
, entries
, filtersProperty
, selectedElemProperty)

, selectedElemProperty
, heightProperty)
/*
private val widthListener = JfxUtils.onNew[Number](n => {
val scrollPaneWidth = n.intValue()
if (scrollPaneWidth < BlockImage.MaxWidth) {
Expand All @@ -107,7 +115,8 @@ class BlockView(name: String
// logTrace(s"ScrollPaneWidth ($scrollPaneWidth) >= SQImage.MaxWidth (${BlockImage.MaxWidth}), not adjusting width of canvas ...")
}
})

*/
/*
val mouseEventHandler = new EventHandler[MouseEvent]() {
override def handle(me: MouseEvent): Unit = {
val index = BlockView.indexOf(me.getX.toInt, me.getY.toInt, blockSizeProperty.get, widthProperty.get)
Expand All @@ -118,47 +127,37 @@ class BlockView(name: String
}
}

*/
init()

def init(): Unit = {
setOnMouseClicked(mouseEventHandler)
// setOnMouseClicked(mouseEventHandler)
addListener()
addBindings()
}

private def addBindings(): Unit = {
imageProperty().bind(blockImage.imageProperty)
setImage(blockImage)
}

private def removeBindings(): Unit = {
imageProperty().unbind()
def shutdown(): Unit = {
blockImage.shutdown()
removeListener()
setImage(null)
}

def addListener(): Unit = {
selectedLineNumberProperty.addListener(selectedLineNumberListener)
selectedEntryProperty.addListener(onClickListener)
widthProperty.addListener(widthListener)
// selectedLineNumberProperty.addListener(selectedLineNumberListener)
//selectedEntryProperty.addListener(onClickListener)
// widthProperty.addListener(widthListener)
}

private def removeListener(): Unit = {
selectedLineNumberProperty.removeListener(selectedLineNumberListener)
selectedEntryProperty.removeListener(onClickListener)
widthProperty.removeListener(widthListener)
}

def shutdown(): Unit = {
blockImage.shutdown()
removeListener()
removeBindings()
//selectedLineNumberProperty.removeListener(selectedLineNumberListener)
//selectedEntryProperty.removeListener(onClickListener)
//widthProperty.removeListener(widthListener)
}

def setHeight(height: Int): Unit = blockImage.setHeight(height)

def setWidth(width: Int): Unit = widthProperty.set(width)
def setWidth(width: Int): Unit = logWarn("nono")//widthProperty.set(width)

private def getEntryAt(index: Int): Option[LogEntry] = Try(entries.get(index)).toOption

def repaint(ctx: String): Unit = blockImage.repaint(ctx)

}
13 changes: 6 additions & 7 deletions app/src/main/scala/app/logorrr/views/block/BlockViewPane.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,22 @@ class BlockViewPane(selectedLineNumberProperty: SimpleIntegerProperty)

val blockViews: Seq[BlockView] = {
// if virtual canvas height is lower than maxheight, just create one sqView and be done with it
if (blockHeight <= BlockImage.MaxHeight) {
if (blockHeight <= BlockImage.Height) {
val name = s"0_${getEntriesSize}"
val blockView = new BlockView(name
, selectedLineNumberProperty
, filtersProperty
, blockSizeProperty
, widthProperty
, selectedElemProperty
, entriesProperty)
, entriesProperty
, new SimpleIntegerProperty(300))
blockView.setWidth(getWidth.toInt)
blockView.setHeight(blockHeight)
Seq(blockView)
} else {
// if the virtual canvas height exceeds SQImage.MaxHeight, iterate and create new SQViews
val nrOfElemsInRow = getWidth.toInt / blockSizeProperty.get()
val nrOfRowsPerSquareView = BlockImage.MaxHeight / blockSizeProperty.get()
val nrOfRowsPerSquareView = BlockImage.Height / blockSizeProperty.get()
val nrElemsInSqView = nrOfRowsPerSquareView * nrOfElemsInRow
var curIndex = 0
val lb = new ListBuffer[BlockView]
Expand All @@ -138,9 +138,9 @@ class BlockViewPane(selectedLineNumberProperty: SimpleIntegerProperty)
, blockSizeProperty
, widthProperty
, selectedElemProperty
, blockViewEntries)
, blockViewEntries
, new SimpleIntegerProperty(300))
blockView.setWidth(getWidth.toInt)
blockView.setHeight(BlockView.calcVirtualHeight(blockSize, blockSize, getWidth.toInt, blockViewEntries.size))
lb.addOne(blockView)
curIndex = curIndex + nrElemsInSqView
}
Expand All @@ -149,7 +149,6 @@ class BlockViewPane(selectedLineNumberProperty: SimpleIntegerProperty)
}

vbox.getChildren.setAll(blockViews: _*)
blockViews.foreach(_.repaint("blockview"))
}
()
}
Expand Down
67 changes: 67 additions & 0 deletions app/src/main/scala/app/logorrr/views/block/Chunk.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package app.logorrr.views.block

import app.logorrr.model.LogEntry

import scala.collection.mutable.ListBuffer

object Chunk {

/** creates a list of LogEntries with the given size */
def mkTestLogEntries(size: Int): java.util.List[LogEntry] = {
val entries = {
(0 until size).foldLeft(new java.util.ArrayList[LogEntry]())((acc, e) => {
acc.add(LogEntry(e, s"t $e", None))
acc
})
}
entries
}

def mkTestChunks(nrEntries: Int
, width: Int
, height: Int
, blocksize: Int): Seq[Chunk] = {
val entries = mkTestLogEntries(nrEntries)
mkChunks(entries, width, height, blocksize)
}

def mkChunks(entries: java.util.List[LogEntry]
, width: Double
, height: Double
, blocksize: Int): Seq[Chunk] = {
if (width != 0 && blocksize != 0) {
// nr of chunks is calculated as follows:
// how many entries fit into a chunk?
// given their size and the width and height of a chunk it is easy to calculate.
val cols = (width / blocksize).toInt
val rows = (height / blocksize).toInt
val nrElements = rows * cols

val entriesSize = entries.size()
var curIndex = 0
val lb = new ListBuffer[Chunk]

while (curIndex < entriesSize) {
val end = if (curIndex + nrElements < entriesSize) {
curIndex + nrElements
} else {
entriesSize
}
val blockViewEntries = entries.subList(curIndex, end)
if (blockViewEntries.size() > 0) {
lb.addOne(Chunk(blockViewEntries))
}
curIndex = curIndex + nrElements
}
lb.toSeq
} else {
Seq()
}

}
}

case class Chunk(entries: java.util.List[LogEntry]) {
require(!entries.isEmpty, "entries was empty")
lazy val name = s"chunk:${entries.get(0).lineNumber}_${entries.get(entries.size() - 1).lineNumber}"
}
Loading

0 comments on commit 1911310

Please sign in to comment.