public void incrementSelection(int rows) {
		int rowSelected = getSelectedRow();

		if (rowSelected < 0 && model.selectedByteStart >= 0) {
			try {
				model.clear();
				clear();
				List<String> lines = reader.readNextChunkFrom(model.selectedByteStart);
				((FVTableModel) getModel()).addRowsToTop(lines);
			}
			catch (IOException e) {
				Msg.error(this, "Error reading next chunk of data starting from byte " +
					model.selectedByteStart, e);
			}
		}

		else if (rowSelected + rows < getRowCount()) {
			Pair byteRange = model.getFilePositionForRow(rowSelected + rows);
			if (byteRange == null) {
				return;
			}
			model.selectedByteStart = byteRange.getStart();
			model.selectedByteEnd = byteRange.getEnd();

			if (!viewportUtility.isInViewport(rowSelected + rows)) {
				viewportUtility.scrollViewportTo(rowSelected + rows);
			}
		}
		else {
			try {

				List<String> lines = reader.readNextChunk();

				if (lines.size() == 0) {
					return;
				}

				((FVTableModel) getModel()).addRowsToBottom(lines);

				Pair byteRange = model.getFilePositionForRow(rowSelected + rows);
				if (byteRange == null) {
					return;
				}
				model.selectedByteStart = byteRange.getStart();
				model.selectedByteEnd = byteRange.getEnd();

				SwingUtilities.invokeLater(() -> {
					if (model.getSize() > model.MAX_VISIBLE_CHUNKS) {
						Chunk chunk = model.remove(0);
						if (chunk == null) {
							return;
						}
						((FVTableModel) getModel()).removeRowsFromTop(chunk.linesInChunk);
	
						// Now slide the viewport back up to account for what we just read in.
						viewportUtility.moveViewportUp(chunk.linesInChunk, false);
					}
				});

			}
			catch (IOException e) {
				Msg.error(this, "Error reading next chunk of data", e);
			}
		}
	}
Moves the table selection down by the number of rows specified, ensuring that selection
does not go beyond the bounds of the file.

@param rows
Ghidra/Framework/Project/src/main/java/ghidra/framework/main/logviewer/ui/FVTable.java