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
ScreenWindow(QObject * parent)31 ScreenWindow::ScreenWindow(QObject* parent)
32 : QObject(parent)
33 , _screen(0)
34 , _windowBuffer(0)
35 , _windowBufferSize(0)
36 , _bufferNeedsUpdate(true)
37 , _windowLines(1)
38 , _currentLine(0)
39 , _trackOutput(true)
40 , _scrollCount(0)
41 {
42 }
~ScreenWindow()43 ScreenWindow::~ScreenWindow()
44 {
45 delete[] _windowBuffer;
46 }
setScreen(Screen * screen)47 void ScreenWindow::setScreen(Screen* screen)
48 {
49 Q_ASSERT( screen );
50
51 _screen = screen;
52 }
53
screen() const54 Screen* ScreenWindow::screen() const
55 {
56 return _screen;
57 }
58
getImage()59 Character* ScreenWindow::getImage()
60 {
61 // reallocate internal buffer if the window size has changed
62 int size = windowLines() * windowColumns();
63 if (_windowBuffer == 0 || _windowBufferSize != size)
64 {
65 delete[] _windowBuffer;
66 _windowBufferSize = size;
67 _windowBuffer = new Character[size];
68 _bufferNeedsUpdate = true;
69 }
70
71 if (!_bufferNeedsUpdate)
72 return _windowBuffer;
73
74 _screen->getImage(_windowBuffer,size,
75 currentLine(),endWindowLine());
76
77 // this window may look beyond the end of the screen, in which
78 // case there will be an unused area which needs to be filled
79 // with blank characters
80 fillUnusedArea();
81
82 _bufferNeedsUpdate = false;
83 return _windowBuffer;
84 }
85
fillUnusedArea()86 void ScreenWindow::fillUnusedArea()
87 {
88 int screenEndLine = _screen->getHistLines() + _screen->getLines() - 1;
89 int windowEndLine = currentLine() + windowLines() - 1;
90
91 int unusedLines = windowEndLine - screenEndLine;
92 int charsToFill = unusedLines * windowColumns();
93
94 Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill,charsToFill);
95 }
96
97 // return the index of the line at the end of this window, or if this window
98 // goes beyond the end of the screen, the index of the line at the end
99 // of the screen.
100 //
101 // when passing a line number to a Screen method, the line number should
102 // never be more than endWindowLine()
103 //
endWindowLine() const104 int ScreenWindow::endWindowLine() const
105 {
106 return std::min(currentLine() + windowLines() - 1,
107 lineCount() - 1);
108 }
getLineProperties()109 QVector<LineProperty> ScreenWindow::getLineProperties()
110 {
111 QVector<LineProperty> result = _screen->getLineProperties(currentLine(),endWindowLine());
112
113 if (result.count() != windowLines())
114 result.resize(windowLines());
115
116 return result;
117 }
118
selectedText(bool preserveLineBreaks) const119 QString ScreenWindow::selectedText( bool preserveLineBreaks ) const
120 {
121 return _screen->selectedText( preserveLineBreaks );
122 }
123
getSelectionStart(int & column,int & line)124 void ScreenWindow::getSelectionStart( int& column , int& line )
125 {
126 _screen->getSelectionStart(column,line);
127 line -= currentLine();
128 }
getSelectionEnd(int & column,int & line)129 void ScreenWindow::getSelectionEnd( int& column , int& line )
130 {
131 _screen->getSelectionEnd(column,line);
132 line -= currentLine();
133 }
setSelectionStart(int column,int line,bool columnMode)134 void ScreenWindow::setSelectionStart( int column , int line , bool columnMode )
135 {
136 _screen->setSelectionStart( column , std::min(line + currentLine(),endWindowLine()) , columnMode);
137
138 _bufferNeedsUpdate = true;
139 emit selectionChanged();
140 }
141
setSelectionEnd(int column,int line)142 void ScreenWindow::setSelectionEnd( int column , int line )
143 {
144 _screen->setSelectionEnd( column , std::min(line + currentLine(),endWindowLine()) );
145
146 _bufferNeedsUpdate = true;
147 emit selectionChanged();
148 }
149
isSelected(int column,int line)150 bool ScreenWindow::isSelected( int column , int line )
151 {
152 return _screen->isSelected( column , std::min(line + currentLine(),endWindowLine()) );
153 }
154
clearSelection()155 void ScreenWindow::clearSelection()
156 {
157 _screen->clearSelection();
158
159 emit selectionChanged();
160 }
161
setWindowLines(int lines)162 void ScreenWindow::setWindowLines(int lines)
163 {
164 Q_ASSERT(lines > 0);
165 _windowLines = lines;
166 }
windowLines() const167 int ScreenWindow::windowLines() const
168 {
169 return _windowLines;
170 }
171
windowColumns() const172 int ScreenWindow::windowColumns() const
173 {
174 return _screen->getColumns();
175 }
176
lineCount() const177 int ScreenWindow::lineCount() const
178 {
179 return _screen->getHistLines() + _screen->getLines();
180 }
181
columnCount() const182 int ScreenWindow::columnCount() const
183 {
184 return _screen->getColumns();
185 }
186
cursorPosition() const187 QPoint ScreenWindow::cursorPosition() const
188 {
189 QPoint position;
190
191 position.setX( _screen->getCursorX() );
192 position.setY( _screen->getCursorY() );
193
194 return position;
195 }
196
currentLine() const197 int ScreenWindow::currentLine() const
198 {
199 return qBound(0,_currentLine,lineCount()-windowLines());
200 }
201
scrollBy(RelativeScrollMode mode,int amount)202 void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount )
203 {
204 if ( mode == ScrollLines )
205 {
206 scrollTo( currentLine() + amount );
207 }
208 else if ( mode == ScrollPages )
209 {
210 scrollTo( currentLine() + amount * ( windowLines() / 2 ) );
211 }
212 }
213
atEndOfOutput() const214 bool ScreenWindow::atEndOfOutput() const
215 {
216 return currentLine() == (lineCount()-windowLines());
217 }
218
scrollTo(int line)219 void ScreenWindow::scrollTo( int line )
220 {
221 int maxCurrentLineNumber = lineCount() - windowLines();
222 line = qBound(0,line,maxCurrentLineNumber);
223
224 const int delta = line - _currentLine;
225 _currentLine = line;
226
227 // keep track of number of lines scrolled by,
228 // this can be reset by calling resetScrollCount()
229 _scrollCount += delta;
230
231 _bufferNeedsUpdate = true;
232
233 emit scrolled(_currentLine);
234 }
235
setTrackOutput(bool trackOutput)236 void ScreenWindow::setTrackOutput(bool trackOutput)
237 {
238 _trackOutput = trackOutput;
239 }
240
trackOutput() const241 bool ScreenWindow::trackOutput() const
242 {
243 return _trackOutput;
244 }
245
scrollCount() const246 int ScreenWindow::scrollCount() const
247 {
248 return _scrollCount;
249 }
250
resetScrollCount()251 void ScreenWindow::resetScrollCount()
252 {
253 _scrollCount = 0;
254 }
255
scrollRegion() const256 QRect ScreenWindow::scrollRegion() const
257 {
258 bool equalToScreenSize = windowLines() == _screen->getLines();
259
260 if ( atEndOfOutput() && equalToScreenSize )
261 return _screen->lastScrolledRegion();
262 else
263 return QRect(0,0,windowColumns(),windowLines());
264 }
265
notifyOutputChanged()266 void ScreenWindow::notifyOutputChanged()
267 {
268 // move window to the bottom of the screen and update scroll count
269 // if this window is currently tracking the bottom of the screen
270 if ( _trackOutput )
271 {
272 _scrollCount -= _screen->scrolledLines();
273 _currentLine = std::max(0,_screen->getHistLines() - (windowLines()-_screen->getLines()));
274 }
275 else
276 {
277 // if the history is not unlimited then it may
278 // have run out of space and dropped the oldest
279 // lines of output - in this case the screen
280 // window's current line number will need to
281 // be adjusted - otherwise the output will scroll
282 _currentLine = std::max(0,_currentLine -
283 _screen->droppedLines());
284
285 // ensure that the screen window's current position does
286 // not go beyond the bottom of the screen
287 _currentLine = std::min( _currentLine , _screen->getHistLines() );
288 }
289
290 _bufferNeedsUpdate = true;
291
292 emit outputChanged();
293 }
294
295 //#include "ScreenWindow.moc"
296