1 | /* |
2 | Copyright (C) 2007 by Robert Knight <robertknight@gmail.com> |
3 | |
4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by |
6 | the Free Software Foundation; either version 2 of the License, or |
7 | (at your option) any later version. |
8 | |
9 | This program is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
17 | 02110-1301 USA. |
18 | */ |
19 | |
20 | // Own |
21 | #include "ScreenWindow.h" |
22 | |
23 | // Qt |
24 | #include <QtDebug> |
25 | |
26 | // Konsole |
27 | #include "Screen.h" |
28 | |
29 | using namespace Konsole; |
30 | |
31 | ScreenWindow::ScreenWindow(QObject* parent) |
32 | : QObject(parent) |
33 | , _windowBuffer(0) |
34 | , _windowBufferSize(0) |
35 | , _bufferNeedsUpdate(true) |
36 | , _windowLines(1) |
37 | , _currentLine(0) |
38 | , _trackOutput(true) |
39 | , _scrollCount(0) |
40 | { |
41 | } |
42 | ScreenWindow::~ScreenWindow() |
43 | { |
44 | delete[] _windowBuffer; |
45 | } |
46 | void ScreenWindow::setScreen(Screen* screen) |
47 | { |
48 | Q_ASSERT( screen ); |
49 | |
50 | _screen = screen; |
51 | } |
52 | |
53 | Screen* ScreenWindow::screen() const |
54 | { |
55 | return _screen; |
56 | } |
57 | |
58 | Character* ScreenWindow::getImage() |
59 | { |
60 | // reallocate internal buffer if the window size has changed |
61 | int size = windowLines() * windowColumns(); |
62 | if (_windowBuffer == 0 || _windowBufferSize != size) |
63 | { |
64 | delete[] _windowBuffer; |
65 | _windowBufferSize = size; |
66 | _windowBuffer = new Character[size]; |
67 | _bufferNeedsUpdate = true; |
68 | } |
69 | |
70 | if (!_bufferNeedsUpdate) |
71 | return _windowBuffer; |
72 | |
73 | _screen->getImage(_windowBuffer,size, |
74 | currentLine(),endWindowLine()); |
75 | |
76 | // this window may look beyond the end of the screen, in which |
77 | // case there will be an unused area which needs to be filled |
78 | // with blank characters |
79 | fillUnusedArea(); |
80 | |
81 | _bufferNeedsUpdate = false; |
82 | return _windowBuffer; |
83 | } |
84 | |
85 | void ScreenWindow::fillUnusedArea() |
86 | { |
87 | int screenEndLine = _screen->getHistLines() + _screen->getLines() - 1; |
88 | int windowEndLine = currentLine() + windowLines() - 1; |
89 | |
90 | int unusedLines = windowEndLine - screenEndLine; |
91 | int charsToFill = unusedLines * windowColumns(); |
92 | |
93 | Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill,charsToFill); |
94 | } |
95 | |
96 | // return the index of the line at the end of this window, or if this window |
97 | // goes beyond the end of the screen, the index of the line at the end |
98 | // of the screen. |
99 | // |
100 | // when passing a line number to a Screen method, the line number should |
101 | // never be more than endWindowLine() |
102 | // |
103 | int ScreenWindow::endWindowLine() const |
104 | { |
105 | return qMin(currentLine() + windowLines() - 1, |
106 | lineCount() - 1); |
107 | } |
108 | QVector<LineProperty> ScreenWindow::getLineProperties() |
109 | { |
110 | QVector<LineProperty> result = _screen->getLineProperties(currentLine(),endWindowLine()); |
111 | |
112 | if (result.count() != windowLines()) |
113 | result.resize(windowLines()); |
114 | |
115 | return result; |
116 | } |
117 | |
118 | QString ScreenWindow::selectedText( bool preserveLineBreaks ) const |
119 | { |
120 | return _screen->selectedText( preserveLineBreaks ); |
121 | } |
122 | |
123 | void ScreenWindow::getSelectionStart( int& column , int& line ) |
124 | { |
125 | _screen->getSelectionStart(column,line); |
126 | line -= currentLine(); |
127 | } |
128 | void ScreenWindow::getSelectionEnd( int& column , int& line ) |
129 | { |
130 | _screen->getSelectionEnd(column,line); |
131 | line -= currentLine(); |
132 | } |
133 | void ScreenWindow::setSelectionStart( int column , int line , bool columnMode ) |
134 | { |
135 | _screen->setSelectionStart( column , qMin(line + currentLine(),endWindowLine()) , columnMode); |
136 | |
137 | _bufferNeedsUpdate = true; |
138 | emit selectionChanged(); |
139 | } |
140 | |
141 | void ScreenWindow::setSelectionEnd( int column , int line ) |
142 | { |
143 | _screen->setSelectionEnd( column , qMin(line + currentLine(),endWindowLine()) ); |
144 | |
145 | _bufferNeedsUpdate = true; |
146 | emit selectionChanged(); |
147 | } |
148 | |
149 | bool ScreenWindow::isSelected( int column , int line ) |
150 | { |
151 | return _screen->isSelected( column , qMin(line + currentLine(),endWindowLine()) ); |
152 | } |
153 | |
154 | void ScreenWindow::clearSelection() |
155 | { |
156 | _screen->clearSelection(); |
157 | |
158 | emit selectionChanged(); |
159 | } |
160 | |
161 | void ScreenWindow::setWindowLines(int lines) |
162 | { |
163 | Q_ASSERT(lines > 0); |
164 | _windowLines = lines; |
165 | } |
166 | int ScreenWindow::windowLines() const |
167 | { |
168 | return _windowLines; |
169 | } |
170 | |
171 | int ScreenWindow::windowColumns() const |
172 | { |
173 | return _screen->getColumns(); |
174 | } |
175 | |
176 | int ScreenWindow::lineCount() const |
177 | { |
178 | return _screen->getHistLines() + _screen->getLines(); |
179 | } |
180 | |
181 | int ScreenWindow::columnCount() const |
182 | { |
183 | return _screen->getColumns(); |
184 | } |
185 | |
186 | QPoint ScreenWindow::cursorPosition() const |
187 | { |
188 | QPoint position; |
189 | |
190 | position.setX( _screen->getCursorX() ); |
191 | position.setY( _screen->getCursorY() ); |
192 | |
193 | return position; |
194 | } |
195 | |
196 | int ScreenWindow::currentLine() const |
197 | { |
198 | return qBound(0,_currentLine,lineCount()-windowLines()); |
199 | } |
200 | |
201 | void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount ) |
202 | { |
203 | if ( mode == ScrollLines ) |
204 | { |
205 | scrollTo( currentLine() + amount ); |
206 | } |
207 | else if ( mode == ScrollPages ) |
208 | { |
209 | scrollTo( currentLine() + amount * ( windowLines() / 2 ) ); |
210 | } |
211 | } |
212 | |
213 | bool ScreenWindow::atEndOfOutput() const |
214 | { |
215 | return currentLine() == (lineCount()-windowLines()); |
216 | } |
217 | |
218 | void ScreenWindow::scrollTo( int line ) |
219 | { |
220 | int maxCurrentLineNumber = lineCount() - windowLines(); |
221 | line = qBound(0,line,maxCurrentLineNumber); |
222 | |
223 | const int delta = line - _currentLine; |
224 | _currentLine = line; |
225 | |
226 | // keep track of number of lines scrolled by, |
227 | // this can be reset by calling resetScrollCount() |
228 | _scrollCount += delta; |
229 | |
230 | _bufferNeedsUpdate = true; |
231 | |
232 | emit scrolled(_currentLine); |
233 | } |
234 | |
235 | void ScreenWindow::setTrackOutput(bool trackOutput) |
236 | { |
237 | _trackOutput = trackOutput; |
238 | } |
239 | |
240 | bool ScreenWindow::trackOutput() const |
241 | { |
242 | return _trackOutput; |
243 | } |
244 | |
245 | int ScreenWindow::scrollCount() const |
246 | { |
247 | return _scrollCount; |
248 | } |
249 | |
250 | void ScreenWindow::resetScrollCount() |
251 | { |
252 | _scrollCount = 0; |
253 | } |
254 | |
255 | QRect ScreenWindow::scrollRegion() const |
256 | { |
257 | bool equalToScreenSize = windowLines() == _screen->getLines(); |
258 | |
259 | if ( atEndOfOutput() && equalToScreenSize ) |
260 | return _screen->lastScrolledRegion(); |
261 | else |
262 | return QRect(0,0,windowColumns(),windowLines()); |
263 | } |
264 | |
265 | void ScreenWindow::notifyOutputChanged() |
266 | { |
267 | // move window to the bottom of the screen and update scroll count |
268 | // if this window is currently tracking the bottom of the screen |
269 | if ( _trackOutput ) |
270 | { |
271 | _scrollCount -= _screen->scrolledLines(); |
272 | _currentLine = qMax(0,_screen->getHistLines() - (windowLines()-_screen->getLines())); |
273 | } |
274 | else |
275 | { |
276 | // if the history is not unlimited then it may |
277 | // have run out of space and dropped the oldest |
278 | // lines of output - in this case the screen |
279 | // window's current line number will need to |
280 | // be adjusted - otherwise the output will scroll |
281 | _currentLine = qMax(0,_currentLine - |
282 | _screen->droppedLines()); |
283 | |
284 | // ensure that the screen window's current position does |
285 | // not go beyond the bottom of the screen |
286 | _currentLine = qMin( _currentLine , _screen->getHistLines() ); |
287 | } |
288 | |
289 | _bufferNeedsUpdate = true; |
290 | |
291 | emit outputChanged(); |
292 | } |
293 | |
294 | //#include "ScreenWindow.moc" |
295 | |