001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.hbtop.terminal.impl;
019
020import static org.apache.hadoop.hbase.hbtop.terminal.impl.EscapeSequences.clearRemainingLine;
021import static org.apache.hadoop.hbase.hbtop.terminal.impl.EscapeSequences.color;
022import static org.apache.hadoop.hbase.hbtop.terminal.impl.EscapeSequences.cursor;
023import static org.apache.hadoop.hbase.hbtop.terminal.impl.EscapeSequences.moveCursor;
024import static org.apache.hadoop.hbase.hbtop.terminal.impl.EscapeSequences.normal;
025
026import java.io.PrintWriter;
027import org.apache.hadoop.hbase.hbtop.terminal.Attributes;
028import org.apache.hadoop.hbase.hbtop.terminal.CursorPosition;
029import org.apache.yetus.audience.InterfaceAudience;
030
031
032/**
033 * Represents a buffer of the terminal screen for double-buffering.
034 */
035@InterfaceAudience.Private
036public class ScreenBuffer {
037  private int columns;
038  private int rows;
039
040  private Cell[][] buffer;
041  private Cell[][] physical;
042
043  private boolean cursorVisible;
044  private int cursorColumn;
045  private int cursorRow;
046
047  public void reallocate(int columns, int rows) {
048    buffer = new Cell[columns][rows];
049    physical = new Cell[columns][rows];
050
051    for (int row = 0; row < rows; row++) {
052      for (int column = 0; column < columns; column++) {
053        buffer[column][row] = new Cell();
054
055        physical[column][row] = new Cell();
056        physical[column][row].unset();
057      }
058    }
059
060    this.columns = columns;
061    this.rows = rows;
062  }
063
064  public void clear() {
065    for (int row = 0; row < rows; row++) {
066      for (int col = 0; col < columns; col++) {
067        buffer[col][row].reset();
068      }
069    }
070  }
071
072  public void flush(PrintWriter output) {
073    StringBuilder sb = new StringBuilder();
074
075    sb.append(normal());
076    Attributes attributes = new Attributes();
077    for (int row = 0; row < rows; row++) {
078      flushRow(row, sb, attributes);
079    }
080
081    if (cursorVisible && cursorRow >= 0 && cursorColumn >= 0 && cursorRow < rows &&
082      cursorColumn < columns) {
083      sb.append(cursor(true));
084      sb.append(moveCursor(cursorColumn, cursorRow));
085    } else {
086      sb.append(cursor(false));
087    }
088
089    output.write(sb.toString());
090    output.flush();
091  }
092
093  private void flushRow(int row, StringBuilder sb, Attributes lastAttributes) {
094    int lastColumn = -1;
095    for (int column = 0; column < columns; column++) {
096      Cell cell = buffer[column][row];
097      Cell pCell = physical[column][row];
098
099      if (!cell.equals(pCell)) {
100        if (lastColumn != column - 1 || lastColumn == -1) {
101          sb.append(moveCursor(column, row));
102        }
103
104        if (cell.isEndOfLine()) {
105          for (int i = column; i < columns; i++) {
106            physical[i][row].set(buffer[i][row]);
107          }
108
109          sb.append(clearRemainingLine());
110          lastAttributes.reset();
111          return;
112        }
113
114        if (!cell.getAttributes().equals(lastAttributes)) {
115          sb.append(color(cell.getForegroundColor(), cell.getBackgroundColor(), cell.isBold(),
116            cell.isReverse(), cell.isBlink(), cell.isUnderline()));
117        }
118
119        sb.append(cell.getChar());
120
121        lastColumn = column;
122        lastAttributes.set(cell.getAttributes());
123
124        physical[column][row].set(cell);
125      }
126    }
127  }
128
129  public CursorPosition getCursorPosition() {
130    return new CursorPosition(cursorColumn, cursorRow);
131  }
132
133  public void setCursorPosition(int column, int row) {
134    cursorVisible = true;
135    cursorColumn = column;
136    cursorRow = row;
137  }
138
139  public void hideCursor() {
140    cursorVisible = false;
141  }
142
143  public void putString(int column, int row, String string, Attributes attributes) {
144    int i = column;
145    for (int j = 0; j < string.length(); j++) {
146      char ch = string.charAt(j);
147      putChar(i, row, ch, attributes);
148      i += 1;
149      if (i == columns) {
150        break;
151      }
152    }
153  }
154
155  public void putChar(int column, int row, char ch, Attributes attributes) {
156    if (column >= 0 && column < columns && row >= 0 && row < rows) {
157      buffer[column][row].setAttributes(attributes);
158      buffer[column][row].setChar(ch);
159    }
160  }
161
162  public void endOfLine(int column, int row) {
163    if (column >= 0 && column < columns && row >= 0 && row < rows) {
164      buffer[column][row].endOfLine();
165      for (int i = column + 1; i < columns; i++) {
166        buffer[i][row].reset();
167      }
168    }
169  }
170}