Skip to content

Commit

Permalink
Merge branch 'release/0.1.2'
Browse files Browse the repository at this point in the history
carlocastoldi committed Apr 4, 2018
2 parents 63f892a + 4863c73 commit 4330ca7
Showing 11 changed files with 362 additions and 332 deletions.
Binary file modified .cache-main
Binary file not shown.
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -2,7 +2,29 @@
![Lanterna screenshot](resources/PacmanLogger.png)
An application with terminal GUI inspired by htop that makes Arch pacman's logs easier to read. Written in Scala

## Dependencies
## Installation
### Dependencies
Mandatory:
- Java (jre)

### Package Manager
#### Arch Linux
Available via AUR here: https://aur.archlinux.org/packages/pacmanlogger-git/

### Manual (sbt)
Compiling:
```bash
git clone https://github.com/carlocastoldi/PacmanLogger.git
cd PacmanLogger
sbt assembly
cp target/scala-2.12/PacmanLogger-assembly-<version>.jar ./pacmanlogger.jar
```
Running:
```bash
java -jar pacmanlogger.jar
```

## Developing tools
- Scala (http://www.scala-lang.org/)
- lanterna-3.0.0 (https://github.com/mabe02/lanterna)
- scala-parser-combinators (https://github.com/scala/scala-parser-combinators)
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name := "PacmanLogger"

version := "0.1.0"
version := "0.1.2"

scalaVersion := "2.12.4"

23 changes: 12 additions & 11 deletions src/main/scala/pacmanlogger/AbstractTable.scala
Original file line number Diff line number Diff line change
@@ -6,15 +6,16 @@ import com.googlecode.lanterna.graphics._
import com.googlecode.lanterna.terminal._

trait AbstractTable {
def getRows: List[List[String]]
def updateValues: Unit
def isLastRow: Boolean
def scrollRows(n: Int): Unit
def scrollStart: Unit
def scrollEnd: Unit
def getScreen: Screen
def getFirstRow: Int
def getTextGraphics: TextGraphics
def draw(terminalSize: TerminalSize, offset: Integer)
def drawRow(titles: List[String], column: Int, row: Int)
def getRows: List[List[String]]
def getAllRows: List[List[String]]
def updateValues: Unit
def isLastRow: Boolean
def scrollRows(n: Int): Unit
def scrollStart: Unit
def scrollEnd: Unit
def getScreen: Screen
def getFirstRow: Int
def getTextGraphics: TextGraphics
def draw(terminalSize: TerminalSize, offset: Integer)
def drawRow(titles: List[String], column: Int, row: Int)
}
132 changes: 66 additions & 66 deletions src/main/scala/pacmanlogger/Cursor.scala
Original file line number Diff line number Diff line change
@@ -4,87 +4,87 @@ import com.googlecode.lanterna._
import com.googlecode.lanterna.graphics._

trait Cursor extends AbstractTable {
var cursorAbsolutePos = 0
var cursorAbsolutePos = 0
var cursorRelativePos = 0
val screen = getScreen
val tg = getTextGraphics
var rows_ = getRows
var nRows_ = rows_.length

abstract override def draw(terminalSize: TerminalSize, offset: Integer) {
super.draw(terminalSize, offset)
if(terminalSize.getRows-3 < cursorRelativePos)
cursorRelativePos = terminalSize.getRows-3
drawCursor(offset)
}

def moveCursor(n: Int, tg: TextGraphics, offset: Int, terminalSize: TerminalSize) {
rows_ = getRows
nRows_ = rows_.length
(cursorRelativePos+n) match {
case i if i >= 0 && i < nRows_ =>
delCursor(offset)
cursorRelativePos += n
drawCursor(offset)
case i if !isLastRow =>
var firstRow_ = getFirstRow
scrollRows(n)
super.draw(terminalSize, offset)
if (terminalSize.getRows - 3 < cursorRelativePos)
cursorRelativePos = terminalSize.getRows - 3
drawCursor(offset)
}

delCursor(offset)
cursorRelativePos += n - (getFirstRow - firstRow_)
def moveCursor(n: Int, tg: TextGraphics, offset: Int, terminalSize: TerminalSize) {
rows_ = getRows
nRows_ = rows_.length
(cursorRelativePos + n) match {
case i if i >= 0 && i < nRows_ =>
delCursor(offset)
cursorRelativePos += n
drawCursor(offset)
case i if !isLastRow =>
var firstRow_ = getFirstRow
scrollRows(n)

if (cursorRelativePos < 0) {
cursorRelativePos = 0
}
delCursor(offset)
cursorRelativePos += n - (getFirstRow - firstRow_)

if (cursorRelativePos > nRows_ - 1) {
cursorRelativePos = nRows_ - 1
}
if (cursorRelativePos < 0) {
cursorRelativePos = 0
}

drawCursor(offset)
draw(terminalSize, offset)
case _ => ()
}
}
if (cursorRelativePos > nRows_ - 1) {
cursorRelativePos = nRows_ - 1
}

def moveCursorStart(tg: TextGraphics, offset: Int, terminalSize: TerminalSize) {
delCursor(offset)
cursorRelativePos = 0
drawCursor(offset)
scrollStart
draw(terminalSize, offset)
}
drawCursor(offset)
draw(terminalSize, offset)
case _ => ()
}
}

def moveCursorEnd(tg: TextGraphics, offset: Int, terminalSize: TerminalSize) {
rows_ = getRows
nRows_ = rows_.length
def moveCursorStart(tg: TextGraphics, offset: Int, terminalSize: TerminalSize) {
delCursor(offset)
cursorRelativePos = 0
drawCursor(offset)
scrollStart
draw(terminalSize, offset)
}

delCursor(offset)
cursorRelativePos = nRows_ - 1
drawCursor(offset)
scrollEnd
draw(terminalSize, offset)
}

def delCursor(offset: Int) {
updateValues
rows_ = getRows
nRows_ = rows_.length
tg.setForegroundColor(TextColor.ANSI.CYAN)
tg.setBackgroundColor(TextColor.ANSI.DEFAULT)
drawRow(rows_(cursorRelativePos), offset, cursorRelativePos+1)
}

def drawCursor(offset: Int) {
updateValues
rows_ = getRows
nRows_ = rows_.length
tg.setForegroundColor(TextColor.ANSI.BLACK)
tg.setBackgroundColor(TextColor.ANSI.CYAN)
drawRow(rows_(cursorRelativePos), offset, cursorRelativePos+1)
}
def moveCursorEnd(tg: TextGraphics, offset: Int, terminalSize: TerminalSize) {
rows_ = getRows
nRows_ = rows_.length

delCursor(offset)
cursorRelativePos = nRows_ - 1
drawCursor(offset)
scrollEnd
draw(terminalSize, offset)
}

def delCursor(offset: Int) {
updateValues
rows_ = getRows
nRows_ = rows_.length
tg.setForegroundColor(TextColor.ANSI.CYAN)
tg.setBackgroundColor(TextColor.ANSI.DEFAULT)
drawRow(rows_(cursorRelativePos), offset, cursorRelativePos + 1)
}

def drawCursor(offset: Int) {
updateValues
rows_ = getRows
nRows_ = rows_.length
tg.setForegroundColor(TextColor.ANSI.BLACK)
tg.setBackgroundColor(TextColor.ANSI.CYAN)
drawRow(rows_(cursorRelativePos), offset, cursorRelativePos + 1)
}
}

trait OptionCursor extends OptionTable with Cursor {
def getSelectedRow = rows_(cursorRelativePos)
def getSelectedRow = rows_(cursorRelativePos)
}
160 changes: 82 additions & 78 deletions src/main/scala/pacmanlogger/Logger.scala
Original file line number Diff line number Diff line change
@@ -8,98 +8,102 @@ import com.googlecode.lanterna.screen._
import com.googlecode.lanterna.input._

class Logger(var logs: List[List[String]]) {
val terminal = new DefaultTerminalFactory().createTerminal

val terminal = new DefaultTerminalFactory().createTerminal
val screen = new TerminalScreen(terminal)
screen.startScreen
screen.setCursorPosition(null)
screen.setCursorPosition(null)

val textGraphics = screen.newTextGraphics
val textGraphics = screen.newTextGraphics
var terminalSize = screen.getTerminalSize
val titles = List("N ","Date","Action","Version1","Version2","Packet")

val titles = List("N ", "Date", "Action", "Version1", "Version2", "Packet")
val mainTable = new FilteredTable(titles, logs, true, screen, textGraphics) with Cursor

val filters = logs.map((l: List[String]) => l(2)).distinct
val filterTable: OptionCursor = new OptionTable("Filter By", filters, List(true,true,true,true,true), mainTable, false, screen, textGraphics) with OptionCursor
val filterTable: OptionCursor = new OptionTable("Filter By", filters, List(true, true, true, true, true), mainTable, false, screen, textGraphics) with OptionCursor
var focussedTable: Cursor = mainTable
var mainTableOffset = 0
var focussedTableOffset = mainTableOffset

def start {
def start {
var state: LoggerState = new MainTableState(this, mainTable, screen)

val f = Future {
while(true) {
val newSize = screen.doResizeIfNecessary
if (newSize != null){
terminalSize = newSize
screen.clear()
mainTable.updateSize
filterTable.updateSize
draw(state)
screen.refresh()
}
Thread.sleep(100)
}
}
mainTable.draw(terminalSize, mainTableOffset)
var keyStroke = screen.pollInput()
while (keyStroke == null || (KeyType.F3 != keyStroke.getKeyType && 'q' != keyStroke.getCharacter)) {
if(keyStroke != null) {
keyStroke.getKeyType match {
case KeyType.ArrowDown => focussedTable.moveCursor(1, textGraphics, focussedTableOffset, terminalSize)
case KeyType.ArrowUp => focussedTable.moveCursor(-1, textGraphics, focussedTableOffset, terminalSize)
case KeyType.PageDown => focussedTable.moveCursor(terminalSize.getRows-2, textGraphics, focussedTableOffset, terminalSize)
case KeyType.Home => focussedTable.moveCursorStart(textGraphics, focussedTableOffset, terminalSize)
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.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
}
while (true) {
val newSize = screen.doResizeIfNecessary
if (newSize != null) {
terminalSize = newSize
screen.clear()
mainTable.updateSize
filterTable.updateSize
draw(state)
screen.refresh()
}
Thread.sleep(100)
}
}
mainTable.draw(terminalSize, mainTableOffset)
var keyStroke = screen.pollInput()
while (keyStroke == null || (KeyType.F3 != keyStroke.getKeyType && 'q' != keyStroke.getCharacter)) {
if (keyStroke != null) {
keyStroke.getKeyType match {
case KeyType.ArrowDown => focussedTable.moveCursor(1, textGraphics, focussedTableOffset, terminalSize)
case KeyType.ArrowUp => focussedTable.moveCursor(-1, textGraphics, focussedTableOffset, terminalSize)
case KeyType.PageDown => focussedTable.moveCursor(terminalSize.getRows - 2, textGraphics, focussedTableOffset, terminalSize)
case KeyType.Home => focussedTable.moveCursorStart(textGraphics, focussedTableOffset, terminalSize)
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.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
}
screen.close
}

def draw(state: LoggerState) {
mainTable.draw(terminalSize,mainTableOffset)
if(mainTableOffset > 0)
focussedTable.draw(terminalSize,0)
drawFoot(state.getFoot, 0)
}

def drawFoot(commands: List[(String,String)], off: Int) {
var offset = off
val columns = terminalSize.getColumns()
val row = terminalSize.getRows-1
commands foreach {
case (k,c) =>
textGraphics.setForegroundColor(TextColor.ANSI.CYAN)
textGraphics.setBackgroundColor(TextColor.ANSI.DEFAULT)
textGraphics.putString(offset, row, k)
offset += k.length
textGraphics.setForegroundColor(TextColor.ANSI.BLACK)
textGraphics.setBackgroundColor(TextColor.ANSI.CYAN)
textGraphics.putString(offset, row, c)
offset += c.length
}
textGraphics.putString(offset, row, " "*(columns-offset))

def draw(state: LoggerState) {
mainTable.draw(terminalSize, mainTableOffset)
if (mainTableOffset > 0)
focussedTable.draw(terminalSize, 0)
drawFoot(state.getFoot, 0)
}

def handleCharacter(keyStroke: KeyStroke, state: LoggerState) {
keyStroke.getCharacter.toChar match {
case 'f' => state.f
}
}
def drawFoot(commands: List[(String, String)], off: Int) {
var offset = off
val columns = terminalSize.getColumns()
val row = terminalSize.getRows - 1
var total = "Total "+mainTable.getAllRows.length
commands foreach {
case (k, c) =>
textGraphics.setForegroundColor(TextColor.ANSI.CYAN)
textGraphics.setBackgroundColor(TextColor.ANSI.DEFAULT)
textGraphics.putString(offset, row, k)
offset += k.length
textGraphics.setForegroundColor(TextColor.ANSI.BLACK)
textGraphics.setBackgroundColor(TextColor.ANSI.CYAN)
textGraphics.putString(offset, row, c)
offset += c.length
}

textGraphics.putString(offset, row, " " * (columns - offset))
textGraphics.putString(offset + columns - offset - total.length, row, total)
}

def handleCharacter(keyStroke: KeyStroke, state: LoggerState) {
keyStroke.getCharacter.toChar match {
case 'f' => state.f
case _ => ()
}
}
}
80 changes: 40 additions & 40 deletions src/main/scala/pacmanlogger/LoggerState.scala
Original file line number Diff line number Diff line change
@@ -5,49 +5,49 @@ import com.googlecode.lanterna.graphics._
import com.googlecode.lanterna.screen._

trait LoggerState {
val table: AbstractTable
def getFoot: List[(String,String)]
def f4: Unit
def f: Unit
def esc: Unit
def enter: Unit
def getNextState: LoggerState
val table: AbstractTable
def getFoot: List[(String, String)]
def f4: Unit
def f: Unit
def esc: Unit
def enter: Unit
def getNextState: LoggerState
}

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 f4 = {
nextState = new FilterTableState(logger, logger.filterTable, screen)
logger.focussedTable = logger.filterTable
logger.mainTableOffset = 18
logger.focussedTableOffset = 0
screen.clear()
}
override def f = f4
override def esc = ()
override def enter = ()
var nextState: LoggerState = this

override def getNextState = nextState
override def getFoot = List(("F3", "Quit"), ("F4", "Filter") /*,("F5","Search"),("F6","SortBy")*/ )
override def f4 = {
nextState = new FilterTableState(logger, logger.filterTable, screen)
logger.focussedTable = logger.filterTable
logger.mainTableOffset = 18
logger.focussedTableOffset = 0
screen.clear()
}
override def f = f4
override def esc = ()
override def enter = ()
}

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 f = esc
override def esc = {
nextState = new MainTableState(logger, logger.filterTable, screen)
logger.focussedTable = logger.mainTable
logger.mainTableOffset = 0
logger.focussedTableOffset = 0
screen.clear()
}
override def enter {
table.switchOption(table.getSelectedRow)
table.updateValues
screen.clear()
}
}
var nextState: LoggerState = this

override def getNextState = nextState
override def getFoot = List(("Enter", "Enable"), ("ESC", "Accept"))
override def f4 = ()
override def f = esc
override def esc = {
nextState = new MainTableState(logger, logger.filterTable, screen)
logger.focussedTable = logger.mainTable
logger.mainTableOffset = 0
logger.focussedTableOffset = 0
screen.clear()
}
override def enter {
table.switchOption(table.getSelectedRow)
table.updateValues
screen.clear()
}
}
8 changes: 4 additions & 4 deletions src/main/scala/pacmanlogger/PacmanLogger.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package pacmanlogger

import java.io.{File,PrintWriter,IOException}
import java.io.{File, PrintWriter, IOException}

object PacmanLogger {
def main(args: Array[String]) = {
@@ -9,10 +9,10 @@ object PacmanLogger {
val p = new PacmanLoggerParser
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})
case p.Success(parsedLogs, _) =>
val logger = new Logger(parsedLogs.zipWithIndex.map { case (x, n) => (n.toString) :: x })
logger.start
case x => println("ERROR: " + x.toString)
case x => println("ERROR: "+x.toString)
}
src close
}
16 changes: 9 additions & 7 deletions src/main/scala/pacmanlogger/PacmanLoggerParser.scala
Original file line number Diff line number Diff line change
@@ -6,14 +6,14 @@ import scala.util.parsing.combinator._
class PacmanLoggerParser extends JavaTokenParsers {
override protected val whiteSpace = "[ \t]+".r

def logs = opt(otherLogs) ~> repsep(alpmLog,otherLogs) <~ opt(otherLogs)
def logs = opt(otherLogs) ~> repsep(alpmLog, otherLogs) <~ opt(otherLogs)
def alpmLog = ("[" ~> time <~ "]") ~ ("[ALPM]" ~> action) ~ pktName ~ pktVers <~ ("\r\n" | "\n") ^^ {
case time ~ action ~ pkt ~ vers => List(time, action, vers.v1, vers.v2, pkt)
}
def otherLogs = rep(otherLog)
def otherLog = (fakeLog|fs) <~ ("\r\n" | "\n")
def otherLog = (fakeLog | fs) <~ ("\r\n" | "\n")
def fakeLog = notAlpm | fakeAlpm
def notAlpm = (("[" ~> time <~ "]") ~> ("[" ~> ("PAMAC"| "ALPM-SCRIPTLET"| "PACMAN" | "PACKAGEKIT") <~ "]") <~ ".*".r)//^^ { _ => ""}
def notAlpm = (("[" ~> time <~ "]") ~> ("[" ~> ("PAMAC" | "ALPM-SCRIPTLET" | "PACMAN" | "PACKAGEKIT") <~ "]") <~ ".*".r) //^^ { _ => ""}
def fakeAlpm = ("[" ~> time <~ "]") ~> "[ALPM]" <~ notAction <~ ".*".r

//def notAction = "^(?!upgraded$|installed$|removed$).*".r
@@ -27,10 +27,12 @@ class PacmanLoggerParser extends JavaTokenParsers {
}
def action = ("downgraded" | "installed" | "removed" | "reinstalled" | "upgraded") ^^ { _ toUpperCase }
def pktName = "[a-zA-Z0-9\\+-_.]+".r <~ "("
def pktVers = "[^()\\s]+".r ~ opt("->" ~> "[^()\\s]+".r ) <~ ")" ^^ { v => v match {
case v1 ~ Some(v2) => PktVersion(v1,v2)
case v1 ~ None => new PktVersion(v1)
}}
def pktVers = "[^()\\s]+".r ~ opt("->" ~> "[^()\\s]+".r) <~ ")" ^^ { v =>
v match {
case v1 ~ Some(v2) => PktVersion(v1, v2)
case v1 ~ None => new PktVersion(v1)
}
}

def fourDig = "[0-9]{4}".r
def twoDig = "[0-9]{2}".r
14 changes: 7 additions & 7 deletions src/main/scala/pacmanlogger/PktVersion.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package pacmanlogger

case class PktVersion(v1: String, v2: String) {
def this(v: String) {
this(v, "")
}
override def toString: String = {
return "%s,%s".format(v1,v2)
}
def this(v: String) {
this(v, "")
}

override def toString: String = {
return "%s,%s".format(v1, v2)
}
}
235 changes: 118 additions & 117 deletions src/main/scala/pacmanlogger/Table.scala
Original file line number Diff line number Diff line change
@@ -6,48 +6,49 @@ import com.googlecode.lanterna.graphics._
import com.googlecode.lanterna.terminal._

class FilteredTable(titles: List[String], tuples: List[List[String]], fullScreen: Boolean, screen: Screen, tg: TextGraphics)
extends AbstractTable {
var colWidths = new Array[Int](titles.length)
extends AbstractTable {

var colWidths = new Array[Int](titles.length)
var terminalSize = screen.getTerminalSize
var firstRow = 0
var filter = (t: List[String]) => true
var filter = (t: List[String]) => true
var filteredRows: List[List[String]] = tuples
var nRows: Int = screen.getTerminalSize.getRows-2
var rows: List[List[String]] = nRows match {
case n if n > filteredRows.length =>
filteredRows
case n if n > (filteredRows.length-firstRow) =>
filteredRows.drop(terminalSize.getRows)
case _ => filteredRows.drop(firstRow).take(nRows)
}

def getRows = rows

def updateRows =
rows = nRows match {
case n if n > filteredRows.length =>
filteredRows
case n if n > (filteredRows.length-firstRow) =>
filteredRows.drop(terminalSize.getRows)
case _ => filteredRows.drop(firstRow).take(nRows)
}
def updateSize = {
terminalSize = screen.getTerminalSize
updateRows
}

var nRows: Int = screen.getTerminalSize.getRows - 2
var rows: List[List[String]] = nRows match {
case n if n > filteredRows.length =>
filteredRows
case n if n > (filteredRows.length - firstRow) =>
filteredRows.drop(terminalSize.getRows)
case _ => filteredRows.drop(firstRow).take(nRows)
}

def getRows = rows
def getAllRows = filteredRows

def updateRows =
rows = nRows match {
case n if n > filteredRows.length =>
filteredRows
case n if n > (filteredRows.length - firstRow) =>
filteredRows.drop(terminalSize.getRows)
case _ => filteredRows.drop(firstRow).take(nRows)
}
def updateSize = {
terminalSize = screen.getTerminalSize
updateRows
}

def updateValues = {
nRows = screen.getTerminalSize.getRows-2
filteredRows = tuples.filter(filter)
updateRows
nRows = screen.getTerminalSize.getRows - 2
filteredRows = tuples.filter(filter)
updateRows
}

override def getScreen = screen
override def getTextGraphics = tg
override def getFirstRow = firstRow
def isLastRow = firstRow+nRows == filteredRows.length+1
override def getFirstRow = firstRow

def isLastRow = firstRow + nRows == filteredRows.length + 1

override def draw(terminalSize: TerminalSize, offset: Integer) {
calcColWidths
@@ -58,107 +59,107 @@ class FilteredTable(titles: List[String], tuples: List[List[String]], fullScreen
tg.setBackgroundColor(TextColor.ANSI.DEFAULT)
val localRows = rows
localRows.zipWithIndex foreach {
case(r,i) => drawRow(r, offset, i+1)
case (r, i) => drawRow(r, offset, i + 1)
}
}

override def drawRow(titles: List[String], column: Int, row: Int) {
val columns = terminalSize.getColumns
val columns = terminalSize.getColumns
var offset = column
titles.zipWithIndex foreach{
case(title,i) if(offset+colWidths(i)+1 <= columns) => tg.putString(offset, row, title+" "*(colWidths(i)-title.length+1))
offset = offset+colWidths(i)
case(title,i) if offset <= columns =>
val width = columns-offset
tg.putString(offset, row, title+" "*(width+1))
offset = offset+colWidths(i)
titles.zipWithIndex foreach {
case (title, i) if (offset + colWidths(i) + 1 <= columns) =>
tg.putString(offset, row, title+" " * (colWidths(i) - title.length + 1))
offset = offset + colWidths(i)
case (title, i) if offset <= columns =>
val width = columns - offset
tg.putString(offset, row, title+" " * (width + 1))
offset = offset + colWidths(i)
case _ => ()
}
if (fullScreen) tg.putString(offset, row, " "*(columns-offset))
if (fullScreen) tg.putString(offset, row, " " * (columns - offset))
}

override def scrollRows(n: Int) {
val totalLength = filteredRows.length
val rowsLength = nRows
if(firstRow+n >= 0 && firstRow+n+rowsLength <= totalLength)
firstRow += n
else if (firstRow+n >= 0 && firstRow+rowsLength <= totalLength)
firstRow = totalLength - rowsLength
else if (firstRow > 0 && firstRow+n+rowsLength <= totalLength)
firstRow = 0
val totalLength = filteredRows.length
val rowsLength = nRows
if (firstRow + n >= 0 && firstRow + n + rowsLength <= totalLength)
firstRow += n
else if (firstRow + n >= 0 && firstRow + rowsLength <= totalLength)
firstRow = totalLength - rowsLength
else if (firstRow > 0 && firstRow + n + rowsLength <= totalLength)
firstRow = 0
}

override def scrollStart {
firstRow = 0
}
override def scrollStart {
firstRow = 0
}

override def scrollEnd {
val totalLength = filteredRows.length
val rowsLength = nRows
override def scrollEnd {
val totalLength = filteredRows.length
val rowsLength = nRows

firstRow = totalLength - rowsLength
}
firstRow = totalLength - rowsLength
}

def calcColWidths {
colWidths = new Array[Int](titles.length)
val localRows = titles::rows
localRows foreach{ row =>
row.zipWithIndex.foreach{
case(element,column) if element.length >= colWidths(column) =>
colWidths.update(column,element.length+1)
case _ => ()
}
}
colWidths = new Array[Int](titles.length)
val localRows = titles :: rows
localRows foreach { row =>
row.zipWithIndex.foreach {
case (element, column) if element.length >= colWidths(column) =>
colWidths.update(column, element.length + 1)
case _ => ()
}
}
}
}

import scala.collection.immutable.HashMap

class OptionTable(titles: String, tuples: List[String], options: List[Boolean], filteredT: FilteredTable, fullScreen: Boolean, screen: Screen, tg: TextGraphics)
extends FilteredTable(List("",titles),
tuples.zip(options).map(t =>
t match {
case (s, true) => List("[X]",s)
case (s, false) => List("[ ]",s)
}
), fullScreen, screen, tg) {

var settings: HashMap[String,Boolean] = {
var m = new HashMap[String,Boolean]
tuples.zip(options) foreach {
case (action,option) => m = m.updated(action,option)
}
m
}

override def updateValues = {
nRows = terminalSize.getRows-2
filteredRows = {
settings.toList map { (t: (String,Boolean)) =>
t match {
case (s,true) => List("[X]",s)
case (s,false) => List("[ ]",s)
}
}
}
updateRows
}

def switchOption(r: List[String]) = {
settings.toList foreach {
case (s,true) if r(1) == s =>
val values: List[Boolean] = settings.toList.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)
case _ => ()
}
filteredT.filter = setFilterFunction
}

def setFilterFunction = {
t: List[String] =>
settings.getOrElse(t(2),false)
}
extends FilteredTable(List("", titles),
tuples.zip(options).map(t =>
t match {
case (s, true) => List("[X]", s)
case (s, false) => List("[ ]", s)
}), fullScreen, screen, tg) {

var settings: HashMap[String, Boolean] = {
var m = new HashMap[String, Boolean]
tuples.zip(options) foreach {
case (action, option) => m = m.updated(action, option)
}
m
}

override def updateValues = {
nRows = terminalSize.getRows - 2
filteredRows = {
settings.toList map { (t: (String, Boolean)) =>
t match {
case (s, true) => List("[X]", s)
case (s, false) => List("[ ]", s)
}
}
}
updateRows
}

def switchOption(r: List[String]) = {
settings.toList foreach {
case (s, true) if r(1) == s =>
val values: List[Boolean] = settings.toList.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)
case _ => ()
}
filteredT.filter = setFilterFunction
}

def setFilterFunction = {
t: List[String] =>
settings.getOrElse(t(2), false)
}
}

0 comments on commit 4330ca7

Please sign in to comment.