Skip to content

Commit

Permalink
#54: remember divider positions
Browse files Browse the repository at this point in the history
  • Loading branch information
rladstaetter committed Jan 23, 2022
1 parent 41661a4 commit 6e375b2
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 90 deletions.
13 changes: 13 additions & 0 deletions app/src/main/scala/app/logorrr/conf/SettingsIO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ object SettingsIO extends CanLog {
SettingsIO.write(settings.copy(recentFiles = updateRecentFilesFn(settings.recentFiles)))
}

def updateDividerPosition(path: Path, dividerPosition: Double): Unit = {
val settings = read()
val defs: Seq[LogReportDefinition] = for (lrd <- settings.recentFiles.logReportDefinitions) yield {
if (lrd.pathAsString == path.toAbsolutePath.toString) {
lrd.copy(dividerPosition = dividerPosition)
} else {
lrd
}
}
SettingsIO.write(settings.copy(recentFiles = settings.recentFiles.copy(logReportDefinitions = defs)))
}


def updateActiveLogFile(path: Path): Unit = {
val settings = read()
val defs: Seq[LogReportDefinition] = for (lrd <- settings.recentFiles.logReportDefinitions) yield {
Expand Down
12 changes: 8 additions & 4 deletions app/src/main/scala/app/logorrr/model/LogReport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ object LogReport extends CanLog {
new LogReport(logFile
, FXCollections.observableList(logEntryStream.collect(Collectors.toList[LogEntry]()))
, filters
, someColumnDef)
, someColumnDef
, lrd.active
, lrd.dividerPosition)
}, s"Imported ${lrd.path.toAbsolutePath.toString} ... ")

