diff --git a/.cache-main b/.cache-main index b46269a..a14a377 100644 Binary files a/.cache-main and b/.cache-main differ diff --git a/build.sbt b/build.sbt index 08b2cd5..a0bb255 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ name := "PacmanLogger" -version := "0.1.2" +version := "0.1.3" scalaVersion := "2.12.4" diff --git a/src/main/scala/pacmanlogger/AbstractTable.scala b/src/main/scala/pacmanlogger/AbstractTable.scala index 746e5ce..d6ccb3e 100644 --- a/src/main/scala/pacmanlogger/AbstractTable.scala +++ b/src/main/scala/pacmanlogger/AbstractTable.scala @@ -7,7 +7,6 @@ import com.googlecode.lanterna.terminal._ trait AbstractTable { def getRows: List[List[String]] -// def setAllRows(newTuples: List[List[String]]): Unit def getAllRows: List[List[String]] def updateValues: Unit def isLastRow: Boolean diff --git a/src/main/scala/pacmanlogger/FilterableTable.scala b/src/main/scala/pacmanlogger/Filterable.scala similarity index 57% rename from src/main/scala/pacmanlogger/FilterableTable.scala rename to src/main/scala/pacmanlogger/Filterable.scala index 97dbcd4..64df101 100644 --- a/src/main/scala/pacmanlogger/FilterableTable.scala +++ b/src/main/scala/pacmanlogger/Filterable.scala @@ -3,9 +3,9 @@ package pacmanlogger import com.googlecode.lanterna.screen._ import com.googlecode.lanterna.graphics._ -class FilterableTable(titles: List[String], totalTuples: List[List[String]], fullScreen: Boolean, screen: Screen, tg: TextGraphics) - extends Table(titles, totalTuples, fullScreen, screen, tg) { - +trait Filterable extends Table { + val totalTuples = tuples + var filter = (t: List[String]) => true tuples = totalTuples.filter(filter) @@ -14,7 +14,7 @@ class FilterableTable(titles: List[String], totalTuples: List[List[String]], ful tuples = totalTuples.filter(filter) } - def setFilter(f: List[String] => Boolean) = { + def setFilterFunction(f: List[String] => Boolean) = { filter = f tuples = totalTuples.filter(filter) } diff --git a/src/main/scala/pacmanlogger/Logger.scala b/src/main/scala/pacmanlogger/Logger.scala index 02a5014..1044db3 100644 --- a/src/main/scala/pacmanlogger/Logger.scala +++ b/src/main/scala/pacmanlogger/Logger.scala @@ -17,10 +17,11 @@ class Logger(var logs: List[List[String]]) { val textGraphics = screen.newTextGraphics var terminalSize = screen.getTerminalSize - val titles = List("N ", "Date", "Action", "Version1", "Version2", "Packet") - val mainTable = new FilterableTable(titles, logs, true, screen, textGraphics) with Cursor - val filters = logs.map((l: List[String]) => l(2)).distinct - val filterTable = new FilterTable("Filter By", filters, List(true, true, true, true, true), mainTable, false, screen, textGraphics) with OptionCursor + val titles = List("Date", "Action", "Version1", "Version2", "Packet") + val mainTable = new Table(titles, logs, true, screen, textGraphics) with Filterable with Sortable with Cursor + val filters = logs.map((l: List[String]) => l(1)).distinct.sortWith(_<_) + val filterTable = new FilterTable("Filter By", filters, 1, mainTable, false, screen, textGraphics) with OptionCursor + val sortByTable = new SortByTable("Sort By", 1, mainTable, false, screen, textGraphics) with OptionCursor var focussedTable: Cursor = mainTable var mainTableOffset = 0 @@ -37,6 +38,7 @@ class Logger(var logs: List[List[String]]) { screen.clear() mainTable.updateSize filterTable.updateSize + sortByTable.updateSize draw(state) screen.refresh() } @@ -45,7 +47,7 @@ class Logger(var logs: List[List[String]]) { } mainTable.draw(terminalSize, mainTableOffset) var keyStroke = screen.pollInput() - while (keyStroke == null || (KeyType.F3 != keyStroke.getKeyType && 'q' != keyStroke.getCharacter)) { + while (keyStroke == null || (KeyType.F3 != keyStroke.getKeyType && 'q' != keyStroke.getCharacter) || focussedTable != mainTable) { if (keyStroke != null) { keyStroke.getKeyType match { case KeyType.ArrowDown => focussedTable.moveCursor(1, textGraphics, focussedTableOffset, terminalSize) @@ -55,16 +57,13 @@ class Logger(var logs: List[List[String]]) { case KeyType.End => focussedTable.moveCursorEnd(textGraphics, focussedTableOffset, terminalSize) case KeyType.PageUp => focussedTable.moveCursor(-(terminalSize.getRows - 2), textGraphics, focussedTableOffset, terminalSize) case KeyType.F4 => state.f4 + case KeyType.F5 => state.f5 case KeyType.Escape => state.esc - case KeyType.Enter => state.enter case KeyType.Character => handleCharacter(keyStroke, state) case _ => () } state = state.getNextState - mainTable.updateValues - filterTable.updateValues } - screen.refresh() draw(state) screen.refresh() keyStroke = screen.readInput @@ -102,7 +101,9 @@ class Logger(var logs: List[List[String]]) { def handleCharacter(keyStroke: KeyStroke, state: LoggerState) { keyStroke.getCharacter.toChar match { + case ' ' => state.space case 'f' => state.f + case 's' => state.s case _ => () } } diff --git a/src/main/scala/pacmanlogger/LoggerState.scala b/src/main/scala/pacmanlogger/LoggerState.scala index e898dd1..04103ac 100644 --- a/src/main/scala/pacmanlogger/LoggerState.scala +++ b/src/main/scala/pacmanlogger/LoggerState.scala @@ -4,21 +4,23 @@ import com.googlecode.lanterna._ import com.googlecode.lanterna.graphics._ import com.googlecode.lanterna.screen._ -trait LoggerState { +abstract class LoggerState { val table: AbstractTable def getFoot: List[(String, String)] - def f4: Unit - def f: Unit - def esc: Unit - def enter: Unit def getNextState: LoggerState + def f4: Unit = () + def f5: Unit = () + def f: Unit = () + def s: Unit = () + def esc: Unit = () + def space: Unit = () } class MainTableState(logger: Logger, val table: AbstractTable, screen: Screen) extends LoggerState { var nextState: LoggerState = this override def getNextState = nextState - override def getFoot = List(("F3", "Quit"), ("F4", "Filter") /*,("F5","Search"),("F6","SortBy")*/ ) + override def getFoot = List(("F3", "Quit "), ("F4", "Filter"), ("F5","SortBy")/*,("F6","Search")*/ ) override def f4 = { nextState = new FilterTableState(logger, logger.filterTable, screen) logger.focussedTable = logger.filterTable @@ -26,27 +28,51 @@ class MainTableState(logger: Logger, val table: AbstractTable, screen: Screen) e logger.focussedTableOffset = 0 screen.clear() } + override def f5 = { + nextState = new SortByTableState(logger, logger.sortByTable, screen) + logger.focussedTable = logger.sortByTable + logger.mainTableOffset = 15 + logger.focussedTableOffset = 0 + screen.clear() + } override def f = f4 - override def esc = () - override def enter = () + override def s = f5 } class FilterTableState(logger: Logger, val table: OptionCursor, screen: Screen) extends LoggerState { var nextState: LoggerState = this override def getNextState = nextState - override def getFoot = List(("Enter", "Enable"), ("ESC", "Accept")) - override def f4 = () + override def getFoot = List(("Space ", "Enable"), ("Esc", "Done ")) override def f = esc override def esc = { - nextState = new MainTableState(logger, logger.filterTable, screen) + nextState = new MainTableState(logger, logger.mainTable, screen) logger.focussedTable = logger.mainTable logger.mainTableOffset = 0 logger.focussedTableOffset = 0 screen.clear() } - override def enter { + override def space { table.click screen.clear() } } + +class SortByTableState(logger: Logger, val table: OptionCursor, screen: Screen) extends LoggerState { + var nextState: LoggerState = this + + override def getNextState = nextState + override def getFoot = List(("Space", "Sort "), ("Esc", "Done ")) + override def s = esc + override def esc = { + nextState = new MainTableState(logger, logger.mainTable, screen) + logger.focussedTable = logger.mainTable + logger.mainTableOffset = 0 + logger.focussedTableOffset = 0 + screen.clear() + } + override def space { + table.click + screen.clear() + } +} \ No newline at end of file diff --git a/src/main/scala/pacmanlogger/OptionTable.scala b/src/main/scala/pacmanlogger/OptionTable.scala index cfb32c2..45489b5 100644 --- a/src/main/scala/pacmanlogger/OptionTable.scala +++ b/src/main/scala/pacmanlogger/OptionTable.scala @@ -4,7 +4,7 @@ import scala.collection.immutable.HashMap import com.googlecode.lanterna.screen._ import com.googlecode.lanterna.graphics._ -abstract class OptionTable(title: String, var optionTuples: List[String], options: List[Boolean], subjectTable: FilterableTable, fullScreen: Boolean, screen: Screen, tg: TextGraphics) +abstract class OptionTable(title: String, optionTuples: List[String], options: List[Boolean], subjectTable: Table, fullScreen: Boolean, screen: Screen, tg: TextGraphics) extends Table(List("", title), optionTuples.zip(options).map(t => t match { @@ -14,11 +14,10 @@ abstract class OptionTable(title: String, var optionTuples: List[String], option def switchOption(r: List[String]): Unit - var settings: HashMap[String, Boolean] = { - var m = new HashMap[String, Boolean] - + var settings: List[(String, Boolean)] = { + var m = List[(String, Boolean)]() optionTuples.zip(options) foreach { - case (action, option) => m = m.updated(action, option) + case (action, option) => m = m :+(action, option) } m } @@ -26,7 +25,7 @@ abstract class OptionTable(title: String, var optionTuples: List[String], option override def updateValues = { nRows = terminalSize.getRows - 2 tuples = { - settings.toList map { (t: (String, Boolean)) => + settings map { (t: (String, Boolean)) => t match { case (s, true) => List("[X]", s) case (s, false) => List("[ ]", s) @@ -37,24 +36,52 @@ abstract class OptionTable(title: String, var optionTuples: List[String], option } } -class FilterTable(title: String, tuples: List[String], options: List[Boolean], filteredTable: FilterableTable, fullScreen: Boolean, screen: Screen, tg: TextGraphics) - extends OptionTable(title, tuples, options, filteredTable, fullScreen, screen, tg) { +class FilterTable(title: String, tuples: List[String], index: Int, options: List[Boolean], filterableTable: Filterable, fullScreen: Boolean, screen: Screen, tg: TextGraphics) + extends OptionTable(title, tuples, options, filterableTable, fullScreen, screen, tg) { + + def this(title: String, tuples: List[String], index: Int, filterableTable: Filterable, fullScreen: Boolean, screen: Screen, tg: TextGraphics) { + this(title, tuples, index, List(true, true, true, true, true), filterableTable, fullScreen, screen, tg) + } override def switchOption(r: List[String]) = { - settings.toList foreach { - case (s, true) if r(1) == s => - val values: List[Boolean] = settings.toList.unzip._2 + settings.zipWithIndex foreach { + case ((s, true),i) if r(1) == s => + val values: List[Boolean] = settings.unzip._2 if (values.indexOf(true) != values.lastIndexOf(true)) - settings = settings.updated(s, false) - case (s, false) if r(1) == s => - settings = settings.updated(s, true) + settings = settings.updated(i,(s, false)) + case ((s, false),i) if r(1) == s => + settings = settings.updated(i,(s, true)) case _ => () } - filteredTable.filter = setFilterFunction + filterableTable.setFilterFunction(filterFunction) + filterableTable.updateValues } - def setFilterFunction = { + def filterFunction = { + val settingsMap = settings.toMap t: List[String] => - settings.getOrElse(t(2), false) + settingsMap.getOrElse(t(index), false) + } +} + +class SortByTable(title: String, var index: Int, sortableTable: Sortable, fullScreen: Boolean, screen: Screen, tg: TextGraphics) + extends OptionTable(title, sortableTable.getTitles, sortableTable.getTitles.zipWithIndex map (t => + t match { + case (_, i) if i == index => true + case _ => false + }), sortableTable, fullScreen, screen, tg) { + val sortingTitles = sortableTable.getTitles + + override def switchOption(r: List[String]) = { + sortingTitles.zipWithIndex foreach { + case (s,i) if r(1) == s => + index = i + settings = settings.updated(i, (s,true)) + case (s,i) => + settings = settings.updated(i, (s,false)) + } + sortableTable.sortByIndex(index) + sortableTable.updateValues + updateValues } } diff --git a/src/main/scala/pacmanlogger/PacmanLogger.scala b/src/main/scala/pacmanlogger/PacmanLogger.scala index 55b0246..fbc0a52 100644 --- a/src/main/scala/pacmanlogger/PacmanLogger.scala +++ b/src/main/scala/pacmanlogger/PacmanLogger.scala @@ -10,7 +10,7 @@ object PacmanLogger { val res = p.parseAll(p.logs, lines) res match { case p.Success(parsedLogs, _) => - val logger = new Logger(parsedLogs.zipWithIndex.map { case (x, n) => (n.toString) :: x }) + val logger = new Logger(parsedLogs) logger.start case x => println("ERROR: "+x.toString) } diff --git a/src/main/scala/pacmanlogger/Sortable.scala b/src/main/scala/pacmanlogger/Sortable.scala new file mode 100644 index 0000000..4b4f64a --- /dev/null +++ b/src/main/scala/pacmanlogger/Sortable.scala @@ -0,0 +1,21 @@ +package pacmanlogger + +import com.googlecode.lanterna.screen._ +import com.googlecode.lanterna.graphics._ + +trait Sortable extends Table { + var sortingIndex = 0 + tuples = tuples.sortWith{_(sortingIndex)<_(sortingIndex)} + + override def updateValues = { + super.updateValues + tuples = tuples.sortWith{_(sortingIndex)<_(sortingIndex)} + } + + def sortByIndex(i: Int) = { + sortingIndex = i + tuples = tuples.sortWith{_(sortingIndex)<_(sortingIndex)} + } + + def getTitles = titles +} \ No newline at end of file diff --git a/src/main/scala/pacmanlogger/Table.scala b/src/main/scala/pacmanlogger/Table.scala index 7ff4606..1803a9f 100644 --- a/src/main/scala/pacmanlogger/Table.scala +++ b/src/main/scala/pacmanlogger/Table.scala @@ -5,7 +5,7 @@ import com.googlecode.lanterna.screen._ import com.googlecode.lanterna.graphics._ import com.googlecode.lanterna.terminal._ -class Table(titles: List[String], var tuples: List[List[String]], fullScreen: Boolean, screen: Screen, tg: TextGraphics) +class Table(val titles: List[String], var tuples: List[List[String]], fullScreen: Boolean, screen: Screen, tg: TextGraphics) extends AbstractTable { var colWidths = new Array[Int](titles.length) @@ -13,15 +13,16 @@ class Table(titles: List[String], var tuples: List[List[String]], fullScreen: Bo var firstRow = 0 var nRows: Int = screen.getTerminalSize.getRows - 2 var rows: List[List[String]] = updateRows + var tuplesLength = tuples.length def getRows = rows def getAllRows = tuples def updateRows = nRows match { - case n if n > tuples.length => + case n if n > tuplesLength => tuples - case n if n > (tuples.length - firstRow) => + case n if n > (tuplesLength - firstRow) => tuples.drop(terminalSize.getRows) case _ => tuples.drop(firstRow).take(nRows) } @@ -35,13 +36,14 @@ class Table(titles: List[String], var tuples: List[List[String]], fullScreen: Bo def updateValues = { nRows = terminalSize.getRows - 2 rows = updateRows + tuplesLength = tuples.length } override def getScreen = screen override def getTextGraphics = tg override def getFirstRow = firstRow - def isLastRow = firstRow + nRows == tuples.length + 1 + def isLastRow = firstRow + nRows == tuplesLength + 1 override def draw(terminalSize: TerminalSize, offset: Integer) { calcColWidths @@ -73,7 +75,7 @@ class Table(titles: List[String], var tuples: List[List[String]], fullScreen: Bo } override def scrollRows(n: Int) { - val totalLength = tuples.length + val totalLength = tuplesLength val rowsLength = nRows if (firstRow + n >= 0 && firstRow + n + rowsLength <= totalLength) firstRow += n @@ -88,7 +90,7 @@ class Table(titles: List[String], var tuples: List[List[String]], fullScreen: Bo } override def scrollEnd { - val totalLength = tuples.length + val totalLength = tuplesLength val rowsLength = nRows firstRow = totalLength - rowsLength