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
29using namespace Konsole;
30
31ScreenWindow::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}
42ScreenWindow::~ScreenWindow()
43{
44 delete[] _windowBuffer;
45}
46void ScreenWindow::setScreen(Screen* screen)
47{
48 Q_ASSERT( screen );
49
50 _screen = screen;
51}
52
53Screen* ScreenWindow::screen() const
54{
55 return _screen;
56}
57
58Character* 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
85void 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//
103int ScreenWindow::endWindowLine() const
104{
105 return qMin(currentLine() + windowLines() - 1,
106 lineCount() - 1);
107}
108QVector<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
118QString ScreenWindow::selectedText( bool preserveLineBreaks ) const
119{
120 return _screen->selectedText( preserveLineBreaks );
121}
122
123void ScreenWindow::getSelectionStart( int& column , int& line )
124{
125 _screen->getSelectionStart(column,line);
126 line -= currentLine();
127}
128void ScreenWindow::getSelectionEnd( int& column , int& line )
129{
130 _screen->getSelectionEnd(column,line);
131 line -= currentLine();
132}
133void 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
141void ScreenWindow::setSelectionEnd( int column , int line )
142{
143 _screen->setSelectionEnd( column , qMin(line + currentLine(),endWindowLine()) );
144
145 _bufferNeedsUpdate = true;
146 emit selectionChanged();
147}
148
149bool ScreenWindow::isSelected( int column , int line )
150{
151 return _screen->isSelected( column , qMin(line + currentLine(),endWindowLine()) );
152}
153
154void ScreenWindow::clearSelection()
155{
156 _screen->clearSelection();
157
158 emit selectionChanged();
159}
160
161void ScreenWindow::setWindowLines(int lines)
162{
163 Q_ASSERT(lines > 0);
164 _windowLines = lines;
165}
166int ScreenWindow::windowLines() const
167{
168 return _windowLines;
169}
170
171int ScreenWindow::windowColumns() const
172{
173 return _screen->getColumns();
174}
175
176int ScreenWindow::lineCount() const
177{
178 return _screen->getHistLines() + _screen->getLines();
179}
180
181int ScreenWindow::columnCount() const
182{
183 return _screen->getColumns();
184}
185
186QPoint ScreenWindow::cursorPosition() const
187{
188 QPoint position;
189
190 position.setX( _screen->getCursorX() );
191 position.setY( _screen->getCursorY() );
192
193 return position;
194}
195
196int ScreenWindow::currentLine() const
197{
198 return qBound(0,_currentLine,lineCount()-windowLines());
199}
200
201void 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
213bool ScreenWindow::atEndOfOutput() const
214{
215 return currentLine() == (lineCount()-windowLines());
216}
217
218void 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
235void ScreenWindow::setTrackOutput(bool trackOutput)
236{
237 _trackOutput = trackOutput;
238}
239
240bool ScreenWindow::trackOutput() const
241{
242 return _trackOutput;
243}
244
245int ScreenWindow::scrollCount() const
246{
247 return _scrollCount;
248}
249
250void ScreenWindow::resetScrollCount()
251{
252 _scrollCount = 0;
253}
254
255QRect 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
265void 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