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