How it works
The main purpose of Rowscope is to read rows from a file, filter them, and present them in a table.
And RowScope has to this without blocking.
So, it has been natural to organize it as pipeline of threads connected by queues or, better, as a pipeline of Scala actors:
RowsFilter and RowsService+FileReader are separate threads.
When requested (button Load), the Rows Filter requests rows to the Rows Service.
The Rows Service uses the File Reader to read a certain amount of rows, that it sends to the Rows Filter, in form of messages.
The Rows Filter filters the received rows with the search text, and sends the matching rows to the table, that shows them.
Then the Rows Filter requests other rows until the number of matching rows is 1000.
When a row gets expanded, the same principle is used;
ExpansionRows and RowsService+FileReader are separate threads.
The RowsService and FilterReader objects are the same as in the main pipeline.
The ExpansionRows object requests the rows (preceding or following the
expanded row) and, when the RowsService responds with them, it sends
them to the table, so that they are displayed.
There is one ExpansionRows object for each expanded row.