private def readFromFile(logFile: Path): util.List[String] = {
Expand Down Expand Up @@ -66,16 +68,18 @@ object LogReport extends CanLog {
case class LogReport(path: Path
, entries: ObservableList[LogEntry]
, filters: Seq[Filter]
, someColumnDef: Option[LogColumnDef]) {
, someColumnDef: Option[LogColumnDef]
, active: Boolean
, dividerPosition: Double) {

val logFileDefinition: LogReportDefinition = LogReportDefinition(path.toAbsolutePath.toString, someColumnDef, false, filters)
val logFileDefinition: LogReportDefinition = LogReportDefinition(path.toAbsolutePath.toString, someColumnDef, active, dividerPosition, filters)
val lengthProperty = new SimpleIntegerProperty(entries.size())
val titleProperty = new SimpleStringProperty(computeTabName)

val tailer = new Tailer(path.toFile, new LTailerListener(entries), 1000, true)

/** start observing log file for changes */
def start(): Unit = new Thread(tailer).start()
def init(): Unit = new Thread(tailer).start()

/** stop observing changes */
def stop(): Unit = tailer.stop()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ object LogReportDefinition {
implicit lazy val reader = deriveReader[LogReportDefinition]
implicit lazy val writer = deriveWriter[LogReportDefinition]

val defaultDividerPosition = 0.5
val defaultActive = false

def apply(p: Path): LogReportDefinition = LogReportDefinition(p.toAbsolutePath.toString, None, false, Filter.seq)
def apply(p: Path): LogReportDefinition = LogReportDefinition(p.toAbsolutePath.toString, None, defaultActive, defaultDividerPosition, Filter.seq)

def apply(p: Path, logColumnDef: LogColumnDef): LogReportDefinition =
LogReportDefinition(p.toAbsolutePath.toString, Option(logColumnDef), false, Filter.seq)
LogReportDefinition(p.toAbsolutePath.toString, Option(logColumnDef), defaultActive, defaultDividerPosition, Filter.seq)

}

Expand All @@ -33,6 +35,7 @@ object LogReportDefinition {
case class LogReportDefinition(pathAsString: String
, someColumnDefinition: Option[LogColumnDef] = None
, active: Boolean
, dividerPosition: Double
, filters: Seq[Filter]) {
val path: Path = Paths.get(pathAsString)

Expand Down
167 changes: 88 additions & 79 deletions app/src/main/scala/app/logorrr/views/LogReportTab.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import app.logorrr.model.{LogEntry, LogReport}
import app.logorrr.util.{CanLog, CollectionUtils, JfxUtils, LogoRRRFonts}
import app.logorrr.views.visual.LogVisualView
import javafx.beans.property.{SimpleBooleanProperty, SimpleIntegerProperty, SimpleListProperty, SimpleObjectProperty}
import javafx.beans.value.{ChangeListener, ObservableValue}
import javafx.beans.value.ChangeListener
import javafx.beans.{InvalidationListener, Observable}
import javafx.collections.transformation.FilteredList
import javafx.scene.control._
Expand All @@ -21,12 +21,13 @@ object LogReportTab {
val lv = new LogReportTab(logReport
, logViewTabPane.sceneWidthProperty.get()
, logViewTabPane.squareWidthProperty.get()
, logReport.logFileDefinition.dividerPosition
, initFileMenu)

logReport.filters.foreach(lv.addFilter)

/** activate invalidation listener on filtered list */
lv.start()
lv.init()
lv.sceneWidthProperty.bind(logViewTabPane.sceneWidthProperty)
lv.squareWidthProperty.bind(logViewTabPane.squareWidthProperty)
lv
Expand All @@ -44,6 +45,7 @@ object LogReportTab {
class LogReportTab(val logReport: LogReport
, val initialSceneWidth: Int
, val initialSquareWidth: Int
, val initialDividerPosition: Double
, initFileMenu: => Unit)
extends Tab with CanLog {

Expand All @@ -53,54 +55,15 @@ class LogReportTab(val logReport: LogReport
/** repaint if entries or filters change */
val repaintInvalidationListener: InvalidationListener = (_: Observable) => repaint()

def start(): Unit = {
logReport.start()
installInvalidationListener()
}

/** don't monitor file anymore if tab is closed, free invalidation listeners */
setOnClosed(_ => closeTab())

/**
* Actions to perform if tab is closed:
*
* - end monitoring of file
* - update config file
* - update file menu
*
*/
def closeTab(): Unit = {
SettingsIO.updateRecentFileSettings(rf => {
val filteredFiles = rf.logReportDefinitions.filterNot(s => s.pathAsString == logReport.logFileDefinition.path.toAbsolutePath.toString)
rf.copy(logReportDefinitions = filteredFiles)
})
initFileMenu
shutdown()
}

def shutdown(): Unit = {
logInfo(s"Closing file ${logReport.path.toAbsolutePath} ...")
uninstallInvalidationListener()
logReport.stop()
}

textProperty.bind(logReport.titleProperty)

/** list of search filters to be applied to a Log Report */
val filtersListProperty = new SimpleListProperty[Filter](CollectionUtils.mkEmptyObservableList())

/** bound to sceneWidthProperty of parent LogViewTabPane */
val sceneWidthProperty = new SimpleIntegerProperty(initialSceneWidth)

def sceneWidth = sceneWidthProperty.get()

/** bound to squareWidthProperty of parent LogViewTabPane */
val squareWidthProperty = new SimpleIntegerProperty(initialSquareWidth)

def getSquareWidth = squareWidthProperty.get()

val InitialRatio = 0.5

/** top component for log view */
val borderPane = new BorderPane()

Expand All @@ -110,20 +73,8 @@ class LogReportTab(val logReport: LogReport
/** list which holds all entries, default to display all (can be changed via buttons) */
val filteredList = new FilteredList[LogEntry](logReport.entries)

def installInvalidationListener(): Unit = {
// to detect when we apply a new filter via filter buttons (see FilterButtonsToolbar)
filteredList.predicateProperty().addListener(repaintInvalidationListener)
logReport.entries.addListener(repaintInvalidationListener)
// if application changes width this will trigger repaint (See Issue #9)
splitPane.widthProperty().addListener(repaintInvalidationListener)
}

def uninstallInvalidationListener(): Unit = {
filteredList.predicateProperty().removeListener(repaintInvalidationListener)
logReport.entries.removeListener(repaintInvalidationListener)
}

private val opsToolBar = new OpsToolBar(this)

private val filterButtonsToolBar = {
val fbtb = new FilterButtonsToolBar(this, filteredList, logReport.entries.size)
fbtb.filtersProperty.bind(filtersListProperty)
Expand All @@ -136,7 +87,7 @@ class LogReportTab(val logReport: LogReport
vb
}

val initialWidth = (sceneWidth * InitialRatio).toInt
val initialWidth = (sceneWidth * initialDividerPosition).toInt

private lazy val logVisualView = {
val lvv = new LogVisualView(filteredList.asScala, initialWidth, getSquareWidth)
Expand All @@ -153,29 +104,98 @@ class LogReportTab(val logReport: LogReport
l
}

borderPane.setTop(opsToolBox)
borderPane.setCenter(splitPane)
borderPane.setBottom(entryLabel)

setContent(borderPane)


/** to share state between visual view and text view. index can be selected by navigation in visual view */
val selectedIndexProperty = new SimpleIntegerProperty()

selectedIndexProperty.bind(logVisualView.selectedIndexProperty)
val selectedEntryProperty = new SimpleObjectProperty[LogEntry]()

selectedIndexProperty.addListener(JfxUtils.onNew[Number](selectEntry))
private val logEntryChangeListener: ChangeListener[LogEntry] = JfxUtils.onNew[LogEntry](updateEntryLabel)


val selectedEntryProperty = new SimpleObjectProperty[LogEntry]()
def init(): Unit = {
borderPane.setTop(opsToolBox)
borderPane.setCenter(splitPane)
borderPane.setBottom(entryLabel)

selectedEntryProperty.bindBidirectional(logVisualView.selectedEntryProperty)
setContent(borderPane)
/** don't monitor file anymore if tab is closed, free invalidation listeners */
setOnClosed(_ => closeTab())

private val logEntryChangeListener: ChangeListener[LogEntry] = JfxUtils.onNew[LogEntry](updateEntryLabel)
textProperty.bind(logReport.titleProperty)

selectedIndexProperty.bind(logVisualView.selectedIndexProperty)

selectedIndexProperty.addListener(JfxUtils.onNew[Number](selectEntry))

selectedEntryProperty.addListener(logEntryChangeListener)
// if user changes selected item in listview, change footer as well
logTextView.listView.getSelectionModel.selectedItemProperty.addListener(logEntryChangeListener)
selectedEntryProperty.bindBidirectional(logVisualView.selectedEntryProperty)

selectedEntryProperty.addListener(logEntryChangeListener)

// if user changes selected item in listview, change footer as well
logTextView.listView.getSelectionModel.selectedItemProperty.addListener(logEntryChangeListener)

splitPane.getItems.addAll(logVisualView, logTextView)


/**
* we are interested just in the first divider. If it changes its position (which means the user interacts) then
* update logVisualView
* */
splitPane.getDividers.get(0).positionProperty().addListener(JfxUtils.onNew {
t1: Number =>
val width = t1.doubleValue() * splitPane.getWidth
SettingsIO.updateDividerPosition(logReport.path, t1.doubleValue())
repaint(width)
})

logReport.init()

setDivider(initialDividerPosition)
installInvalidationListener()
}

/**
* Actions to perform if tab is closed:
*
* - end monitoring of file
* - update config file
* - update file menu
*
*/
def closeTab(): Unit = {
SettingsIO.updateRecentFileSettings(rf => {
val filteredFiles = rf.logReportDefinitions.filterNot(s => s.pathAsString == logReport.logFileDefinition.path.toAbsolutePath.toString)
rf.copy(logReportDefinitions = filteredFiles)
})
initFileMenu
shutdown()
}

def shutdown(): Unit = {
logInfo(s"Closing file ${logReport.path.toAbsolutePath} ...")
uninstallInvalidationListener()
logReport.stop()
}

def sceneWidth = sceneWidthProperty.get()

def getSquareWidth = squareWidthProperty.get()

def installInvalidationListener(): Unit = {
// to detect when we apply a new filter via filter buttons (see FilterButtonsToolbar)
filteredList.predicateProperty().addListener(repaintInvalidationListener)
logReport.entries.addListener(repaintInvalidationListener)
// if application changes width this will trigger repaint (See Issue #9)
splitPane.widthProperty().addListener(repaintInvalidationListener)
}

def uninstallInvalidationListener(): Unit = {
filteredList.predicateProperty().removeListener(repaintInvalidationListener)
logReport.entries.removeListener(repaintInvalidationListener)
}

def selectEntry(number: Number): Unit = logTextView.selectEntryByIndex(number.intValue)

Expand All @@ -192,18 +212,7 @@ class LogReportTab(val logReport: LogReport
}
}

splitPane.getItems.addAll(logVisualView, logTextView)

/**
* we are interested just in the first divider. If it changes its position (which means the user interacts) then
* update logVisualView
* */
splitPane.getDividers.get(0).positionProperty().addListener(new ChangeListener[Number] {
override def changed(observableValue: ObservableValue[_ <: Number], t: Number, t1: Number): Unit = {
val width = t1.doubleValue() * splitPane.getWidth
repaint(width)
}
})
def setDivider(pos: Double): Unit = splitPane.getDividers.get(0).setPosition(pos)

def addFilter(filter: Filter): Unit = filtersListProperty.add(filter)

Expand Down
5 changes: 4 additions & 1 deletion app/src/main/scala/app/logorrr/views/LogViewTabPane.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ class LogViewTabPane(initFileMenu: => Unit)
})
}

def add(logReport: LogReport): Unit = getTabs.add(LogReportTab(this, logReport, initFileMenu))
def add(logReport: LogReport): Unit = {
val tab = LogReportTab(this, logReport, initFileMenu)
getTabs.add(tab)
}

def contains(p: Path): Boolean = getLogReportTabs.exists(lr => lr.logReport.path.toAbsolutePath.toString == p.toAbsolutePath.toString)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,16 @@ class AppMainBorderPane(initialSceneWidth: Int
val path = f.toPath
if (Files.exists(path)) {
if (!contains(path)) {
val logFileDefinition = LogReportDefinition(path.toAbsolutePath.toString, None, true, Filter.seq)
val logFileDefinition =
LogReportDefinition(path.toAbsolutePath.toString
, None
, active = true
, LogReportDefinition.defaultDividerPosition
, Filter.seq)
SettingsIO.updateRecentFileSettings(rf => rf.copy(logReportDefinitions = logFileDefinition +: rf.logReportDefinitions))
reInitMenuBarFn
addLogReport(logFileDefinition)
logViewTabPane.selectLog(path)
selectLog(path)
} else {
logWarn(s"${path.toAbsolutePath.toString} is already opened ...")
}
Expand Down
6 changes: 4 additions & 2 deletions app/src/main/scala/app/logorrr/views/main/LogoRRRMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ class LogoRRRMain(hostServices: HostServices
// the last one
settings.recentFiles.someActive match {
case Some(value) => selectLog(value.path)
case None => selectLastLogReport()
case None =>
logError("No active log file entries found.")
selectLastLogReport()
}
// only after having initialized we activate change listeners */
ambp.init()
Expand All @@ -49,7 +51,7 @@ class LogoRRRMain(hostServices: HostServices
logTrace(s"Try to open log file ${path.toAbsolutePath.toString}")

if (!ambp.contains(path)) {
SettingsIO.updateRecentFileSettings(rf => rf.copy(logReportDefinitions = LogReportDefinition(path.toString, None, true, Filter.seq) +: rf.logReportDefinitions))
SettingsIO.updateRecentFileSettings(rf => rf.copy(logReportDefinitions = LogReportDefinition(path.toString, None, true, LogReportDefinition.defaultDividerPosition, Filter.seq) +: rf.logReportDefinitions))
addLogReport(LogReportDefinition(path))
selectLog(path)
initFileMenu()
Expand Down

0 comments on commit 6e375b2

Please sign in to comment.