File indexing completed on 2025-01-19 04:23:30

0001 /*
0002     Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
0003 
0004     This program is free software; you can redistribute it and/or modify
0005     it under the terms of the GNU General Public License as published by
0006     the Free Software Foundation; either version 2 of the License, or
0007     (at your option) any later version.
0008 
0009     This program is distributed in the hope that it will be useful,
0010     but WITHOUT ANY WARRANTY; without even the implied warranty of
0011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012     GNU General Public License for more details.
0013 
0014     You should have received a copy of the GNU General Public License
0015     along with this program; if not, write to the Free Software
0016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0017     02110-1301  USA.
0018 */
0019 
0020 // Own
0021 #include "ScreenWindow.h"
0022 
0023 // Qt
0024 #include <QtDebug>
0025 
0026 // Konsole
0027 #include "Screen.h"
0028 
0029 using namespace Konsole;
0030 
0031 ScreenWindow::ScreenWindow(QObject* parent)
0032     : QObject(parent)
0033     , _windowBuffer(0)
0034     , _windowBufferSize(0)
0035     , _bufferNeedsUpdate(true)
0036     , _windowLines(1)
0037     , _currentLine(0)
0038     , _trackOutput(true)
0039     , _scrollCount(0)
0040 {
0041 }
0042 ScreenWindow::~ScreenWindow()
0043 {
0044     delete[] _windowBuffer;
0045 }
0046 void ScreenWindow::setScreen(Screen* screen)
0047 {
0048     Q_ASSERT( screen );
0049 
0050     _screen = screen;
0051 }
0052 
0053 Screen* ScreenWindow::screen() const
0054 {
0055     return _screen;
0056 }
0057 
0058 Character* ScreenWindow::getImage()
0059 {
0060     // reallocate internal buffer if the window size has changed
0061     int size = windowLines() * windowColumns();
0062     if (_windowBuffer == 0 || _windowBufferSize != size)
0063     {
0064         delete[] _windowBuffer;
0065         _windowBufferSize = size;
0066         _windowBuffer = new Character[size];
0067         _bufferNeedsUpdate = true;
0068     }
0069 
0070      if (!_bufferNeedsUpdate)
0071         return _windowBuffer;
0072 
0073     _screen->getImage(_windowBuffer,size,
0074                       currentLine(),endWindowLine());
0075 
0076     // this window may look beyond the end of the screen, in which
0077     // case there will be an unused area which needs to be filled
0078     // with blank characters
0079     fillUnusedArea();
0080 
0081     _bufferNeedsUpdate = false;
0082     return _windowBuffer;
0083 }
0084 
0085 void ScreenWindow::fillUnusedArea()
0086 {
0087     int screenEndLine = _screen->getHistLines() + _screen->getLines() - 1;
0088     int windowEndLine = currentLine() + windowLines() - 1;
0089 
0090     int unusedLines = windowEndLine - screenEndLine;
0091     int charsToFill = unusedLines * windowColumns();
0092 
0093     Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill,charsToFill);
0094 }
0095 
0096 // return the index of the line at the end of this window, or if this window
0097 // goes beyond the end of the screen, the index of the line at the end
0098 // of the screen.
0099 //
0100 // when passing a line number to a Screen method, the line number should
0101 // never be more than endWindowLine()
0102 //
0103 int ScreenWindow::endWindowLine() const
0104 {
0105     return qMin(currentLine() + windowLines() - 1,
0106                 lineCount() - 1);
0107 }
0108 QVector<LineProperty> ScreenWindow::getLineProperties()
0109 {
0110     QVector<LineProperty> result = _screen->getLineProperties(currentLine(),endWindowLine());
0111 
0112     if (result.count() != windowLines())
0113         result.resize(windowLines());
0114 
0115     return result;
0116 }
0117 
0118 QString ScreenWindow::selectedText( bool preserveLineBreaks ) const
0119 {
0120     return _screen->selectedText( preserveLineBreaks );
0121 }
0122 
0123 void ScreenWindow::getSelectionStart( int& column , int& line )
0124 {
0125     _screen->getSelectionStart(column,line);
0126     line -= currentLine();
0127 }
0128 void ScreenWindow::getSelectionEnd( int& column , int& line )
0129 {
0130     _screen->getSelectionEnd(column,line);
0131     line -= currentLine();
0132 }
0133 void ScreenWindow::setSelectionStart( int column , int line , bool columnMode )
0134 {
0135     _screen->setSelectionStart( column , qMin(line + currentLine(),endWindowLine())  , columnMode);
0136 
0137     _bufferNeedsUpdate = true;
0138     Q_EMIT selectionChanged();
0139 }
0140 
0141 void ScreenWindow::setSelectionEnd( int column , int line )
0142 {
0143     _screen->setSelectionEnd( column , qMin(line + currentLine(),endWindowLine()) );
0144 
0145     _bufferNeedsUpdate = true;
0146     Q_EMIT selectionChanged();
0147 }
0148 
0149 bool ScreenWindow::isSelected( int column , int line )
0150 {
0151     return _screen->isSelected( column , qMin(line + currentLine(),endWindowLine()) );
0152 }
0153 
0154 void ScreenWindow::clearSelection()
0155 {
0156     _screen->clearSelection();
0157 
0158     Q_EMIT selectionChanged();
0159 }
0160 
0161 void ScreenWindow::setWindowLines(int lines)
0162 {
0163     Q_ASSERT(lines > 0);
0164     _windowLines = lines;
0165 }
0166 int ScreenWindow::windowLines() const
0167 {
0168     return _windowLines;
0169 }
0170 
0171 int ScreenWindow::windowColumns() const
0172 {
0173     return _screen->getColumns();
0174 }
0175 
0176 int ScreenWindow::lineCount() const
0177 {
0178     return _screen->getHistLines() + _screen->getLines();
0179 }
0180 
0181 int ScreenWindow::columnCount() const
0182 {
0183     return _screen->getColumns();
0184 }
0185 
0186 QPoint ScreenWindow::cursorPosition() const
0187 {
0188     QPoint position;
0189 
0190     position.setX( _screen->getCursorX() );
0191     position.setY( _screen->getCursorY() );
0192 
0193     return position;
0194 }
0195 
0196 int ScreenWindow::currentLine() const
0197 {
0198     return qBound(0,_currentLine,lineCount()-windowLines());
0199 }
0200 
0201 void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount )
0202 {
0203     if ( mode == ScrollLines )
0204     {
0205         scrollTo( currentLine() + amount );
0206     }
0207     else if ( mode == ScrollPages )
0208     {
0209         scrollTo( currentLine() + amount * ( windowLines() / 2 ) );
0210     }
0211 }
0212 
0213 bool ScreenWindow::atEndOfOutput() const
0214 {
0215     return currentLine() == (lineCount()-windowLines());
0216 }
0217 
0218 void ScreenWindow::scrollTo( int line )
0219 {
0220     int maxCurrentLineNumber = lineCount() - windowLines();
0221     line = qBound(0,line,maxCurrentLineNumber);
0222 
0223     const int delta = line - _currentLine;
0224     _currentLine = line;
0225 
0226     // keep track of number of lines scrolled by,
0227     // this can be reset by calling resetScrollCount()
0228     _scrollCount += delta;
0229 
0230     _bufferNeedsUpdate = true;
0231 
0232     Q_EMIT scrolled(_currentLine);
0233 }
0234 
0235 void ScreenWindow::setTrackOutput(bool trackOutput)
0236 {
0237     _trackOutput = trackOutput;
0238 }
0239 
0240 bool ScreenWindow::trackOutput() const
0241 {
0242     return _trackOutput;
0243 }
0244 
0245 int ScreenWindow::scrollCount() const
0246 {
0247     return _scrollCount;
0248 }
0249 
0250 void ScreenWindow::resetScrollCount()
0251 {
0252     _scrollCount = 0;
0253 }
0254 
0255 QRect ScreenWindow::scrollRegion() const
0256 {
0257     bool equalToScreenSize = windowLines() == _screen->getLines();
0258 
0259     if ( atEndOfOutput() && equalToScreenSize )
0260         return _screen->lastScrolledRegion();
0261     else
0262         return QRect(0,0,windowColumns(),windowLines());
0263 }
0264 
0265 void ScreenWindow::selectAll()
0266 {
0267     _screen->selectAll();
0268 
0269     _bufferNeedsUpdate = true;
0270     Q_EMIT selectionChanged();
0271 }
0272 
0273 void ScreenWindow::notifyOutputChanged()
0274 {
0275     // move window to the bottom of the screen and update scroll count
0276     // if this window is currently tracking the bottom of the screen
0277     if ( _trackOutput )
0278     {
0279         _scrollCount -= _screen->scrolledLines();
0280         _currentLine = qMax(0,_screen->getHistLines() - (windowLines()-_screen->getLines()));
0281     }
0282     else
0283     {
0284         // if the history is not unlimited then it may
0285         // have run out of space and dropped the oldest
0286         // lines of output - in this case the screen
0287         // window's current line number will need to
0288         // be adjusted - otherwise the output will scroll
0289         _currentLine = qMax(0,_currentLine -
0290                               _screen->droppedLines());
0291 
0292         // ensure that the screen window's current position does
0293         // not go beyond the bottom of the screen
0294         _currentLine = qMin( _currentLine , _screen->getHistLines() );
0295     }
0296 
0297     _bufferNeedsUpdate = true;
0298 
0299     Q_EMIT outputChanged();
0300 }
0301 
0302 //#include "ScreenWindow.moc"